[libguestfs/f19] Backport cachemode parameter from upstream (RHBZ#1044762).
Richard W.M. Jones
rjones at fedoraproject.org
Fri Dec 20 22:35:37 UTC 2013
commit 9409a05fbb6da8a3860c9a80c7eecbc875e5f831
Author: Richard W.M. Jones <rjones at redhat.com>
Date: Fri Dec 20 22:18:48 2013 +0000
Backport cachemode parameter from upstream (RHBZ#1044762).
- Use git to manage patches, add copy-patches.sh script.
0001-New-API-add-drive-scratch.patch | 148 +++++
...ntroduce-cachemode-parameter-to-control-d.patch | 566 ++++++++++++++++++++
...re-all-scratch-drives-use-cachemode-unsaf.patch | 39 ++
...Use-cachemode-unsafe-for-the-overlay-disk.patch | 27 +
...cachemode-unsafe-for-the-virt-rescue-scra.patch | 64 +++
...ct-Always-use-cache-unsafe-for-the-applia.patch | 43 ++
copy-patches.sh | 53 ++
libguestfs.spec | 44 ++-
8 files changed, 983 insertions(+), 1 deletions(-)
---
diff --git a/0001-New-API-add-drive-scratch.patch b/0001-New-API-add-drive-scratch.patch
new file mode 100644
index 0000000..cfd4249
--- /dev/null
+++ b/0001-New-API-add-drive-scratch.patch
@@ -0,0 +1,148 @@
+From dc6db5144a0e4f4b8238ef9b77949ac548991a52 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones at redhat.com>
+Date: Fri, 19 Jul 2013 14:09:56 +0100
+Subject: [PATCH] New API: add-drive-scratch.
+
+This adds a temporary scratch drive to the handle.
+
+(cherry picked from commit 1b11a83d5248511abbf86775601eb6e25a36c1ee)
+(cherry picked from commit eaffd8105fcd164616aad47cea2b2bf56686acfa)
+---
+ generator/actions.ml | 15 +++++++++++++++
+ gobject/Makefile.inc | 2 ++
+ po/POTFILES | 1 +
+ src/drives.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 71 insertions(+)
+
+diff --git a/generator/actions.ml b/generator/actions.ml
+index 1d44a47..4e6b687 100644
+--- a/generator/actions.ml
++++ b/generator/actions.ml
+@@ -2954,6 +2954,21 @@ it is set to the empty string (but never C<NULL>)." };
+ longdesc = "\
+ Get the program name. See C<guestfs_set_program>." };
+
++ { defaults with
++ name = "add_drive_scratch";
++ style = RErr, [Int64 "size"], [OString "name"; OString "label"];
++ blocking = false;
++ fish_alias = ["scratch"];
++ shortdesc = "add a temporary scratch drive";
++ longdesc = "\
++This command adds a temporary scratch drive to the handle. The
++C<size> parameter is the virtual size (in bytes). The scratch
++drive is blank initially (all reads return zeroes until you start
++writing to it). The drive is deleted when the handle is closed.
++
++The optional arguments C<name> and C<label> are passed through to
++C<guestfs_add_drive>." };
++
+ ]
+
+ (* daemon_functions are any functions which cause some action
+diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc
+index 69f7215..17da527 100644
+--- a/gobject/Makefile.inc
++++ b/gobject/Makefile.inc
+@@ -51,6 +51,7 @@ guestfs_gobject_headers= \
+ include/guestfs-gobject/optargs-inspect_get_icon.h \
+ include/guestfs-gobject/optargs-mount_local.h \
+ include/guestfs-gobject/optargs-umount_local.h \
++ include/guestfs-gobject/optargs-add_drive_scratch.h \
+ include/guestfs-gobject/optargs-is_file.h \
+ include/guestfs-gobject/optargs-is_dir.h \
+ include/guestfs-gobject/optargs-umount.h \
+@@ -123,6 +124,7 @@ guestfs_gobject_sources= \
+ src/optargs-inspect_get_icon.c \
+ src/optargs-mount_local.c \
+ src/optargs-umount_local.c \
++ src/optargs-add_drive_scratch.c \
+ src/optargs-is_file.c \
+ src/optargs-is_dir.c \
+ src/optargs-umount.c \
+diff --git a/po/POTFILES b/po/POTFILES
+index 71a539b..a083887 100644
+--- a/po/POTFILES
++++ b/po/POTFILES
+@@ -150,6 +150,7 @@ fuse/guestunmount.c
+ fuse/test-guestunmount-fd.c
+ gobject/src/optargs-add_domain.c
+ gobject/src/optargs-add_drive.c
++gobject/src/optargs-add_drive_scratch.c
+ gobject/src/optargs-btrfs_filesystem_resize.c
+ gobject/src/optargs-btrfs_fsck.c
+ gobject/src/optargs-compress_device_out.c
+diff --git a/src/drives.c b/src/drives.c
+index f515ede..98aead2 100644
+--- a/src/drives.c
++++ b/src/drives.c
+@@ -33,6 +33,7 @@
+ #include <netdb.h>
+ #include <arpa/inet.h>
+ #include <assert.h>
++#include <sys/types.h>
+
+ #include <pcre.h>
+
+@@ -1070,6 +1071,58 @@ guestfs__add_drive_ro_with_if (guestfs_h *g, const char *filename,
+ }
+
+ int
++guestfs__add_drive_scratch (guestfs_h *g, int64_t size,
++ const struct guestfs_add_drive_scratch_argv *optargs)
++{
++ struct guestfs_add_drive_opts_argv add_drive_optargs;
++ CLEANUP_FREE char *filename = NULL;
++ int fd;
++
++ /* Some parameters we always set. */
++ add_drive_optargs.bitmask = GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
++ add_drive_optargs.format = "raw";
++
++ /* Copy the optional arguments through to guestfs_add_drive_opts. */
++ if (optargs->bitmask & GUESTFS_ADD_DRIVE_SCRATCH_NAME_BITMASK) {
++ add_drive_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_NAME_BITMASK;
++ add_drive_optargs.name = optargs->name;
++ }
++ if (optargs->bitmask & GUESTFS_ADD_DRIVE_SCRATCH_LABEL_BITMASK) {
++ add_drive_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_LABEL_BITMASK;
++ add_drive_optargs.label = optargs->label;
++ }
++
++ /* Create the temporary file. We don't have to worry about cleanup
++ * because everything in g->tmpdir is 'rm -rf'd when the handle is
++ * closed.
++ */
++ if (guestfs___lazy_make_tmpdir (g) == -1)
++ return -1;
++ filename = safe_asprintf (g, "%s/scratch.%d", g->tmpdir, ++g->unique);
++
++ /* Create a raw format temporary disk. */
++ fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, 0600);
++ if (fd == -1) {
++ perrorf (g, "open: %s", filename);
++ return -1;
++ }
++
++ if (ftruncate (fd, size) == -1) {
++ perrorf (g, "ftruncate: %s", filename);
++ close (fd);
++ return -1;
++ }
++
++ if (close (fd) == -1) {
++ perrorf (g, "close: %s", filename);
++ return -1;
++ }
++
++ /* Call guestfs_add_drive_opts to add the drive. */
++ return guestfs_add_drive_opts_argv (g, filename, &add_drive_optargs);
++}
++
++int
+ guestfs__add_cdrom (guestfs_h *g, const char *filename)
+ {
+ if (strchr (filename, ':') != NULL) {
+--
+1.8.3.1
+
diff --git a/0002-add_drive-Introduce-cachemode-parameter-to-control-d.patch b/0002-add_drive-Introduce-cachemode-parameter-to-control-d.patch
new file mode 100644
index 0000000..ec3ee11
--- /dev/null
+++ b/0002-add_drive-Introduce-cachemode-parameter-to-control-d.patch
@@ -0,0 +1,566 @@
+From fe3d4b9f9e70b6ec61e5eb8a5c7076729d6e1ad8 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones at redhat.com>
+Date: Sat, 31 Aug 2013 22:24:40 +0100
+Subject: [PATCH] add_drive: Introduce 'cachemode' parameter to control drive
+ caching.
+
+This commit adds an optional 'cachemode' parameter to the 'add_drive'
+API to control caching. This corresponds approximately to the
+'-drive ...,cache=' parameter in qemu, but the choices are much more
+restrictive, just 'writeback' or 'unsafe', for reasons outlined below.
+
+The caching modes supported by recent QEMU are:
+
+ writeback:
+ - Reports data writes completed when data is present in the host
+ page cache.
+ Only safe provided guest correctly issues flush operations.
+
+ writethrough:
+ - Reports data writes completed only when each write has been
+ flushed to disk. Performance is reported as not good.
+
+ none:
+ - Uses O_DIRECT (avoids all interaction with host cache), but does
+ not ensure every write is flushed to disk.
+ Only safe provided guest correctly issues flush operations.
+
+ directsync:
+ - Uses O_DIRECT (avoids all interaction with host cache), and
+ ensures every write has been flushed to disk.
+
+ unsafe:
+ - No special handling.
+
+Since the libguestfs appliance kernel always issues flush operations
+(eg. for filesystem journalling and for sync) the following modes can
+be ignored: 'directsync', 'writethrough'.
+
+That leaves 'writeback', 'none' and 'unsafe'. However 'none' is both
+a constant source of pain (RHBZ#994517), is inefficient because it
+doesn't use the host cache, and does not give us any safety guarantees
+over and above 'writeback'. Therefore we should ignore 'none'.
+
+This leaves 'writeback' (safe) and 'unsafe' (fast, useful for scratch
+disks), which is what we implement in this patch.
+
+Note that the previous behaviour was to use 'none' if possible, else
+to use 'writeback'. The new behaviour is to use 'writeback' only
+which is (in safety terms) equivalent to 'none', and also faster and
+less painful (RHBZ#994517).
+
+This patch also allows you to specify a cache mode for network drives
+which also previously defaulted to 'writeback'.
+
+There is a considerable performance benefit to using unsafe (for
+scratch disks only, of course). The C API tests only use scratch
+disks (since they are just tests, the final state of the disk doesn't
+matter), and this decreases total run time from 202 seconds to 163
+seconds, about 25% faster.
+
+(cherry picked from commit 749e947bb0103f19feda0f29b6cbbf3cbfa350da)
+(cherry picked from commit c7304d0c8ebe38bc90547f149026ca279a4e7c46)
+---
+ generator/actions.ml | 30 ++++++++++-
+ src/drives.c | 141 +++++++++++++++++--------------------------------
+ src/guestfs-internal.h | 2 +-
+ src/launch-direct.c | 4 +-
+ src/launch-libvirt.c | 11 ++--
+ 5 files changed, 85 insertions(+), 103 deletions(-)
+
+diff --git a/generator/actions.ml b/generator/actions.ml
+index 4e6b687..eda43ed 100644
+--- a/generator/actions.ml
++++ b/generator/actions.ml
+@@ -1246,7 +1246,7 @@ not all belong to a single logical operating system
+
+ { defaults with
+ name = "add_drive";
+- style = RErr, [String "filename"], [OBool "readonly"; OString "format"; OString "iface"; OString "name"; OString "label"; OString "protocol"; OStringList "server"; OString "username"; OString "secret"];
++ style = RErr, [String "filename"], [OBool "readonly"; OString "format"; OString "iface"; OString "name"; OString "label"; OString "protocol"; OStringList "server"; OString "username"; OString "secret"; OString "cachemode"];
+ once_had_no_optargs = true;
+ blocking = false;
+ fish_alias = ["add"];
+@@ -1436,6 +1436,34 @@ If not given, then a secret matching the given username will be looked up in the
+ default keychain locations, or if no username is given, then no authentication
+ will be used.
+
++=item C<cachemode>
++
++Choose whether or not libguestfs will obey sync operations (safe but slow)
++or not (unsafe but fast). The possible values for this string are:
++
++=over 4
++
++=item C<cachemode = \"writeback\">
++
++This is the default.
++
++Write operations in the API do not return until a L<write(2)>
++call has completed in the host [but note this does not imply
++that anything gets written to disk].
++
++Sync operations in the API, including implicit syncs caused by
++filesystem journalling, will not return until an L<fdatasync(2)>
++call has completed in the host, indicating that data has been
++committed to disk.
++
++=item C<cachemode = \"unsafe\">
++
++In this mode, there are no guarantees. Libguestfs may cache
++anything and ignore sync requests. This is suitable only
++for scratch or temporary disks.
++
++=back
++
+ =back" };
+
+ { defaults with
+diff --git a/src/drives.c b/src/drives.c
+index 98aead2..a6cc45a 100644
+--- a/src/drives.c
++++ b/src/drives.c
+@@ -86,8 +86,7 @@ static struct drive *
+ create_drive_file (guestfs_h *g, const char *path,
+ bool readonly, const char *format,
+ const char *iface, const char *name,
+- const char *disk_label,
+- bool use_cache_none)
++ const char *disk_label, const char *cachemode)
+ {
+ struct drive *drv = safe_calloc (g, 1, sizeof *drv);
+
+@@ -99,7 +98,7 @@ create_drive_file (guestfs_h *g, const char *path,
+ drv->iface = iface ? safe_strdup (g, iface) : NULL;
+ drv->name = name ? safe_strdup (g, name) : NULL;
+ drv->disk_label = disk_label ? safe_strdup (g, disk_label) : NULL;
+- drv->use_cache_none = use_cache_none;
++ drv->cachemode = cachemode ? safe_strdup (g, cachemode) : NULL;
+
+ drv->priv = drv->free_priv = NULL;
+
+@@ -114,8 +113,7 @@ create_drive_non_file (guestfs_h *g,
+ const char *username, const char *secret,
+ bool readonly, const char *format,
+ const char *iface, const char *name,
+- const char *disk_label,
+- bool use_cache_none)
++ const char *disk_label, const char *cachemode)
+ {
+ struct drive *drv = safe_calloc (g, 1, sizeof *drv);
+
+@@ -131,7 +129,7 @@ create_drive_non_file (guestfs_h *g,
+ drv->iface = iface ? safe_strdup (g, iface) : NULL;
+ drv->name = name ? safe_strdup (g, name) : NULL;
+ drv->disk_label = disk_label ? safe_strdup (g, disk_label) : NULL;
+- drv->use_cache_none = use_cache_none;
++ drv->cachemode = cachemode ? safe_strdup (g, cachemode) : NULL;
+
+ drv->priv = drv->free_priv = NULL;
+
+@@ -146,8 +144,7 @@ create_drive_curl (guestfs_h *g,
+ const char *username, const char *secret,
+ bool readonly, const char *format,
+ const char *iface, const char *name,
+- const char *disk_label,
+- bool use_cache_none)
++ const char *disk_label, const char *cachemode)
+ {
+ if (secret != NULL) {
+ error (g, _("curl: you cannot specify a secret with this protocol"));
+@@ -179,7 +176,7 @@ create_drive_curl (guestfs_h *g,
+ servers, nr_servers, exportname,
+ username, secret,
+ readonly, format, iface, name, disk_label,
+- use_cache_none);
++ cachemode);
+ }
+
+ static struct drive *
+@@ -189,8 +186,7 @@ create_drive_gluster (guestfs_h *g,
+ const char *username, const char *secret,
+ bool readonly, const char *format,
+ const char *iface, const char *name,
+- const char *disk_label,
+- bool use_cache_none)
++ const char *disk_label, const char *cachemode)
+ {
+ if (username != NULL) {
+ error (g, _("gluster: you cannot specify a username with this protocol"));
+@@ -220,7 +216,7 @@ create_drive_gluster (guestfs_h *g,
+ servers, nr_servers, exportname,
+ username, secret,
+ readonly, format, iface, name, disk_label,
+- use_cache_none);
++ cachemode);
+ }
+
+ static int
+@@ -242,8 +238,7 @@ create_drive_nbd (guestfs_h *g,
+ const char *username, const char *secret,
+ bool readonly, const char *format,
+ const char *iface, const char *name,
+- const char *disk_label,
+- bool use_cache_none)
++ const char *disk_label, const char *cachemode)
+ {
+ if (username != NULL) {
+ error (g, _("nbd: you cannot specify a username with this protocol"));
+@@ -266,7 +261,7 @@ create_drive_nbd (guestfs_h *g,
+ servers, nr_servers, exportname,
+ username, secret,
+ readonly, format, iface, name, disk_label,
+- use_cache_none);
++ cachemode);
+ }
+
+ static struct drive *
+@@ -276,8 +271,7 @@ create_drive_rbd (guestfs_h *g,
+ const char *username, const char *secret,
+ bool readonly, const char *format,
+ const char *iface, const char *name,
+- const char *disk_label,
+- bool use_cache_none)
++ const char *disk_label, const char *cachemode)
+ {
+ size_t i;
+
+@@ -312,7 +306,7 @@ create_drive_rbd (guestfs_h *g,
+ servers, nr_servers, exportname,
+ username, secret,
+ readonly, format, iface, name, disk_label,
+- use_cache_none);
++ cachemode);
+ }
+
+ static struct drive *
+@@ -322,8 +316,7 @@ create_drive_sheepdog (guestfs_h *g,
+ const char *username, const char *secret,
+ bool readonly, const char *format,
+ const char *iface, const char *name,
+- const char *disk_label,
+- bool use_cache_none)
++ const char *disk_label, const char *cachemode)
+ {
+ size_t i;
+
+@@ -362,7 +355,7 @@ create_drive_sheepdog (guestfs_h *g,
+ servers, nr_servers, exportname,
+ username, secret,
+ readonly, format, iface, name, disk_label,
+- use_cache_none);
++ cachemode);
+ }
+
+ static struct drive *
+@@ -372,8 +365,7 @@ create_drive_ssh (guestfs_h *g,
+ const char *username, const char *secret,
+ bool readonly, const char *format,
+ const char *iface, const char *name,
+- const char *disk_label,
+- bool use_cache_none)
++ const char *disk_label, const char *cachemode)
+ {
+ if (secret != NULL) {
+ error (g, _("ssh: you cannot specify a secret with this protocol"));
+@@ -410,7 +402,7 @@ create_drive_ssh (guestfs_h *g,
+ servers, nr_servers, exportname,
+ username, secret,
+ readonly, format, iface, name, disk_label,
+- use_cache_none);
++ cachemode);
+ }
+
+ static struct drive *
+@@ -420,8 +412,7 @@ create_drive_iscsi (guestfs_h *g,
+ const char *username, const char *secret,
+ bool readonly, const char *format,
+ const char *iface, const char *name,
+- const char *disk_label,
+- bool use_cache_none)
++ const char *disk_label, const char *cachemode)
+ {
+ if (username != NULL) {
+ error (g, _("iscsi: you cannot specify a username with this protocol"));
+@@ -458,7 +449,7 @@ create_drive_iscsi (guestfs_h *g,
+ servers, nr_servers, exportname,
+ username, secret,
+ readonly, format, iface, name, disk_label,
+- use_cache_none);
++ cachemode);
+ }
+
+ /* Traditionally you have been able to use /dev/null as a filename, as
+@@ -537,6 +528,7 @@ free_drive_struct (struct drive *drv)
+ free (drv->iface);
+ free (drv->name);
+ free (drv->disk_label);
++ free (drv->cachemode);
+
+ if (drv->priv && drv->free_priv)
+ drv->free_priv (drv->priv);
+@@ -555,7 +547,7 @@ drive_to_string (guestfs_h *g, const struct drive *drv)
+ p = guestfs___drive_source_qemu_param (g, &drv->src);
+
+ return safe_asprintf
+- (g, "%s%s%s%s%s%s%s%s%s%s%s",
++ (g, "%s%s%s%s%s%s%s%s%s%s%s%s",
+ p,
+ drv->readonly ? " readonly" : "",
+ drv->format ? " format=" : "",
+@@ -566,7 +558,8 @@ drive_to_string (guestfs_h *g, const struct drive *drv)
+ drv->name ? : "",
+ drv->disk_label ? " label=" : "",
+ drv->disk_label ? : "",
+- drv->use_cache_none ? " cache=none" : "");
++ drv->cachemode ? " cache=" : "",
++ drv->cachemode ? : "");
+ }
+
+ /* Add struct drive to the g->drives vector at the given index. */
+@@ -621,47 +614,6 @@ guestfs___free_drives (guestfs_h *g)
+ g->nr_drives = 0;
+ }
+
+-/* cache=none improves reliability in the event of a host crash.
+- *
+- * However this option causes qemu to try to open the file with
+- * O_DIRECT. This fails on some filesystem types (notably tmpfs).
+- * So we check if we can open the file with or without O_DIRECT,
+- * and use cache=none (or not) accordingly.
+- *
+- * Notes:
+- *
+- * (1) In qemu, cache=none and cache=off are identical.
+- *
+- * (2) cache=none does not disable caching entirely. qemu still
+- * maintains a writeback cache internally, which will be written out
+- * when qemu is killed (with SIGTERM). It disables *host kernel*
+- * caching by using O_DIRECT. To disable caching entirely in kernel
+- * and qemu we would need to use cache=directsync but there is a
+- * performance penalty for that.
+- *
+- * (3) This function is only called on the !readonly path. We must
+- * try to open with O_RDWR to test that the file is readable and
+- * writable here.
+- */
+-static int
+-test_cache_none (guestfs_h *g, const char *filename)
+-{
+- int fd = open (filename, O_RDWR|O_DIRECT);
+- if (fd >= 0) {
+- close (fd);
+- return 1;
+- }
+-
+- fd = open (filename, O_RDWR);
+- if (fd >= 0) {
+- close (fd);
+- return 0;
+- }
+-
+- perrorf (g, "%s", filename);
+- return -1;
+-}
+-
+ /* Check string parameter matches ^[-_[:alnum:]]+$ (in C locale). */
+ static int
+ valid_format_iface (const char *str)
+@@ -827,7 +779,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
+ struct drive_server *servers = NULL;
+ const char *username;
+ const char *secret;
+- int use_cache_none;
++ const char *cachemode;
+ struct drive *drv;
+ size_t i, drv_index;
+
+@@ -853,6 +805,8 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
+ ? optargs->username : NULL;
+ secret = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_SECRET_BITMASK
+ ? optargs->secret : NULL;
++ cachemode = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_CACHEMODE_BITMASK
++ ? optargs->cachemode : NULL;
+
+ if (format && !valid_format_iface (format)) {
+ error (g, _("%s parameter is empty or contains disallowed characters"),
+@@ -871,6 +825,12 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
+ free_drive_servers (servers, nr_servers);
+ return -1;
+ }
++ if (cachemode &&
++ !(STREQ (cachemode, "writeback") || STREQ (cachemode, "unsafe"))) {
++ error (g, _("cachemode parameter must be 'writeback' (default) or 'unsafe'"));
++ free_drive_servers (servers, nr_servers);
++ return -1;
++ }
+
+ if (STREQ (protocol, "file")) {
+ if (servers != NULL) {
+@@ -891,23 +851,16 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
+ drv = create_drive_dev_null (g, readonly, format, iface, name,
+ disk_label);
+ else {
+- /* For writable files, see if we can use cache=none. This also
+- * checks for the existence of the file. For readonly we have
+- * to do the check explicitly.
++ /* We have to check for the existence of the file since that's
++ * required by the API.
+ */
+- use_cache_none = readonly ? false : test_cache_none (g, filename);
+- if (use_cache_none == -1)
++ if (access (filename, R_OK) == -1) {
++ perrorf (g, "%s", filename);
+ return -1;
+-
+- if (readonly) {
+- if (access (filename, R_OK) == -1) {
+- perrorf (g, "%s", filename);
+- return -1;
+- }
+ }
+
+ drv = create_drive_file (g, filename, readonly, format, iface, name,
+- disk_label, use_cache_none);
++ disk_label, cachemode);
+ }
+ }
+ else if (STREQ (protocol, "ftp")) {
+@@ -915,71 +868,71 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
+ servers, nr_servers, filename,
+ username, secret,
+ readonly, format, iface, name,
+- disk_label, false);
++ disk_label, cachemode);
+ }
+ else if (STREQ (protocol, "ftps")) {
+ drv = create_drive_curl (g, drive_protocol_ftps,
+ servers, nr_servers, filename,
+ username, secret,
+ readonly, format, iface, name,
+- disk_label, false);
++ disk_label, cachemode);
+ }
+ else if (STREQ (protocol, "gluster")) {
+ drv = create_drive_gluster (g, servers, nr_servers, filename,
+ username, secret,
+ readonly, format, iface, name,
+- disk_label, false);
++ disk_label, cachemode);
+ }
+ else if (STREQ (protocol, "http")) {
+ drv = create_drive_curl (g, drive_protocol_http,
+ servers, nr_servers, filename,
+ username, secret,
+ readonly, format, iface, name,
+- disk_label, false);
++ disk_label, cachemode);
+ }
+ else if (STREQ (protocol, "https")) {
+ drv = create_drive_curl (g, drive_protocol_https,
+ servers, nr_servers, filename,
+ username, secret,
+ readonly, format, iface, name,
+- disk_label, false);
++ disk_label, cachemode);
+ }
+ else if (STREQ (protocol, "iscsi")) {
+ drv = create_drive_iscsi (g, servers, nr_servers, filename,
+ username, secret,
+ readonly, format, iface, name,
+- disk_label, false);
++ disk_label, cachemode);
+ }
+ else if (STREQ (protocol, "nbd")) {
+ drv = create_drive_nbd (g, servers, nr_servers, filename,
+ username, secret,
+ readonly, format, iface, name,
+- disk_label, false);
++ disk_label, cachemode);
+ }
+ else if (STREQ (protocol, "rbd")) {
+ drv = create_drive_rbd (g, servers, nr_servers, filename,
+ username, secret,
+ readonly, format, iface, name,
+- disk_label, false);
++ disk_label, cachemode);
+ }
+ else if (STREQ (protocol, "sheepdog")) {
+ drv = create_drive_sheepdog (g, servers, nr_servers, filename,
+ username, secret,
+ readonly, format, iface, name,
+- disk_label, false);
++ disk_label, cachemode);
+ }
+ else if (STREQ (protocol, "ssh")) {
+ drv = create_drive_ssh (g, servers, nr_servers, filename,
+ username, secret,
+ readonly, format, iface, name,
+- disk_label, false);
++ disk_label, cachemode);
+ }
+ else if (STREQ (protocol, "tftp")) {
+ drv = create_drive_curl (g, drive_protocol_tftp,
+ servers, nr_servers, filename,
+ username, secret,
+ readonly, format, iface, name,
+- disk_label, false);
++ disk_label, cachemode);
+ }
+ else {
+ error (g, _("unknown protocol '%s'"), protocol);
+diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
+index 347068b..8dc9983 100644
+--- a/src/guestfs-internal.h
++++ b/src/guestfs-internal.h
+@@ -197,7 +197,7 @@ struct drive {
+ char *iface;
+ char *name;
+ char *disk_label;
+- bool use_cache_none;
++ char *cachemode;
+
+ /* Data used by the backend. */
+ void *priv;
+diff --git a/src/launch-direct.c b/src/launch-direct.c
+index 82e9c12..414658e 100644
+--- a/src/launch-direct.c
++++ b/src/launch-direct.c
+@@ -992,10 +992,10 @@ qemu_drive_param (guestfs_h *g, const struct drive *drv, size_t index)
+ iface = "virtio";
+
+ return safe_asprintf
+- (g, "file=%s%s%s%s%s%s%s,id=hd%zu,if=%s",
++ (g, "file=%s%s,cache=%s%s%s%s%s,id=hd%zu,if=%s",
+ escaped_file,
+ drv->readonly ? ",snapshot=on" : "",
+- drv->use_cache_none ? ",cache=none" : "",
++ drv->cachemode ? drv->cachemode : "writeback",
+ drv->format ? ",format=" : "",
+ drv->format ? drv->format : "",
+ drv->disk_label ? ",serial=" : "",
+diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
+index faafeba..16a5453 100644
+--- a/src/launch-libvirt.c
++++ b/src/launch-libvirt.c
+@@ -1218,11 +1218,12 @@ construct_libvirt_xml_disk (guestfs_h *g,
+ return -1;
+ }
+
+- if (drv->use_cache_none) {
+- XMLERROR (-1,
+- xmlTextWriterWriteAttribute (xo, BAD_CAST "cache",
+- BAD_CAST "none"));
+- }
++ XMLERROR (-1,
++ xmlTextWriterWriteAttribute (xo, BAD_CAST "cache",
++ BAD_CAST (drv->cachemode ?
++ drv->cachemode :
++ "writeback")));
++
+ XMLERROR (-1, xmlTextWriterEndElement (xo));
+
+ if (drv->disk_label) {
+--
+1.8.3.1
+
diff --git a/0003-drives-Ensure-all-scratch-drives-use-cachemode-unsaf.patch b/0003-drives-Ensure-all-scratch-drives-use-cachemode-unsaf.patch
new file mode 100644
index 0000000..d44a49d
--- /dev/null
+++ b/0003-drives-Ensure-all-scratch-drives-use-cachemode-unsaf.patch
@@ -0,0 +1,39 @@
+From 5f54c5961f154f83dfe36caf319dcc75718c5ad2 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones at redhat.com>
+Date: Sat, 31 Aug 2013 22:38:03 +0100
+Subject: [PATCH] drives: Ensure all scratch drives use cachemode "unsafe".
+
+They are _scratch_ drives so any data on them doesn't matter and can
+be reconstructed in the event of a host system crash.
+
+(cherry picked from commit 96cd7fcecb031bfe6baa49addfb026ae988fb7c1)
+(cherry picked from commit 053061f66f79d21bb48d089717a171470e05e47e)
+---
+ src/drives.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/drives.c b/src/drives.c
+index a6cc45a..ebd17f3 100644
+--- a/src/drives.c
++++ b/src/drives.c
+@@ -1027,13 +1027,15 @@ int
+ guestfs__add_drive_scratch (guestfs_h *g, int64_t size,
+ const struct guestfs_add_drive_scratch_argv *optargs)
+ {
+- struct guestfs_add_drive_opts_argv add_drive_optargs;
++ struct guestfs_add_drive_opts_argv add_drive_optargs = { .bitmask = 0 };
+ CLEANUP_FREE char *filename = NULL;
+ int fd;
+
+ /* Some parameters we always set. */
+- add_drive_optargs.bitmask = GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
++ add_drive_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
+ add_drive_optargs.format = "raw";
++ add_drive_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_CACHEMODE_BITMASK;
++ add_drive_optargs.cachemode = "unsafe";
+
+ /* Copy the optional arguments through to guestfs_add_drive_opts. */
+ if (optargs->bitmask & GUESTFS_ADD_DRIVE_SCRATCH_NAME_BITMASK) {
+--
+1.8.3.1
+
diff --git a/0004-sparsify-Use-cachemode-unsafe-for-the-overlay-disk.patch b/0004-sparsify-Use-cachemode-unsafe-for-the-overlay-disk.patch
new file mode 100644
index 0000000..5bcadae
--- /dev/null
+++ b/0004-sparsify-Use-cachemode-unsafe-for-the-overlay-disk.patch
@@ -0,0 +1,27 @@
+From 31a4bc0065dc2d4b4812b38f5296c771e7c088cd Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones at redhat.com>
+Date: Sat, 31 Aug 2013 22:47:44 +0100
+Subject: [PATCH] sparsify: Use cachemode "unsafe" for the overlay disk.
+
+(cherry picked from commit f3a9c9f867bed178d1aabf9675955f633bf3069a)
+(cherry picked from commit 322bf1dd40559d554f5c7540adbe49deacd5f590)
+---
+ sparsify/sparsify.ml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sparsify/sparsify.ml b/sparsify/sparsify.ml
+index 7f0090b..77dd2c7 100644
+--- a/sparsify/sparsify.ml
++++ b/sparsify/sparsify.ml
+@@ -265,7 +265,7 @@ let g =
+ if verbose then g#set_verbose true;
+
+ (* Note that the temporary overlay disk is always qcow2 format. *)
+- g#add_drive ~format:"qcow2" ~readonly:false overlaydisk;
++ g#add_drive ~format:"qcow2" ~readonly:false ~cachemode:"unsafe" overlaydisk;
+
+ if not quiet then Progress.set_up_progress_bar ~machine_readable g;
+ g#launch ();
+--
+1.8.3.1
+
diff --git a/0005-rescue-Use-cachemode-unsafe-for-the-virt-rescue-scra.patch b/0005-rescue-Use-cachemode-unsafe-for-the-virt-rescue-scra.patch
new file mode 100644
index 0000000..f5cb8fb
--- /dev/null
+++ b/0005-rescue-Use-cachemode-unsafe-for-the-virt-rescue-scra.patch
@@ -0,0 +1,64 @@
+From 50d33d4463ad702fdd79484b9441fb2565d76dae Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones at redhat.com>
+Date: Sat, 31 Aug 2013 22:48:04 +0100
+Subject: [PATCH] rescue: Use cachemode "unsafe" for the virt-rescue --scratch
+ option.
+
+(cherry picked from commit 3f0748f1fc64e42517c0d4535c27b1f32da86023)
+(cherry picked from commit 1e421afa988195bead6650c421d9752fed32b73f)
+---
+ fish/options.c | 5 +++++
+ fish/options.h | 1 +
+ rescue/rescue.c | 1 +
+ 3 files changed, 7 insertions(+)
+
+diff --git a/fish/options.c b/fish/options.c
+index 6d63afa..75d61ad 100644
+--- a/fish/options.c
++++ b/fish/options.c
+@@ -110,6 +110,10 @@ add_drives (struct drv *drv, char next_drive)
+ ad_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_FORMAT_BITMASK;
+ ad_optargs.format = drv->a.format;
+ }
++ if (drv->a.cachemode) {
++ ad_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_CACHEMODE_BITMASK;
++ ad_optargs.cachemode = drv->a.cachemode;
++ }
+
+ r = guestfs_add_drive_opts_argv (g, drv->a.filename, &ad_optargs);
+ if (r == -1)
+@@ -254,6 +258,7 @@ free_drives (struct drv *drv)
+ case drv_a:
+ free (drv->a.filename);
+ /* a.format is an optarg, so don't free it */
++ /* a.cachemode is a static string, so don't free it */
+ break;
+ case drv_uri:
+ free (drv->uri.path);
+diff --git a/fish/options.h b/fish/options.h
+index 507ec1c..e2192b5 100644
+--- a/fish/options.h
++++ b/fish/options.h
+@@ -60,6 +60,7 @@ struct drv {
+ struct {
+ char *filename; /* disk filename */
+ const char *format; /* format (NULL == autodetect) */
++ const char *cachemode;/* cachemode (NULL == default) */
+ } a;
+ struct {
+ char *path; /* disk path */
+diff --git a/rescue/rescue.c b/rescue/rescue.c
+index 65dd473..942c54a 100644
+--- a/rescue/rescue.c
++++ b/rescue/rescue.c
+@@ -580,6 +580,7 @@ add_scratch_disk (struct drv **drvs)
+ exit (EXIT_FAILURE);
+ }
+ drv->a.format = "raw";
++ drv->a.cachemode = "unsafe"; /* because it's a scratch disk */
+ drv->next = *drvs;
+ *drvs = drv;
+ }
+--
+1.8.3.1
+
diff --git a/0006-launch-direct-Always-use-cache-unsafe-for-the-applia.patch b/0006-launch-direct-Always-use-cache-unsafe-for-the-applia.patch
new file mode 100644
index 0000000..21b3be1
--- /dev/null
+++ b/0006-launch-direct-Always-use-cache-unsafe-for-the-applia.patch
@@ -0,0 +1,43 @@
+From b54c131813d7a109a00c39d2597ae5ada8b68807 Mon Sep 17 00:00:00 2001
+From: "Richard W.M. Jones" <rjones at redhat.com>
+Date: Thu, 5 Sep 2013 18:45:24 +0100
+Subject: [PATCH] launch: direct: Always use cache=unsafe for the appliance.
+
+The code to select writeback was redundant, because current
+qemu always supports cache=unsafe.
+
+(cherry picked from commit 011c9639267f5f1bfac41e664b2c57cc12deabf8)
+(cherry picked from commit 5be3a863c57aa56677338b499c4d6774d6384c3d)
+---
+ src/launch-direct.c | 12 ++----------
+ 1 file changed, 2 insertions(+), 10 deletions(-)
+
+diff --git a/src/launch-direct.c b/src/launch-direct.c
+index 414658e..798d130 100644
+--- a/src/launch-direct.c
++++ b/src/launch-direct.c
+@@ -375,19 +375,11 @@ launch_direct (guestfs_h *g, const char *arg)
+
+ /* Add the ext2 appliance drive (after all the drives). */
+ if (has_appliance_drive) {
+- 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";
+- }
+-
+ size_t buf2_len = strlen (appliance) + 64;
+ char buf2[buf2_len];
+ add_cmdline (g, "-drive");
+- snprintf (buf2, buf2_len, "file=%s,snapshot=on,id=appliance,if=%s%s",
+- appliance, virtio_scsi ? "none" : "virtio", cachemode);
++ snprintf (buf2, buf2_len, "file=%s,snapshot=on,id=appliance,if=%s",
++ appliance, virtio_scsi ? "none" : "virtio");
+ add_cmdline (g, buf2);
+
+ if (virtio_scsi) {
+--
+1.8.3.1
+
diff --git a/copy-patches.sh b/copy-patches.sh
new file mode 100755
index 0000000..f288543
--- /dev/null
+++ b/copy-patches.sh
@@ -0,0 +1,53 @@
+#!/bin/bash -
+
+set -e
+
+# Maintainer script to copy patches from the git repo to the current
+# directory. Use it like this:
+# ./copy-patches.sh
+
+# Check we're in the right directory.
+if [ ! -f libguestfs.spec ]; then
+ echo "$0: run this from the directory containing 'libguestfs.spec'"
+ exit 1
+fi
+
+git_checkout=$HOME/d/libguestfs-fedora-19
+if [ ! -d $git_checkout ]; then
+ echo "$0: $git_checkout does not exist"
+ echo "This script is only for use by the maintainer when preparing a"
+ echo "libguestfs release for Fedora 19."
+ exit 1
+fi
+
+# Get the base version of libguestfs.
+version=`grep '^Version:' libguestfs.spec | awk '{print $2}'`
+
+# Remove any existing patches.
+git rm -f [0-9]*.patch ||:
+rm -f [0-9]*.patch
+
+# Get the patches.
+(cd $git_checkout; rm -f [0-9]*.patch; git format-patch -N $version)
+mv $git_checkout/[0-9]*.patch .
+
+# Remove any not to be applied.
+rm -f *NOT-FOR-RPM*.patch
+
+# Add the patches.
+git add [0-9]*.patch
+
+# Print out the patch lines.
+echo
+echo "--- Copy the following text into libguestfs.spec file"
+echo
+
+echo "# Git-managed patches."
+for f in [0-9]*.patch; do
+ n=`echo $f | awk -F- '{print $1}'`
+ echo "Patch$n: $f"
+done
+
+echo "# Add any non-git patches here."
+echo
+echo "--- End of text"
diff --git a/libguestfs.spec b/libguestfs.spec
index d7c1297..d802fcc 100644
--- a/libguestfs.spec
+++ b/libguestfs.spec
@@ -12,13 +12,33 @@ Summary: Access and modify virtual machine disk images
Name: libguestfs
Epoch: 1
Version: 1.22.7
-Release: 2%{?dist}
+Release: 3%{?dist}
License: LGPLv2+
# Source and patches.
URL: http://libguestfs.org/
Source0: http://libguestfs.org/download/1.22-stable/%{name}-%{version}.tar.gz
+# Note we use the fedora-19 branch from the upstream repo which
+# contains only upstream, backported patches, but conveniently manages
+# them in git. In order to update this list, run the
+# 'copy-patches.sh' script.
+
+# Git-managed patches.
+Patch0001: 0001-New-API-add-drive-scratch.patch
+Patch0002: 0002-add_drive-Introduce-cachemode-parameter-to-control-d.patch
+Patch0003: 0003-drives-Ensure-all-scratch-drives-use-cachemode-unsaf.patch
+Patch0004: 0004-sparsify-Use-cachemode-unsafe-for-the-overlay-disk.patch
+Patch0005: 0005-rescue-Use-cachemode-unsafe-for-the-virt-rescue-scra.patch
+Patch0006: 0006-launch-direct-Always-use-cache-unsafe-for-the-applia.patch
+# Add any non-git patches here.
+
+# Use git for patch management.
+BuildRequires: git
+
+# Run autotools after applying the patches.
+BuildRequires: autoconf, automake, libtool, gettext-devel
+
# Basic build requirements:
BuildRequires: perl(Pod::Simple)
BuildRequires: perl(Pod::Man)
@@ -133,6 +153,8 @@ Source3: 99-guestfsd.rules
# Replacement README file for Fedora users.
Source4: README-replacement.in
+Source5: copy-patches.sh
+
# https://fedoraproject.org/wiki/Packaging:No_Bundled_Libraries#Packages_granted_exceptions
Provides: bundled(gnulib)
@@ -522,6 +544,19 @@ for %{name}.
%prep
%setup -q
+# Use git to manage patches.
+# http://rwmj.wordpress.com/2011/08/09/nice-rpm-git-patch-management-trick/
+git init
+git config user.email "libguestfs at redhat.com"
+git config user.name "libguestfs"
+git add .
+git commit -a -q -m "%{version} baseline"
+git am %{patches}
+
+# Patches affect Makefile.am and configure.ac, so rerun autotools.
+autoreconf -i
+autoconf
+
if [ "$(getenforce | tr '[A-Z]' '[a-z]')" != "disabled" ]; then
# For sVirt to work, the local temporary directory we use in the
# tests must be labelled the same way as /tmp.
@@ -578,6 +613,9 @@ fi
--enable-install-daemon \
$extra
+# Patches above add man pages, so this is needed.
+make -C po-docs update-po
+
# 'INSTALLDIRS' ensures that Perl and Ruby libs are installed in the
# vendor dir not the site dir.
make V=1 INSTALLDIRS=vendor %{?_smp_mflags}
@@ -897,6 +935,10 @@ mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/run/libguestfs
%changelog
+* Fri Dec 20 2013 Richard W.M. Jones <rjones at redhat.com> - 1:1.22.7-3
+- Backport cachemode parameter from upstream (RHBZ#1044762).
+- Use git to manage patches, add copy-patches.sh script.
+
* Tue Oct 22 2013 Richard W.M. Jones <rjones at redhat.com> - 1:1.22.7-2
- Don't use versioned jar file (RHBZ#1022133).
More information about the scm-commits
mailing list