[PATCH v2] virt-make-fs: add '--blocksize' option support
by Mykola Ivanets
From: Nikolay Ivanets <stenavin(a)gmail.com>
This patch adds '--blocksize' command line option for virt-make-fs
tool. This option allows specifying disk sector size as described in
'guestfs_add_drive_opts' libguestfs API.
---
make-fs/make-fs.c | 30 ++++++++++++++++++++++++++++--
make-fs/test-virt-make-fs.sh | 5 ++++-
make-fs/virt-make-fs.pod | 10 ++++++++++
3 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/make-fs/make-fs.c b/make-fs/make-fs.c
index 5d8c3a385..8027b6419 100644
--- a/make-fs/make-fs.c
+++ b/make-fs/make-fs.c
@@ -54,10 +54,12 @@ int in_virt_rescue = 0;
static const char *format = "raw", *label = NULL,
*partition = NULL, *size_str = NULL, *type = "ext2";
+static int blocksize = 0;
enum { HELP_OPTION = CHAR_MAX + 1 };
static const char options[] = "F:s:t:Vvx";
static const struct option long_options[] = {
+ { "blocksize", 1, 0, 0 },
{ "debug", 0, 0, 'v' }, /* for compat with Perl tool */
{ "floppy", 0, 0, 0 },
{ "format", 1, 0, 'F' },
@@ -87,6 +89,7 @@ usage (int status)
" %s [--options] input.tar.gz output.img\n"
" %s [--options] directory output.img\n"
"Options:\n"
+ " --blocksize=512|4096 Set sector size of the output disk\n"
" --floppy Make a virtual floppy disk\n"
" -F|--format=raw|qcow2|.. Set output format\n"
" --help Display brief help\n"
@@ -146,6 +149,9 @@ main (int argc, char *argv[])
partition = "mbr";
else
partition = optarg;
+ } else if (STREQ (long_options[option_index].name, "blocksize")) {
+ if (sscanf (optarg, "%d", &blocksize) != 1)
+ error (EXIT_FAILURE, 0, _("--blocksize option is not numeric"));
} else
error (EXIT_FAILURE, 0,
_("unknown long option: %s (%d)"),
@@ -678,11 +684,23 @@ do_make_fs (const char *input, const char *output_str)
estimate, estimate / 1024, estimate / 4096);
}
+ /* For partition alignment and extra space at the end of the disk: by
+ * default we create first partition at 128 sector boundary and leave the
+ * last 128 sectors at the end of the disk free.
+ */
+ if (partition)
+ estimate += 2 * 128 * blocksize;
+
estimate += 256 * 1024; /* For superblocks &c. */
if (STRPREFIX (type, "ext") && type[3] >= '3') {
- /* For ext3+, add some more for the journal. */
- estimate += 1024 * 1024;
+ /* For ext3+, add some more for the journal. Journal should be at least
+ * 1024 file system blocks. By default file system block size is 1024
+ * bytes if disk sector size is 512 bytes and 4096 bytes if disk sector
+ * size is 4096 bytes. Note that default file system block size may be
+ * changed via /etc/mke2fs.conf but we cannot handle that at the moment.
+ */
+ estimate += 1024 * (blocksize == 512 ? 1024 : 4096);
}
else if (STREQ (type, "ntfs")) {
@@ -697,6 +715,13 @@ do_make_fs (const char *input, const char *output_str)
estimate += 256 * 1024 * 1024;
}
+ else if (STREQ (type, "xfs")) {
+ /* xfs requires at least 4096 file system blocks. By default block size
+ * is 4096 bytes.
+ */
+ estimate += 4096 * 4096;
+ }
+
/* Add 10%, see above. */
estimate *= 1.10;
@@ -718,6 +743,7 @@ do_make_fs (const char *input, const char *output_str)
if (guestfs_add_drive_opts (g, output,
GUESTFS_ADD_DRIVE_OPTS_FORMAT, format,
+ GUESTFS_ADD_DRIVE_OPTS_BLOCKSIZE, blocksize,
-1) == -1)
return -1;
diff --git a/make-fs/test-virt-make-fs.sh b/make-fs/test-virt-make-fs.sh
index 79d058b6a..01c332b1d 100755
--- a/make-fs/test-virt-make-fs.sh
+++ b/make-fs/test-virt-make-fs.sh
@@ -83,9 +83,12 @@ size=`random_choice`
choices=("" --label=FOO)
label=`random_choice`
+choices=(--blocksize=512 --blocksize=4096)
+blocksize=`random_choice`
+
if [ -n "$LIBGUESTFS_DEBUG" ]; then debug=--debug; fi
-params="$type $format $partition $size $label $debug"
+params="$type $format $partition $size $label $blocksize $debug"
echo "test-virt-make-fs: parameters: $params"
rm -f test.file test.tar output.img
diff --git a/make-fs/virt-make-fs.pod b/make-fs/virt-make-fs.pod
index 76ccbd120..bd4802c7c 100644
--- a/make-fs/virt-make-fs.pod
+++ b/make-fs/virt-make-fs.pod
@@ -122,6 +122,16 @@ or rerun virt-make-fs to build another image from scratch.
Display brief help.
+=item B<--blocksize=512>
+
+=item B<--blocksize=4096>
+
+This parameter sets the sector size of the output disk image.
+
+The default is C<512> bytes.
+
+See also L<guestfs(3)/guestfs_add_drive_opts>.
+
=item B<--floppy>
Create a virtual floppy disk.
--
2.17.2
4 years, 9 months
Re: [Libguestfs] [PATCH v2] mlcustomize: Trim whitespaces from commands read from file (RHBZ#1351000)
by Richard W.M. Jones
On Wed, Jan 29, 2020 at 03:07:12PM +0100, Martin Kletzander wrote:
> From: Martin Kletzander <mkletzan(a)redhat.com>
>
> The first split does not care about the whole string, it is just trying to get
> the command name in front, so triml is just right.
>
> Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
> ---
> mlcustomize/customize_cmdline.ml | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/mlcustomize/customize_cmdline.ml b/mlcustomize/customize_cmdline.ml
> index c062379879e2..abd21a4cbca5 100644
> --- a/mlcustomize/customize_cmdline.ml
> +++ b/mlcustomize/customize_cmdline.ml
> @@ -481,6 +481,7 @@ let rec argspec () =
> ] in
> let lines = read_whole_file filename in
> let lines = String.lines_split lines in
> + let lines = List.map String.triml lines in
> let lines = List.filter (
> fun line ->
> String.length line > 0 && line.[0] <> '#'
Seems OK to me, so ACK.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into KVM guests.
http://libguestfs.org/virt-v2v
4 years, 9 months
[PATCH 0/1] virt-make-fs: add '--blocksize' option support
by Mykola Ivanets
From: Nikolay Ivanets <stenavin(a)gmail.com>
This patch adds 4096 bytes sector size for output disk.
Side notes:
While working on this patch I reveal long standing issue: virt-make-fs can fail
if source directory/archive contains certain amount of really small or empty
files or wide tree of directories. That is because of lack of available inodes
on a small file system to keep files structure. In fact, the overall size of the
source is not enought information to create minimal file system which can hold
all files and directories. And in general it is hard-to-impossible to achive
this (while keeping file system as small as possible) for all possible file
systems without relying on internal knowlage about file system organization.
We do very basic adjustments in our estimations but that is not enough.
Nevertheless the above observations are not related to provided patch itself.
Nikolay Ivanets (1):
virt-make-fs: add '--blocksize' option support
make-fs/make-fs.c | 28 ++++++++++++++++++++++++++--
make-fs/test-virt-make-fs.sh | 5 ++++-
make-fs/virt-make-fs.pod | 10 ++++++++++
3 files changed, 40 insertions(+), 3 deletions(-)
--
2.17.2
4 years, 9 months
*** buffer overflow detected *** accessing invalid FD in libguestfs
by Veselin Kozhuharski
We have extended collectd virt plugin to extract info about disk usage from
a libvirt domain using libguestfs. In addition to my previous mail I am
attaching some more infomration about the problem.
Currently the collectd plugin works fine and retrieves the required
statistics. The problem that I face happens after certain number of cycles
(getting disk usage statistics). Collectd is terminated with the following
error:
Feb 20 15:09:36 tve50 collectd[17720]: *** buffer overflow detected ***:
/usr/sbin/collectd terminated
This happens after about 490-500 calls of my statistics read function.
Collectd is terminated with signal SIGABRT with the following backtrace:
(gdb) bt
#0 0x00007ffff71f2e97 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x00007ffff71f4801 in abort () from /lib/x86_64-linux-gnu/libc.so.6
#2 0x00007ffff723d897 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#3 0x00007ffff72e8cff in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#4 0x00007ffff72e8d21 in __fortify_fail () from
/lib/x86_64-linux-gnu/libc.so.6
#5 0x00007ffff72e6a10 in __chk_fail () from /lib/x86_64-linux-gnu/libc.so.6
#6 0x00007ffff72e8c0a in __fdelt_warn () from
/lib/x86_64-linux-gnu/libc.so.6
#7 0x00007ffff47ed8ba in loop (cmd=cmd@entry=0x7fffbc02abe0) at
../../../lib/command.c:662
#8 0x00007ffff47ee2f5 in guestfs_int_cmd_run (cmd=0x7fffbc02abe0) at
../../../lib/command.c:767
#9 0x00007ffff47efefc in disk_create_qcow2 (optargs=0x7fffbc008d60,
backingfile=0x7fffbc09ef30
"/var/lib/nova/instances/5ca86029-d296-4261-9a67-908bdd6c4eab/disk",
size=-1,
orig_filename=0x7fffbc0301f0 "/tmp/libguestfszZtmRI/overlay1.qcow2",
g=0x7fffbc008d60) at ../../../lib/create.c:348
#10 guestfs_impl_disk_create (g=g@entry=0x7fffbc008d60,
filename=filename@entry=0x7fffbc0301f0
"/tmp/libguestfszZtmRI/overlay1.qcow2", format=<optimized out>,
format@entry=0x7ffff4843998 "qcow2", size=size@entry=-1,
optargs=optargs@entry=0x7fffca7fb1a0) at ../../../lib/create.c:88
#11 0x00007ffff4794ca5 in guestfs_disk_create_argv (g=g@entry=0x7fffbc008d60,
filename=filename@entry=0x7fffbc0301f0
"/tmp/libguestfszZtmRI/overlay1.qcow2",
format=format@entry=0x7ffff4843998 "qcow2", size=size@entry=-1,
optargs=optargs@entry=0x7fffca7fb1a0) at ../../../lib/actions-3.c:224
#12 0x00007ffff4807b18 in create_cow_overlay_direct (g=0x7fffbc008d60,
datav=<optimized out>, drv=0x7fffbc03a890) at
../../../lib/launch-direct.c:89
#13 0x00007ffff47f0b44 in create_overlay (g=0x7fffbc008d60,
drv=0x7fffbc03a890) at ../../../lib/drives.c:87
#14 0x00007ffff47f0d7b in create_drive_file (g=g@entry=0x7fffbc008d60,
data=data@entry=0x7fffca7fb2a0) at ../../../lib/drives.c:119
#15 0x00007ffff47f1c55 in guestfs_impl_add_drive_opts
(g=g@entry=0x7fffbc008d60,
filename=<optimized out>,
filename@entry=0x7fffbc10d540
"/var/lib/nova/instances/5ca86029-d296-4261-9a67-908bdd6c4eab/disk",
optargs=optargs@entry=0x7fffca7fb420) at ../../../lib/drives.c:826
#16 0x00007ffff4784927 in guestfs_add_drive_opts_argv
(g=g@entry=0x7fffbc008d60,
filename=filename@entry=0x7fffbc10d540
"/var/lib/nova/instances/5ca86029-d296-4261-9a67-908bdd6c4eab/disk",
optargs=optargs@entry=0x7fffca7fb420) at ../../../lib/actions-2.c:180
#17 0x00007ffff48128e0 in add_disk (g=g@entry=0x7fffbc008d60,
filename=0x7fffbc10d540
"/var/lib/nova/instances/5ca86029-d296-4261-9a67-908bdd6c4eab/disk",
format=<optimized out>,
readonly_in_xml=<optimized out>, protocol=<optimized out>,
server=<optimized out>, username=0x0, secret=0x0, datavp=0x7fffca7fb610) at
../../../lib/libvirt-domain.c:396
#18 0x00007ffff4813cd6 in for_each_disk (f=0x7ffff48127e0 <add_disk>,
data=0x7fffca7fb610, doc=0x7fffbc10cf80, conn=0x7fffbc01fa10,
g=0x7fffbc008d60)
at ../../../lib/libvirt-domain.c:782
#19 guestfs_impl_add_libvirt_dom (g=g@entry=0x7fffbc008d60,
domvp=domvp@entry=0x7fffbc064000, optargs=optargs@entry=0x7fffca7fb790) at
../../../lib/libvirt-domain.c:323
#20 0x00007ffff47ab2c3 in guestfs_add_libvirt_dom_argv
(g=g@entry=0x7fffbc008d60,
dom=dom@entry=0x7fffbc064000, optargs=optargs@entry=0x7fffca7fb790) at
../../../lib/actions-4.c:174
#21 0x00007ffff4812cf6 in guestfs_impl_add_domain (g=g@entry=0x7fffbc008d60,
domain_name=domain_name@entry=0x7fffbc0338e0 "tve50:00000013",
optargs=optargs@entry=0x7fffca7fb8c0)
at ../../../lib/libvirt-domain.c:163
#22 0x00007ffff4760368 in guestfs_add_domain_argv (g=0x7fffbc008d60,
dom=0x7fffbc0338e0 "tve50:00000013", optargs=optargs@entry=0x7fffca7fb8c0)
at ../../../lib/actions-0.c:139
#23 0x00007ffff47dfc38 in guestfs_add_domain_va (g=<optimized out>,
dom=<optimized out>, args=args@entry=0x7fffca7fb920) at
../../../lib/actions-variants.c:107
#24 0x00007ffff47dfee4 in guestfs_add_domain (g=g@entry=0x7fffbc008d60,
dom=dom@entry=0x7fffbc0338e0 "tve50:00000013") at
../../../lib/actions-variants.c:45
#25 0x00007ffff4a78bec in refresh_lists (inst=inst@entry=0x7ffff4c7f940
<lv_read_user_data>) at src/virt.c:2049
#26 0x00007ffff4a7a327 in lv_read (ud=<optimized out>) at src/virt.c:1656
#27 0x0000555555564a1c in plugin_read_thread (args=<optimized out>) at
src/daemon/plugin.c:540
#28 0x00007ffff79b66db in start_thread () from
/lib/x86_64-linux-gnu/libpthread.so.0
#29 0x00007ffff72d588f in clone () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) quit
Deeper analysis shows the error is related to file descriptors handling
using FD_* macros in loop() function, most probably trying to access fd
which is outside the valid range.
Any hints how to avoid or handle this situation would be highly appreciated.
--
*Veselin Kozhuharski** |* Software Engineer
Direct: +359 2 439 2590 ext. 3912 *|* Mobile: +359 887 412116 |
veselin_k*(a)telco.com
<mzabaruk(a)telco.com>*
*Telco Systems | **www.telco.com <http://www.telco.com/>*
Follow us: *LinkedIn <http://www.linkedin.com/company/telco-systems>*
| *Twitter
<http://twitter.com/TelcoSystems>* | *Facebook
<https://www.facebook.com/TelcoSystems>* | *YouTube
<http://www.youtube.com/TelcoSystems>* | *Blog <http://www.telco.com/blog>*
|
4 years, 9 months
[PATCH] docs: fix instructions for building from git
by Daniel P. Berrangé
On current Fedora releases the ocaml modules will fail to
link unless CFLAGS contains -fPIC.
The autogen.sh script only updates the 'gnulib' submodule,
and so the build will fail due to the missing 'common'
submodule. This needs to be manually initialized at checkout.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
The above was required for me to build on Fedora 31, but I
don't think it is entirely satisfactory. IMHO, configure
ought to add -fPIC automatically if it is needed by the
distro. I also expected autogen.sh to update the submodules
besides just gnulib.
docs/guestfs-building.pod | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/guestfs-building.pod b/docs/guestfs-building.pod
index 4bed86391..005626515 100644
--- a/docs/guestfs-building.pod
+++ b/docs/guestfs-building.pod
@@ -414,7 +414,8 @@ git.
git clone https://github.com/libguestfs/libguestfs
cd libguestfs
- ./autogen.sh
+ git submodule update --init
+ CFLAGS=-fPIC ./autogen.sh
make
=head1 BUILDING FROM TARBALLS
--
2.24.1
4 years, 9 months
[PATCH] Update common submodule (RHBZ#1351000)
by Martin Kletzander
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
common | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common b/common
index c33e0036c70c..12f3fb0f6ccd 160000
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit c33e0036c70ce68d40df92e4a6c0423e136e005c
+Subproject commit 12f3fb0f6ccdacb4c6fb81385550b62665fc1497
--
2.25.1
4 years, 9 months
[PATCH v2] add versioned directory for guest agent on EL8
by Tomáš Golembiovský
There was no source directory for EL8 guest agent (only EL6 and EL7).
RHBZ#1791802
Signed-off-by: Tomáš Golembiovský <tgolembi(a)redhat.com>
---
v2v/windows_virtio.ml | 1 +
1 file changed, 1 insertion(+)
diff --git a/v2v/windows_virtio.ml b/v2v/windows_virtio.ml
index 5ec7664b..86bc8c0a 100644
--- a/v2v/windows_virtio.ml
+++ b/v2v/windows_virtio.ml
@@ -192,6 +192,7 @@ and install_linux_tools g inspect =
(match inspect.i_major_version with
| 6 -> Some "el6"
| 7 -> Some "el7"
+ | 8 -> Some "el8"
| _ -> None)
| "sles" | "suse-based" | "opensuse" -> Some "lp151"
| _ -> None in
--
2.24.1
4 years, 9 months
Plans for nbdkit 1.18 release?
by Richard W.M. Jones
Hi Eric,
nbdkit 1.16 was released over 3 months ago, and there has been quite a
lot of upstream development since then, so it could be about time for
a new stable release. Anything in particular that you would like to
get in to 1.18? Or anything we've added that you have reservations
about supporting long-term?
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-top is 'top' for virtual machines. Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://people.redhat.com/~rjones/virt-top
4 years, 9 months
alternatives for hooking dlopen() without LD_LIBRARY_PATH or LD_AUDIT?
by Eric Blake
I've got a situation where I need to hook a dlopen() made by VDDK, a
proprietary library, where it passes a relative name expecting to
resolve to a copy of several libraries, including libstdc++.so, that it
installs alongside itself, and fails to load if that resolves to the
system libstdc++.so. The simplest solution of providing LD_LIBRARY_PATH
is enough to load VDDK, but then poisons any child process which
likewise fail to load if they pick up VDDK's libstdc++.so instead of the
system one. Up to now, we've documented throwing the burden on the end
user who has to write convoluted:
LD_LIBRARY_PATH_save=$LD_LIBRARY_PATH \
LD_LIBRARY_PATH=/path/to/vddklibs:$LD_LIBRARY_PATH \
nbdkit vddk libdir=/path/to/vddklibs file --run \
'LD_LIBRARY_PATH=$LD_LIBRARY_PATH_save; program args'
where we would rather the end-user could get away with a more concise:
nbdkit vddk libdir=/path/to/vddklibs file --run 'program args'
Sequentially, we have this scenario:
nbdkit vddk libdir=/path/to/libs file --run 'program args'
- nbdkit binary calls dlopen("/path/to/nbdkit-vddk-plugin.so")
- nbdkit-vddk-plugin.so calls
dlopen("/path/to/libs/libvixDiskLibs.so") using the libdir= argument
to load vddk (rather than dlopen("libvixDiskLibs.so") relying on
LD_LIBRARY_PATH)
- vddk's initializer calls dlopen("libcrypto.so") expecting to
open /path/to/libs/libcrypto.so, but either LD_LIBRARY_PATH
made that possible (at which point we have to scrub it before
a child process will be penalized), or we have to find a way to
rewrite vddk's dlopen call from relative into absolute before
passing it to the real dlopen
- nbdkit binary spawns a child process to exec 'program args'
- program does not want /path/to/libs in its search path
Writing my own dlopen() wrapper directly in nbdkit seems like a
non-starter (my override has to come from a shared library before it can
replace the shared version that would be imported from -ldl, at least
for all subsequent shared library loads that want to bind to the
override). And if I read 'man dlopen' correctly, since nbdkit used
dlopen() to load nbdkit-vddk-plugin.so, then dlopen() is already bound
in the main context, so unless I use RTLD_DEEPBIND from nbdkit, then
nbdkit-vddk-plugin.so will also see dlopen() bound to -dl rather than
anything it loads locally; but even with RTLD_DEEPBIND, it sounds like
that higher precedence lasts only for nbdkit-vddk-plugin.so and does not
extend to later bindings performed for libvixDiskLib.so (which means
vddk is back to -ldl's dlopen, without my hook). Thus, to hook dlopen
within the same process, I need some way to create a scope where I can
provide a shared dlopen() that will take precedence when resolving
symbols during the load of libvixDiskLib.so, but where that hook code
can still defer back to the real dlopen() from -ldl and does not
penalize child processes.
I managed to create a solution that avoids the need to set
LD_PRELOAD_PATH at all by installing a shared library that hooks
dlopen(), then loading both my shim and vddk via dlmopen() without the
use of RTLD_GLOBAL or RTLD_DEEPBIND. More links on my solution:
https://www.redhat.com/archives/libguestfs/2020-February/msg00154.html
https://bugzilla.redhat.com/show_bug.cgi?id=1756307#c7
https://sourceware.org/bugzilla/show_bug.cgi?id=15971#c5
However, when Florian saw it, he suggested that my solution of dlmopen()
for a shim library that overrides dlopen() is reinventing what
la_objsearch() can already do. This is in part because the moment you
dlmopen() a library into a separate namespace, you can't debug it (both
glibc and gdb need additional patches to expose alternative namespaces
for debugging), but there may be other nasty surprises lurking.
But after spending more than an hour playing with la_objsearch() and
reading 'man rtld-audit', it looks like an audit library cannot be
triggered in glibc except by listing it in LD_AUDIT in the environment
during exec - which is back to the same problem we have with needing
LD_LIBRARY_PATH in the environment. Furthermore, although I know that
glibc's audit interface is slightly different from the Solaris version
it copied from, the Solaris documentation states that an audit library
has some rather tough restrictions (including that using 'malloc' is
unsafe,
https://docs.oracle.com/cd/E36784_01/html/E36857/chapter6-3.html#scrolltoc
"Some system interfaces assume that the interfaces are the only instance
of their implementation within a process. Examples of such
implementations are signals and malloc(3C). Audit libraries should avoid
using such interfaces, as doing so can inadvertently alter the behavior
of the application."). But Solaris also stated that a library could
serve as an audit entry point without LD_AUDIT if it is registered
locally, via -Wl,-paudit.so.1 when creating the shared library
(https://docs.oracle.com/cd/E36784_01/html/E36857/chapter6-18.html#scrolltoc);
it doesn't seem that this functionality exists with glibc
(/usr/lib64/libaudit.so on Linux has nothing to do with rtld-audit).
Does anyone have any ideas on how to let a shared library implement an
audit interface for just its own process, without having to edit
LD_AUDIT or re-exec the process? Or is there yet another way to hook a
program to rewrite misbehaving dlopen() calls without relying on either
dlmopen() or la_objsearch(), or requiring pre-set environment variables,
or having to re-exec a process?
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
4 years, 9 months