ae23c9
From cff7af832cadce3d5afd2819483b1b61a115ace2 Mon Sep 17 00:00:00 2001
ae23c9
From: Kevin Wolf <kwolf@redhat.com>
ae23c9
Date: Thu, 10 Jan 2019 12:44:32 +0000
ae23c9
Subject: [PATCH 02/14] block: Add auto-read-only option
ae23c9
ae23c9
RH-Author: Kevin Wolf <kwolf@redhat.com>
ae23c9
Message-id: <20190110124442.30132-3-kwolf@redhat.com>
ae23c9
Patchwork-id: 83952
ae23c9
O-Subject: [RHEL-8.0 qemu-kvm PATCH 02/12] block: Add auto-read-only option
ae23c9
Bugzilla: 1644996
ae23c9
RH-Acked-by: Max Reitz <mreitz@redhat.com>
ae23c9
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
ae23c9
RH-Acked-by: Eric Blake <eblake@redhat.com>
ae23c9
ae23c9
If a management application builds the block graph node by node, the
ae23c9
protocol layer doesn't inherit its read-only option from the format
ae23c9
layer any more, so it must be set explicitly.
ae23c9
ae23c9
Backing files should work on read-only storage, but at the same time, a
ae23c9
block job like commit should be able to reopen them read-write if they
ae23c9
are on read-write storage. However, without option inheritance, reopen
ae23c9
only changes the read-only option for the root node (typically the
ae23c9
format layer), but not the protocol layer, so reopening fails (the
ae23c9
format layer wants to get write permissions, but the protocol layer is
ae23c9
still read-only).
ae23c9
ae23c9
A simple workaround for the problem in the management tool would be to
ae23c9
open the protocol layer always read-write and to make only the format
ae23c9
layer read-only for backing files. However, sometimes the file is
ae23c9
actually stored on read-only storage and we don't know whether the image
ae23c9
can be opened read-write (for example, for NBD it depends on the server
ae23c9
we're trying to connect to). This adds an option that makes QEMU try to
ae23c9
open the image read-write, but allows it to degrade to a read-only mode
ae23c9
without returning an error.
ae23c9
ae23c9
The documentation for this option is consciously phrased in a way that
ae23c9
allows QEMU to switch to a better model eventually: Instead of trying
ae23c9
when the image is first opened, making the read-only flag dynamic and
ae23c9
changing it automatically whenever the first BLK_PERM_WRITE user is
ae23c9
attached or the last one is detached would be much more useful
ae23c9
behaviour.
ae23c9
ae23c9
Unfortunately, this more useful behaviour is also a lot harder to
ae23c9
implement, and libvirt needs a solution now before it can switch to
ae23c9
-blockdev, so let's start with this easier approach for now.
ae23c9
ae23c9
Instead of adding a new auto-read-only option, turning the existing
ae23c9
read-only into an enum (with a bool alternate for compatibility) was
ae23c9
considered, but it complicated the implementation to the point that it
ae23c9
didn't seem to be worth it.
ae23c9
ae23c9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ae23c9
Reviewed-by: Eric Blake <eblake@redhat.com>
ae23c9
(cherry picked from commit e35bdc123a4ace9f4d3fccaaf88907014e2438cd)
ae23c9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ae23c9
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
ae23c9
---
ae23c9
 block.c               | 17 +++++++++++++++++
ae23c9
 block/vvfat.c         |  1 +
ae23c9
 blockdev.c            |  2 +-
ae23c9
 include/block/block.h |  2 ++
ae23c9
 qapi/block-core.json  |  7 +++++++
ae23c9
 5 files changed, 28 insertions(+), 1 deletion(-)
ae23c9
ae23c9
diff --git a/block.c b/block.c
ae23c9
index 6f1d53b..f357975 100644
ae23c9
--- a/block.c
ae23c9
+++ b/block.c
ae23c9
@@ -905,6 +905,7 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
ae23c9
 
ae23c9
     /* Inherit the read-only option from the parent if it's not set */
ae23c9
     qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
ae23c9
+    qdict_copy_default(child_options, parent_options, BDRV_OPT_AUTO_READ_ONLY);
ae23c9
 
ae23c9
     /* Our block drivers take care to send flushes and respect unmap policy,
ae23c9
      * so we can default to enable both on lower layers regardless of the
ae23c9
@@ -1028,6 +1029,7 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
ae23c9
 
ae23c9
     /* backing files always opened read-only */
ae23c9
     qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on");
ae23c9
+    qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
ae23c9
     flags &= ~BDRV_O_COPY_ON_READ;
ae23c9
 
ae23c9
     /* snapshot=on is handled on the top layer */
ae23c9
@@ -1117,6 +1119,10 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
ae23c9
         *flags |= BDRV_O_RDWR;
ae23c9
     }
ae23c9
 
ae23c9
+    assert(qemu_opt_find(opts, BDRV_OPT_AUTO_READ_ONLY));
ae23c9
+    if (qemu_opt_get_bool_del(opts, BDRV_OPT_AUTO_READ_ONLY, false)) {
ae23c9
+        *flags |= BDRV_O_AUTO_RDONLY;
ae23c9
+    }
ae23c9
 }
ae23c9
 
ae23c9
 static void update_options_from_flags(QDict *options, int flags)
ae23c9
@@ -1131,6 +1137,10 @@ static void update_options_from_flags(QDict *options, int flags)
ae23c9
     if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
ae23c9
         qdict_put_bool(options, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
ae23c9
     }
ae23c9
+    if (!qdict_haskey(options, BDRV_OPT_AUTO_READ_ONLY)) {
ae23c9
+        qdict_put_bool(options, BDRV_OPT_AUTO_READ_ONLY,
ae23c9
+                       flags & BDRV_O_AUTO_RDONLY);
ae23c9
+    }
ae23c9
 }
ae23c9
 
ae23c9
 static void bdrv_assign_node_name(BlockDriverState *bs,
ae23c9
@@ -1304,6 +1314,11 @@ QemuOptsList bdrv_runtime_opts = {
ae23c9
             .help = "Node is opened in read-only mode",
ae23c9
         },
ae23c9
         {
ae23c9
+            .name = BDRV_OPT_AUTO_READ_ONLY,
ae23c9
+            .type = QEMU_OPT_BOOL,
ae23c9
+            .help = "Node can become read-only if opening read-write fails",
ae23c9
+        },
ae23c9
+        {
ae23c9
             .name = "detect-zeroes",
ae23c9
             .type = QEMU_OPT_STRING,
ae23c9
             .help = "try to optimize zero writes (off, on, unmap)",
ae23c9
@@ -2490,6 +2505,8 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
ae23c9
         qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
ae23c9
         qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
ae23c9
         qdict_set_default_str(qdict, BDRV_OPT_READ_ONLY, "off");
ae23c9
+        qdict_set_default_str(qdict, BDRV_OPT_AUTO_READ_ONLY, "off");
ae23c9
+
ae23c9
     }
ae23c9
 
ae23c9
     bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp);
ae23c9
diff --git a/block/vvfat.c b/block/vvfat.c
ae23c9
index c7d2ed2..3efce9e 100644
ae23c9
--- a/block/vvfat.c
ae23c9
+++ b/block/vvfat.c
ae23c9
@@ -3130,6 +3130,7 @@ static void vvfat_qcow_options(int *child_flags, QDict *child_options,
ae23c9
                                int parent_flags, QDict *parent_options)
ae23c9
 {
ae23c9
     qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
ae23c9
+    qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
ae23c9
     qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
ae23c9
 }
ae23c9
 
ae23c9
diff --git a/blockdev.c b/blockdev.c
ae23c9
index 56a3d0f..be650d0 100644
ae23c9
--- a/blockdev.c
ae23c9
+++ b/blockdev.c
ae23c9
@@ -2760,7 +2760,7 @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
ae23c9
 
ae23c9
     bdrv_flags = blk_get_open_flags_from_root_state(blk);
ae23c9
     bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
ae23c9
-        BDRV_O_PROTOCOL);
ae23c9
+        BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
ae23c9
 
ae23c9
     if (!has_read_only) {
ae23c9
         read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
ae23c9
diff --git a/include/block/block.h b/include/block/block.h
ae23c9
index 8e78daf..6ee8b2a 100644
ae23c9
--- a/include/block/block.h
ae23c9
+++ b/include/block/block.h
ae23c9
@@ -114,6 +114,7 @@ typedef struct HDGeometry {
ae23c9
                                       select an appropriate protocol driver,
ae23c9
                                       ignoring the format layer */
ae23c9
 #define BDRV_O_NO_IO       0x10000 /* don't initialize for I/O */
ae23c9
+#define BDRV_O_AUTO_RDONLY 0x20000 /* degrade to read-only if opening read-write fails */
ae23c9
 
ae23c9
 #define BDRV_O_CACHE_MASK  (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH)
ae23c9
 
ae23c9
@@ -124,6 +125,7 @@ typedef struct HDGeometry {
ae23c9
 #define BDRV_OPT_CACHE_DIRECT   "cache.direct"
ae23c9
 #define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush"
ae23c9
 #define BDRV_OPT_READ_ONLY      "read-only"
ae23c9
+#define BDRV_OPT_AUTO_READ_ONLY "auto-read-only"
ae23c9
 #define BDRV_OPT_DISCARD        "discard"
ae23c9
 #define BDRV_OPT_FORCE_SHARE    "force-share"
ae23c9
 
ae23c9
diff --git a/qapi/block-core.json b/qapi/block-core.json
ae23c9
index db47fb8..5e5f4f9 100644
ae23c9
--- a/qapi/block-core.json
ae23c9
+++ b/qapi/block-core.json
ae23c9
@@ -3604,6 +3604,12 @@
ae23c9
 #                 either generally or in certain configurations. In this case,
ae23c9
 #                 the default value does not work and the option must be
ae23c9
 #                 specified explicitly.
ae23c9
+# @auto-read-only: if true and @read-only is false, QEMU may automatically
ae23c9
+#                  decide not to open the image read-write as requested, but
ae23c9
+#                  fall back to read-only instead (and switch between the modes
ae23c9
+#                  later), e.g. depending on whether the image file is writable
ae23c9
+#                  or whether a writing user is attached to the node
ae23c9
+#                  (default: false, since 3.1)
ae23c9
 # @detect-zeroes: detect and optimize zero writes (Since 2.1)
ae23c9
 #                 (default: off)
ae23c9
 # @force-share:   force share all permission on added nodes.
ae23c9
@@ -3619,6 +3625,7 @@
ae23c9
             '*discard': 'BlockdevDiscardOptions',
ae23c9
             '*cache': 'BlockdevCacheOptions',
ae23c9
             '*read-only': 'bool',
ae23c9
+            '*auto-read-only': 'bool',
ae23c9
             '*force-share': 'bool',
ae23c9
             '*detect-zeroes': 'BlockdevDetectZeroesOptions' },
ae23c9
   'discriminator': 'driver',
ae23c9
-- 
ae23c9
1.8.3.1
ae23c9