Richard W.M. Jones
2012-Jun-12 17:15 UTC
[Libguestfs] [PATCH 0/5] Assorted patches to add virtio-scsi support.
These assorted patches end up with adding virtio-scsi support to libguestfs. It passes libguestfs-test-tool, but I haven't yet tried to run the full set of tests. In theory > 26 devices can be added, but it's likely that certain parts of the daemon will break if you actually try this. This of course needs to be fixed. Thanks Paolo Bonzini for invaluable help. Rich.
Richard W.M. Jones
2012-Jun-12 17:15 UTC
[Libguestfs] [PATCH 1/5] 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 17:15 UTC
[Libguestfs] [PATCH 2/5] 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 17:15 UTC
[Libguestfs] [PATCH 4/5] 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..3db2443 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 17:15 UTC
[Libguestfs] [PATCH 5/5] appliance: Add support for virtio-scsi.
From: "Richard W.M. Jones" <rjones at redhat.com> This requires febootstrap >= 3.15. --- README | 2 +- src/guestfs-internal.h | 3 ++ src/launch.c | 141 +++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 121 insertions(+), 25 deletions(-) diff --git a/README b/README index 4dd2075..a17863f 100644 --- a/README +++ b/README @@ -55,7 +55,7 @@ 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 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 3db2443..5aed29f 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,60 @@ 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 (qemu_supports_virtio_scsi (g)) { + 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]; + int virtio_scsi = qemu_supports_virtio_scsi (g); + 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 +841,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 +859,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 +1466,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 +1495,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 +1549,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