[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