psss / rpms / libguestfs

Forked from rpms/libguestfs 5 years ago
Clone

Blame 0002-add_drive-Introduce-cachemode-parameter-to-control-d.patch

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