More comprehensive support for virtio-scsi. Passes all the tests. Rich.
Richard W.M. Jones
2012-Jun-12 21:15 UTC
[Libguestfs] [PATCH v2 1/9] New API: fstrim - allow filesystem trim.
From: "Richard W.M. Jones" <rjones at redhat.com> --- daemon/Makefile.am | 1 + daemon/fstrim.c | 97 ++++++++++++++++++++++++++++++++++++++++ generator/generator_actions.ml | 27 ++++++++++- gobject/Makefile.inc | 6 ++- po/POTFILES | 2 + src/MAX_PROC_NR | 2 +- 6 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 daemon/fstrim.c diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 02c21df..9e2a633 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -114,6 +114,7 @@ guestfsd_SOURCES = \ fill.c \ find.c \ fsck.c \ + fstrim.c \ glob.c \ grep.c \ grub.c \ diff --git a/daemon/fstrim.c b/daemon/fstrim.c new file mode 100644 index 0000000..e2daf6a --- /dev/null +++ b/daemon/fstrim.c @@ -0,0 +1,97 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2012 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "guestfs_protocol.h" +#include "daemon.h" +#include "actions.h" +#include "optgroups.h" + +#define MAX_ARGS 64 + +int +optgroup_fstrim_available (void) +{ + return prog_exists ("fstrim"); +} + +/* Takes optional arguments, consult optargs_bitmask. */ +int +do_fstrim (const char *path, + int64_t offset, int64_t length, int64_t minimumfreeextent) +{ + const char *argv[MAX_ARGS]; + size_t i = 0; + char offset_s[64], length_s[64], mfe_s[64]; + char *err; + int r; + + ADD_ARG (argv, i, "fstrim"); + + if ((optargs_bitmask & GUESTFS_FSTRIM_OFFSET_BITMASK)) { + if (offset < 0) { + reply_with_error ("offset < 0"); + return -1; + } + + snprintf (offset_s, sizeof offset_s, "%" PRIi64, offset); + ADD_ARG (argv, i, "-o"); + ADD_ARG (argv, i, offset_s); + } + + if ((optargs_bitmask & GUESTFS_FSTRIM_LENGTH_BITMASK)) { + if (length <= 0) { + reply_with_error ("length <= 0"); + return -1; + } + + snprintf (length_s, sizeof length_s, "%" PRIi64, length); + ADD_ARG (argv, i, "-l"); + ADD_ARG (argv, i, length_s); + } + + if ((optargs_bitmask & GUESTFS_FSTRIM_MINIMUMFREEEXTENT_BITMASK)) { + if (minimumfreeextent <= 0) { + reply_with_error ("minimumfreeextent <= 0"); + return -1; + } + + snprintf (mfe_s, sizeof mfe_s, "%" PRIi64, minimumfreeextent); + ADD_ARG (argv, i, "-m"); + ADD_ARG (argv, i, mfe_s); + } + + ADD_ARG (argv, i, path); + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + if (r == -1) { + reply_with_error ("%s", err); + free (err); + return -1; + } + free (err); + + return 0; +} diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index cfbce00..120278a 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -6821,8 +6821,9 @@ The filesystem must be mounted read-write. The filesystem contents are not affected, but any free space in the filesystem is freed. -In future (but not currently) these zeroed blocks will be -\"sparsified\" - that is, given back to the host."); +Free space is not \"trimmed\". You may want to call +C<guestfs_fstrim> either as an alternative to this, +or after calling this, depending on your requirements."); ("lvcreate_free", (RErr, [String "logvol"; String "volgroup"; Int "percent"], []), 312, [Optional "lvm2"], [InitEmpty, Always, TestOutputList ( @@ -7259,6 +7260,28 @@ a later version of the filesystem, or having incompatible features. See also C<guestfs_available>, L<guestfs(3)/AVAILABILITY>."); + ("fstrim", (RErr, [Pathname "mountpoint"], [OInt64 "offset"; OInt64 "length"; OInt64 "minimumfreeextent"]), 334, [Optional "fstrim"], + [], + "trim free space in a filesystem", + "\ +Trim the free space in the filesystem mounted on C<mountpoint>. +The filesystem must be mounted read-write. + +The filesystem contents are not affected, but any free space +in the filesystem is \"trimmed\", that is, given back to the host +device, thus making disk images more sparse, allowing unused space +in qcow2 files to be reused, etc. + +This operation requires support in libguestfs, the mounted +filesystem, the host filesystem, qemu and the host kernel. +If this support isn't present it may give an error or even +appear to run but do nothing. + +See also C<guestfs_zero_free_space>. That is a slightly +different operation that turns free space in the filesystem +into zeroes. It is valid to call C<guestfs_fstrim> either +instead of, or after calling C<guestfs_zero_free_space>."); + ] let all_functions = non_daemon_functions @ daemon_functions diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index d4db407..056c5f5 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -61,7 +61,8 @@ guestfs_gobject_headers= \ include/guestfs-gobject/optargs-ntfsclone_out.h \ include/guestfs-gobject/optargs-mkfs_btrfs.h \ include/guestfs-gobject/optargs-set_e2attrs.h \ - include/guestfs-gobject/optargs-btrfs_fsck.h + include/guestfs-gobject/optargs-btrfs_fsck.h \ + include/guestfs-gobject/optargs-fstrim.h guestfs_gobject_sources= \ src/session.c \ @@ -104,4 +105,5 @@ guestfs_gobject_sources= \ src/optargs-ntfsclone_out.c \ src/optargs-mkfs_btrfs.c \ src/optargs-set_e2attrs.c \ - src/optargs-btrfs_fsck.c + src/optargs-btrfs_fsck.c \ + src/optargs-fstrim.c diff --git a/po/POTFILES b/po/POTFILES index 9d3282e..747b341 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -34,6 +34,7 @@ daemon/fill.c daemon/find.c daemon/findfs.c daemon/fsck.c +daemon/fstrim.c daemon/glob.c daemon/grep.c daemon/grub.c @@ -142,6 +143,7 @@ gobject/src/optargs-copy_device_to_file.c gobject/src/optargs-copy_file_to_device.c gobject/src/optargs-copy_file_to_file.c gobject/src/optargs-e2fsck.c +gobject/src/optargs-fstrim.c gobject/src/optargs-inspect_get_icon.c gobject/src/optargs-md_create.c gobject/src/optargs-mkfs_btrfs.c diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 55bd0ac..0ae9d1e 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -333 +334 -- 1.7.10.1
Richard W.M. Jones
2012-Jun-12 21:15 UTC
[Libguestfs] [PATCH v2 2/9] Remove ./configure --with-drive-if and --with-net-if options.
From: "Richard W.M. Jones" <rjones at redhat.com> These were used to select the default drive and network interface. They both default to 'virtio'. These were added back in the day when virtio was buggy, so that packagers could revert to using ide/ne2k_pci to work around distro bugs. However virtio has been stable in qemu for a very long time, so it seems unlikely that any packager would need to use these, and in any case it would be better to do this detection at runtime (cf. for virtio-scsi). --- configure.ac | 23 ----------------------- src/launch.c | 13 +++++++------ 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/configure.ac b/configure.ac index 5ba2018..69da9a5 100644 --- a/configure.ac +++ b/configure.ac @@ -644,29 +644,6 @@ the --with-qemu option. fi fi -dnl Set default drive interface used by the guestfs_add_drive_opts call -dnl ('-drive ...,if=...' option to qemu). -dnl -dnl If you encounter performance problems with virtio (RHBZ#509383) -dnl then try '--with-drive-if=ide'. -AC_ARG_WITH([drive-if], - [AS_HELP_STRING([--with-drive-if], - [set default driver (ide|scsi|virtio) @<:@default=virtio@:>@])], - [], - [with_drive_if=virtio]) -AC_DEFINE_UNQUOTED([DRIVE_IF],["$with_drive_if"],[Default drive interface.]) - -dnl Set interface used by the network. Normally you should -dnl leave this at the default (virtio-net-pci) but you can use the -dnl alternative (ne2k_pci) because of bugs in virtio networking -dnl eg. https://bugzilla.redhat.com/show_bug.cgi?id=516022 -AC_ARG_WITH([net-if], - [AS_HELP_STRING([--with-net-if], - [set default net driver (virtio-net-pci|ne2k_pci) @<:@default=virtio-net-pci@:>@])], - [], - [with_net_if=virtio-net-pci]) -AC_DEFINE_UNQUOTED([NET_IF],["$with_net_if"],[Default network interface.]) - dnl Enable packet dumps when in verbose mode. This generates lots dnl of debug info, only useful for people debugging the RPC mechanism. AC_ARG_ENABLE([packet-dump], diff --git a/src/launch.c b/src/launch.c index 3b1f91c..7bc913b 100644 --- a/src/launch.c +++ b/src/launch.c @@ -356,7 +356,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, format = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK ? safe_strdup (g, optargs->format) : NULL; iface = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_IFACE_BITMASK - ? safe_strdup (g, optargs->iface) : safe_strdup (g, DRIVE_IF); + ? safe_strdup (g, optargs->iface) : NULL; name = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_NAME_BITMASK ? safe_strdup (g, optargs->name) : NULL; @@ -365,7 +365,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename, "format"); goto err_out; } - if (!valid_format_iface (iface)) { + if (iface && !valid_format_iface (iface)) { error (g, _("%s parameter is empty or contains disallowed characters"), "iface"); goto err_out; @@ -788,7 +788,7 @@ launch_appliance (guestfs_h *g) add_cmdline (g, "-netdev"); add_cmdline (g, "user,id=usernet,net=169.254.0.0/16"); add_cmdline (g, "-device"); - add_cmdline (g, NET_IF ",netdev=usernet"); + add_cmdline (g, "virtio-net-pci,netdev=usernet"); } #if defined(__arm__) @@ -837,7 +837,7 @@ launch_appliance (guestfs_h *g) char buf2[PATH_MAX + 64]; add_cmdline (g, "-drive"); - snprintf (buf2, sizeof buf2, "file=%s,snapshot=on,if=" DRIVE_IF "%s", + snprintf (buf2, sizeof buf2, "file=%s,snapshot=on,if=virtio%s", appliance, cachemode); add_cmdline (g, buf2); } @@ -1464,7 +1464,8 @@ qemu_drive_param (guestfs_h *g, const struct drive *drv) char *r; len += strlen (drv->path) * 2; /* every "," could become ",," */ - len += strlen (drv->iface); + if (drv->iface) + len += strlen (drv->iface); if (drv->format) len += strlen (drv->format); @@ -1487,7 +1488,7 @@ qemu_drive_param (guestfs_h *g, const struct drive *drv) drv->use_cache_off ? ",cache=off" : "", drv->format ? ",format=" : "", drv->format ? drv->format : "", - drv->iface); + drv->iface ? drv->iface : "virtio"); return r; /* caller frees */ } -- 1.7.10.1
From: "Richard W.M. Jones" <rjones at redhat.com> QEMU 1.0 was released at the end of 2011. Remove all the cruft about detecting broken -machine type which was only required for QEMU 0.15. This also reverts commit 30ecbf3ec2ada68f7e125a180553e31b069033b7. Even on ARM you can pass -machine accel=kvm:tcg and qemu does the right thing, so I'm not sure why we wanted to disable that. --- README | 2 +- configure.ac | 68 ++++++++++++++++++---------------------------------------- src/launch.c | 27 +++++------------------ 3 files changed, 27 insertions(+), 70 deletions(-) diff --git a/README b/README index 2b133c6..4dd2075 100644 --- a/README +++ b/README @@ -46,7 +46,7 @@ For basic functionality and the C tools: - look at appliance/packagelist.in and install as many of the packages that apply to your distro as possible -- recent QEMU >= 0.13 (0.14 or later is better) with virtio-serial support +- QEMU >= 1.0. - kernel >= 2.6.34 with virtio-serial support enabled. diff --git a/configure.ac b/configure.ac index 69da9a5..ca0f9f1 100644 --- a/configure.ac +++ b/configure.ac @@ -568,55 +568,29 @@ working. ]) fi - AS_IF([test "x$QEMU_OPTIONS" = "x"],[ - dnl qemu 0.15 was released with broken support for '-machine', - dnl requiring you to add the machine type: '-machine pc,[...]'. - dnl The problem is that 'pc' is only applicable for PC-like - dnl hardware, so we cannot do this as a general solution. Since - dnl qemu 0.15, this problem has been fixed so now the default - dnl machine type is chosen (qemu commit 2645c6dcaf6ea2a51a). - dnl - dnl We need to work out if this qemu is the broken version, so we - dnl can add 'pc' just for this broken version. - dnl - dnl Note that old qemu didn't support the '-machine' option at all. - dnl - dnl We use the -kernel option for testing this, because this option - dnl is processed very late, after qemu has set up the machine. - AC_MSG_CHECKING([for broken '-machine accel=tcg' option in $QEMU]) - LC_ALL=C $QEMU -nographic -machine accel=tcg -kernel /NO_SUCH_FILE \ - > config1.tmp 2>&1 - LC_ALL=C $QEMU -nographic -machine pc,accel=tcg -kernel /NO_SUCH_FILE \ - > config2.tmp 2>&1 - if cmp -s config1.tmp config2.tmp; then - AC_MSG_RESULT([no]) - else - AC_MSG_RESULT([yes]) - AC_DEFINE([QEMU_MACHINE_TYPE_IS_BROKEN],[1],[qemu -machine accel=tcg option is broken (in qemu 0.15 only)]) - fi - rm config1.tmp config2.tmp - - dnl See if the '-machine [pc,]accel=tcg' option is required in - dnl order to run the virtio-serial test below. This happens when - dnl we run qemu-kvm inside a VM without forcing TCG: - dnl - dnl Could not access KVM kernel module: No such file or directory - dnl failed to initialize KVM: No such file or directory - dnl No accelerator found! - AC_MSG_CHECKING([if -machine @<:@pc,@:>@accel=tcg option is required to test virtio-serial feature]) - if $QEMU -nographic -device \? >/dev/null 2>&1; then - : - elif $QEMU -machine accel=tcg -nographic -device \? >/dev/null 2>&1; then - QEMU_OPTIONS_FOR_TEST="-machine accel=tcg" - elif $QEMU -machine pc,accel=tcg -nographic -device \? >/dev/null 2>&1; then - QEMU_OPTIONS_FOR_TEST="-machine pc,accel=tcg" - # else nothing ... it'll fail below. - fi - AC_MSG_RESULT([$QEMU_OPTIONS_FOR_TEST]) - ]) + AC_MSG_CHECKING([that $QEMU -version works]) + if $QEMU -version >&AS_MESSAGE_LOG_FD 2>&1; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_FAILURE( +[$QEMU -version: command failed. + +This could be a very old version of qemu, or qemu might not be +working. +]) + fi + + AC_MSG_CHECKING([for $QEMU version >= 1]) + if $QEMU -version | grep -sq 'version @<:@1-@:>@'; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_FAILURE([$QEMU version must be >= 1.0.]) + fi AC_MSG_CHECKING([for virtio-serial support in $QEMU]) - if $QEMU $QEMU_OPTIONS $QEMU_OPTIONS_FOR_TEST -nographic -device \? 2>&1 | grep -sq virtio-serial; then + if $QEMU $QEMU_OPTIONS -machine accel=kvm:tcg -device \? 2>&1 | grep -sq virtio-serial; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) diff --git a/src/launch.c b/src/launch.c index 7bc913b..e175dd9 100644 --- a/src/launch.c +++ b/src/launch.c @@ -678,29 +678,13 @@ launch_appliance (guestfs_h *g) add_cmdline_shell_unquoted (g, QEMU_OPTIONS); } - /* The #if on the next line should really be "architectures for - * which KVM is commonly available. - */ -#if defined(__i386__) || defined(__x86_64__) /* The qemu -machine option (added 2010-12) is a bit more sane * since it falls back through various different acceleration * modes, so try that first (thanks Markus Armbruster). */ if (qemu_supports (g, "-machine")) { add_cmdline (g, "-machine"); -#if QEMU_MACHINE_TYPE_IS_BROKEN - /* Workaround for qemu 0.15: We have to add the '[type=]pc' - * since there is no default. This is not a permanent solution - * because this only works on PC-like hardware. Other platforms - * like ppc would need a different machine type. - * - * This bug is fixed in qemu commit 2645c6dcaf6ea2a51a, and was - * not a problem in qemu < 0.15. - */ - add_cmdline (g, "pc,accel=kvm:tcg"); -#else add_cmdline (g, "accel=kvm:tcg"); -#endif } else { /* qemu sometimes needs this option to enable hardware * virtualization, but some versions of 'qemu-kvm' will use KVM @@ -718,7 +702,6 @@ launch_appliance (guestfs_h *g) is_openable (g, "/dev/kvm", O_RDWR|O_CLOEXEC)) add_cmdline (g, "-enable-kvm"); } -#endif /* i386 or x86-64 */ if (g->smp > 1) { snprintf (buf, sizeof buf, "%d", g->smp); @@ -1339,11 +1322,11 @@ test_qemu (guestfs_h *g) snprintf (cmd, sizeof cmd, "LC_ALL=C '%s' -nographic -help", g->qemu); - /* qemu -help should always work (qemu -version OTOH wasn't - * supported by qemu 0.9). If this command doesn't work then it - * probably indicates that the qemu binary is missing. + /* If this command doesn't work then it probably indicates that the + * qemu binary is missing. */ if (test_qemu_cmd (g, cmd, &g->qemu_help) == -1) { + qemu_error: error (g, _("command failed: %s\n\nIf qemu is located on a non-standard path, try setting the LIBGUESTFS_QEMU\nenvironment variable. There may also be errors printed above."), cmd); return -1; @@ -1352,8 +1335,8 @@ test_qemu (guestfs_h *g) snprintf (cmd, sizeof cmd, "LC_ALL=C '%s' -nographic -version 2>/dev/null", g->qemu); - /* Intentionally ignore errors from qemu -version. */ - ignore_value (test_qemu_cmd (g, cmd, &g->qemu_version)); + if (test_qemu_cmd (g, cmd, &g->qemu_version) == -1) + goto qemu_error; return 0; } -- 1.7.10.1
Richard W.M. Jones
2012-Jun-12 21:15 UTC
[Libguestfs] [PATCH v2 4/9] Record output of qemu -device '?'.
From: "Richard W.M. Jones" <rjones at redhat.com> This allows us to find out what qemu devices are supported at runtime. --- configure.ac | 8 ++++++++ src/guestfs-internal.h | 1 + src/guestfs.c | 1 + src/launch.c | 9 +++++++++ 4 files changed, 19 insertions(+) diff --git a/configure.ac b/configure.ac index ca0f9f1..9eae5a0 100644 --- a/configure.ac +++ b/configure.ac @@ -589,6 +589,14 @@ working. AC_MSG_FAILURE([$QEMU version must be >= 1.0.]) fi + AC_MSG_CHECKING([that $QEMU -machine accel=kvm:tcg -device ? works]) + if $QEMU -machine accel=kvm:tcg -device \? >&AS_MESSAGE_LOG_FD 2>&1; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_FAILURE([$QEMU -machine accel=kvm:tcg -device ? doesn't work.]) + fi + AC_MSG_CHECKING([for virtio-serial support in $QEMU]) if $QEMU $QEMU_OPTIONS -machine accel=kvm:tcg -device \? 2>&1 | grep -sq virtio-serial; then AC_MSG_RESULT([yes]) diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 4e82966..fb4868c 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -187,6 +187,7 @@ struct guestfs_h char *tmpdir; /* Temporary directory containing socket. */ char *qemu_help, *qemu_version; /* Output of qemu -help, qemu -version. */ + char *qemu_devices; /* Output of qemu -device ? */ char **cmdline; /* Qemu command line. */ size_t cmdline_size; diff --git a/src/guestfs.c b/src/guestfs.c index f296a0c..561fab4 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -270,6 +270,7 @@ guestfs_close (guestfs_h *g) free (g->append); free (g->qemu_help); free (g->qemu_version); + free (g->qemu_devices); free (g); } diff --git a/src/launch.c b/src/launch.c index e175dd9..1eae027 100644 --- a/src/launch.c +++ b/src/launch.c @@ -1319,6 +1319,8 @@ test_qemu (guestfs_h *g) g->qemu_help = NULL; free (g->qemu_version); g->qemu_version = NULL; + free (g->qemu_devices); + g->qemu_devices = NULL; snprintf (cmd, sizeof cmd, "LC_ALL=C '%s' -nographic -help", g->qemu); @@ -1338,6 +1340,13 @@ test_qemu (guestfs_h *g) if (test_qemu_cmd (g, cmd, &g->qemu_version) == -1) goto qemu_error; + snprintf (cmd, sizeof cmd, + "LC_ALL=C '%s' -nographic -machine accel=kvm:tcg -device '?' 2>&1", + g->qemu); + + if (test_qemu_cmd (g, cmd, &g->qemu_devices) == -1) + goto qemu_error; + return 0; } -- 1.7.10.1
Richard W.M. Jones
2012-Jun-12 21:15 UTC
[Libguestfs] [PATCH v2 5/9] appliance: Add support for virtio-scsi.
From: "Richard W.M. Jones" <rjones at redhat.com> This requires febootstrap >= 3.15. --- README | 3 +- src/guestfs-internal.h | 3 ++ src/launch.c | 140 +++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 121 insertions(+), 25 deletions(-) diff --git a/README b/README index 4dd2075..51ee4a0 100644 --- a/README +++ b/README @@ -55,11 +55,12 @@ For basic functionality and the C tools: to make complex changes to the ./configure command line to get it to work if you don't have virtio) -- febootstrap >= 3.3 (it is best to use the latest version) +- febootstrap >= 3.15 Notes: (1) febootstrap 2.x WILL NOT WORK (2) febootstrap 3.x is distro-independent, and is required on Debian and other distros as well as Fedora + (3) that is the minimum version, but later versions are better - XDR, rpcgen (on Linux these are provided by glibc) diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index fb4868c..0cdc8f2 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -257,6 +257,9 @@ struct guestfs_h int ml_read_only; /* If mounted read-only. */ int ml_debug_calls; /* Extra debug info on each FUSE call. */ #endif + + /* Used by src/launch.c:qemu_supports_virtio_scsi */ + int virtio_scsi; }; /* Per-filesystem data stored for inspect_os. */ diff --git a/src/launch.c b/src/launch.c index 1eae027..b7a08ba 100644 --- a/src/launch.c +++ b/src/launch.c @@ -78,7 +78,10 @@ static int64_t timeval_diff (const struct timeval *x, const struct timeval *y); static void print_qemu_command_line (guestfs_h *g, char **argv); static int connect_unix_socket (guestfs_h *g, const char *sock); static int qemu_supports (guestfs_h *g, const char *option); -static char *qemu_drive_param (guestfs_h *g, const struct drive *drv); +static int qemu_supports_device (guestfs_h *g, const char *device_name); +static int qemu_supports_virtio_scsi (guestfs_h *g); +static char *qemu_drive_param (guestfs_h *g, const struct drive *drv, size_t index); +static char *drive_name (size_t index, char *ret); #if 0 static int qemu_supports_re (guestfs_h *g, const pcre *option_regex); @@ -248,7 +251,7 @@ guestfs__debug_drives (guestfs_h *g) ret = safe_malloc (g, sizeof (char *) * (count + 1)); for (i = 0, drv = g->drives; drv; i++, drv = drv->next) - ret[i] = qemu_drive_param (g, drv); + ret[i] = qemu_drive_param (g, drv, i); ret[count] = NULL; @@ -620,6 +623,7 @@ launch_appliance (guestfs_h *g) if (r == 0) { /* Child (qemu). */ char buf[256]; + int virtio_scsi = qemu_supports_virtio_scsi (g); /* Set up the full command line. Do this in the subprocess so we * don't need to worry about cleaning up. @@ -660,15 +664,59 @@ launch_appliance (guestfs_h *g) /* Add drives */ struct drive *drv = g->drives; + size_t drv_index = 0; + + if (virtio_scsi) { + /* Create the virtio-scsi bus. */ + add_cmdline (g, "-device"); + add_cmdline (g, "virtio-scsi-pci,id=scsi"); + } + while (drv != NULL) { /* Construct the final -drive parameter. */ - char *buf = qemu_drive_param (g, drv); + char *buf = qemu_drive_param (g, drv, drv_index); add_cmdline (g, "-drive"); add_cmdline (g, buf); free (buf); + if (virtio_scsi && drv->iface == NULL) { + char buf2[64]; + snprintf (buf2, sizeof buf2, "scsi-hd,drive=hd%zu", drv_index); + add_cmdline (g, "-device"); + add_cmdline (g, buf2); + } + drv = drv->next; + drv_index++; + } + + char appliance_root[64] = ""; + + /* Add the ext2 appliance drive (after all the drives). */ + if (appliance) { + const char *cachemode = ""; + if (qemu_supports (g, "cache=")) { + if (qemu_supports (g, "unsafe")) + cachemode = ",cache=unsafe"; + else if (qemu_supports (g, "writeback")) + cachemode = ",cache=writeback"; + } + + char buf2[PATH_MAX + 64]; + add_cmdline (g, "-drive"); + snprintf (buf2, sizeof buf2, "file=%s,snapshot=on,id=appliance,if=%s%s", + appliance, virtio_scsi ? "none" : "virtio", cachemode); + add_cmdline (g, buf2); + + if (virtio_scsi) { + add_cmdline (g, "-device"); + add_cmdline (g, "scsi-hd,drive=appliance"); + } + + snprintf (appliance_root, sizeof appliance_root, "root=/dev/%cd", + virtio_scsi ? 's' : 'v'); + drive_name (drv_index, &appliance_root[12]); } if (STRNEQ (QEMU_OPTIONS, "")) { @@ -792,10 +840,12 @@ launch_appliance (guestfs_h *g) /* Linux kernel command line. */ snprintf (buf, sizeof buf, LINUX_CMDLINE + "%s " /* (root) */ "%s " /* (selinux) */ "%s " /* (verbose) */ "TERM=%s " /* (TERM environment variable) */ "%s", /* (append) */ + appliance_root, g->selinux ? "selinux=1 enforcing=0" : "selinux=0", g->verbose ? "guestfs_verbose=1" : "", getenv ("TERM") ? : "linux", @@ -808,23 +858,6 @@ launch_appliance (guestfs_h *g) add_cmdline (g, "-append"); add_cmdline (g, buf); - /* Add the ext2 appliance drive (last of all). */ - if (appliance) { - const char *cachemode = ""; - if (qemu_supports (g, "cache=")) { - if (qemu_supports (g, "unsafe")) - cachemode = ",cache=unsafe"; - else if (qemu_supports (g, "writeback")) - cachemode = ",cache=writeback"; - } - - char buf2[PATH_MAX + 64]; - add_cmdline (g, "-drive"); - snprintf (buf2, sizeof buf2, "file=%s,snapshot=on,if=virtio%s", - appliance, cachemode); - add_cmdline (g, buf2); - } - /* Finish off the command line. */ incr_cmdline_size (g); g->cmdline[g->cmdline_size-1] = NULL; @@ -1432,6 +1465,20 @@ qemu_supports_re (guestfs_h *g, const pcre *option_regex) } #endif +/* Test if device is supported by qemu (currently just greps the -device ? + * output). + */ +static int +qemu_supports_device (guestfs_h *g, const char *device_name) +{ + if (!g->qemu_devices) { + if (test_qemu (g) == -1) + return -1; + } + + return strstr (g->qemu_devices, device_name) != NULL; +} + #if defined(__i386__) || defined(__x86_64__) /* Check if a file can be opened. */ static int @@ -1447,13 +1494,39 @@ is_openable (guestfs_h *g, const char *path, int flags) } #endif +/* Returns 1 = use virtio-scsi, or 0 = use virtio-blk. */ +static int +qemu_supports_virtio_scsi (guestfs_h *g) +{ + int r; + + /* g->virtio_scsi has these values: + * 0 = untested (after handle creation) + * 1 = supported + * 2 = not supported (use virtio-blk) + * 3 = test failed (use virtio-blk) + */ + if (g->virtio_scsi == 0) { + r = qemu_supports_device (g, "virtio-scsi-pci"); + if (r > 0) + g->virtio_scsi = 1; + else if (r == 0) + g->virtio_scsi = 2; + else + g->virtio_scsi = 3; + } + + return g->virtio_scsi == 1; +} + static char * -qemu_drive_param (guestfs_h *g, const struct drive *drv) +qemu_drive_param (guestfs_h *g, const struct drive *drv, size_t index) { size_t i; - size_t len = 64; + size_t len = 128; const char *p; char *r; + const char *iface; len += strlen (drv->path) * 2; /* every "," could become ",," */ if (drv->iface) @@ -1475,16 +1548,35 @@ qemu_drive_param (guestfs_h *g, const struct drive *drv) r[i++] = *p; } - snprintf (&r[i], len-i, "%s%s%s%s,if=%s", + if (drv->iface) + iface = drv->iface; + else if (qemu_supports_virtio_scsi (g)) + iface = "none"; /* sic */ + else + iface = "virtio"; + + snprintf (&r[i], len-i, "%s%s%s%s,id=hd%zu,if=%s", drv->readonly ? ",snapshot=on" : "", drv->use_cache_off ? ",cache=off" : "", drv->format ? ",format=" : "", drv->format ? drv->format : "", - drv->iface ? drv->iface : "virtio"); + index, + iface); return r; /* caller frees */ } +/* https://rwmj.wordpress.com/2011/01/09/how-are-linux-drives-named-beyond-drive-26-devsdz/ */ +static char * +drive_name (size_t index, char *ret) +{ + if (index > 26) + ret = drive_name (index / 26, ret); + index %= 26; + *ret++ = 'a' + index; + return ret; +} + /* You had to call this function after launch in versions <= 1.0.70, * but it is now a no-op. */ -- 1.7.10.1
Richard W.M. Jones
2012-Jun-12 21:15 UTC
[Libguestfs] [PATCH v2 6/9] daemon: Always pass -F option to mke2fs.
From: "Richard W.M. Jones" <rjones at redhat.com> Apparently e2fsprogs only knows that "/dev/sda" is a whole device, but doesn't think that "/dev/vda" is. On switching the default device over to virtio-scsi, that causes mke2fs without -F option to complain and ask for an interactive prompt. Adding -F forces it to go ahead anyway. This caused several less-used APIs to break with virtio-scsi. --- daemon/ext2.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/daemon/ext2.c b/daemon/ext2.c index 6824752..7876e66 100644 --- a/daemon/ext2.c +++ b/daemon/ext2.c @@ -377,7 +377,7 @@ do_mke2journal (int blocksize, const char *device) snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize); r = command (NULL, &err, - prog, "-O", "journal_dev", "-b", blocksize_s, + prog, "-F", "-O", "journal_dev", "-b", blocksize_s, device, NULL); if (r == -1) { reply_with_error ("%s", err); @@ -409,7 +409,7 @@ do_mke2journal_L (int blocksize, const char *label, const char *device) snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize); r = command (NULL, &err, - prog, "-O", "journal_dev", "-b", blocksize_s, + prog, "-F", "-O", "journal_dev", "-b", blocksize_s, "-L", label, device, NULL); if (r == -1) { @@ -436,7 +436,7 @@ do_mke2journal_U (int blocksize, const char *uuid, const char *device) snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize); r = command (NULL, &err, - prog, "-O", "journal_dev", "-b", blocksize_s, + prog, "-F", "-O", "journal_dev", "-b", blocksize_s, "-U", uuid, device, NULL); if (r == -1) { @@ -468,7 +468,7 @@ do_mke2fs_J (const char *fstype, int blocksize, const char *device, snprintf (jdev, len+32, "device=%s", journal); r = command (NULL, &err, - prog, "-t", fstype, "-J", jdev, "-b", blocksize_s, + prog, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s, device, NULL); if (r == -1) { reply_with_error ("%s", err); @@ -505,7 +505,7 @@ do_mke2fs_JL (const char *fstype, int blocksize, const char *device, snprintf (jdev, len+32, "device=LABEL=%s", label); r = command (NULL, &err, - prog, "-t", fstype, "-J", jdev, "-b", blocksize_s, + prog, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s, device, NULL); if (r == -1) { reply_with_error ("%s", err); @@ -536,7 +536,7 @@ do_mke2fs_JU (const char *fstype, int blocksize, const char *device, snprintf (jdev, len+32, "device=UUID=%s", uuid); r = command (NULL, &err, - prog, "-t", fstype, "-J", jdev, "-b", blocksize_s, + prog, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s, device, NULL); if (r == -1) { reply_with_error ("%s", err); -- 1.7.10.1
Richard W.M. Jones
2012-Jun-12 21:15 UTC
[Libguestfs] [PATCH v2 7/9] tests/lvm: Don't hard-code /dev/vda in test.
From: "Richard W.M. Jones" <rjones at redhat.com> Break virtio-scsi where the devices are /dev/sda etc. --- tests/lvm/test-lvm-mapping.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lvm/test-lvm-mapping.pl b/tests/lvm/test-lvm-mapping.pl index 3e6faa5..b92a5c5 100755 --- a/tests/lvm/test-lvm-mapping.pl +++ b/tests/lvm/test-lvm-mapping.pl @@ -81,7 +81,7 @@ foreach my $uuid (@lvuuids_in_VG) { @lvs_in_VG = sort @lvs_in_VG; unless (@pvs_in_VG == 2 && - $pvs_in_VG[0] eq "/dev/vda1" && $pvs_in_VG[1] eq "/dev/vda2") { + $pvs_in_VG[0] =~ m{/dev/.da1} && $pvs_in_VG[1] =~ m{/dev/.da2}) { die "unexpected set of PVs for volume group VG: [", join (", ", @pvs_in_VG), "]\n" } -- 1.7.10.1
Richard W.M. Jones
2012-Jun-12 21:15 UTC
[Libguestfs] [PATCH v2 8/9] tests: Fix spelling in comment.
From: "Richard W.M. Jones" <rjones at redhat.com> --- tests/md/test-inspect-fstab.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/md/test-inspect-fstab.sh b/tests/md/test-inspect-fstab.sh index fec42c0..d1cf610 100755 --- a/tests/md/test-inspect-fstab.sh +++ b/tests/md/test-inspect-fstab.sh @@ -36,10 +36,10 @@ cat <<'EOF' > test.fstab # Xen-style partition names. /dev/xvda1 /boot ext2 default 0 0 -# Non-existant device. +# Non-existent device. /dev/sdb3 /var ext2 default 0 0 -# Non-existant mountpoint. +# Non-existent mountpoint. /dev/VG/LV1 /nosuchfile ext2 default 0 0 EOF -- 1.7.10.1
Richard W.M. Jones
2012-Jun-12 21:15 UTC
[Libguestfs] [PATCH v2 9/9] tests/md: Don't hard code /dev/vda in expected output of tests.
From: "Richard W.M. Jones" <rjones at redhat.com> Use a small sed script to canonicalize the device names. --- tests/md/test-inspect-fstab.sh | 15 ++++++++------- tests/md/test-list-filesystems.sh | 12 ++++++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/tests/md/test-inspect-fstab.sh b/tests/md/test-inspect-fstab.sh index d1cf610..62e2e94 100755 --- a/tests/md/test-inspect-fstab.sh +++ b/tests/md/test-inspect-fstab.sh @@ -23,6 +23,7 @@ set -e export LANG=C guestfish=../../fish/guestfish +canonical="sed s,/dev/vd,/dev/sd,g" rm -f test1.img test.fstab test.output @@ -50,12 +51,12 @@ $guestfish -a test1.img <<'EOF' EOF # This will give a warning, but should not fail. -$guestfish -a test1.img -i <<'EOF' | sort > test.output +$guestfish -a test1.img -i <<'EOF' | sort | $canonical > test.output inspect-get-mountpoints /dev/VG/Root EOF if [ "$(cat test.output)" != "/: /dev/VG/Root -/boot: /dev/vda1 +/boot: /dev/sda1 /nosuchfile: /dev/VG/LV1 /var: /dev/sdb3" ]; then echo "$0: error #1: unexpected output from inspect-get-mountpoints command" @@ -78,7 +79,7 @@ $guestfish -a test1.img <<'EOF' upload test.fstab /etc/fstab EOF -$guestfish <<'EOF' > test.output +$guestfish <<'EOF' | $canonical > test.output add-drive-opts test1.img readonly:true name:xvdg run inspect-os @@ -87,7 +88,7 @@ EOF if [ "$(cat test.output)" != "/dev/VG/Root /: /dev/VG/Root -/boot: /dev/vda1" ]; then +/boot: /dev/sda1" ]; then echo "$0: error #2: unexpected output from inspect-get-mountpoints command" cat test.output exit 1 @@ -109,7 +110,7 @@ $guestfish -a test1.img <<'EOF' upload test.fstab /etc/fstab EOF -$guestfish <<'EOF' > test.output +$guestfish <<'EOF' | $canonical > test.output add-drive-opts test1.img readonly:true name:cciss/c1d3 run inspect-os @@ -118,8 +119,8 @@ EOF if [ "$(cat test.output)" != "/dev/VG/Root /: /dev/VG/Root -/boot: /dev/vda1 -/var: /dev/vda" ]; then +/boot: /dev/sda1 +/var: /dev/sda" ]; then echo "$0: error #3: unexpected output from inspect-get-mountpoints command" cat test.output exit 1 diff --git a/tests/md/test-list-filesystems.sh b/tests/md/test-list-filesystems.sh index 9aea21a..b9a0340 100755 --- a/tests/md/test-list-filesystems.sh +++ b/tests/md/test-list-filesystems.sh @@ -20,6 +20,8 @@ set -e +rm -f test.output + # Create 2 disks partitioned as: # sda1: 20M ext3 # sda2: 20M MD (md127) @@ -30,8 +32,7 @@ set -e # md127 : 20M ext4 # vg0 : 16M LV (lv0) # lv0 : 16M vfat -output=$( -../../fish/guestfish <<EOF +../../fish/guestfish <<EOF | sed s,/dev/vd,/dev/sd,g > test.output # Add 2 empty disks sparse fs-test1.img 50M sparse fs-test2.img 50M @@ -59,18 +60,17 @@ mkfs vfat /dev/vg0/lv0 list-filesystems EOF -) -expected="/dev/vda1: ext3 +expected="/dev/sda1: ext3 /dev/md127: ext4 /dev/vg0/lv0: vfat" # Check the output of list-filesystems -if [ "$output" != "$expected" ]; then +if [ "$(cat test.output)" != "$expected" ]; then echo "$0: error: output of list-filesystems did not match expected output" printf "%s\n" "$output" exit 1; fi -rm -f fs-test1.img fs-test2.img +rm -f fs-test1.img fs-test2.img test.output -- 1.7.10.1