mrc0mmand / rpms / libguestfs

Forked from rpms/libguestfs 3 years ago
Clone

Blame SOURCES/0023-add_drive-Introduce-cachemode-parameter-to-control-d.patch

022f11
From c7304d0c8ebe38bc90547f149026ca279a4e7c46 Mon Sep 17 00:00:00 2001
022f11
From: "Richard W.M. Jones" <rjones@redhat.com>
022f11
Date: Sat, 31 Aug 2013 22:24:40 +0100
022f11
Subject: [PATCH] add_drive: Introduce 'cachemode' parameter to control drive
022f11
 caching.
022f11
022f11
This commit adds an optional 'cachemode' parameter to the 'add_drive'
022f11
API to control caching.  This corresponds approximately to the
022f11
'-drive ...,cache=' parameter in qemu, but the choices are much more
022f11
restrictive, just 'writeback' or 'unsafe', for reasons outlined below.
022f11
022f11
The caching modes supported by recent QEMU are:
022f11
022f11
  writeback:
022f11
   - Reports data writes completed when data is present in the host
022f11
     page cache.
022f11
     Only safe provided guest correctly issues flush operations.
022f11
022f11
  writethrough:
022f11
   - Reports data writes completed only when each write has been
022f11
     flushed to disk.  Performance is reported as not good.
022f11
022f11
  none:
022f11
   - Uses O_DIRECT (avoids all interaction with host cache), but does
022f11
     not ensure every write is flushed to disk.
022f11
     Only safe provided guest correctly issues flush operations.
022f11
022f11
  directsync:
022f11
   - Uses O_DIRECT (avoids all interaction with host cache), and
022f11
     ensures every write has been flushed to disk.
022f11
022f11
  unsafe:
022f11
   - No special handling.
022f11
022f11
Since the libguestfs appliance kernel always issues flush operations
022f11
(eg. for filesystem journalling and for sync) the following modes can
022f11
be ignored: 'directsync', 'writethrough'.
022f11
022f11
That leaves 'writeback', 'none' and 'unsafe'.  However 'none' is both
022f11
a constant source of pain (RHBZ#994517), is inefficient because it
022f11
doesn't use the host cache, and does not give us any safety guarantees
022f11
over and above 'writeback'.  Therefore we should ignore 'none'.
022f11
022f11
This leaves 'writeback' (safe) and 'unsafe' (fast, useful for scratch
022f11
disks), which is what we implement in this patch.
022f11
022f11
Note that the previous behaviour was to use 'none' if possible, else
022f11
to use 'writeback'.  The new behaviour is to use 'writeback' only
022f11
which is (in safety terms) equivalent to 'none', and also faster and
022f11
less painful (RHBZ#994517).
022f11
022f11
This patch also allows you to specify a cache mode for network drives
022f11
which also previously defaulted to 'writeback'.
022f11
022f11
There is a considerable performance benefit to using unsafe (for
022f11
scratch disks only, of course).  The C API tests only use scratch
022f11
disks (since they are just tests, the final state of the disk doesn't
022f11
matter), and this decreases total run time from 202 seconds to 163
022f11
seconds, about 25% faster.
022f11
022f11
(cherry picked from commit 749e947bb0103f19feda0f29b6cbbf3cbfa350da)
022f11
---
022f11
 generator/actions.ml   |  30 ++++++++++-
022f11
 src/drives.c           | 141 +++++++++++++++++--------------------------------
022f11
 src/guestfs-internal.h |   2 +-
022f11
 src/launch-direct.c    |   4 +-
022f11
 src/launch-libvirt.c   |  11 ++--
022f11
 5 files changed, 85 insertions(+), 103 deletions(-)
022f11
022f11
diff --git a/generator/actions.ml b/generator/actions.ml
022f11
index 435411b..8bc37de 100644
022f11
--- a/generator/actions.ml
022f11
+++ b/generator/actions.ml
022f11
@@ -1246,7 +1246,7 @@ not all belong to a single logical operating system
022f11
 
022f11
   { defaults with
022f11
     name = "add_drive";
022f11
-    style = RErr, [String "filename"], [OBool "readonly"; OString "format"; OString "iface"; OString "name"; OString "label"; OString "protocol"; OStringList "server"; OString "username"; OString "secret"];
022f11
+    style = RErr, [String "filename"], [OBool "readonly"; OString "format"; OString "iface"; OString "name"; OString "label"; OString "protocol"; OStringList "server"; OString "username"; OString "secret"; OString "cachemode"];
022f11
     once_had_no_optargs = true;
022f11
     blocking = false;
022f11
     fish_alias = ["add"];
022f11
@@ -1436,6 +1436,34 @@ If not given, then a secret matching the given username will be looked up in the
022f11
 default keychain locations, or if no username is given, then no authentication
022f11
 will be used.
022f11
 
022f11
+=item C<cachemode>
022f11
+
022f11
+Choose whether or not libguestfs will obey sync operations (safe but slow)
022f11
+or not (unsafe but fast).  The possible values for this string are:
022f11
+
022f11
+=over 4
022f11
+
022f11
+=item C<cachemode = \"writeback\">
022f11
+
022f11
+This is the default.
022f11
+
022f11
+Write operations in the API do not return until a L<write(2)>
022f11
+call has completed in the host [but note this does not imply
022f11
+that anything gets written to disk].
022f11
+
022f11
+Sync operations in the API, including implicit syncs caused by
022f11
+filesystem journalling, will not return until an L<fdatasync(2)>
022f11
+call has completed in the host, indicating that data has been
022f11
+committed to disk.
022f11
+
022f11
+=item C<cachemode = \"unsafe\">
022f11
+
022f11
+In this mode, there are no guarantees.  Libguestfs may cache
022f11
+anything and ignore sync requests.  This is suitable only
022f11
+for scratch or temporary disks.
022f11
+
022f11
+=back
022f11
+
022f11
 =back" };
022f11
 
022f11
   { defaults with
022f11
diff --git a/src/drives.c b/src/drives.c
022f11
index 3854961..97be2ed 100644
022f11
--- a/src/drives.c
022f11
+++ b/src/drives.c
022f11
@@ -86,8 +86,7 @@ static struct drive *
022f11
 create_drive_file (guestfs_h *g, const char *path,
022f11
                    bool readonly, const char *format,
022f11
                    const char *iface, const char *name,
022f11
-                   const char *disk_label,
022f11
-                   bool use_cache_none)
022f11
+                   const char *disk_label, const char *cachemode)
022f11
 {
022f11
   struct drive *drv = safe_calloc (g, 1, sizeof *drv);
022f11
 
022f11
@@ -99,7 +98,7 @@ create_drive_file (guestfs_h *g, const char *path,
022f11
   drv->iface = iface ? safe_strdup (g, iface) : NULL;
022f11
   drv->name = name ? safe_strdup (g, name) : NULL;
022f11
   drv->disk_label = disk_label ? safe_strdup (g, disk_label) : NULL;
022f11
-  drv->use_cache_none = use_cache_none;
022f11
+  drv->cachemode = cachemode ? safe_strdup (g, cachemode) : NULL;
022f11
 
022f11
   drv->priv = drv->free_priv = NULL;
022f11
 
022f11
@@ -114,8 +113,7 @@ create_drive_non_file (guestfs_h *g,
022f11
                        const char *username, const char *secret,
022f11
                        bool readonly, const char *format,
022f11
                        const char *iface, const char *name,
022f11
-                       const char *disk_label,
022f11
-                       bool use_cache_none)
022f11
+                       const char *disk_label, const char *cachemode)
022f11
 {
022f11
   struct drive *drv = safe_calloc (g, 1, sizeof *drv);
022f11
 
022f11
@@ -131,7 +129,7 @@ create_drive_non_file (guestfs_h *g,
022f11
   drv->iface = iface ? safe_strdup (g, iface) : NULL;
022f11
   drv->name = name ? safe_strdup (g, name) : NULL;
022f11
   drv->disk_label = disk_label ? safe_strdup (g, disk_label) : NULL;
022f11
-  drv->use_cache_none = use_cache_none;
022f11
+  drv->cachemode = cachemode ? safe_strdup (g, cachemode) : NULL;
022f11
 
022f11
   drv->priv = drv->free_priv = NULL;
022f11
 
022f11
@@ -146,8 +144,7 @@ create_drive_curl (guestfs_h *g,
022f11
                    const char *username, const char *secret,
022f11
                    bool readonly, const char *format,
022f11
                    const char *iface, const char *name,
022f11
-                   const char *disk_label,
022f11
-                   bool use_cache_none)
022f11
+                   const char *disk_label, const char *cachemode)
022f11
 {
022f11
   if (secret != NULL) {
022f11
     error (g, _("curl: you cannot specify a secret with this protocol"));
022f11
@@ -179,7 +176,7 @@ create_drive_curl (guestfs_h *g,
022f11
                                 servers, nr_servers, exportname,
022f11
                                 username, secret,
022f11
                                 readonly, format, iface, name, disk_label,
022f11
-                                use_cache_none);
022f11
+                                cachemode);
022f11
 }
022f11
 
022f11
 static struct drive *
022f11
@@ -189,8 +186,7 @@ create_drive_gluster (guestfs_h *g,
022f11
                       const char *username, const char *secret,
022f11
                       bool readonly, const char *format,
022f11
                       const char *iface, const char *name,
022f11
-                      const char *disk_label,
022f11
-                      bool use_cache_none)
022f11
+                      const char *disk_label, const char *cachemode)
022f11
 {
022f11
   if (username != NULL) {
022f11
     error (g, _("gluster: you cannot specify a username with this protocol"));
022f11
@@ -220,7 +216,7 @@ create_drive_gluster (guestfs_h *g,
022f11
                                 servers, nr_servers, exportname,
022f11
                                 username, secret,
022f11
                                 readonly, format, iface, name, disk_label,
022f11
-                                use_cache_none);
022f11
+                                cachemode);
022f11
 }
022f11
 
022f11
 static int
022f11
@@ -242,8 +238,7 @@ create_drive_nbd (guestfs_h *g,
022f11
                   const char *username, const char *secret,
022f11
                   bool readonly, const char *format,
022f11
                   const char *iface, const char *name,
022f11
-                  const char *disk_label,
022f11
-                  bool use_cache_none)
022f11
+                  const char *disk_label, const char *cachemode)
022f11
 {
022f11
   if (username != NULL) {
022f11
     error (g, _("nbd: you cannot specify a username with this protocol"));
022f11
@@ -266,7 +261,7 @@ create_drive_nbd (guestfs_h *g,
022f11
                                 servers, nr_servers, exportname,
022f11
                                 username, secret,
022f11
                                 readonly, format, iface, name, disk_label,
022f11
-                                use_cache_none);
022f11
+                                cachemode);
022f11
 }
022f11
 
022f11
 static struct drive *
022f11
@@ -276,8 +271,7 @@ create_drive_rbd (guestfs_h *g,
022f11
                   const char *username, const char *secret,
022f11
                   bool readonly, const char *format,
022f11
                   const char *iface, const char *name,
022f11
-                  const char *disk_label,
022f11
-                  bool use_cache_none)
022f11
+                  const char *disk_label, const char *cachemode)
022f11
 {
022f11
   size_t i;
022f11
 
022f11
@@ -312,7 +306,7 @@ create_drive_rbd (guestfs_h *g,
022f11
                                 servers, nr_servers, exportname,
022f11
                                 username, secret,
022f11
                                 readonly, format, iface, name, disk_label,
022f11
-                                use_cache_none);
022f11
+                                cachemode);
022f11
 }
022f11
 
022f11
 static struct drive *
022f11
@@ -322,8 +316,7 @@ create_drive_sheepdog (guestfs_h *g,
022f11
                        const char *username, const char *secret,
022f11
                        bool readonly, const char *format,
022f11
                        const char *iface, const char *name,
022f11
-                       const char *disk_label,
022f11
-                       bool use_cache_none)
022f11
+                       const char *disk_label, const char *cachemode)
022f11
 {
022f11
   size_t i;
022f11
 
022f11
@@ -362,7 +355,7 @@ create_drive_sheepdog (guestfs_h *g,
022f11
                                 servers, nr_servers, exportname,
022f11
                                 username, secret,
022f11
                                 readonly, format, iface, name, disk_label,
022f11
-                                use_cache_none);
022f11
+                                cachemode);
022f11
 }
022f11
 
022f11
 static struct drive *
022f11
@@ -372,8 +365,7 @@ create_drive_ssh (guestfs_h *g,
022f11
                   const char *username, const char *secret,
022f11
                   bool readonly, const char *format,
022f11
                   const char *iface, const char *name,
022f11
-                  const char *disk_label,
022f11
-                  bool use_cache_none)
022f11
+                  const char *disk_label, const char *cachemode)
022f11
 {
022f11
   if (secret != NULL) {
022f11
     error (g, _("ssh: you cannot specify a secret with this protocol"));
022f11
@@ -410,7 +402,7 @@ create_drive_ssh (guestfs_h *g,
022f11
                                 servers, nr_servers, exportname,
022f11
                                 username, secret,
022f11
                                 readonly, format, iface, name, disk_label,
022f11
-                                use_cache_none);
022f11
+                                cachemode);
022f11
 }
022f11
 
022f11
 static struct drive *
022f11
@@ -420,8 +412,7 @@ create_drive_iscsi (guestfs_h *g,
022f11
                     const char *username, const char *secret,
022f11
                     bool readonly, const char *format,
022f11
                     const char *iface, const char *name,
022f11
-                    const char *disk_label,
022f11
-                    bool use_cache_none)
022f11
+                    const char *disk_label, const char *cachemode)
022f11
 {
022f11
   if (username != NULL) {
022f11
     error (g, _("iscsi: you cannot specify a username with this protocol"));
022f11
@@ -458,7 +449,7 @@ create_drive_iscsi (guestfs_h *g,
022f11
                                 servers, nr_servers, exportname,
022f11
                                 username, secret,
022f11
                                 readonly, format, iface, name, disk_label,
022f11
-                                use_cache_none);
022f11
+                                cachemode);
022f11
 }
022f11
 
022f11
 /* Traditionally you have been able to use /dev/null as a filename, as
022f11
@@ -537,6 +528,7 @@ free_drive_struct (struct drive *drv)
022f11
   free (drv->iface);
022f11
   free (drv->name);
022f11
   free (drv->disk_label);
022f11
+  free (drv->cachemode);
022f11
 
022f11
   if (drv->priv && drv->free_priv)
022f11
     drv->free_priv (drv->priv);
022f11
@@ -555,7 +547,7 @@ drive_to_string (guestfs_h *g, const struct drive *drv)
022f11
   p = guestfs___drive_source_qemu_param (g, &drv->src);
022f11
 
022f11
   return safe_asprintf
022f11
-    (g, "%s%s%s%s%s%s%s%s%s%s%s",
022f11
+    (g, "%s%s%s%s%s%s%s%s%s%s%s%s",
022f11
      p,
022f11
      drv->readonly ? " readonly" : "",
022f11
      drv->format ? " format=" : "",
022f11
@@ -566,7 +558,8 @@ drive_to_string (guestfs_h *g, const struct drive *drv)
022f11
      drv->name ? : "",
022f11
      drv->disk_label ? " label=" : "",
022f11
      drv->disk_label ? : "",
022f11
-     drv->use_cache_none ? " cache=none" : "");
022f11
+     drv->cachemode ? " cache=" : "",
022f11
+     drv->cachemode ? : "");
022f11
 }
022f11
 
022f11
 /* Add struct drive to the g->drives vector at the given index. */
022f11
@@ -621,47 +614,6 @@ guestfs___free_drives (guestfs_h *g)
022f11
   g->nr_drives = 0;
022f11
 }
022f11
 
022f11
-/* cache=none improves reliability in the event of a host crash.
022f11
- *
022f11
- * However this option causes qemu to try to open the file with
022f11
- * O_DIRECT.  This fails on some filesystem types (notably tmpfs).
022f11
- * So we check if we can open the file with or without O_DIRECT,
022f11
- * and use cache=none (or not) accordingly.
022f11
- *
022f11
- * Notes:
022f11
- *
022f11
- * (1) In qemu, cache=none and cache=off are identical.
022f11
- *
022f11
- * (2) cache=none does not disable caching entirely.  qemu still
022f11
- * maintains a writeback cache internally, which will be written out
022f11
- * when qemu is killed (with SIGTERM).  It disables *host kernel*
022f11
- * caching by using O_DIRECT.  To disable caching entirely in kernel
022f11
- * and qemu we would need to use cache=directsync but there is a
022f11
- * performance penalty for that.
022f11
- *
022f11
- * (3) This function is only called on the !readonly path.  We must
022f11
- * try to open with O_RDWR to test that the file is readable and
022f11
- * writable here.
022f11
- */
022f11
-static int
022f11
-test_cache_none (guestfs_h *g, const char *filename)
022f11
-{
022f11
-  int fd = open (filename, O_RDWR|O_DIRECT);
022f11
-  if (fd >= 0) {
022f11
-    close (fd);
022f11
-    return 1;
022f11
-  }
022f11
-
022f11
-  fd = open (filename, O_RDWR);
022f11
-  if (fd >= 0) {
022f11
-    close (fd);
022f11
-    return 0;
022f11
-  }
022f11
-
022f11
-  perrorf (g, "%s", filename);
022f11
-  return -1;
022f11
-}
022f11
-
022f11
 /* Check string parameter matches ^[-_[:alnum:]]+$ (in C locale). */
022f11
 static int
022f11
 valid_format_iface (const char *str)
022f11
@@ -827,7 +779,7 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
022f11
   struct drive_server *servers = NULL;
022f11
   const char *username;
022f11
   const char *secret;
022f11
-  int use_cache_none;
022f11
+  const char *cachemode;
022f11
   struct drive *drv;
022f11
   size_t i, drv_index;
022f11
 
022f11
@@ -853,6 +805,8 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
022f11
     ? optargs->username : NULL;
022f11
   secret = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_SECRET_BITMASK
022f11
     ? optargs->secret : NULL;
022f11
+  cachemode = optargs->bitmask & GUESTFS_ADD_DRIVE_OPTS_CACHEMODE_BITMASK
022f11
+    ? optargs->cachemode : NULL;
022f11
 
022f11
   if (format && !valid_format_iface (format)) {
022f11
     error (g, _("%s parameter is empty or contains disallowed characters"),
022f11
@@ -871,6 +825,12 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
022f11
     free_drive_servers (servers, nr_servers);
022f11
     return -1;
022f11
   }
022f11
+  if (cachemode &&
022f11
+      !(STREQ (cachemode, "writeback") || STREQ (cachemode, "unsafe"))) {
022f11
+    error (g, _("cachemode parameter must be 'writeback' (default) or 'unsafe'"));
022f11
+    free_drive_servers (servers, nr_servers);
022f11
+    return -1;
022f11
+  }
022f11
 
022f11
   if (STREQ (protocol, "file")) {
022f11
     if (servers != NULL) {
022f11
@@ -893,23 +853,16 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
022f11
       drv = create_drive_dev_null (g, readonly, format, iface, name,
022f11
                                    disk_label);
022f11
     else {
022f11
-      /* For writable files, see if we can use cache=none.  This also
022f11
-       * checks for the existence of the file.  For readonly we have
022f11
-       * to do the check explicitly.
022f11
+      /* We have to check for the existence of the file since that's
022f11
+       * required by the API.
022f11
        */
022f11
-      use_cache_none = readonly ? false : test_cache_none (g, filename);
022f11
-      if (use_cache_none == -1)
022f11
+      if (access (filename, R_OK) == -1) {
022f11
+        perrorf (g, "%s", filename);
022f11
         return -1;
022f11
-
022f11
-      if (readonly) {
022f11
-        if (access (filename, R_OK) == -1) {
022f11
-          perrorf (g, "%s", filename);
022f11
-          return -1;
022f11
-        }
022f11
       }
022f11
 
022f11
       drv = create_drive_file (g, filename, readonly, format, iface, name,
022f11
-                               disk_label, use_cache_none);
022f11
+                               disk_label, cachemode);
022f11
     }
022f11
   }
022f11
   else if (STREQ (protocol, "ftp")) {
022f11
@@ -917,71 +870,71 @@ guestfs__add_drive_opts (guestfs_h *g, const char *filename,
022f11
                              servers, nr_servers, filename,
022f11
                              username, secret,
022f11
                              readonly, format, iface, name,
022f11
-                             disk_label, false);
022f11
+                             disk_label, cachemode);
022f11
   }
022f11
   else if (STREQ (protocol, "ftps")) {
022f11
     drv = create_drive_curl (g, drive_protocol_ftps,
022f11
                              servers, nr_servers, filename,
022f11
                              username, secret,
022f11
                              readonly, format, iface, name,
022f11
-                             disk_label, false);
022f11
+                             disk_label, cachemode);
022f11
   }
022f11
   else if (STREQ (protocol, "gluster")) {
022f11
     drv = create_drive_gluster (g, servers, nr_servers, filename,
022f11
                                 username, secret,
022f11
                                 readonly, format, iface, name,
022f11
-                                disk_label, false);
022f11
+                                disk_label, cachemode);
022f11
   }
022f11
   else if (STREQ (protocol, "http")) {
022f11
     drv = create_drive_curl (g, drive_protocol_http,
022f11
                              servers, nr_servers, filename,
022f11
                              username, secret,
022f11
                              readonly, format, iface, name,
022f11
-                             disk_label, false);
022f11
+                             disk_label, cachemode);
022f11
   }
022f11
   else if (STREQ (protocol, "https")) {
022f11
     drv = create_drive_curl (g, drive_protocol_https,
022f11
                              servers, nr_servers, filename,
022f11
                              username, secret,
022f11
                              readonly, format, iface, name,
022f11
-                             disk_label, false);
022f11
+                             disk_label, cachemode);
022f11
   }
022f11
   else if (STREQ (protocol, "iscsi")) {
022f11
     drv = create_drive_iscsi (g, servers, nr_servers, filename,
022f11
                               username, secret,
022f11
                               readonly, format, iface, name,
022f11
-                              disk_label, false);
022f11
+                              disk_label, cachemode);
022f11
   }
022f11
   else if (STREQ (protocol, "nbd")) {
022f11
     drv = create_drive_nbd (g, servers, nr_servers, filename,
022f11
                             username, secret,
022f11
                             readonly, format, iface, name,
022f11
-                            disk_label, false);
022f11
+                            disk_label, cachemode);
022f11
   }
022f11
   else if (STREQ (protocol, "rbd")) {
022f11
     drv = create_drive_rbd (g, servers, nr_servers, filename,
022f11
                             username, secret,
022f11
                             readonly, format, iface, name,
022f11
-                            disk_label, false);
022f11
+                            disk_label, cachemode);
022f11
   }
022f11
   else if (STREQ (protocol, "sheepdog")) {
022f11
     drv = create_drive_sheepdog (g, servers, nr_servers, filename,
022f11
                                  username, secret,
022f11
                                  readonly, format, iface, name,
022f11
-                                 disk_label, false);
022f11
+                                 disk_label, cachemode);
022f11
   }
022f11
   else if (STREQ (protocol, "ssh")) {
022f11
     drv = create_drive_ssh (g, servers, nr_servers, filename,
022f11
                             username, secret,
022f11
                             readonly, format, iface, name,
022f11
-                            disk_label, false);
022f11
+                            disk_label, cachemode);
022f11
   }
022f11
   else if (STREQ (protocol, "tftp")) {
022f11
     drv = create_drive_curl (g, drive_protocol_tftp,
022f11
                              servers, nr_servers, filename,
022f11
                              username, secret,
022f11
                              readonly, format, iface, name,
022f11
-                             disk_label, false);
022f11
+                             disk_label, cachemode);
022f11
   }
022f11
   else {
022f11
     error (g, _("unknown protocol '%s'"), protocol);
022f11
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
022f11
index 8fd6388..d789dcc 100644
022f11
--- a/src/guestfs-internal.h
022f11
+++ b/src/guestfs-internal.h
022f11
@@ -179,7 +179,7 @@ struct drive {
022f11
   char *iface;
022f11
   char *name;
022f11
   char *disk_label;
022f11
-  bool use_cache_none;
022f11
+  char *cachemode;
022f11
 
022f11
   /* Data used by the backend. */
022f11
   void *priv;
022f11
diff --git a/src/launch-direct.c b/src/launch-direct.c
022f11
index 299a3d9..3866c9b 100644
022f11
--- a/src/launch-direct.c
022f11
+++ b/src/launch-direct.c
022f11
@@ -1008,10 +1008,10 @@ qemu_drive_param (guestfs_h *g, const struct drive *drv, size_t index)
022f11
     iface = "virtio";
022f11
 
022f11
   return safe_asprintf
022f11
-    (g, "file=%s%s%s%s%s%s%s,id=hd%zu,if=%s",
022f11
+    (g, "file=%s%s,cache=%s%s%s%s%s,id=hd%zu,if=%s",
022f11
      escaped_file,
022f11
      drv->readonly ? ",snapshot=on" : "",
022f11
-     drv->use_cache_none ? ",cache=none" : "",
022f11
+     drv->cachemode ? drv->cachemode : "writeback",
022f11
      drv->format ? ",format=" : "",
022f11
      drv->format ? drv->format : "",
022f11
      drv->disk_label ? ",serial=" : "",
022f11
diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
022f11
index ff3d720..3690b1d 100644
022f11
--- a/src/launch-libvirt.c
022f11
+++ b/src/launch-libvirt.c
022f11
@@ -1218,11 +1218,12 @@ construct_libvirt_xml_disk (guestfs_h *g,
022f11
     return -1;
022f11
   }
022f11
 
022f11
-  if (drv->use_cache_none) {
022f11
-    XMLERROR (-1,
022f11
-              xmlTextWriterWriteAttribute (xo, BAD_CAST "cache",
022f11
-                                           BAD_CAST "none"));
022f11
-  }
022f11
+  XMLERROR (-1,
022f11
+            xmlTextWriterWriteAttribute (xo, BAD_CAST "cache",
022f11
+                                         BAD_CAST (drv->cachemode ?
022f11
+                                                   drv->cachemode :
022f11
+                                                   "writeback")));
022f11
+
022f11
   XMLERROR (-1, xmlTextWriterEndElement (xo));
022f11
 
022f11
   if (drv->disk_label) {
022f11
-- 
022f11
1.8.3.1
022f11