|
|
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 |
|