All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more
@ 2015-05-08 17:21 Kevin Wolf
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries() Kevin Wolf
                   ` (33 more replies)
  0 siblings, 34 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

First of all, sorry for the lengthy series that attacks more things than
could fit in the subject line. However, for the most part the changes
are hard to separate: Either it's just infrastructure without a user, or
it's a user, but the infrastructure changes wouldn't be complete.

The only independent part that could be separated out are the qcow2
patches, but they are a nice demonstration of the new infrastructure
somewhere about halfway through the series, so I thought it would be
nice to leave them in anyway.

Originally, the goal of the series was just to make cache modes
configurable for backing files. However, I realised soon that while
flags are inherited, the same thing is missing for arbitrary options.
And then it turned out that there's bdrv_reopen(), too, and that that
needs a bit more work if we don't want it to break... (see KVM Forum
talk last year)

So this is how it worked out - this series contains:

- A common infrastructure for opening child nodes, so that...
- ...the block layer knows all the children of a BDS now
- ...VMDK allows passing options to individual extents
- A node knows from which other node it inherited flags and options;
  this is respected when recalculating flags and options for child nodes
  on bdrv_reopen() (i.e. if the node didn't inherit originally from a
  parent node, it now doesn't on reopen either)
- You can now use node name references for backing files
- bdrv_reopen() accepts options now (and qcow2 makes use of it)
- And finally you can set cache mode options for backing files and other
  children now (and the reopen behaviour even makes sense)

Kevin Wolf (34):
  qdict: Add qdict_array_entries()
  qdict: Add qdict_{set,copy}_default()
  quorum: Use bdrv_open_image()
  vmdk: Use bdrv_open_image()
  block: Use macro for cache option names
  block: Use QemuOpts in bdrv_open_common()
  block: Move flag inheritance to bdrv_open_inherited()
  block: Add list of children to BlockDriverState
  block: Add BlockDriverState.inherits_from
  block: Fix reopen flag inheritance
  block: Allow references for backing files
  block: Allow specifying driver-specific options to reopen
  qemu-io: Add command 'reopen'
  qcow2: Factor out qcow2_update_options()
  qcow2: Move qcow2_update_options() call up
  qcow2: Move rest of option handling to qcow2_update_options()
  qcow2: Leave s unchanged on qcow2_update_options() failure
  qcow2: Fix memory leak in qcow2_update_options() error path
  qcow2: Make qcow2_update_options() suitable for transactions
  qcow2: Support updating driver-specific options in reopen
  block: Consider all block layer options in append_open_options
  block: Exclude nested options only for children in
    append_open_options()
  block: Pass driver-specific options to .bdrv_refresh_filename()
  block: Keep "driver" in bs->options
  block: Allow specifying child options in reopen
  block: reopen: Document option precedence and refactor accordingly
  block: Add infrastructure for option inheritance
  block: Introduce bs->explicit_options
  qemu-iotests: Remove cache mode test without medium
  block: reopen: Extract QemuOpts for generic block layer options
  block: Move cache options into options QDict
  qemu-iotests: Try setting cache mode for children
  qemu-iotests: Test cache mode option inheritance
  qemu-iotests: Test reopen with node-name/driver options

 block.c                    | 502 +++++++++++++++++++++++++----
 block/blkdebug.c           |  19 +-
 block/blkverify.c          |   6 +-
 block/commit.c             |   4 +-
 block/mirror.c             |   2 +-
 block/nbd.c                |  10 +-
 block/qcow2.c              | 359 ++++++++++++++-------
 block/quorum.c             |  53 +---
 block/vmdk.c               |  61 ++--
 blockdev.c                 |  39 +--
 include/block/block.h      |  20 +-
 include/block/block_int.h  |  24 +-
 include/qapi/qmp/qdict.h   |   4 +
 qemu-io-cmds.c             |  71 +++++
 qobject/qdict.c            | 102 +++++-
 tests/qemu-iotests/051     |  16 +-
 tests/qemu-iotests/051.out |  59 +++-
 tests/qemu-iotests/132     | 336 ++++++++++++++++++++
 tests/qemu-iotests/132.out | 767 +++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/133     |  90 ++++++
 tests/qemu-iotests/133.out |  22 ++
 tests/qemu-iotests/group   |   2 +
 22 files changed, 2230 insertions(+), 338 deletions(-)
 create mode 100755 tests/qemu-iotests/132
 create mode 100644 tests/qemu-iotests/132.out
 create mode 100755 tests/qemu-iotests/133
 create mode 100644 tests/qemu-iotests/133.out

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries()
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-08 20:06   ` Eric Blake
  2015-05-11 13:56   ` [Qemu-devel] " Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set,copy}_default() Kevin Wolf
                   ` (32 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/qapi/qmp/qdict.h |  1 +
 qobject/qdict.c          | 68 +++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
index d68f4eb..d20db94 100644
--- a/include/qapi/qmp/qdict.h
+++ b/include/qapi/qmp/qdict.h
@@ -70,6 +70,7 @@ void qdict_flatten(QDict *qdict);
 
 void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
 void qdict_array_split(QDict *src, QList **dst);
+int qdict_array_entries(QDict *src, const char *subqdict);
 
 void qdict_join(QDict *dest, QDict *src, bool overwrite);
 
diff --git a/qobject/qdict.c b/qobject/qdict.c
index ea239f0..2fcb7fe 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -597,17 +597,18 @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start)
     }
 }
 
-static bool qdict_has_prefixed_entries(const QDict *src, const char *start)
+static int qdict_count_prefixed_entries(const QDict *src, const char *start)
 {
     const QDictEntry *entry;
+    int count = 0;
 
     for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
         if (strstart(entry->key, start, NULL)) {
-            return true;
+            count++;
         }
     }
 
-    return false;
+    return count;
 }
 
 /**
@@ -646,7 +647,7 @@ void qdict_array_split(QDict *src, QList **dst)
         snprintf_ret = snprintf(prefix, 32, "%u.", i);
         assert(snprintf_ret < 32);
 
-        is_subqdict = qdict_has_prefixed_entries(src, prefix);
+        is_subqdict = qdict_count_prefixed_entries(src, prefix);
 
         // There may be either a single subordinate object (named "%u") or
         // multiple objects (each with a key prefixed "%u."), but not both.
@@ -667,6 +668,65 @@ void qdict_array_split(QDict *src, QList **dst)
 }
 
 /**
+ * qdict_array_valid(): Returns the number of direct array entries if the
+ * sub-QDict of src specified by the prefix in subqdict (or src itself for
+ * prefix == "") is valid as an array, i.e. the length of the created list if
+ * the sub-QDict would become empty after calling qdict_array_split() on it. If
+ * the array is not valid, -1 is returned.
+ */
+int qdict_array_entries(QDict *src, const char *subqdict)
+{
+    const QDictEntry *entry;
+    unsigned i;
+    unsigned entries = 0;
+    size_t subqdict_len = strlen(subqdict);
+
+    assert(!subqdict_len || subqdict[subqdict_len - 1] == '.');
+
+    for (i = 0; i < UINT_MAX; i++) {
+        QObject *subqobj;
+        int subqdict_entries;
+        size_t slen = 32 + subqdict_len;
+        char indexstr[slen], prefix[slen];
+        size_t snprintf_ret;
+
+        snprintf_ret = snprintf(indexstr, slen, "%s%u", subqdict, i);
+        assert(snprintf_ret < slen);
+
+        subqobj = qdict_get(src, indexstr);
+
+        snprintf_ret = snprintf(prefix, slen, "%s%u.", subqdict, i);
+        assert(snprintf_ret < slen);
+
+        subqdict_entries = qdict_count_prefixed_entries(src, prefix);
+
+        /* There may be either a single subordinate object (named "%u") or
+         * multiple objects (each with a key prefixed "%u."), but not both. */
+        if (subqobj && subqdict_entries) {
+            return -1;
+        } else if (!subqobj && !subqdict_entries) {
+            break;
+        }
+
+        entries += subqdict_entries ? subqdict_entries : 1;
+    }
+
+    /* Consider everything handled that isn't part of the given sub-QDict */
+    for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
+        if (!strstart(qdict_entry_key(entry), subqdict, NULL)) {
+            entries++;
+        }
+    }
+
+    /* Anything left in the sub-QDict that wasn't handled? */
+    if (qdict_size(src) != entries) {
+        return -1;
+    }
+
+    return i;
+}
+
+/**
  * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
  * elements from src to dest.
  *
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set,copy}_default()
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries() Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-08 21:30   ` [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set, copy}_default() Eric Blake
  2015-05-11 14:16   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 03/34] quorum: Use bdrv_open_image() Kevin Wolf
                   ` (31 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

In the block layer functions that determine options for a child block
device, it's a common pattern to either copy options from the parent's
options or to set a default string if the option isn't explicitly set
yet for the child. Provide convenience functions so that it becomes a
one-liner for each option.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/qapi/qmp/qdict.h |  3 +++
 qobject/qdict.c          | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
index d20db94..9fbf68e 100644
--- a/include/qapi/qmp/qdict.h
+++ b/include/qapi/qmp/qdict.h
@@ -65,6 +65,9 @@ int64_t qdict_get_try_int(const QDict *qdict, const char *key,
 int qdict_get_try_bool(const QDict *qdict, const char *key, int def_value);
 const char *qdict_get_try_str(const QDict *qdict, const char *key);
 
+void qdict_copy_default(QDict *dst, QDict *src, const char *key);
+void qdict_set_default_str(QDict *dst, const char *key, const char *val);
+
 QDict *qdict_clone_shallow(const QDict *src);
 void qdict_flatten(QDict *qdict);
 
diff --git a/qobject/qdict.c b/qobject/qdict.c
index 2fcb7fe..45ba42c 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -477,6 +477,40 @@ static void qdict_destroy_obj(QObject *obj)
     g_free(qdict);
 }
 
+/**
+ * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the
+ * value of 'key' in 'src' is copied there (and the refcount increased
+ * accordingly).
+ */
+void qdict_copy_default(QDict *dst, QDict *src, const char *key)
+{
+    QObject *val;
+
+    if (qdict_haskey(dst, key)) {
+        return;
+    }
+
+    val = qdict_get(src, key);
+    if (val) {
+        qobject_incref(val);
+        qdict_put_obj(dst, key, val);
+    }
+}
+
+/**
+ * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet,
+ * 'val' is put there, with the QDict taking the reference. Otherwise, the
+ * refcount of 'val' is decreased.
+ */
+void qdict_set_default_str(QDict *dst, const char *key, const char *val)
+{
+    if (qdict_haskey(dst, key)) {
+        return;
+    }
+
+    qdict_put(dst, key, qstring_from_str(val));
+}
+
 static void qdict_flatten_qdict(QDict *qdict, QDict *target,
                                 const char *prefix);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 03/34] quorum: Use bdrv_open_image()
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries() Kevin Wolf
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set,copy}_default() Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-08 21:33   ` Eric Blake
                     ` (3 more replies)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 04/34] vmdk: " Kevin Wolf
                   ` (30 subsequent siblings)
  33 siblings, 4 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Besides standardising on a single interface for opening child nodes,
this simplifies the .bdrv_open() implementation of the quorum block
driver by using block layer functionality for handling BlockdevRefs.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/quorum.c | 51 +++++++++++----------------------------------------
 1 file changed, 11 insertions(+), 40 deletions(-)

diff --git a/block/quorum.c b/block/quorum.c
index f91ef75..a33881a 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -866,25 +866,18 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
     Error *local_err = NULL;
     QemuOpts *opts = NULL;
     bool *opened;
-    QDict *sub = NULL;
-    QList *list = NULL;
-    const QListEntry *lentry;
     int i;
     int ret = 0;
 
     qdict_flatten(options);
-    qdict_extract_subqdict(options, &sub, "children.");
-    qdict_array_split(sub, &list);
 
-    if (qdict_size(sub)) {
-        error_setg(&local_err, "Invalid option children.%s",
-                   qdict_first(sub)->key);
+    /* count how many different children are present */
+    s->num_children = qdict_array_entries(options, "children.");
+    if (s->num_children < 0) {
+        error_setg(&local_err, "Option children is not a valid array");
         ret = -EINVAL;
         goto exit;
     }
-
-    /* count how many different children are present */
-    s->num_children = qlist_size(list);
     if (s->num_children < 2) {
         error_setg(&local_err,
                    "Number of provided children must be greater than 1");
@@ -937,37 +930,17 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
     s->bs = g_new0(BlockDriverState *, s->num_children);
     opened = g_new0(bool, s->num_children);
 
-    for (i = 0, lentry = qlist_first(list); lentry;
-         lentry = qlist_next(lentry), i++) {
-        QDict *d;
-        QString *string;
-
-        switch (qobject_type(lentry->value))
-        {
-            /* List of options */
-            case QTYPE_QDICT:
-                d = qobject_to_qdict(lentry->value);
-                QINCREF(d);
-                ret = bdrv_open(&s->bs[i], NULL, NULL, d, flags, NULL,
-                                &local_err);
-                break;
-
-            /* QMP reference */
-            case QTYPE_QSTRING:
-                string = qobject_to_qstring(lentry->value);
-                ret = bdrv_open(&s->bs[i], NULL, qstring_get_str(string), NULL,
-                                flags, NULL, &local_err);
-                break;
-
-            default:
-                error_setg(&local_err, "Specification of child block device %i "
-                           "is invalid", i);
-                ret = -EINVAL;
-        }
+    for (i = 0; i < s->num_children; i++) {
+        char indexstr[32];
+        ret = snprintf(indexstr, 32, "children.%d", i);
+        assert(ret < 32);
 
+        ret = bdrv_open_image(&s->bs[i], NULL, options, indexstr, flags,
+                              false, &local_err);
         if (ret < 0) {
             goto close_exit;
         }
+
         opened[i] = true;
     }
 
@@ -990,8 +963,6 @@ exit:
     if (local_err) {
         error_propagate(errp, local_err);
     }
-    QDECREF(list);
-    QDECREF(sub);
     return ret;
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 04/34] vmdk: Use bdrv_open_image()
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (2 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 03/34] quorum: Use bdrv_open_image() Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-08 22:00   ` Eric Blake
                     ` (2 more replies)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names Kevin Wolf
                   ` (29 subsequent siblings)
  33 siblings, 3 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Besides standardising on a single interface for opening child nodes,
this patch allows the user to specify options to individual extent
nodes. Overriding file names isn't possible with this yet, so it's of
limited usefulness, but still a step forward.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/vmdk.c | 34 +++++++++++++++++++++-------------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/block/vmdk.c b/block/vmdk.c
index b66745d..641e026 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -543,7 +543,7 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
 }
 
 static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
-                               Error **errp);
+                               QDict *options, Error **errp);
 
 static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset,
                             Error **errp)
@@ -582,7 +582,7 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset,
 
 static int vmdk_open_vmdk4(BlockDriverState *bs,
                            BlockDriverState *file,
-                           int flags, Error **errp)
+                           int flags, QDict *options, Error **errp)
 {
     int ret;
     uint32_t magic;
@@ -606,7 +606,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
             if (!buf) {
                 return -EINVAL;
             }
-            ret = vmdk_open_desc_file(bs, flags, buf, errp);
+            ret = vmdk_open_desc_file(bs, flags, buf, options, errp);
             g_free(buf);
             return ret;
         }
@@ -763,7 +763,7 @@ static int vmdk_parse_description(const char *desc, const char *opt_name,
 /* Open an extent file and append to bs array */
 static int vmdk_open_sparse(BlockDriverState *bs,
                             BlockDriverState *file, int flags,
-                            char *buf, Error **errp)
+                            char *buf, QDict *options, Error **errp)
 {
     uint32_t magic;
 
@@ -773,7 +773,7 @@ static int vmdk_open_sparse(BlockDriverState *bs,
             return vmdk_open_vmfs_sparse(bs, file, flags, errp);
             break;
         case VMDK4_MAGIC:
-            return vmdk_open_vmdk4(bs, file, flags, errp);
+            return vmdk_open_vmdk4(bs, file, flags, options, errp);
             break;
         default:
             error_setg(errp, "Image not in VMDK format");
@@ -783,7 +783,8 @@ static int vmdk_open_sparse(BlockDriverState *bs,
 }
 
 static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
-                              const char *desc_file_path, Error **errp)
+                              const char *desc_file_path, QDict *options,
+                              Error **errp)
 {
     int ret;
     int matches;
@@ -797,6 +798,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
     BlockDriverState *extent_file;
     BDRVVmdkState *s = bs->opaque;
     VmdkExtent *extent;
+    char extent_opt_prefix[32];
 
     while (*p) {
         /* parse extent line in one of below formats:
@@ -846,8 +848,13 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
         extent_path = g_malloc0(PATH_MAX);
         path_combine(extent_path, PATH_MAX, desc_file_path, fname);
         extent_file = NULL;
-        ret = bdrv_open(&extent_file, extent_path, NULL, NULL,
-                        bs->open_flags | BDRV_O_PROTOCOL, NULL, errp);
+
+        ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents);
+        assert(ret < 32);
+
+        ret = bdrv_open_image(&extent_file, extent_path,
+                              options, extent_opt_prefix,
+                              bs->open_flags | BDRV_O_PROTOCOL, false, errp);
         g_free(extent_path);
         if (ret) {
             return ret;
@@ -870,7 +877,8 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
             if (!buf) {
                 ret = -EINVAL;
             } else {
-                ret = vmdk_open_sparse(bs, extent_file, bs->open_flags, buf, errp);
+                ret = vmdk_open_sparse(bs, extent_file, bs->open_flags, buf,
+                                       options, errp);
             }
             g_free(buf);
             if (ret) {
@@ -898,7 +906,7 @@ next_line:
 }
 
 static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
-                               Error **errp)
+                               QDict *options, Error **errp)
 {
     int ret;
     char ct[128];
@@ -920,7 +928,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
     }
     s->create_type = g_strdup(ct);
     s->desc_offset = 0;
-    ret = vmdk_parse_extents(buf, bs, bs->file->exact_filename, errp);
+    ret = vmdk_parse_extents(buf, bs, bs->file->exact_filename, options, errp);
 exit:
     return ret;
 }
@@ -942,11 +950,11 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
     switch (magic) {
         case VMDK3_MAGIC:
         case VMDK4_MAGIC:
-            ret = vmdk_open_sparse(bs, bs->file, flags, buf, errp);
+            ret = vmdk_open_sparse(bs, bs->file, flags, buf, options, errp);
             s->desc_offset = 0x200;
             break;
         default:
-            ret = vmdk_open_desc_file(bs, flags, buf, errp);
+            ret = vmdk_open_desc_file(bs, flags, buf, options, errp);
             break;
     }
     if (ret) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (3 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 04/34] vmdk: " Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-08 22:54   ` Eric Blake
                     ` (4 more replies)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 06/34] block: Use QemuOpts in bdrv_open_common() Kevin Wolf
                   ` (28 subsequent siblings)
  33 siblings, 5 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 blockdev.c            | 24 ++++++++++++------------
 include/block/block.h |  8 ++++++++
 2 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 5eaf77e..77cbe72 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -391,13 +391,13 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
         }
     }
 
-    if (qemu_opt_get_bool(opts, "cache.writeback", true)) {
+    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true)) {
         bdrv_flags |= BDRV_O_CACHE_WB;
     }
-    if (qemu_opt_get_bool(opts, "cache.direct", false)) {
+    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
         bdrv_flags |= BDRV_O_NOCACHE;
     }
-    if (qemu_opt_get_bool(opts, "cache.no-flush", false)) {
+    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
         bdrv_flags |= BDRV_O_NO_FLUSH;
     }
 
@@ -733,16 +733,16 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
         }
 
         /* Specific options take precedence */
-        if (!qemu_opt_get(all_opts, "cache.writeback")) {
-            qemu_opt_set_bool(all_opts, "cache.writeback",
+        if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_WB)) {
+            qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_WB,
                               !!(flags & BDRV_O_CACHE_WB), &error_abort);
         }
-        if (!qemu_opt_get(all_opts, "cache.direct")) {
-            qemu_opt_set_bool(all_opts, "cache.direct",
+        if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_DIRECT)) {
+            qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_DIRECT,
                               !!(flags & BDRV_O_NOCACHE), &error_abort);
         }
-        if (!qemu_opt_get(all_opts, "cache.no-flush")) {
-            qemu_opt_set_bool(all_opts, "cache.no-flush",
+        if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_NO_FLUSH)) {
+            qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_NO_FLUSH,
                               !!(flags & BDRV_O_NO_FLUSH), &error_abort);
         }
         qemu_opt_unset(all_opts, "cache");
@@ -3106,15 +3106,15 @@ QemuOptsList qemu_common_drive_opts = {
             .type = QEMU_OPT_STRING,
             .help = "discard operation (ignore/off, unmap/on)",
         },{
-            .name = "cache.writeback",
+            .name = BDRV_OPT_CACHE_WB,
             .type = QEMU_OPT_BOOL,
             .help = "enables writeback mode for any caches",
         },{
-            .name = "cache.direct",
+            .name = BDRV_OPT_CACHE_DIRECT,
             .type = QEMU_OPT_BOOL,
             .help = "enables use of O_DIRECT (bypass the host page cache)",
         },{
-            .name = "cache.no-flush",
+            .name = BDRV_OPT_CACHE_NO_FLUSH,
             .type = QEMU_OPT_BOOL,
             .help = "ignore any flush requests for the device",
         },{
diff --git a/include/block/block.h b/include/block/block.h
index 7d1a717..86bdac8 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -90,6 +90,14 @@ typedef struct HDGeometry {
 
 #define BDRV_O_CACHE_MASK  (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
 
+
+/* Option names of options parsed by the block layer */
+
+#define BDRV_OPT_CACHE_WB       "cache.writeback"
+#define BDRV_OPT_CACHE_DIRECT   "cache.direct"
+#define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush"
+
+
 #define BDRV_SECTOR_BITS   9
 #define BDRV_SECTOR_SIZE   (1ULL << BDRV_SECTOR_BITS)
 #define BDRV_SECTOR_MASK   ~(BDRV_SECTOR_SIZE - 1)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 06/34] block: Use QemuOpts in bdrv_open_common()
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (4 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-08 22:57   ` Eric Blake
  2015-05-11 14:57   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 07/34] block: Move flag inheritance to bdrv_open_inherited() Kevin Wolf
                   ` (27 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Instead of manually parsing options and then deleting them from the
options QDict, just use QemuOpts like most other places that deal with
block device options.

More options will be added there and then QemuOpts is a lot more
managable than open-coding everything.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c | 37 ++++++++++++++++++++++++++++++++-----
 1 file changed, 32 insertions(+), 5 deletions(-)

diff --git a/block.c b/block.c
index 7904098..cea022f 100644
--- a/block.c
+++ b/block.c
@@ -757,6 +757,19 @@ static void bdrv_assign_node_name(BlockDriverState *bs,
     QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list);
 }
 
+static QemuOptsList bdrv_runtime_opts = {
+    .name = "bdrv_common",
+    .head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head),
+    .desc = {
+        {
+            .name = "node-name",
+            .type = QEMU_OPT_STRING,
+            .help = "Node name of the block device node",
+        },
+        { /* end of list */ }
+    },
+};
+
 /*
  * Common part for opening disk images and files
  *
@@ -768,6 +781,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
     int ret, open_flags;
     const char *filename;
     const char *node_name = NULL;
+    QemuOpts *opts;
     Error *local_err = NULL;
 
     assert(drv != NULL);
@@ -788,19 +802,28 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
 
     trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
 
-    node_name = qdict_get_try_str(options, "node-name");
+    opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
+    qemu_opts_absorb_qdict(opts, options, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto fail_opts;
+    }
+
+    node_name = qemu_opt_get(opts, "node-name");
     bdrv_assign_node_name(bs, node_name, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto fail_opts;
     }
-    qdict_del(options, "node-name");
 
     /* bdrv_open() with directly using a protocol as drv. This layer is already
      * opened, so assign it to bs (while file becomes a closed BlockDriverState)
      * and return immediately. */
     if (file != NULL && drv->bdrv_file_open) {
         bdrv_swap(file, bs);
+        qemu_opts_del(opts);
         return 0;
     }
 
@@ -817,7 +840,8 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
                         ? "Driver '%s' can only be used for read-only devices"
                         : "Driver '%s' is not whitelisted",
                    drv->format_name);
-        return -ENOTSUP;
+        ret = -ENOTSUP;
+        goto fail_opts;
     }
 
     assert(bs->copy_on_read == 0); /* bdrv_new() and bdrv_close() make it so */
@@ -826,7 +850,8 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
             bdrv_enable_copy_on_read(bs);
         } else {
             error_setg(errp, "Can't use copy-on-read on read-only device");
-            return -EINVAL;
+            ret = -EINVAL;
+            goto fail_opts;
         }
     }
 
@@ -898,6 +923,8 @@ free_and_fail:
     g_free(bs->opaque);
     bs->opaque = NULL;
     bs->drv = NULL;
+fail_opts:
+    qemu_opts_del(opts);
     return ret;
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 07/34] block: Move flag inheritance to bdrv_open_inherited()
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (5 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 06/34] block: Use QemuOpts in bdrv_open_common() Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-08 23:20   ` Eric Blake
                     ` (2 more replies)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState Kevin Wolf
                   ` (26 subsequent siblings)
  33 siblings, 3 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Instead of letting every caller of bdrv_open() determine the right flags
for its child node manually and pass them to the function, pass the
parent node and the role of the newly opened child (like backing file,
protocol layer, etc.).

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c                   | 74 ++++++++++++++++++++++++++++++++++++++---------
 block/blkdebug.c          |  2 +-
 block/blkverify.c         |  4 +--
 block/quorum.c            |  4 +--
 block/vmdk.c              |  5 ++--
 include/block/block.h     |  4 ++-
 include/block/block_int.h |  7 +++++
 7 files changed, 78 insertions(+), 22 deletions(-)

diff --git a/block.c b/block.c
index cea022f..c4f0fb4 100644
--- a/block.c
+++ b/block.c
@@ -79,6 +79,12 @@ static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
 static QLIST_HEAD(, BlockDriver) bdrv_drivers =
     QLIST_HEAD_INITIALIZER(bdrv_drivers);
 
+static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
+                             const char *reference, QDict *options, int flags,
+                             BlockDriverState* parent,
+                             const BdrvChildRole *child_role,
+                             BlockDriver *drv, Error **errp);
+
 static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
 /* If non-zero, use only whitelisted block drivers */
 static int use_bdrv_whitelist;
@@ -672,8 +678,8 @@ static int bdrv_temp_snapshot_flags(int flags)
 }
 
 /*
- * Returns the flags that bs->file should get, based on the given flags for
- * the parent BDS
+ * Returns the flags that bs->file should get if a protocol driver is expected,
+ * based on the given flags for the parent BDS
  */
 static int bdrv_inherited_flags(int flags)
 {
@@ -690,6 +696,25 @@ static int bdrv_inherited_flags(int flags)
     return flags;
 }
 
+const BdrvChildRole child_file = {
+    .inherit_flags = bdrv_inherited_flags,
+};
+
+/*
+ * Returns the flags that bs->file should get if the use of formats (and not
+ * only protocols) is permitted for it, based on the given flags for the parent
+ * BDS
+ */
+static int bdrv_inherited_fmt_flags(int parent_flags)
+{
+    int flags = child_file.inherit_flags(parent_flags);
+    return flags & ~BDRV_O_PROTOCOL;
+}
+
+const BdrvChildRole child_format = {
+    .inherit_flags = bdrv_inherited_fmt_flags,
+};
+
 /*
  * Returns the flags that bs->backing_hd should get, based on the given flags
  * for the parent BDS
@@ -705,6 +730,10 @@ static int bdrv_backing_flags(int flags)
     return flags;
 }
 
+static const BdrvChildRole child_backing = {
+    .inherit_flags = bdrv_backing_flags,
+};
+
 static int bdrv_open_flags(BlockDriverState *bs, int flags)
 {
     int open_flags = flags | BDRV_O_CACHE_WB;
@@ -827,7 +856,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
         return 0;
     }
 
-    bs->open_flags = flags;
     bs->guest_block_size = 512;
     bs->request_alignment = 512;
     bs->zero_beyond_eof = true;
@@ -1134,9 +1162,10 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
     }
 
     assert(bs->backing_hd == NULL);
-    ret = bdrv_open(&backing_hd,
-                    *backing_filename ? backing_filename : NULL, NULL, options,
-                    bdrv_backing_flags(bs->open_flags), NULL, &local_err);
+    ret = bdrv_open_inherit(&backing_hd,
+                            *backing_filename ? backing_filename : NULL,
+                            NULL, options, 0, bs, &child_backing,
+                            NULL, &local_err);
     if (ret < 0) {
         bdrv_unref(backing_hd);
         backing_hd = NULL;
@@ -1170,7 +1199,8 @@ free_exit:
  * To conform with the behavior of bdrv_open(), *pbs has to be NULL.
  */
 int bdrv_open_image(BlockDriverState **pbs, const char *filename,
-                    QDict *options, const char *bdref_key, int flags,
+                    QDict *options, const char *bdref_key,
+                    BlockDriverState* parent, const BdrvChildRole *child_role,
                     bool allow_none, Error **errp)
 {
     QDict *image_options;
@@ -1198,7 +1228,8 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
         goto done;
     }
 
-    ret = bdrv_open(pbs, filename, reference, image_options, flags, NULL, errp);
+    ret = bdrv_open_inherit(pbs, filename, reference, image_options, 0,
+                            parent, child_role, NULL, errp);
 
 done:
     qdict_del(options, bdref_key);
@@ -1285,9 +1316,11 @@ out:
  * should be opened. If specified, neither options nor a filename may be given,
  * nor can an existing BDS be reused (that is, *pbs has to be NULL).
  */
-int bdrv_open(BlockDriverState **pbs, const char *filename,
-              const char *reference, QDict *options, int flags,
-              BlockDriver *drv, Error **errp)
+static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
+                             const char *reference, QDict *options, int flags,
+                             BlockDriverState* parent,
+                             const BdrvChildRole *child_role,
+                             BlockDriver *drv, Error **errp)
 {
     int ret;
     BlockDriverState *file = NULL, *bs;
@@ -1296,6 +1329,8 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
     int snapshot_flags = 0;
 
     assert(pbs);
+    assert(!child_role || !flags);
+    assert(!child_role == !parent);
 
     if (reference) {
         bool options_non_empty = options ? qdict_size(options) : false;
@@ -1333,6 +1368,10 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
         options = qdict_new();
     }
 
+    if (child_role) {
+        flags = child_role->inherit_flags(parent->open_flags);
+    }
+
     ret = bdrv_fill_options(&options, &filename, flags, drv, &local_err);
     if (local_err) {
         goto fail;
@@ -1358,6 +1397,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
         flags &= ~BDRV_O_PROTOCOL;
     }
 
+    bs->open_flags = flags;
     bs->options = options;
     options = qdict_clone_shallow(options);
 
@@ -1372,9 +1412,9 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
         }
 
         assert(file == NULL);
+        bs->open_flags = flags;
         ret = bdrv_open_image(&file, filename, options, "file",
-                              bdrv_inherited_flags(flags),
-                              true, &local_err);
+                              bs, &child_file, true, &local_err);
         if (ret < 0) {
             goto fail;
         }
@@ -1491,6 +1531,14 @@ close_and_fail:
     return ret;
 }
 
+int bdrv_open(BlockDriverState **pbs, const char *filename,
+              const char *reference, QDict *options, int flags,
+              BlockDriver *drv, Error **errp)
+{
+    return bdrv_open_inherit(pbs, filename, reference, options, flags, NULL,
+                             NULL, drv, errp);
+}
+
 typedef struct BlockReopenQueueEntry {
      bool prepared;
      BDRVReopenState state;
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 3c30edb..17b7c85 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -431,7 +431,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
     /* Open the backing file */
     assert(bs->file == NULL);
     ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image",
-                          flags | BDRV_O_PROTOCOL, false, &local_err);
+                          bs, &child_file, false, &local_err);
     if (ret < 0) {
         error_propagate(errp, local_err);
         goto out;
diff --git a/block/blkverify.c b/block/blkverify.c
index 438dff8..d277e63 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -125,7 +125,7 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
     /* Open the raw file */
     assert(bs->file == NULL);
     ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-raw"), options,
-                          "raw", flags | BDRV_O_PROTOCOL, false, &local_err);
+                          "raw", bs, &child_file, false, &local_err);
     if (ret < 0) {
         error_propagate(errp, local_err);
         goto fail;
@@ -134,7 +134,7 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
     /* Open the test file */
     assert(s->test_file == NULL);
     ret = bdrv_open_image(&s->test_file, qemu_opt_get(opts, "x-image"), options,
-                          "test", flags, false, &local_err);
+                          "test", bs, &child_format, false, &local_err);
     if (ret < 0) {
         error_propagate(errp, local_err);
         s->test_file = NULL;
diff --git a/block/quorum.c b/block/quorum.c
index a33881a..77e55b2 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -935,8 +935,8 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
         ret = snprintf(indexstr, 32, "children.%d", i);
         assert(ret < 32);
 
-        ret = bdrv_open_image(&s->bs[i], NULL, options, indexstr, flags,
-                              false, &local_err);
+        ret = bdrv_open_image(&s->bs[i], NULL, options, indexstr, bs,
+                              &child_format, false, &local_err);
         if (ret < 0) {
             goto close_exit;
         }
diff --git a/block/vmdk.c b/block/vmdk.c
index 641e026..69bab3a 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -852,9 +852,8 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
         ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents);
         assert(ret < 32);
 
-        ret = bdrv_open_image(&extent_file, extent_path,
-                              options, extent_opt_prefix,
-                              bs->open_flags | BDRV_O_PROTOCOL, false, errp);
+        ret = bdrv_open_image(&extent_file, extent_path, options,
+                              extent_opt_prefix, bs, &child_file, false, errp);
         g_free(extent_path);
         if (ret) {
             return ret;
diff --git a/include/block/block.h b/include/block/block.h
index 86bdac8..27ab2c8 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -12,6 +12,7 @@
 /* block.c */
 typedef struct BlockDriver BlockDriver;
 typedef struct BlockJob BlockJob;
+typedef struct BdrvChildRole BdrvChildRole;
 
 typedef struct BlockDriverInfo {
     /* in bytes, 0 if irrelevant */
@@ -203,7 +204,8 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
 int bdrv_parse_cache_flags(const char *mode, int *flags);
 int bdrv_parse_discard_flags(const char *mode, int *flags);
 int bdrv_open_image(BlockDriverState **pbs, const char *filename,
-                    QDict *options, const char *bdref_key, int flags,
+                    QDict *options, const char *bdref_key,
+                    BlockDriverState* parent, const BdrvChildRole *child_role,
                     bool allow_none, Error **errp);
 void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
 int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index db29b74..eb01ea2 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -327,6 +327,13 @@ typedef struct BdrvAioNotifier {
     QLIST_ENTRY(BdrvAioNotifier) list;
 } BdrvAioNotifier;
 
+struct BdrvChildRole {
+    int (*inherit_flags)(int parent_flags);
+};
+
+extern const BdrvChildRole child_file;
+extern const BdrvChildRole child_format;
+
 /*
  * Note: the function bdrv_append() copies and swaps contents of
  * BlockDriverStates, so if you add new fields to this struct, please
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (6 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 07/34] block: Move flag inheritance to bdrv_open_inherited() Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-08 23:34   ` Eric Blake
                     ` (2 more replies)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 09/34] block: Add BlockDriverState.inherits_from Kevin Wolf
                   ` (25 subsequent siblings)
  33 siblings, 3 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

This allows iterating over all children of a given BDS, not only
including bs->file and bs->backing_hd, but also driver-specific
ones like VMDK extents or Quorum children.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c                   | 27 +++++++++++++++++++++++++++
 include/block/block_int.h |  8 ++++++++
 2 files changed, 35 insertions(+)

diff --git a/block.c b/block.c
index c4f0fb4..59f54ed 100644
--- a/block.c
+++ b/block.c
@@ -1301,6 +1301,19 @@ out:
     return ret;
 }
 
+static void bdrv_attach_child(BlockDriverState *parent_bs,
+                              BlockDriverState *child_bs,
+                              const BdrvChildRole *child_role)
+{
+    BdrvChild *child = g_new(BdrvChild, 1);
+    *child = (BdrvChild) {
+        .bs     = child_bs,
+        .role   = child_role,
+    };
+
+    QLIST_INSERT_HEAD(&parent_bs->children, child, next);
+}
+
 /*
  * Opens a disk image (raw, qcow2, vmdk, ...)
  *
@@ -1353,6 +1366,9 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
             return -ENODEV;
         }
         bdrv_ref(bs);
+        if (child_role) {
+            bdrv_attach_child(parent, bs, child_role);
+        }
         *pbs = bs;
         return 0;
     }
@@ -1495,6 +1511,10 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
         goto close_and_fail;
     }
 
+    if (child_role) {
+        bdrv_attach_child(parent, bs, child_role);
+    }
+
     QDECREF(options);
     *pbs = bs;
     return 0;
@@ -1789,6 +1809,12 @@ void bdrv_close(BlockDriverState *bs)
     notifier_list_notify(&bs->close_notifiers, bs);
 
     if (bs->drv) {
+        BdrvChild *child, *next;
+
+        QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
+            g_free(child);
+        }
+
         if (bs->backing_hd) {
             BlockDriverState *backing_hd = bs->backing_hd;
             bdrv_set_backing_hd(bs, NULL);
@@ -1999,6 +2025,7 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
     /* The contents of 'tmp' will become bs_top, as we are
      * swapping bs_new and bs_top contents. */
     bdrv_set_backing_hd(bs_top, bs_new);
+    bdrv_attach_child(bs_top, bs_new, &child_backing);
 }
 
 static void bdrv_delete(BlockDriverState *bs)
diff --git a/include/block/block_int.h b/include/block/block_int.h
index eb01ea2..12c7fb3 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -334,6 +334,12 @@ struct BdrvChildRole {
 extern const BdrvChildRole child_file;
 extern const BdrvChildRole child_format;
 
+typedef struct BdrvChild {
+    BlockDriverState *bs;
+    const BdrvChildRole *role;
+    QLIST_ENTRY(BdrvChild) next;
+} BdrvChild;
+
 /*
  * Note: the function bdrv_append() copies and swaps contents of
  * BlockDriverStates, so if you add new fields to this struct, please
@@ -428,6 +434,8 @@ struct BlockDriverState {
     /* long-running background operation */
     BlockJob *job;
 
+    QLIST_HEAD(, BdrvChild) children;
+
     QDict *options;
     BlockdevDetectZeroesOptions detect_zeroes;
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 09/34] block: Add BlockDriverState.inherits_from
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (7 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-08 23:39   ` Eric Blake
  2015-05-11 15:50   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 10/34] block: Fix reopen flag inheritance Kevin Wolf
                   ` (24 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Currently, the block layer assumes that any block node can have only one
parent, and if it has a parent, that it inherits some options/flags from
this parent.

This is not true any more: With references used in block device
creation, a single node can be used by multiple parents, or it can be
created separately and not inherit flags from any parent.

To handle reopens correctly, a node must know from which parent it
inherited options. This patch adds the information to BlockDriverState.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c                   | 17 +++++++++++++++++
 include/block/block_int.h |  4 ++++
 2 files changed, 21 insertions(+)

diff --git a/block.c b/block.c
index 59f54ed..59585a9 100644
--- a/block.c
+++ b/block.c
@@ -1385,6 +1385,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
     }
 
     if (child_role) {
+        bs->inherits_from = parent;
         flags = child_role->inherit_flags(parent->open_flags);
     }
 
@@ -1812,6 +1813,9 @@ void bdrv_close(BlockDriverState *bs)
         BdrvChild *child, *next;
 
         QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
+            if (child->bs->inherits_from == bs) {
+                child->bs->inherits_from = NULL;
+            }
             g_free(child);
         }
 
@@ -1959,6 +1963,7 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
 void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
 {
     BlockDriverState tmp;
+    BdrvChild *child;
 
     /* The code needs to swap the node_name but simply swapping node_list won't
      * work so first remove the nodes from the graph list, do the swap then
@@ -2003,6 +2008,18 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
         QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_old, node_list);
     }
 
+    /* Update references in bs->opaque and children */
+    QLIST_FOREACH(child, &bs_old->children, next) {
+        if (child->bs->inherits_from == bs_new) {
+            child->bs->inherits_from = bs_old;
+        }
+    }
+    QLIST_FOREACH(child, &bs_new->children, next) {
+        if (child->bs->inherits_from == bs_old) {
+            child->bs->inherits_from = bs_new;
+        }
+    }
+
     bdrv_rebind(bs_new);
     bdrv_rebind(bs_old);
 }
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 12c7fb3..2fad5f8 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -434,6 +434,10 @@ struct BlockDriverState {
     /* long-running background operation */
     BlockJob *job;
 
+    /* The node that this node inherited default options from (and a reopen on
+     * which can affect this node by changing these defaults). This is always a
+     * parent node of this node. */
+    BlockDriverState *inherits_from;
     QLIST_HEAD(, BdrvChild) children;
 
     QDict *options;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 10/34] block: Fix reopen flag inheritance
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (8 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 09/34] block: Add BlockDriverState.inherits_from Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-11 16:04   ` Max Reitz
  2015-05-12 14:32   ` Eric Blake
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 11/34] block: Allow references for backing files Kevin Wolf
                   ` (23 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

When reopening an image, the block layer already takes care to reopen
bs->file as well with recalculated inherited flags. The same must happen
for any other child (most notably missing before this patch: backing
files).

If bs->file (or any other child) didn't originally inherit from bs, e.g.
because it was created separately and then only referenced, it must not
inherit flags on reopen either, so check the inherited_from field before
propagation the reopen down.

VMDK already reopened its extents manually; this code can now be
dropped.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c      | 13 +++++++++++--
 block/vmdk.c | 28 ++--------------------------
 2 files changed, 13 insertions(+), 28 deletions(-)

diff --git a/block.c b/block.c
index 59585a9..e93bf63 100644
--- a/block.c
+++ b/block.c
@@ -1590,6 +1590,8 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
     assert(bs != NULL);
 
     BlockReopenQueueEntry *bs_entry;
+    BdrvChild *child;
+
     if (bs_queue == NULL) {
         bs_queue = g_new0(BlockReopenQueue, 1);
         QSIMPLEQ_INIT(bs_queue);
@@ -1598,8 +1600,15 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
     /* bdrv_open() masks this flag out */
     flags &= ~BDRV_O_PROTOCOL;
 
-    if (bs->file) {
-        bdrv_reopen_queue(bs_queue, bs->file, bdrv_inherited_flags(flags));
+    QLIST_FOREACH(child, &bs->children, next) {
+        int child_flags;
+
+        if (child->bs->inherits_from != bs) {
+            continue;
+        }
+
+        child_flags = child->role->inherit_flags(flags);
+        bdrv_reopen_queue(bs_queue, child->bs, child_flags);
     }
 
     bs_entry = g_new0(BlockReopenQueueEntry, 1);
diff --git a/block/vmdk.c b/block/vmdk.c
index 69bab3a..920de89 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -321,37 +321,13 @@ static int vmdk_is_cid_valid(BlockDriverState *bs)
     return 1;
 }
 
-/* Queue extents, if any, for reopen() */
+/* We have nothing to do for VMDK reopen, stubs just return success */
 static int vmdk_reopen_prepare(BDRVReopenState *state,
                                BlockReopenQueue *queue, Error **errp)
 {
-    BDRVVmdkState *s;
-    int ret = -1;
-    int i;
-    VmdkExtent *e;
-
     assert(state != NULL);
     assert(state->bs != NULL);
-
-    if (queue == NULL) {
-        error_setg(errp, "No reopen queue for VMDK extents");
-        goto exit;
-    }
-
-    s = state->bs->opaque;
-
-    assert(s != NULL);
-
-    for (i = 0; i < s->num_extents; i++) {
-        e = &s->extents[i];
-        if (e->file != state->bs->file) {
-            bdrv_reopen_queue(queue, e->file, state->flags);
-        }
-    }
-    ret = 0;
-
-exit:
-    return ret;
+    return 0;
 }
 
 static int vmdk_parent_open(BlockDriverState *bs)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 11/34] block: Allow references for backing files
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (9 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 10/34] block: Fix reopen flag inheritance Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-11 16:19   ` Max Reitz
                     ` (2 more replies)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 12/34] block: Allow specifying driver-specific options to reopen Kevin Wolf
                   ` (22 subsequent siblings)
  33 siblings, 3 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

For bs->file, using references to existing BDSes has been possible for a
while already. This patch enables the same for bs->backing_hd.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c               | 42 ++++++++++++++++++++++++------------------
 block/mirror.c        |  2 +-
 include/block/block.h |  3 ++-
 3 files changed, 27 insertions(+), 20 deletions(-)

diff --git a/block.c b/block.c
index e93bf63..95dc51e 100644
--- a/block.c
+++ b/block.c
@@ -1109,30 +1109,41 @@ out:
 /*
  * Opens the backing file for a BlockDriverState if not yet open
  *
- * options is a QDict of options to pass to the block drivers, or NULL for an
- * empty set of options. The reference to the QDict is transferred to this
- * function (even on failure), so if the caller intends to reuse the dictionary,
- * it needs to use QINCREF() before calling bdrv_file_open.
+ * bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
+ * That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
+ * itself, all options starting with "${bdref_key}." are considered part of the
+ * BlockdevRef.
+ *
+ * TODO Can this be unified with bdrv_open_image()?
  */
-int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
+int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
+                           const char *bdref_key, Error **errp)
 {
     char *backing_filename = g_malloc0(PATH_MAX);
+    char *bdref_key_dot;
+    const char *reference = NULL;
     int ret = 0;
     BlockDriverState *backing_hd;
+    QDict *options;
     Error *local_err = NULL;
 
     if (bs->backing_hd != NULL) {
-        QDECREF(options);
         goto free_exit;
     }
 
     /* NULL means an empty set of options */
-    if (options == NULL) {
-        options = qdict_new();
+    if (parent_options == NULL) {
+        parent_options = qdict_new();
     }
 
     bs->open_flags &= ~BDRV_O_NO_BACKING;
-    if (qdict_haskey(options, "file.filename")) {
+
+    bdref_key_dot = g_strdup_printf("%s.", bdref_key);
+    qdict_extract_subqdict(parent_options, &options, bdref_key_dot);
+    g_free(bdref_key_dot);
+
+    reference = qdict_get_try_str(parent_options, bdref_key);
+    if (reference || qdict_haskey(options, "file.filename")) {
         backing_filename[0] = '\0';
     } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
         QDECREF(options);
@@ -1155,20 +1166,17 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
         goto free_exit;
     }
 
-    backing_hd = bdrv_new();
-
     if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
         qdict_put(options, "driver", qstring_from_str(bs->backing_format));
     }
 
     assert(bs->backing_hd == NULL);
+    backing_hd = NULL;
     ret = bdrv_open_inherit(&backing_hd,
                             *backing_filename ? backing_filename : NULL,
-                            NULL, options, 0, bs, &child_backing,
+                            reference, options, 0, bs, &child_backing,
                             NULL, &local_err);
     if (ret < 0) {
-        bdrv_unref(backing_hd);
-        backing_hd = NULL;
         bs->open_flags |= BDRV_O_NO_BACKING;
         error_setg(errp, "Could not open backing file: %s",
                    error_get_pretty(local_err));
@@ -1176,6 +1184,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
         goto free_exit;
     }
     bdrv_set_backing_hd(bs, backing_hd);
+    qdict_del(parent_options, bdref_key);
 
 free_exit:
     g_free(backing_filename);
@@ -1463,10 +1472,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
 
     /* If there is a backing file, use it */
     if ((flags & BDRV_O_NO_BACKING) == 0) {
-        QDict *backing_options;
-
-        qdict_extract_subqdict(options, &backing_options, "backing.");
-        ret = bdrv_open_backing_file(bs, backing_options, &local_err);
+        ret = bdrv_open_backing_file(bs, options, "backing", &local_err);
         if (ret < 0) {
             goto close_and_fail;
         }
diff --git a/block/mirror.c b/block/mirror.c
index 58f391a..f1bc342 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -592,7 +592,7 @@ static void mirror_complete(BlockJob *job, Error **errp)
     Error *local_err = NULL;
     int ret;
 
-    ret = bdrv_open_backing_file(s->target, NULL, &local_err);
+    ret = bdrv_open_backing_file(s->target, NULL, "backing", &local_err);
     if (ret < 0) {
         error_propagate(errp, local_err);
         return;
diff --git a/include/block/block.h b/include/block/block.h
index 27ab2c8..341a551 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -208,7 +208,8 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
                     BlockDriverState* parent, const BdrvChildRole *child_role,
                     bool allow_none, Error **errp);
 void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
-int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
+int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
+                           const char *bdref_key, Error **errp);
 int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp);
 int bdrv_open(BlockDriverState **pbs, const char *filename,
               const char *reference, QDict *options, int flags,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 12/34] block: Allow specifying driver-specific options to reopen
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (10 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 11/34] block: Allow references for backing files Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-11 16:35   ` Max Reitz
  2015-05-12 14:59   ` Eric Blake
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 13/34] qemu-io: Add command 'reopen' Kevin Wolf
                   ` (21 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c               | 42 +++++++++++++++++++++++++++++++++++++++---
 block/commit.c        |  4 ++--
 include/block/block.h |  4 +++-
 3 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/block.c b/block.c
index 95dc51e..561cefd 100644
--- a/block.c
+++ b/block.c
@@ -1584,6 +1584,9 @@ typedef struct BlockReopenQueueEntry {
  *
  * bs is the BlockDriverState to add to the reopen queue.
  *
+ * options contains the changed options for the associated bs
+ * (the BlockReopenQueue takes the ownership)
+ *
  * flags contains the open flags for the associated bs
  *
  * returns a pointer to bs_queue, which is either the newly allocated
@@ -1591,18 +1594,28 @@ typedef struct BlockReopenQueueEntry {
  *
  */
 BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
-                                    BlockDriverState *bs, int flags)
+                                    BlockDriverState *bs,
+                                    QDict *options, int flags)
 {
     assert(bs != NULL);
 
     BlockReopenQueueEntry *bs_entry;
     BdrvChild *child;
+    QDict *old_options;
 
     if (bs_queue == NULL) {
         bs_queue = g_new0(BlockReopenQueue, 1);
         QSIMPLEQ_INIT(bs_queue);
     }
 
+    if (!options) {
+        options = qdict_new();
+    }
+
+    old_options = qdict_clone_shallow(bs->options);
+    qdict_join(options, old_options, false);
+    QDECREF(old_options);
+
     /* bdrv_open() masks this flag out */
     flags &= ~BDRV_O_PROTOCOL;
 
@@ -1614,13 +1627,15 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
         }
 
         child_flags = child->role->inherit_flags(flags);
-        bdrv_reopen_queue(bs_queue, child->bs, child_flags);
+        /* TODO Pass down child flags (backing.*, extents.*, ...) */
+        bdrv_reopen_queue(bs_queue, child->bs, NULL, child_flags);
     }
 
     bs_entry = g_new0(BlockReopenQueueEntry, 1);
     QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry);
 
     bs_entry->state.bs = bs;
+    bs_entry->state.options = options;
     bs_entry->state.flags = flags;
 
     return bs_queue;
@@ -1673,6 +1688,7 @@ cleanup:
         if (ret && bs_entry->prepared) {
             bdrv_reopen_abort(&bs_entry->state);
         }
+        QDECREF(bs_entry->state.options);
         g_free(bs_entry);
     }
     g_free(bs_queue);
@@ -1685,7 +1701,7 @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
 {
     int ret = -1;
     Error *local_err = NULL;
-    BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, bdrv_flags);
+    BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
 
     ret = bdrv_reopen_multiple(queue, &local_err);
     if (local_err != NULL) {
@@ -1761,6 +1777,26 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
         goto error;
     }
 
+    /* Options that are not handled are only okay if they are unchanged
+     * compared to the old state. It is expected that some options are only
+     * used for the initial open, but not reopen (e.g. filename) */
+    if (qdict_size(reopen_state->options)) {
+        const QDictEntry *entry = qdict_first(reopen_state->options);
+
+        do {
+            QString *new_obj = qobject_to_qstring(entry->value);
+            const char *new = qstring_get_str(new_obj);
+            const char *old = qdict_get_try_str(reopen_state->bs->options,
+                                                entry->key);
+
+            if (!new != !old || strcmp(new, old)) {
+                error_setg(errp, "Cannot change the option '%s'", entry->key);
+                ret = -EINVAL;
+                goto error;
+            }
+        } while ((entry = qdict_next(reopen_state->options, entry)));
+    }
+
     ret = 0;
 
 error:
diff --git a/block/commit.c b/block/commit.c
index cfa2bbe..2c07d12 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -235,11 +235,11 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
 
     /* convert base & overlay_bs to r/w, if necessary */
     if (!(orig_base_flags & BDRV_O_RDWR)) {
-        reopen_queue = bdrv_reopen_queue(reopen_queue, base,
+        reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
                                          orig_base_flags | BDRV_O_RDWR);
     }
     if (!(orig_overlay_flags & BDRV_O_RDWR)) {
-        reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs,
+        reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL,
                                          orig_overlay_flags | BDRV_O_RDWR);
     }
     if (reopen_queue) {
diff --git a/include/block/block.h b/include/block/block.h
index 341a551..1287013 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -146,6 +146,7 @@ typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue;
 typedef struct BDRVReopenState {
     BlockDriverState *bs;
     int flags;
+    QDict *options;
     void *opaque;
 } BDRVReopenState;
 
@@ -215,7 +216,8 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
               const char *reference, QDict *options, int flags,
               BlockDriver *drv, Error **errp);
 BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
-                                    BlockDriverState *bs, int flags);
+                                    BlockDriverState *bs,
+                                    QDict *options, int flags);
 int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
 int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp);
 int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 13/34] qemu-io: Add command 'reopen'
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (11 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 12/34] block: Allow specifying driver-specific options to reopen Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-11 16:50   ` Max Reitz
  2015-05-12 15:05   ` Eric Blake
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options() Kevin Wolf
                   ` (20 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qemu-io-cmds.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 1afcfc0..ef8f3fd 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -1978,6 +1978,76 @@ static const cmdinfo_t map_cmd = {
        .oneline        = "prints the allocated areas of a file",
 };
 
+static int reopen_f(BlockBackend *blk, int argc, char **argv);
+
+static QemuOptsList reopen_opts = {
+    .name = "reopen",
+    .merge_lists = true,
+    .head = QTAILQ_HEAD_INITIALIZER(reopen_opts.head),
+    .desc = {
+        /* no elements => accept any params */
+        { /* end of list */ }
+    },
+};
+
+static const cmdinfo_t reopen_cmd = {
+       .name           = "reopen",
+       .argmin         = 0,
+       .argmax         = -1,
+       .cfunc          = reopen_f,
+       .args           = "",
+       .oneline        = "reopens an image with new options",
+};
+
+static int reopen_f(BlockBackend *blk, int argc, char **argv)
+{
+    BlockDriverState *bs = blk_bs(blk);
+    QemuOpts *qopts;
+    QDict *opts;
+    int c;
+    int flags = bs->open_flags;
+
+    BlockReopenQueue *brq;
+    Error *local_err = NULL;
+
+    while ((c = getopt(argc, argv, "c:o:r")) != EOF) {
+        switch (c) {
+        case 'c':
+            if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
+                error_report("Invalid cache option: %s", optarg);
+                return 0;
+            }
+            break;
+        case 'o':
+            if (!qemu_opts_parse(&reopen_opts, optarg, 0)) {
+                printf("could not parse option list -- %s\n", optarg);
+                qemu_opts_reset(&reopen_opts);
+                return 0;
+            }
+            break;
+        case 'r':
+            flags &= ~BDRV_O_RDWR;
+            break;
+        default:
+            qemu_opts_reset(&reopen_opts);
+            return qemuio_command_usage(&reopen_cmd);
+        }
+    }
+
+    qopts = qemu_opts_find(&reopen_opts, NULL);
+    opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
+    qemu_opts_reset(&reopen_opts);
+
+    brq = bdrv_reopen_queue(NULL, bs, opts, flags);
+    bdrv_reopen_multiple(brq, &local_err);
+    if (local_err) {
+        qerror_report_err(local_err);
+        error_free(local_err);
+    }
+
+    return 0;
+}
+
 static int break_f(BlockBackend *blk, int argc, char **argv)
 {
     int ret;
@@ -2265,6 +2335,7 @@ static void __attribute((constructor)) init_qemuio_commands(void)
     qemuio_add_command(&discard_cmd);
     qemuio_add_command(&alloc_cmd);
     qemuio_add_command(&map_cmd);
+    qemuio_add_command(&reopen_cmd);
     qemuio_add_command(&break_cmd);
     qemuio_add_command(&remove_break_cmd);
     qemuio_add_command(&resume_cmd);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options()
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (12 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 13/34] qemu-io: Add command 'reopen' Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-12 20:04   ` Eric Blake
                     ` (2 more replies)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 15/34] qcow2: Move qcow2_update_options() call up Kevin Wolf
                   ` (19 subsequent siblings)
  33 siblings, 3 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Eventually we want to be able to change options at runtime. As a first
step towards that goal, separate some option handling code from the
general initialisation code in qcow2_open().

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/qcow2.c | 135 +++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 76 insertions(+), 59 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index b9a72e3..db535d4 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -538,6 +538,80 @@ static void read_cache_sizes(QemuOpts *opts, uint64_t *l2_cache_size,
     }
 }
 
+static int qcow2_update_options(BlockDriverState *bs, QemuOpts *opts,
+                                int flags, Error **errp)
+{
+    BDRVQcowState *s = bs->opaque;
+    const char *opt_overlap_check, *opt_overlap_check_template;
+    int overlap_check_template = 0;
+    int i;
+    int ret;
+
+    s->use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
+        (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS));
+
+    s->discard_passthrough[QCOW2_DISCARD_NEVER] = false;
+    s->discard_passthrough[QCOW2_DISCARD_ALWAYS] = true;
+    s->discard_passthrough[QCOW2_DISCARD_REQUEST] =
+        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_REQUEST,
+                          flags & BDRV_O_UNMAP);
+    s->discard_passthrough[QCOW2_DISCARD_SNAPSHOT] =
+        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_SNAPSHOT, true);
+    s->discard_passthrough[QCOW2_DISCARD_OTHER] =
+        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
+
+    opt_overlap_check = qemu_opt_get(opts, QCOW2_OPT_OVERLAP);
+    opt_overlap_check_template = qemu_opt_get(opts, QCOW2_OPT_OVERLAP_TEMPLATE);
+    if (opt_overlap_check_template && opt_overlap_check &&
+        strcmp(opt_overlap_check_template, opt_overlap_check))
+    {
+        error_setg(errp, "Conflicting values for qcow2 options '"
+                   QCOW2_OPT_OVERLAP "' ('%s') and '" QCOW2_OPT_OVERLAP_TEMPLATE
+                   "' ('%s')", opt_overlap_check, opt_overlap_check_template);
+        ret = -EINVAL;
+        goto fail;
+    }
+    if (!opt_overlap_check) {
+        opt_overlap_check = opt_overlap_check_template ?: "cached";
+    }
+
+    if (!strcmp(opt_overlap_check, "none")) {
+        overlap_check_template = 0;
+    } else if (!strcmp(opt_overlap_check, "constant")) {
+        overlap_check_template = QCOW2_OL_CONSTANT;
+    } else if (!strcmp(opt_overlap_check, "cached")) {
+        overlap_check_template = QCOW2_OL_CACHED;
+    } else if (!strcmp(opt_overlap_check, "all")) {
+        overlap_check_template = QCOW2_OL_ALL;
+    } else {
+        error_setg(errp, "Unsupported value '%s' for qcow2 option "
+                   "'overlap-check'. Allowed are either of the following: "
+                   "none, constant, cached, all", opt_overlap_check);
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    s->overlap_check = 0;
+    for (i = 0; i < QCOW2_OL_MAX_BITNR; i++) {
+        /* overlap-check defines a template bitmask, but every flag may be
+         * overwritten through the associated boolean option */
+        s->overlap_check |=
+            qemu_opt_get_bool(opts, overlap_bool_option_names[i],
+                              overlap_check_template & (1 << i)) << i;
+    }
+
+    if (s->use_lazy_refcounts && s->qcow_version < 3) {
+        error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
+                   "qemu 1.1 compatibility level");
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    ret = 0;
+fail:
+    return ret;
+}
+
 static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
                       Error **errp)
 {
@@ -549,8 +623,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
     Error *local_err = NULL;
     uint64_t ext_end;
     uint64_t l1_vm_state_index;
-    const char *opt_overlap_check, *opt_overlap_check_template;
-    int overlap_check_template = 0;
     uint64_t l2_cache_size, refcount_cache_size;
 
     ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
@@ -924,69 +996,14 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     /* Enable lazy_refcounts according to image and command line options */
-    s->use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
-        (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS));
-
-    s->discard_passthrough[QCOW2_DISCARD_NEVER] = false;
-    s->discard_passthrough[QCOW2_DISCARD_ALWAYS] = true;
-    s->discard_passthrough[QCOW2_DISCARD_REQUEST] =
-        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_REQUEST,
-                          flags & BDRV_O_UNMAP);
-    s->discard_passthrough[QCOW2_DISCARD_SNAPSHOT] =
-        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_SNAPSHOT, true);
-    s->discard_passthrough[QCOW2_DISCARD_OTHER] =
-        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
-
-    opt_overlap_check = qemu_opt_get(opts, QCOW2_OPT_OVERLAP);
-    opt_overlap_check_template = qemu_opt_get(opts, QCOW2_OPT_OVERLAP_TEMPLATE);
-    if (opt_overlap_check_template && opt_overlap_check &&
-        strcmp(opt_overlap_check_template, opt_overlap_check))
-    {
-        error_setg(errp, "Conflicting values for qcow2 options '"
-                   QCOW2_OPT_OVERLAP "' ('%s') and '" QCOW2_OPT_OVERLAP_TEMPLATE
-                   "' ('%s')", opt_overlap_check, opt_overlap_check_template);
-        ret = -EINVAL;
-        goto fail;
-    }
-    if (!opt_overlap_check) {
-        opt_overlap_check = opt_overlap_check_template ?: "cached";
-    }
-
-    if (!strcmp(opt_overlap_check, "none")) {
-        overlap_check_template = 0;
-    } else if (!strcmp(opt_overlap_check, "constant")) {
-        overlap_check_template = QCOW2_OL_CONSTANT;
-    } else if (!strcmp(opt_overlap_check, "cached")) {
-        overlap_check_template = QCOW2_OL_CACHED;
-    } else if (!strcmp(opt_overlap_check, "all")) {
-        overlap_check_template = QCOW2_OL_ALL;
-    } else {
-        error_setg(errp, "Unsupported value '%s' for qcow2 option "
-                   "'overlap-check'. Allowed are either of the following: "
-                   "none, constant, cached, all", opt_overlap_check);
-        ret = -EINVAL;
+    ret = qcow2_update_options(bs, opts, flags, errp);
+    if (ret < 0) {
         goto fail;
     }
 
-    s->overlap_check = 0;
-    for (i = 0; i < QCOW2_OL_MAX_BITNR; i++) {
-        /* overlap-check defines a template bitmask, but every flag may be
-         * overwritten through the associated boolean option */
-        s->overlap_check |=
-            qemu_opt_get_bool(opts, overlap_bool_option_names[i],
-                              overlap_check_template & (1 << i)) << i;
-    }
-
     qemu_opts_del(opts);
     opts = NULL;
 
-    if (s->use_lazy_refcounts && s->qcow_version < 3) {
-        error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
-                   "qemu 1.1 compatibility level");
-        ret = -EINVAL;
-        goto fail;
-    }
-
 #ifdef DEBUG_ALLOC
     {
         BdrvCheckResult result = {0};
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 15/34] qcow2: Move qcow2_update_options() call up
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (13 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options() Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-12 20:15   ` Eric Blake
  2015-05-13 11:25   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 16/34] qcow2: Move rest of option handling to qcow2_update_options() Kevin Wolf
                   ` (18 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

qcow2_update_options() only updates some variables in BDRVQcowState and
doesn't really depend on other parts of it being initialised yet, so it
can be moved so that it immediately follows the other half of option
handling code in qcow2_open().

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/qcow2.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index db535d4..761ba30 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -911,6 +911,15 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
         goto fail;
     }
 
+    /* Enable lazy_refcounts according to image and command line options */
+    ret = qcow2_update_options(bs, opts, flags, errp);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    qemu_opts_del(opts);
+    opts = NULL;
+
     s->cluster_cache = g_malloc(s->cluster_size);
     /* one more sector for decompressed data alignment */
     s->cluster_data = qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
@@ -995,15 +1004,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
         }
     }
 
-    /* Enable lazy_refcounts according to image and command line options */
-    ret = qcow2_update_options(bs, opts, flags, errp);
-    if (ret < 0) {
-        goto fail;
-    }
-
-    qemu_opts_del(opts);
-    opts = NULL;
-
 #ifdef DEBUG_ALLOC
     {
         BdrvCheckResult result = {0};
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 16/34] qcow2: Move rest of option handling to qcow2_update_options()
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (14 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 15/34] qcow2: Move qcow2_update_options() call up Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-12 20:47   ` Eric Blake
  2015-05-13 11:38   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 17/34] qcow2: Leave s unchanged on qcow2_update_options() failure Kevin Wolf
                   ` (17 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

With this commit, the handling of driver-specific options in
qcow2_open() is completely separated out into qcow2_update_options().

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/qcow2.c | 109 +++++++++++++++++++++++++++++-----------------------------
 1 file changed, 55 insertions(+), 54 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index 761ba30..a4a267d 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -538,15 +538,64 @@ static void read_cache_sizes(QemuOpts *opts, uint64_t *l2_cache_size,
     }
 }
 
-static int qcow2_update_options(BlockDriverState *bs, QemuOpts *opts,
+static int qcow2_update_options(BlockDriverState *bs, QDict *options,
                                 int flags, Error **errp)
 {
     BDRVQcowState *s = bs->opaque;
+    QemuOpts *opts = NULL;
     const char *opt_overlap_check, *opt_overlap_check_template;
     int overlap_check_template = 0;
+    uint64_t l2_cache_size, refcount_cache_size;
     int i;
+    Error *local_err = NULL;
     int ret;
 
+    opts = qemu_opts_create(&qcow2_runtime_opts, NULL, 0, &error_abort);
+    qemu_opts_absorb_qdict(opts, options, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    /* get L2 table/refcount block cache size from command line options */
+    read_cache_sizes(opts, &l2_cache_size, &refcount_cache_size, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    l2_cache_size /= s->cluster_size;
+    if (l2_cache_size < MIN_L2_CACHE_SIZE) {
+        l2_cache_size = MIN_L2_CACHE_SIZE;
+    }
+    if (l2_cache_size > INT_MAX) {
+        error_setg(errp, "L2 cache size too big");
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    refcount_cache_size /= s->cluster_size;
+    if (refcount_cache_size < MIN_REFCOUNT_CACHE_SIZE) {
+        refcount_cache_size = MIN_REFCOUNT_CACHE_SIZE;
+    }
+    if (refcount_cache_size > INT_MAX) {
+        error_setg(errp, "Refcount cache size too big");
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    /* alloc L2 table/refcount block cache */
+    s->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
+    s->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
+    if (s->l2_table_cache == NULL || s->refcount_block_cache == NULL) {
+        error_setg(errp, "Could not allocate metadata caches");
+        ret = -ENOMEM;
+        goto fail;
+    }
+
+    /* Enable lazy_refcounts according to image and command line options */
     s->use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
         (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS));
 
@@ -609,6 +658,9 @@ static int qcow2_update_options(BlockDriverState *bs, QemuOpts *opts,
 
     ret = 0;
 fail:
+    qemu_opts_del(opts);
+    opts = NULL;
+
     return ret;
 }
 
@@ -619,11 +671,9 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
     unsigned int len, i;
     int ret = 0;
     QCowHeader header;
-    QemuOpts *opts = NULL;
     Error *local_err = NULL;
     uint64_t ext_end;
     uint64_t l1_vm_state_index;
-    uint64_t l2_cache_size, refcount_cache_size;
 
     ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
     if (ret < 0) {
@@ -866,60 +916,12 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
         }
     }
 
-    /* get L2 table/refcount block cache size from command line options */
-    opts = qemu_opts_create(&qcow2_runtime_opts, NULL, 0, &error_abort);
-    qemu_opts_absorb_qdict(opts, options, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        ret = -EINVAL;
-        goto fail;
-    }
-
-    read_cache_sizes(opts, &l2_cache_size, &refcount_cache_size, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        ret = -EINVAL;
-        goto fail;
-    }
-
-    l2_cache_size /= s->cluster_size;
-    if (l2_cache_size < MIN_L2_CACHE_SIZE) {
-        l2_cache_size = MIN_L2_CACHE_SIZE;
-    }
-    if (l2_cache_size > INT_MAX) {
-        error_setg(errp, "L2 cache size too big");
-        ret = -EINVAL;
-        goto fail;
-    }
-
-    refcount_cache_size /= s->cluster_size;
-    if (refcount_cache_size < MIN_REFCOUNT_CACHE_SIZE) {
-        refcount_cache_size = MIN_REFCOUNT_CACHE_SIZE;
-    }
-    if (refcount_cache_size > INT_MAX) {
-        error_setg(errp, "Refcount cache size too big");
-        ret = -EINVAL;
-        goto fail;
-    }
-
-    /* alloc L2 table/refcount block cache */
-    s->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
-    s->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
-    if (s->l2_table_cache == NULL || s->refcount_block_cache == NULL) {
-        error_setg(errp, "Could not allocate metadata caches");
-        ret = -ENOMEM;
-        goto fail;
-    }
-
-    /* Enable lazy_refcounts according to image and command line options */
-    ret = qcow2_update_options(bs, opts, flags, errp);
+    /* Parse driver-specific options */
+    ret = qcow2_update_options(bs, options, flags, errp);
     if (ret < 0) {
         goto fail;
     }
 
-    qemu_opts_del(opts);
-    opts = NULL;
-
     s->cluster_cache = g_malloc(s->cluster_size);
     /* one more sector for decompressed data alignment */
     s->cluster_data = qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
@@ -1013,7 +1015,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
     return ret;
 
  fail:
-    qemu_opts_del(opts);
     g_free(s->unknown_header_fields);
     cleanup_unknown_header_ext(bs);
     qcow2_free_snapshots(bs);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 17/34] qcow2: Leave s unchanged on qcow2_update_options() failure
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (15 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 16/34] qcow2: Move rest of option handling to qcow2_update_options() Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-12 20:57   ` Eric Blake
  2015-05-13 11:47   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 18/34] qcow2: Fix memory leak in qcow2_update_options() error path Kevin Wolf
                   ` (16 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

On return, either all new options should be applied to BDRVQcowState (on
success), or all of the old setting should be preserved (on failure).

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/qcow2.c | 52 ++++++++++++++++++++++++++++++++--------------------
 1 file changed, 32 insertions(+), 20 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index a4a267d..abe22f3 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -546,6 +546,9 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
     const char *opt_overlap_check, *opt_overlap_check_template;
     int overlap_check_template = 0;
     uint64_t l2_cache_size, refcount_cache_size;
+    Qcow2Cache* l2_table_cache;
+    Qcow2Cache* refcount_block_cache;
+    bool use_lazy_refcounts;
     int i;
     Error *local_err = NULL;
     int ret;
@@ -587,28 +590,25 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
     }
 
     /* alloc L2 table/refcount block cache */
-    s->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
-    s->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
-    if (s->l2_table_cache == NULL || s->refcount_block_cache == NULL) {
+    l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
+    refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
+    if (l2_table_cache == NULL || refcount_block_cache == NULL) {
         error_setg(errp, "Could not allocate metadata caches");
         ret = -ENOMEM;
         goto fail;
     }
 
     /* Enable lazy_refcounts according to image and command line options */
-    s->use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
+    use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
         (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS));
+    if (use_lazy_refcounts && s->qcow_version < 3) {
+        error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
+                   "qemu 1.1 compatibility level");
+        ret = -EINVAL;
+        goto fail;
+    }
 
-    s->discard_passthrough[QCOW2_DISCARD_NEVER] = false;
-    s->discard_passthrough[QCOW2_DISCARD_ALWAYS] = true;
-    s->discard_passthrough[QCOW2_DISCARD_REQUEST] =
-        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_REQUEST,
-                          flags & BDRV_O_UNMAP);
-    s->discard_passthrough[QCOW2_DISCARD_SNAPSHOT] =
-        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_SNAPSHOT, true);
-    s->discard_passthrough[QCOW2_DISCARD_OTHER] =
-        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
-
+    /* Overlap check options */
     opt_overlap_check = qemu_opt_get(opts, QCOW2_OPT_OVERLAP);
     opt_overlap_check_template = qemu_opt_get(opts, QCOW2_OPT_OVERLAP_TEMPLATE);
     if (opt_overlap_check_template && opt_overlap_check &&
@@ -640,6 +640,10 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
         goto fail;
     }
 
+    /*
+     * Start updating fields in BDRVQcowState.
+     * After this point no failure is allowed any more.
+     */
     s->overlap_check = 0;
     for (i = 0; i < QCOW2_OL_MAX_BITNR; i++) {
         /* overlap-check defines a template bitmask, but every flag may be
@@ -649,12 +653,20 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
                               overlap_check_template & (1 << i)) << i;
     }
 
-    if (s->use_lazy_refcounts && s->qcow_version < 3) {
-        error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
-                   "qemu 1.1 compatibility level");
-        ret = -EINVAL;
-        goto fail;
-    }
+    s->l2_table_cache = l2_table_cache;
+    s->refcount_block_cache = refcount_block_cache;
+
+    s->use_lazy_refcounts = use_lazy_refcounts;
+
+    s->discard_passthrough[QCOW2_DISCARD_NEVER] = false;
+    s->discard_passthrough[QCOW2_DISCARD_ALWAYS] = true;
+    s->discard_passthrough[QCOW2_DISCARD_REQUEST] =
+        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_REQUEST,
+                          flags & BDRV_O_UNMAP);
+    s->discard_passthrough[QCOW2_DISCARD_SNAPSHOT] =
+        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_SNAPSHOT, true);
+    s->discard_passthrough[QCOW2_DISCARD_OTHER] =
+        qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
 
     ret = 0;
 fail:
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 18/34] qcow2: Fix memory leak in qcow2_update_options() error path
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (16 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 17/34] qcow2: Leave s unchanged on qcow2_update_options() failure Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-12 21:26   ` Eric Blake
  2015-05-13 11:52   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 19/34] qcow2: Make qcow2_update_options() suitable for transactions Kevin Wolf
                   ` (15 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/qcow2.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index abe22f3..84d6e0f 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -546,8 +546,8 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
     const char *opt_overlap_check, *opt_overlap_check_template;
     int overlap_check_template = 0;
     uint64_t l2_cache_size, refcount_cache_size;
-    Qcow2Cache* l2_table_cache;
-    Qcow2Cache* refcount_block_cache;
+    Qcow2Cache* l2_table_cache = NULL;
+    Qcow2Cache* refcount_block_cache = NULL;
     bool use_lazy_refcounts;
     int i;
     Error *local_err = NULL;
@@ -670,6 +670,14 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
 
     ret = 0;
 fail:
+    if (ret < 0) {
+        if (l2_table_cache) {
+            qcow2_cache_destroy(bs, l2_table_cache);
+        }
+        if (refcount_block_cache) {
+            qcow2_cache_destroy(bs, refcount_block_cache);
+        }
+    }
     qemu_opts_del(opts);
     opts = NULL;
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 19/34] qcow2: Make qcow2_update_options() suitable for transactions
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (17 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 18/34] qcow2: Fix memory leak in qcow2_update_options() error path Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-12 21:40   ` Eric Blake
  2015-05-13 12:06   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 20/34] qcow2: Support updating driver-specific options in reopen Kevin Wolf
                   ` (14 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Before we can allow updating options at runtime with bdrv_reopen(), we
need to split the function into prepare/commit/abort parts.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/qcow2.c | 101 ++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 67 insertions(+), 34 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index 84d6e0f..fc9375e 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -538,17 +538,24 @@ static void read_cache_sizes(QemuOpts *opts, uint64_t *l2_cache_size,
     }
 }
 
-static int qcow2_update_options(BlockDriverState *bs, QDict *options,
-                                int flags, Error **errp)
+typedef struct Qcow2ReopenState {
+    Qcow2Cache* l2_table_cache;
+    Qcow2Cache* refcount_block_cache;
+    bool use_lazy_refcounts;
+    int overlap_check;
+    bool discard_passthrough[QCOW2_DISCARD_MAX];
+} Qcow2ReopenState;
+
+static int qcow2_update_options_prepare(BlockDriverState *bs,
+                                        Qcow2ReopenState *r,
+                                        QDict *options, int flags,
+                                        Error **errp)
 {
     BDRVQcowState *s = bs->opaque;
     QemuOpts *opts = NULL;
     const char *opt_overlap_check, *opt_overlap_check_template;
     int overlap_check_template = 0;
     uint64_t l2_cache_size, refcount_cache_size;
-    Qcow2Cache* l2_table_cache = NULL;
-    Qcow2Cache* refcount_block_cache = NULL;
-    bool use_lazy_refcounts;
     int i;
     Error *local_err = NULL;
     int ret;
@@ -590,18 +597,18 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
     }
 
     /* alloc L2 table/refcount block cache */
-    l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
-    refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
-    if (l2_table_cache == NULL || refcount_block_cache == NULL) {
+    r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
+    r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
+    if (r->l2_table_cache == NULL || r->refcount_block_cache == NULL) {
         error_setg(errp, "Could not allocate metadata caches");
         ret = -ENOMEM;
         goto fail;
     }
 
     /* Enable lazy_refcounts according to image and command line options */
-    use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
+    r->use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
         (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS));
-    if (use_lazy_refcounts && s->qcow_version < 3) {
+    if (r->use_lazy_refcounts && s->qcow_version < 3) {
         error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
                    "qemu 1.1 compatibility level");
         ret = -EINVAL;
@@ -640,46 +647,72 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
         goto fail;
     }
 
-    /*
-     * Start updating fields in BDRVQcowState.
-     * After this point no failure is allowed any more.
-     */
-    s->overlap_check = 0;
+    r->overlap_check = 0;
     for (i = 0; i < QCOW2_OL_MAX_BITNR; i++) {
         /* overlap-check defines a template bitmask, but every flag may be
          * overwritten through the associated boolean option */
-        s->overlap_check |=
+        r->overlap_check |=
             qemu_opt_get_bool(opts, overlap_bool_option_names[i],
                               overlap_check_template & (1 << i)) << i;
     }
 
-    s->l2_table_cache = l2_table_cache;
-    s->refcount_block_cache = refcount_block_cache;
-
-    s->use_lazy_refcounts = use_lazy_refcounts;
-
-    s->discard_passthrough[QCOW2_DISCARD_NEVER] = false;
-    s->discard_passthrough[QCOW2_DISCARD_ALWAYS] = true;
-    s->discard_passthrough[QCOW2_DISCARD_REQUEST] =
+    r->discard_passthrough[QCOW2_DISCARD_NEVER] = false;
+    r->discard_passthrough[QCOW2_DISCARD_ALWAYS] = true;
+    r->discard_passthrough[QCOW2_DISCARD_REQUEST] =
         qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_REQUEST,
                           flags & BDRV_O_UNMAP);
-    s->discard_passthrough[QCOW2_DISCARD_SNAPSHOT] =
+    r->discard_passthrough[QCOW2_DISCARD_SNAPSHOT] =
         qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_SNAPSHOT, true);
-    s->discard_passthrough[QCOW2_DISCARD_OTHER] =
+    r->discard_passthrough[QCOW2_DISCARD_OTHER] =
         qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
 
     ret = 0;
 fail:
-    if (ret < 0) {
-        if (l2_table_cache) {
-            qcow2_cache_destroy(bs, l2_table_cache);
-        }
-        if (refcount_block_cache) {
-            qcow2_cache_destroy(bs, refcount_block_cache);
-        }
-    }
     qemu_opts_del(opts);
     opts = NULL;
+    return ret;
+}
+
+static void qcow2_update_options_commit(BlockDriverState *bs,
+                                        Qcow2ReopenState *r)
+{
+    BDRVQcowState *s = bs->opaque;
+    int i;
+
+    s->l2_table_cache = r->l2_table_cache;
+    s->refcount_block_cache = r->refcount_block_cache;
+
+    s->overlap_check = r->overlap_check;
+    s->use_lazy_refcounts = r->use_lazy_refcounts;
+
+    for (i = 0; i < QCOW2_DISCARD_MAX; i++) {
+        s->discard_passthrough[i] = r->discard_passthrough[i];
+    }
+}
+
+static void qcow2_update_options_abort(BlockDriverState *bs,
+                                       Qcow2ReopenState *r)
+{
+    if (r->l2_table_cache) {
+        qcow2_cache_destroy(bs, r->l2_table_cache);
+    }
+    if (r->refcount_block_cache) {
+        qcow2_cache_destroy(bs, r->refcount_block_cache);
+    }
+}
+
+static int qcow2_update_options(BlockDriverState *bs, QDict *options,
+                                int flags, Error **errp)
+{
+    Qcow2ReopenState r = {};
+    int ret;
+
+    ret = qcow2_update_options_prepare(bs, &r, options, flags, errp);
+    if (ret >= 0) {
+        qcow2_update_options_commit(bs, &r);
+    } else {
+        qcow2_update_options_abort(bs, &r);
+    }
 
     return ret;
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 20/34] qcow2: Support updating driver-specific options in reopen
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (18 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 19/34] qcow2: Make qcow2_update_options() suitable for transactions Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-12 21:47   ` Eric Blake
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 21/34] block: Consider all block layer options in append_open_options Kevin Wolf
                   ` (13 subsequent siblings)
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

For updating the cache sizes or disabling lazy refcounts there is a bit
more to do than just changing the variables, but otherwise we're all set
for changing options during bdrv_reopen().

Just implement the missing pieces and hook the functions up in
bdrv_reopen().

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/qcow2.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 64 insertions(+), 6 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index fc9375e..940447b 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -596,7 +596,24 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
         goto fail;
     }
 
-    /* alloc L2 table/refcount block cache */
+    /* alloc new L2 table/refcount block cache, flush old one */
+    if (s->l2_table_cache) {
+        ret = qcow2_cache_flush(bs, s->l2_table_cache);
+        if (ret) {
+            error_setg_errno(errp, -ret, "Failed to flush the L2 table cache");
+            goto fail;
+        }
+    }
+
+    if (s->refcount_block_cache) {
+        ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+        if (ret) {
+            error_setg_errno(errp, -ret,
+                             "Failed to flush the refcount block cache");
+            goto fail;
+        }
+    }
+
     r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
     r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
     if (r->l2_table_cache == NULL || r->refcount_block_cache == NULL) {
@@ -605,7 +622,7 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
         goto fail;
     }
 
-    /* Enable lazy_refcounts according to image and command line options */
+    /* lazy-refcounts; flush if going from enabled to disabled */
     r->use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
         (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS));
     if (r->use_lazy_refcounts && s->qcow_version < 3) {
@@ -615,6 +632,14 @@ static int qcow2_update_options_prepare(BlockDriverState *bs,
         goto fail;
     }
 
+    if (s->use_lazy_refcounts && !r->use_lazy_refcounts) {
+        ret = qcow2_mark_clean(bs);
+        if (ret < 0) {
+            error_setg_errno(errp, -ret, "Failed to disable lazy refcounts");
+            goto fail;
+        }
+    }
+
     /* Overlap check options */
     opt_overlap_check = qemu_opt_get(opts, QCOW2_OPT_OVERLAP);
     opt_overlap_check_template = qemu_opt_get(opts, QCOW2_OPT_OVERLAP_TEMPLATE);
@@ -679,6 +704,12 @@ static void qcow2_update_options_commit(BlockDriverState *bs,
     BDRVQcowState *s = bs->opaque;
     int i;
 
+    if (s->l2_table_cache) {
+        qcow2_cache_destroy(bs, s->l2_table_cache);
+    }
+    if (s->refcount_block_cache) {
+        qcow2_cache_destroy(bs, s->refcount_block_cache);
+    }
     s->l2_table_cache = r->l2_table_cache;
     s->refcount_block_cache = r->refcount_block_cache;
 
@@ -1135,26 +1166,51 @@ static int qcow2_set_key(BlockDriverState *bs, const char *key)
     return 0;
 }
 
-/* We have no actual commit/abort logic for qcow2, but we need to write out any
- * unwritten data if we reopen read-only. */
 static int qcow2_reopen_prepare(BDRVReopenState *state,
                                 BlockReopenQueue *queue, Error **errp)
 {
+    Qcow2ReopenState *r;
     int ret;
 
+    r = g_new0(Qcow2ReopenState, 1);
+    state->opaque = r;
+
+    ret = qcow2_update_options_prepare(state->bs, r, state->options,
+                                       state->flags, errp);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    /* We need to write out any unwritten data if we reopen read-only. */
     if ((state->flags & BDRV_O_RDWR) == 0) {
         ret = bdrv_flush(state->bs);
         if (ret < 0) {
-            return ret;
+            goto fail;
         }
 
         ret = qcow2_mark_clean(state->bs);
         if (ret < 0) {
-            return ret;
+            goto fail;
         }
     }
 
     return 0;
+
+fail:
+    qcow2_update_options_abort(state->bs, r);
+    return ret;
+}
+
+static void qcow2_reopen_commit(BDRVReopenState *state)
+{
+    qcow2_update_options_commit(state->bs, state->opaque);
+    g_free(state->opaque);
+}
+
+static void qcow2_reopen_abort(BDRVReopenState *state)
+{
+    qcow2_update_options_abort(state->bs, state->opaque);
+    g_free(state->opaque);
 }
 
 static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
@@ -3000,6 +3056,8 @@ BlockDriver bdrv_qcow2 = {
     .bdrv_open          = qcow2_open,
     .bdrv_close         = qcow2_close,
     .bdrv_reopen_prepare  = qcow2_reopen_prepare,
+    .bdrv_reopen_commit   = qcow2_reopen_commit,
+    .bdrv_reopen_abort    = qcow2_reopen_abort,
     .bdrv_create        = qcow2_create,
     .bdrv_has_zero_init = bdrv_has_zero_init_1,
     .bdrv_co_get_block_status = qcow2_co_get_block_status,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 21/34] block: Consider all block layer options in append_open_options
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (19 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 20/34] qcow2: Support updating driver-specific options in reopen Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-12 21:59   ` Eric Blake
  2015-05-13 12:26   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 22/34] block: Exclude nested options only for children in append_open_options() Kevin Wolf
                   ` (12 subsequent siblings)
  33 siblings, 2 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

The code already special-cased "node-name", which is currently the only
option passed in the QDict that isn't driver-specific. Generalise the
code to take all general block layer options into consideration.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/block.c b/block.c
index 561cefd..e329a47 100644
--- a/block.c
+++ b/block.c
@@ -4036,20 +4036,30 @@ out:
 static bool append_open_options(QDict *d, BlockDriverState *bs)
 {
     const QDictEntry *entry;
+    QemuOptDesc *desc;
     bool found_any = false;
 
     for (entry = qdict_first(bs->options); entry;
          entry = qdict_next(bs->options, entry))
     {
-        /* Only take options for this level and exclude all non-driver-specific
-         * options */
-        if (!strchr(qdict_entry_key(entry), '.') &&
-            strcmp(qdict_entry_key(entry), "node-name"))
-        {
-            qobject_incref(qdict_entry_value(entry));
-            qdict_put_obj(d, qdict_entry_key(entry), qdict_entry_value(entry));
-            found_any = true;
+        /* Only take options for this level */
+        if (strchr(qdict_entry_key(entry), '.')) {
+            continue;
         }
+
+        /* And exclude all non-driver-specific options */
+        for (desc = bdrv_runtime_opts.desc; desc->name; desc++) {
+            if (!strcmp(qdict_entry_key(entry), desc->name)) {
+                break;
+            }
+        }
+        if (desc->name) {
+            continue;
+        }
+
+        qobject_incref(qdict_entry_value(entry));
+        qdict_put_obj(d, qdict_entry_key(entry), qdict_entry_value(entry));
+        found_any = true;
     }
 
     return found_any;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 22/34] block: Exclude nested options only for children in append_open_options()
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (20 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 21/34] block: Consider all block layer options in append_open_options Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-13 12:49   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 23/34] block: Pass driver-specific options to .bdrv_refresh_filename() Kevin Wolf
                   ` (11 subsequent siblings)
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Some drivers have nested options (e.g. blkdebug rule arrays), which
don't belong to a child node and shouldn't be removed. Don't remove all
options with "." in their name, but check for the complete prefixes of
actually existing child nodes.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c                   | 30 +++++++++++++++++++-----------
 include/block/block_int.h |  1 +
 2 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/block.c b/block.c
index e329a47..e9a1d76 100644
--- a/block.c
+++ b/block.c
@@ -81,7 +81,7 @@ static QLIST_HEAD(, BlockDriver) bdrv_drivers =
 
 static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
                              const char *reference, QDict *options, int flags,
-                             BlockDriverState* parent,
+                             BlockDriverState* parent, const char *child_name,
                              const BdrvChildRole *child_role,
                              BlockDriver *drv, Error **errp);
 
@@ -1174,8 +1174,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
     backing_hd = NULL;
     ret = bdrv_open_inherit(&backing_hd,
                             *backing_filename ? backing_filename : NULL,
-                            reference, options, 0, bs, &child_backing,
-                            NULL, &local_err);
+                            reference, options, 0, bs, "backing",
+                            &child_backing, NULL, &local_err);
     if (ret < 0) {
         bs->open_flags |= BDRV_O_NO_BACKING;
         error_setg(errp, "Could not open backing file: %s",
@@ -1238,7 +1238,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
     }
 
     ret = bdrv_open_inherit(pbs, filename, reference, image_options, 0,
-                            parent, child_role, NULL, errp);
+                            parent, bdref_key, child_role, NULL, errp);
 
 done:
     qdict_del(options, bdref_key);
@@ -1312,11 +1312,13 @@ out:
 
 static void bdrv_attach_child(BlockDriverState *parent_bs,
                               BlockDriverState *child_bs,
+                              const char *child_name,
                               const BdrvChildRole *child_role)
 {
     BdrvChild *child = g_new(BdrvChild, 1);
     *child = (BdrvChild) {
         .bs     = child_bs,
+        .name   = child_name,
         .role   = child_role,
     };
 
@@ -1340,7 +1342,7 @@ static void bdrv_attach_child(BlockDriverState *parent_bs,
  */
 static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
                              const char *reference, QDict *options, int flags,
-                             BlockDriverState* parent,
+                             BlockDriverState* parent, const char *child_name,
                              const BdrvChildRole *child_role,
                              BlockDriver *drv, Error **errp)
 {
@@ -1376,7 +1378,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
         }
         bdrv_ref(bs);
         if (child_role) {
-            bdrv_attach_child(parent, bs, child_role);
+            bdrv_attach_child(parent, bs, child_name, child_role);
         }
         *pbs = bs;
         return 0;
@@ -1519,7 +1521,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
     }
 
     if (child_role) {
-        bdrv_attach_child(parent, bs, child_role);
+        bdrv_attach_child(parent, bs, child_name, child_role);
     }
 
     QDECREF(options);
@@ -1563,7 +1565,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
               BlockDriver *drv, Error **errp)
 {
     return bdrv_open_inherit(pbs, filename, reference, options, flags, NULL,
-                             NULL, drv, errp);
+                             NULL, NULL, drv, errp);
 }
 
 typedef struct BlockReopenQueueEntry {
@@ -2093,7 +2095,7 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
     /* The contents of 'tmp' will become bs_top, as we are
      * swapping bs_new and bs_top contents. */
     bdrv_set_backing_hd(bs_top, bs_new);
-    bdrv_attach_child(bs_top, bs_new, &child_backing);
+    bdrv_attach_child(bs_top, bs_new, "backing", &child_backing);
 }
 
 static void bdrv_delete(BlockDriverState *bs)
@@ -4037,13 +4039,19 @@ static bool append_open_options(QDict *d, BlockDriverState *bs)
 {
     const QDictEntry *entry;
     QemuOptDesc *desc;
+    BdrvChild *child;
     bool found_any = false;
 
     for (entry = qdict_first(bs->options); entry;
          entry = qdict_next(bs->options, entry))
     {
-        /* Only take options for this level */
-        if (strchr(qdict_entry_key(entry), '.')) {
+        /* Exclude options for children */
+        QLIST_FOREACH(child, &bs->children, next) {
+            if (strstart(qdict_entry_key(entry), child->name, NULL)) {
+                break;
+            }
+        }
+        if (child) {
             continue;
         }
 
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 2fad5f8..90da3f7 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -336,6 +336,7 @@ extern const BdrvChildRole child_format;
 
 typedef struct BdrvChild {
     BlockDriverState *bs;
+    const char *name;
     const BdrvChildRole *role;
     QLIST_ENTRY(BdrvChild) next;
 } BdrvChild;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 23/34] block: Pass driver-specific options to .bdrv_refresh_filename()
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (21 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 22/34] block: Exclude nested options only for children in append_open_options() Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-13 12:57   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 24/34] block: Keep "driver" in bs->options Kevin Wolf
                   ` (10 subsequent siblings)
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

In order to decide whether a blkdebug: filename can be produced or a
json: one is necessary, blkdebug checked whether bs->options had more
options than just "config", "x-image" or "image" (the latter including
nested options). That doesn't work well when generic block layer options
are present.

This patch passes an option QDict to the driver that contains only
driver-specific options, i.e. the options for the general block layer as
well as child nodes are already filtered out. Works much better this
way.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c                   |  5 ++++-
 block/blkdebug.c          | 17 ++++++-----------
 block/blkverify.c         |  2 +-
 block/nbd.c               | 10 +++++-----
 block/quorum.c            |  2 +-
 include/block/block_int.h |  2 +-
 6 files changed, 18 insertions(+), 20 deletions(-)

diff --git a/block.c b/block.c
index e9a1d76..7c0c9db 100644
--- a/block.c
+++ b/block.c
@@ -4109,7 +4109,10 @@ void bdrv_refresh_filename(BlockDriverState *bs)
             bs->full_open_options = NULL;
         }
 
-        drv->bdrv_refresh_filename(bs);
+        opts = qdict_new();
+        append_open_options(opts, bs);
+        drv->bdrv_refresh_filename(bs, opts);
+        QDECREF(opts);
     } else if (bs->file) {
         /* Try to reconstruct valid information from the underlying file */
         bool has_open_options;
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 17b7c85..34967f8 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -726,17 +726,15 @@ static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
     return bdrv_truncate(bs->file, offset);
 }
 
-static void blkdebug_refresh_filename(BlockDriverState *bs)
+static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
 {
     QDict *opts;
     const QDictEntry *e;
     bool force_json = false;
 
-    for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
+    for (e = qdict_first(options); e; e = qdict_next(options, e)) {
         if (strcmp(qdict_entry_key(e), "config") &&
-            strcmp(qdict_entry_key(e), "x-image") &&
-            strcmp(qdict_entry_key(e), "image") &&
-            strncmp(qdict_entry_key(e), "image.", strlen("image.")))
+            strcmp(qdict_entry_key(e), "x-image"))
         {
             force_json = true;
             break;
@@ -752,7 +750,7 @@ static void blkdebug_refresh_filename(BlockDriverState *bs)
     if (!force_json && bs->file->exact_filename[0]) {
         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
                  "blkdebug:%s:%s",
-                 qdict_get_try_str(bs->options, "config") ?: "",
+                 qdict_get_try_str(options, "config") ?: "",
                  bs->file->exact_filename);
     }
 
@@ -762,11 +760,8 @@ static void blkdebug_refresh_filename(BlockDriverState *bs)
     QINCREF(bs->file->full_open_options);
     qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
 
-    for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
-        if (strcmp(qdict_entry_key(e), "x-image") &&
-            strcmp(qdict_entry_key(e), "image") &&
-            strncmp(qdict_entry_key(e), "image.", strlen("image.")))
-        {
+    for (e = qdict_first(options); e; e = qdict_next(options, e)) {
+        if (strcmp(qdict_entry_key(e), "x-image")) {
             qobject_incref(qdict_entry_value(e));
             qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e));
         }
diff --git a/block/blkverify.c b/block/blkverify.c
index d277e63..112c209 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -304,7 +304,7 @@ static void blkverify_attach_aio_context(BlockDriverState *bs,
     bdrv_attach_aio_context(s->test_file, new_context);
 }
 
-static void blkverify_refresh_filename(BlockDriverState *bs)
+static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
 {
     BDRVBlkverifyState *s = bs->opaque;
 
diff --git a/block/nbd.c b/block/nbd.c
index 2176186..5cf8267 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -339,13 +339,13 @@ static void nbd_attach_aio_context(BlockDriverState *bs,
     nbd_client_attach_aio_context(bs, new_context);
 }
 
-static void nbd_refresh_filename(BlockDriverState *bs)
+static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
 {
     QDict *opts = qdict_new();
-    const char *path   = qdict_get_try_str(bs->options, "path");
-    const char *host   = qdict_get_try_str(bs->options, "host");
-    const char *port   = qdict_get_try_str(bs->options, "port");
-    const char *export = qdict_get_try_str(bs->options, "export");
+    const char *path   = qdict_get_try_str(options, "path");
+    const char *host   = qdict_get_try_str(options, "host");
+    const char *port   = qdict_get_try_str(options, "port");
+    const char *export = qdict_get_try_str(options, "export");
 
     qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("nbd")));
 
diff --git a/block/quorum.c b/block/quorum.c
index 77e55b2..cb66dec 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -999,7 +999,7 @@ static void quorum_attach_aio_context(BlockDriverState *bs,
     }
 }
 
-static void quorum_refresh_filename(BlockDriverState *bs)
+static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
 {
     BDRVQuorumState *s = bs->opaque;
     QDict *opts;
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 90da3f7..c9333b2 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -129,7 +129,7 @@ struct BlockDriver {
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
     int (*bdrv_make_empty)(BlockDriverState *bs);
 
-    void (*bdrv_refresh_filename)(BlockDriverState *bs);
+    void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options);
 
     /* aio */
     BlockAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs,
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 24/34] block: Keep "driver" in bs->options
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (22 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 23/34] block: Pass driver-specific options to .bdrv_refresh_filename() Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-13 13:22   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 25/34] block: Allow specifying child options in reopen Kevin Wolf
                   ` (9 subsequent siblings)
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Instead of passing a separate drv argument to bdrv_open_common(), just
make sure that a "driver" option is set in the QDict. This also means
that a "driver" entry is consistently present in bs->options now.

This is another step towards keeping all options in the QDict (which is
the represenation of the blockdev-add QMP command).

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c | 54 ++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 38 insertions(+), 16 deletions(-)

diff --git a/block.c b/block.c
index 7c0c9db..ef39c74 100644
--- a/block.c
+++ b/block.c
@@ -795,6 +795,11 @@ static QemuOptsList bdrv_runtime_opts = {
             .type = QEMU_OPT_STRING,
             .help = "Node name of the block device node",
         },
+        {
+            .name = "driver",
+            .type = QEMU_OPT_STRING,
+            .help = "Block driver to use for the node",
+        },
         { /* end of list */ }
     },
 };
@@ -805,18 +810,31 @@ static QemuOptsList bdrv_runtime_opts = {
  * Removes all processed options from *options.
  */
 static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
-    QDict *options, int flags, BlockDriver *drv, Error **errp)
+                            QDict *options, int flags, Error **errp)
 {
     int ret, open_flags;
     const char *filename;
+    const char *driver_name = NULL;
     const char *node_name = NULL;
     QemuOpts *opts;
+    BlockDriver *drv;
     Error *local_err = NULL;
 
-    assert(drv != NULL);
     assert(bs->file == NULL);
     assert(options != NULL && bs->options != options);
 
+    opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
+    qemu_opts_absorb_qdict(opts, options, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto fail_opts;
+    }
+
+    driver_name = qemu_opt_get(opts, "driver");
+    drv = bdrv_find_format(driver_name);
+    assert(drv != NULL);
+
     if (file != NULL) {
         filename = file->filename;
     } else {
@@ -831,14 +849,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
 
     trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
 
-    opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
-    qemu_opts_absorb_qdict(opts, options, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        ret = -EINVAL;
-        goto fail_opts;
-    }
-
     node_name = qemu_opt_get(opts, "node-name");
     bdrv_assign_node_name(bs, node_name, &local_err);
     if (local_err) {
@@ -1405,12 +1415,15 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
         goto fail;
     }
 
+    bs->open_flags = flags;
+    bs->options = options;
+    options = qdict_clone_shallow(options);
+
     /* Find the right image format driver */
     drv = NULL;
     drvname = qdict_get_try_str(options, "driver");
     if (drvname) {
         drv = bdrv_find_format(drvname);
-        qdict_del(options, "driver");
         if (!drv) {
             error_setg(errp, "Unknown driver: '%s'", drvname);
             ret = -EINVAL;
@@ -1425,10 +1438,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
         flags &= ~BDRV_O_PROTOCOL;
     }
 
-    bs->open_flags = flags;
-    bs->options = options;
-    options = qdict_clone_shallow(options);
-
     /* Open image file without format layer */
     if ((flags & BDRV_O_PROTOCOL) == 0) {
         if (flags & BDRV_O_RDWR) {
@@ -1455,6 +1464,19 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
         if (ret < 0) {
             goto fail;
         }
+        /*
+         * This option update would logically belong in bdrv_fill_options(),
+         * but we first need to open bs->file for the probing to work, while
+         * opening bs->file already requires the (mostly) final set of options
+         * so that cache mode etc. can be inherited.
+         *
+         * Adding the driver later is somewhat ugly, but it's not an option
+         * that would ever be inherited, so it's correct. We just need to make
+         * sure to update both bs->options (which has the full effective
+         * options for bs) and options (which has file.* already removed).
+         */
+        qdict_put(bs->options, "driver", qstring_from_str(drv->format_name));
+        qdict_put(options, "driver", qstring_from_str(drv->format_name));
     } else if (!drv) {
         error_setg(errp, "Must specify either driver or file");
         ret = -EINVAL;
@@ -1462,7 +1484,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
     }
 
     /* Open the image */
-    ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
+    ret = bdrv_open_common(bs, file, options, flags, &local_err);
     if (ret < 0) {
         goto fail;
     }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 25/34] block: Allow specifying child options in reopen
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (23 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 24/34] block: Keep "driver" in bs->options Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-13 13:41   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 26/34] block: reopen: Document option precedence and refactor accordingly Kevin Wolf
                   ` (8 subsequent siblings)
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

If the child was defined in the same context (-drive argument or
blockdev-add QMP command) as its parent, a reopen of the parent should
work the same and allow changing options of the child.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/block.c b/block.c
index ef39c74..8a31d62 100644
--- a/block.c
+++ b/block.c
@@ -1644,15 +1644,23 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
     flags &= ~BDRV_O_PROTOCOL;
 
     QLIST_FOREACH(child, &bs->children, next) {
+        QDict *new_child_options;
+        char *child_key_dot;
         int child_flags;
 
+        /* reopen can only change the options of block devices that were
+         * implicitly created and inherited options. For other (referenced)
+         * block devices, a syntax like "backing.foo" results in an error. */
         if (child->bs->inherits_from != bs) {
             continue;
         }
 
+        child_key_dot = g_strdup_printf("%s.", child->name);
+        qdict_extract_subqdict(options, &new_child_options, child_key_dot);
+        g_free(child_key_dot);
+
         child_flags = child->role->inherit_flags(flags);
-        /* TODO Pass down child flags (backing.*, extents.*, ...) */
-        bdrv_reopen_queue(bs_queue, child->bs, NULL, child_flags);
+        bdrv_reopen_queue(bs_queue, child->bs, new_child_options, child_flags);
     }
 
     bs_entry = g_new0(BlockReopenQueueEntry, 1);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 26/34] block: reopen: Document option precedence and refactor accordingly
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (24 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 25/34] block: Allow specifying child options in reopen Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-13 14:47   ` Max Reitz
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 27/34] block: Add infrastructure for option inheritance Kevin Wolf
                   ` (7 subsequent siblings)
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

The interesting part of reopening an image is from which sources the
effective options should be taken, i.e. which options take precedence
over which other options. This patch documents the precedence that will
be implemented in the following patches.

It also refactors bdrv_reopen_queue(), so that the top-level reopened
node is handled the same way as children are. Option/flag inheritance
from the parent becomes just one item in the list and is done at the
beginning of the function, similar to how the other items are/will be
handled.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c | 39 +++++++++++++++++++++++++++++++++------
 1 file changed, 33 insertions(+), 6 deletions(-)

diff --git a/block.c b/block.c
index 8a31d62..1e5625f 100644
--- a/block.c
+++ b/block.c
@@ -1617,9 +1617,13 @@ typedef struct BlockReopenQueueEntry {
  * bs_queue, or the existing bs_queue being used.
  *
  */
-BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
-                                    BlockDriverState *bs,
-                                    QDict *options, int flags)
+static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
+                                                 BlockDriverState *bs,
+                                                 QDict *options,
+                                                 int flags,
+                                                 const BdrvChildRole *role,
+                                                 QDict *parent_options,
+                                                 int parent_flags)
 {
     assert(bs != NULL);
 
@@ -1636,6 +1640,22 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
         options = qdict_new();
     }
 
+    /*
+     * Precedence of options:
+     * 1. Explicitly passed in options (highest)
+     * 2. TODO Set in flags (only for top level)
+     * 3. TODO Retained from explicitly set options of bs
+     * 4. TODO Inherited from parent node
+     * 5. Retained from effective options of bs
+     */
+
+    /* Inherit from parent node */
+    if (parent_options) {
+        assert(!flags);
+        flags = role->inherit_flags(parent_flags);
+    }
+
+    /* Old values are used for options that aren't set yet */
     old_options = qdict_clone_shallow(bs->options);
     qdict_join(options, old_options, false);
     QDECREF(old_options);
@@ -1646,7 +1666,6 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
     QLIST_FOREACH(child, &bs->children, next) {
         QDict *new_child_options;
         char *child_key_dot;
-        int child_flags;
 
         /* reopen can only change the options of block devices that were
          * implicitly created and inherited options. For other (referenced)
@@ -1659,8 +1678,8 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
         qdict_extract_subqdict(options, &new_child_options, child_key_dot);
         g_free(child_key_dot);
 
-        child_flags = child->role->inherit_flags(flags);
-        bdrv_reopen_queue(bs_queue, child->bs, new_child_options, child_flags);
+        bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options, 0,
+                                child->role, options, flags);
     }
 
     bs_entry = g_new0(BlockReopenQueueEntry, 1);
@@ -1673,6 +1692,14 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
     return bs_queue;
 }
 
+BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
+                                    BlockDriverState *bs,
+                                    QDict *options, int flags)
+{
+    return bdrv_reopen_queue_child(bs_queue, bs, options, flags,
+                                   NULL, NULL, 0);
+}
+
 /*
  * Reopen multiple BlockDriverStates atomically & transactionally.
  *
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 27/34] block: Add infrastructure for option inheritance
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (25 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 26/34] block: reopen: Document option precedence and refactor accordingly Kevin Wolf
@ 2015-05-08 17:21 ` Kevin Wolf
  2015-05-13 15:10   ` Max Reitz
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 28/34] block: Introduce bs->explicit_options Kevin Wolf
                   ` (6 subsequent siblings)
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Options are not actually inherited from the parent node yet, but this
commit lays the grounds for doing so.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c                   | 51 ++++++++++++++++++++++++++---------------------
 include/block/block_int.h |  3 ++-
 2 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/block.c b/block.c
index 1e5625f..9259b42 100644
--- a/block.c
+++ b/block.c
@@ -678,11 +678,14 @@ static int bdrv_temp_snapshot_flags(int flags)
 }
 
 /*
- * Returns the flags that bs->file should get if a protocol driver is expected,
- * based on the given flags for the parent BDS
+ * Returns the options and flags that bs->file should get if a protocol driver
+ * is expected, based on the given flags for the parent BDS
  */
-static int bdrv_inherited_flags(int flags)
+static void bdrv_inherited_options(int *child_flags, QDict *child_options,
+                                   int parent_flags, QDict *parent_options)
 {
+    int flags = parent_flags;
+
     /* Enable protocol handling, disable format probing for bs->file */
     flags |= BDRV_O_PROTOCOL;
 
@@ -693,45 +696,46 @@ static int bdrv_inherited_flags(int flags)
     /* Clear flags that only apply to the top layer */
     flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
 
-    return flags;
+    *child_flags = flags;
 }
 
 const BdrvChildRole child_file = {
-    .inherit_flags = bdrv_inherited_flags,
+    .inherit_options = bdrv_inherited_options,
 };
 
-/*
- * Returns the flags that bs->file should get if the use of formats (and not
- * only protocols) is permitted for it, based on the given flags for the parent
- * BDS
- */
-static int bdrv_inherited_fmt_flags(int parent_flags)
+static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options,
+                                       int parent_flags, QDict *parent_options)
 {
-    int flags = child_file.inherit_flags(parent_flags);
-    return flags & ~BDRV_O_PROTOCOL;
+    child_file.inherit_options(child_flags, child_options,
+                               parent_flags, parent_options);
+
+    *child_flags &= ~BDRV_O_PROTOCOL;
 }
 
 const BdrvChildRole child_format = {
-    .inherit_flags = bdrv_inherited_fmt_flags,
+    .inherit_options = bdrv_inherited_fmt_options,
 };
 
 /*
- * Returns the flags that bs->backing_hd should get, based on the given flags
- * for the parent BDS
+ * Returns the options and flags that bs->backing_hd should get, based on the
+ * given options and flags for the parent BDS
  */
-static int bdrv_backing_flags(int flags)
+static void bdrv_backing_options(int *child_flags, QDict *child_options,
+                                 int parent_flags, QDict *parent_options)
 {
+    int flags = parent_flags;
+
     /* backing files always opened read-only */
     flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
 
     /* snapshot=on is handled on the top layer */
     flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
 
-    return flags;
+    *child_flags = flags;
 }
 
 static const BdrvChildRole child_backing = {
-    .inherit_flags = bdrv_backing_flags,
+    .inherit_options = bdrv_backing_options,
 };
 
 static int bdrv_open_flags(BlockDriverState *bs, int flags)
@@ -1407,7 +1411,8 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
 
     if (child_role) {
         bs->inherits_from = parent;
-        flags = child_role->inherit_flags(parent->open_flags);
+        child_role->inherit_options(&flags, options,
+                                    parent->open_flags, parent->options);
     }
 
     ret = bdrv_fill_options(&options, &filename, flags, drv, &local_err);
@@ -1445,7 +1450,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
         }
         if (flags & BDRV_O_SNAPSHOT) {
             snapshot_flags = bdrv_temp_snapshot_flags(flags);
-            flags = bdrv_backing_flags(flags);
+            bdrv_backing_options(&flags, options, flags, options);
         }
 
         assert(file == NULL);
@@ -1645,14 +1650,14 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
      * 1. Explicitly passed in options (highest)
      * 2. TODO Set in flags (only for top level)
      * 3. TODO Retained from explicitly set options of bs
-     * 4. TODO Inherited from parent node
+     * 4. Inherited from parent node
      * 5. Retained from effective options of bs
      */
 
     /* Inherit from parent node */
     if (parent_options) {
         assert(!flags);
-        flags = role->inherit_flags(parent_flags);
+        role->inherit_options(&flags, options, parent_flags, parent_options);
     }
 
     /* Old values are used for options that aren't set yet */
diff --git a/include/block/block_int.h b/include/block/block_int.h
index c9333b2..1cae8d4 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -328,7 +328,8 @@ typedef struct BdrvAioNotifier {
 } BdrvAioNotifier;
 
 struct BdrvChildRole {
-    int (*inherit_flags)(int parent_flags);
+    void (*inherit_options)(int *child_flags, QDict *child_options,
+                            int parent_flags, QDict *parent_options);
 };
 
 extern const BdrvChildRole child_file;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 28/34] block: Introduce bs->explicit_options
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (26 preceding siblings ...)
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 27/34] block: Add infrastructure for option inheritance Kevin Wolf
@ 2015-05-08 17:22 ` Kevin Wolf
  2015-05-15 17:47   ` Max Reitz
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 29/34] qemu-iotests: Remove cache mode test without medium Kevin Wolf
                   ` (5 subsequent siblings)
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:22 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

bs->options doesn't only contain options that the user explicitly
requested, but also option that were derived from flags, the filename or
inherited from the parent node.

For reopen, it is important to know the difference because reopening the
parent can change inherited values in child nodes, but it shouldn't
change any options that were explicitly specified for the child.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c                   | 20 ++++++++++++++++++--
 include/block/block.h     |  1 +
 include/block/block_int.h |  1 +
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/block.c b/block.c
index 9259b42..d76e385 100644
--- a/block.c
+++ b/block.c
@@ -1408,6 +1408,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
     if (options == NULL) {
         options = qdict_new();
     }
+    bs->explicit_options = qdict_clone_shallow(options);
 
     if (child_role) {
         bs->inherits_from = parent;
@@ -1559,6 +1560,7 @@ fail:
     if (file != NULL) {
         bdrv_unref(file);
     }
+    QDECREF(bs->explicit_options);
     QDECREF(bs->options);
     QDECREF(options);
     bs->options = NULL;
@@ -1634,7 +1636,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
 
     BlockReopenQueueEntry *bs_entry;
     BdrvChild *child;
-    QDict *old_options;
+    QDict *old_options, *explicit_options;
 
     if (bs_queue == NULL) {
         bs_queue = g_new0(BlockReopenQueue, 1);
@@ -1649,11 +1651,18 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
      * Precedence of options:
      * 1. Explicitly passed in options (highest)
      * 2. TODO Set in flags (only for top level)
-     * 3. TODO Retained from explicitly set options of bs
+     * 3. Retained from explicitly set options of bs
      * 4. Inherited from parent node
      * 5. Retained from effective options of bs
      */
 
+    /* Old explicitly set values (don't overwrite by inherited value) */
+    old_options = qdict_clone_shallow(bs->explicit_options);
+    qdict_join(options, old_options, false);
+    QDECREF(old_options);
+
+    explicit_options = qdict_clone_shallow(options);
+
     /* Inherit from parent node */
     if (parent_options) {
         assert(!flags);
@@ -1692,6 +1701,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
 
     bs_entry->state.bs = bs;
     bs_entry->state.options = options;
+    bs_entry->state.explicit_options = explicit_options;
     bs_entry->state.flags = flags;
 
     return bs_queue;
@@ -1886,6 +1896,9 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
     }
 
     /* set BDS specific flags now */
+    QDECREF(reopen_state->bs->explicit_options);
+
+    reopen_state->bs->explicit_options   = reopen_state->explicit_options;
     reopen_state->bs->open_flags         = reopen_state->flags;
     reopen_state->bs->enable_write_cache = !!(reopen_state->flags &
                                               BDRV_O_CACHE_WB);
@@ -1909,6 +1922,8 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
     if (drv->bdrv_reopen_abort) {
         drv->bdrv_reopen_abort(reopen_state);
     }
+
+    QDECREF(reopen_state->explicit_options);
 }
 
 
@@ -1952,6 +1967,7 @@ void bdrv_close(BlockDriverState *bs)
         bs->sg = 0;
         bs->zero_beyond_eof = false;
         QDECREF(bs->options);
+        QDECREF(bs->explicit_options);
         bs->options = NULL;
         QDECREF(bs->full_open_options);
         bs->full_open_options = NULL;
diff --git a/include/block/block.h b/include/block/block.h
index 1287013..08bd0fe 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -147,6 +147,7 @@ typedef struct BDRVReopenState {
     BlockDriverState *bs;
     int flags;
     QDict *options;
+    QDict *explicit_options;
     void *opaque;
 } BDRVReopenState;
 
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 1cae8d4..a2e96bb 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -443,6 +443,7 @@ struct BlockDriverState {
     QLIST_HEAD(, BdrvChild) children;
 
     QDict *options;
+    QDict *explicit_options;
     BlockdevDetectZeroesOptions detect_zeroes;
 
     /* The error object in use for blocking operations on backing_hd */
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 29/34] qemu-iotests: Remove cache mode test without medium
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (27 preceding siblings ...)
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 28/34] block: Introduce bs->explicit_options Kevin Wolf
@ 2015-05-08 17:22 ` Kevin Wolf
  2015-05-15 17:53   ` Max Reitz
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 30/34] block: reopen: Extract QemuOpts for generic block layer options Kevin Wolf
                   ` (4 subsequent siblings)
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:22 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

Specifying the cache mode for a driver without a medium is not a useful
thing to do: As long as there is no medium, the cache mode doesn't make
a difference, and once the 'change' command is used to insert a medium,
it ignores the old cache mode and makes the new medium use
cache=writethrough.

Later patches will make it an error to specify the cache mode for an
empty drive. Remove the corresponding test case.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 tests/qemu-iotests/051     | 14 --------------
 tests/qemu-iotests/051.out | 26 --------------------------
 2 files changed, 40 deletions(-)

diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 0360f37..e236685 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -176,20 +176,6 @@ run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a
 run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk
 
 echo
-echo === Cache modes ===
-echo
-
-# Cannot use the test image because cache=none might not work on the host FS
-# Use cdrom so that we won't get errors about missing media
-
-run_qemu -drive media=cdrom,cache=none
-run_qemu -drive media=cdrom,cache=directsync
-run_qemu -drive media=cdrom,cache=writeback
-run_qemu -drive media=cdrom,cache=writethrough
-run_qemu -drive media=cdrom,cache=unsafe
-run_qemu -drive media=cdrom,cache=invalid_value
-
-echo
 echo === Specifying the protocol layer ===
 echo
 
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index 2890eac..2e3b48a 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -221,32 +221,6 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
 
 
-=== Cache modes ===
-
-Testing: -drive media=cdrom,cache=none
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
-
-Testing: -drive media=cdrom,cache=directsync
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
-
-Testing: -drive media=cdrom,cache=writeback
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
-
-Testing: -drive media=cdrom,cache=writethrough
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
-
-Testing: -drive media=cdrom,cache=unsafe
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
-
-Testing: -drive media=cdrom,cache=invalid_value
-QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option
-
-
 === Specifying the protocol layer ===
 
 Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 30/34] block: reopen: Extract QemuOpts for generic block layer options
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (28 preceding siblings ...)
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 29/34] qemu-iotests: Remove cache mode test without medium Kevin Wolf
@ 2015-05-08 17:22 ` Kevin Wolf
  2015-05-15 18:07   ` Max Reitz
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 31/34] block: Move cache options into options QDict Kevin Wolf
                   ` (3 subsequent siblings)
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:22 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

This patch adds a QemuOpts for generic block layer options to
bdrv_reopen_prepare(). The only two options that exist currently
(node-name and driver) cannot be changed, so the only thing we do is
putting them right back into the QDict so that we check at the end that
they are indeed unchanged.

We will add new options soon that can actually be changed.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/block.c b/block.c
index d76e385..8faa5ce 100644
--- a/block.c
+++ b/block.c
@@ -1808,11 +1808,34 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
     int ret = -1;
     Error *local_err = NULL;
     BlockDriver *drv;
+    QemuOpts *opts;
+    const char *value;
 
     assert(reopen_state != NULL);
     assert(reopen_state->bs->drv != NULL);
     drv = reopen_state->bs->drv;
 
+    /* Process generic block layer options */
+    opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
+    qemu_opts_absorb_qdict(opts, reopen_state->options, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto error;
+    }
+
+    /* node-name and driver must be unchanged. Put them back into the QDict, so
+     * that they are checked at the end of this function. */
+    value = qemu_opt_get(opts, "node-name");
+    if (value) {
+        qdict_put(reopen_state->options, "node-name", qstring_from_str(value));
+    }
+
+    value = qemu_opt_get(opts, "driver");
+    if (value) {
+        qdict_put(reopen_state->options, "driver", qstring_from_str(value));
+    }
+
     /* if we are to stay read-only, do not allow permission change
      * to r/w */
     if (!(reopen_state->bs->open_flags & BDRV_O_ALLOW_RDWR) &&
@@ -1874,6 +1897,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
     ret = 0;
 
 error:
+    qemu_opts_del(opts);
     return ret;
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 31/34] block: Move cache options into options QDict
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (29 preceding siblings ...)
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 30/34] block: reopen: Extract QemuOpts for generic block layer options Kevin Wolf
@ 2015-05-08 17:22 ` Kevin Wolf
  2015-05-15 18:43   ` Max Reitz
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 32/34] qemu-iotests: Try setting cache mode for children Kevin Wolf
                   ` (2 subsequent siblings)
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:22 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

This adds the cache mode options to the QDict, so that they can be
specified for child nodes (e.g. backing.cache.direct=off).

The cache modes are not removed from the flags at this point; instead,
options and flags are kept in sync. If the user specifies both flags and
options, the options take precedence.

Child node inherit cache modes as options now, they don't use flags any
more.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c    | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 blockdev.c | 27 +++++---------------
 2 files changed, 88 insertions(+), 24 deletions(-)

diff --git a/block.c b/block.c
index 8faa5ce..2430070 100644
--- a/block.c
+++ b/block.c
@@ -27,6 +27,7 @@
 #include "block/block_int.h"
 #include "block/blockjob.h"
 #include "qemu/module.h"
+#include "qapi/qmp/qbool.h"
 #include "qapi/qmp/qjson.h"
 #include "sysemu/block-backend.h"
 #include "sysemu/sysemu.h"
@@ -689,9 +690,15 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
     /* Enable protocol handling, disable format probing for bs->file */
     flags |= BDRV_O_PROTOCOL;
 
+    /* If the cache mode isn't explicitly set, inherit direct and no-flush from
+     * the parent. */
+    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
+    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
+
     /* Our block drivers take care to send flushes and respect unmap policy,
      * so we can enable both unconditionally on lower layers. */
-    flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP;
+    qdict_set_default_str(child_options, BDRV_OPT_CACHE_WB, "on");
+    flags |= BDRV_O_UNMAP;
 
     /* Clear flags that only apply to the top layer */
     flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
@@ -725,6 +732,11 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
 {
     int flags = parent_flags;
 
+    /* The cache mode is inherited unmodified for backing files */
+    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_WB);
+    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
+    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
+
     /* backing files always opened read-only */
     flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
 
@@ -758,6 +770,42 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
     return open_flags;
 }
 
+static void update_flags_from_options(int *flags, QemuOpts *opts)
+{
+    *flags &= ~BDRV_O_CACHE_MASK;
+
+    assert(qemu_opt_find(opts, BDRV_OPT_CACHE_WB));
+    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, false)) {
+        *flags |= BDRV_O_CACHE_WB;
+    }
+
+    assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH));
+    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
+        *flags |= BDRV_O_NO_FLUSH;
+    }
+
+    assert(qemu_opt_find(opts, BDRV_OPT_CACHE_DIRECT));
+    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
+        *flags |= BDRV_O_NOCACHE;
+    }
+}
+
+static void update_options_from_flags(QDict *options, int flags)
+{
+    if (!qdict_haskey(options, BDRV_OPT_CACHE_WB)) {
+        qdict_put(options, BDRV_OPT_CACHE_WB,
+                  qbool_from_int(flags & BDRV_O_CACHE_WB));
+    }
+    if (!qdict_haskey(options, BDRV_OPT_CACHE_DIRECT)) {
+        qdict_put(options, BDRV_OPT_CACHE_DIRECT,
+                  qbool_from_int(flags & BDRV_O_NOCACHE));
+    }
+    if (!qdict_haskey(options, BDRV_OPT_CACHE_NO_FLUSH)) {
+        qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH,
+                  qbool_from_int(flags & BDRV_O_NO_FLUSH));
+    }
+}
+
 static void bdrv_assign_node_name(BlockDriverState *bs,
                                   const char *node_name,
                                   Error **errp)
@@ -804,6 +852,20 @@ static QemuOptsList bdrv_runtime_opts = {
             .type = QEMU_OPT_STRING,
             .help = "Block driver to use for the node",
         },
+        {
+            .name = BDRV_OPT_CACHE_WB,
+            .type = QEMU_OPT_BOOL,
+            .help = "Enable writeback mode",
+        },
+        {
+            .name = BDRV_OPT_CACHE_DIRECT,
+            .type = QEMU_OPT_BOOL,
+        },
+        {
+            .name = BDRV_OPT_CACHE_NO_FLUSH,
+            .type = QEMU_OPT_BOOL,
+            .help = "Ignore flush requests",
+        },
         { /* end of list */ }
     },
 };
@@ -907,7 +969,9 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
     bs->drv = drv;
     bs->opaque = g_malloc0(drv->instance_size);
 
-    bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
+    /* Apply cache mode options */
+    update_flags_from_options(&bs->open_flags, opts);
+    bdrv_set_enable_write_cache(bs, bs->open_flags & BDRV_O_CACHE_WB);
 
     /* Open the image, either directly or using a protocol */
     if (drv->bdrv_file_open) {
@@ -1025,6 +1089,9 @@ static int bdrv_fill_options(QDict **options, const char **pfilename, int flags,
         *pfilename = filename = NULL;
     }
 
+    /* Translate cache options from flags into options */
+    update_options_from_flags(*options, flags);
+
     /* Fetch the file name from the options QDict if necessary */
     if (protocol && filename) {
         if (!qdict_haskey(*options, "filename")) {
@@ -1650,12 +1717,22 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
     /*
      * Precedence of options:
      * 1. Explicitly passed in options (highest)
-     * 2. TODO Set in flags (only for top level)
+     * 2. Set in flags (only for top level)
      * 3. Retained from explicitly set options of bs
      * 4. Inherited from parent node
      * 5. Retained from effective options of bs
      */
 
+    if (!parent_options) {
+        /*
+         * Any setting represented by flags is always updated. If the
+         * corresponding QDict option is set, it takes precedence. Otherwise
+         * the flag is translated into a QDict option. The old setting of bs is
+         * not considered.
+         */
+        update_options_from_flags(options, flags);
+    }
+
     /* Old explicitly set values (don't overwrite by inherited value) */
     old_options = qdict_clone_shallow(bs->explicit_options);
     qdict_join(options, old_options, false);
@@ -1824,6 +1901,8 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
         goto error;
     }
 
+    update_flags_from_options(&reopen_state->flags, opts);
+
     /* node-name and driver must be unchanged. Put them back into the QDict, so
      * that they are checked at the end of this function. */
     value = qemu_opt_get(opts, "node-name");
diff --git a/blockdev.c b/blockdev.c
index 77cbe72..90853aa 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -391,15 +391,12 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
         }
     }
 
-    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true)) {
-        bdrv_flags |= BDRV_O_CACHE_WB;
-    }
-    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
-        bdrv_flags |= BDRV_O_NOCACHE;
-    }
-    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
-        bdrv_flags |= BDRV_O_NO_FLUSH;
-    }
+    /* bdrv_open() defaults to the values in bdrv_flags (for compatibility with
+     * other callers) rather than what we want as the real defaults. Apply the
+     * defaults here instead. */
+    qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_WB, "on");
+    qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
+    qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
 
 #ifdef CONFIG_LINUX_AIO
     if ((buf = qemu_opt_get(opts, "aio")) != NULL) {
@@ -3106,18 +3103,6 @@ QemuOptsList qemu_common_drive_opts = {
             .type = QEMU_OPT_STRING,
             .help = "discard operation (ignore/off, unmap/on)",
         },{
-            .name = BDRV_OPT_CACHE_WB,
-            .type = QEMU_OPT_BOOL,
-            .help = "enables writeback mode for any caches",
-        },{
-            .name = BDRV_OPT_CACHE_DIRECT,
-            .type = QEMU_OPT_BOOL,
-            .help = "enables use of O_DIRECT (bypass the host page cache)",
-        },{
-            .name = BDRV_OPT_CACHE_NO_FLUSH,
-            .type = QEMU_OPT_BOOL,
-            .help = "ignore any flush requests for the device",
-        },{
             .name = "aio",
             .type = QEMU_OPT_STRING,
             .help = "host AIO implementation (threads, native)",
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 32/34] qemu-iotests: Try setting cache mode for children
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (30 preceding siblings ...)
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 31/34] block: Move cache options into options QDict Kevin Wolf
@ 2015-05-08 17:22 ` Kevin Wolf
  2015-05-15 18:52   ` Max Reitz
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 33/34] qemu-iotests: Test cache mode option inheritance Kevin Wolf
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 34/34] qemu-iotests: Test reopen with node-name/driver options Kevin Wolf
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:22 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

This is a basic test for specifying cache modes for child nodes on the
command line. It doesn't take much time and works without O_DIRECT
support.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 tests/qemu-iotests/051     | 12 +++++++++
 tests/qemu-iotests/051.out | 63 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index e236685..c825191 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -176,6 +176,18 @@ run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a
 run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk
 
 echo
+echo === Cache modes ===
+echo
+
+# Can't test direct=on here because O_DIRECT might not be supported on this FS
+# Test 132 checks the direct=on cases
+
+for cache in writeback writethrough unsafe invalid_value; do
+    echo -e "info block\ninfo block file\ninfo block backing\ninfo block backing-file" | \
+    run_qemu -drive file="$TEST_IMG",cache=$cache,backing.file.filename="$TEST_IMG.base",backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
+done
+
+echo
 echo === Specifying the protocol layer ===
 echo
 
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index 2e3b48a..74ced74 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -221,6 +221,69 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
 
 
+=== Cache modes ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K
+ide0-hd0: TEST_DIR/t.qcow2 (qcow2)
+    Cache mode:       writeback
+    Backing file:     TEST_DIR/t.qcow2.base (chain depth: 1)
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block f^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block fi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block fil^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block file^[[K
+
+file: TEST_DIR/t.qcow2 (file)
+    Cache mode:       writeback
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block b^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ba^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block bac^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block back^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backin^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing^[[K
+backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
+    Cache mode:       writeback, ignore flushes
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block b^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ba^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block bac^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block back^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backin^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-f^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-fi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D!
 ^[[D^[[Dinfo block backing-fil^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-file^[[K
+
+backing-file: TEST_DIR/t.qcow2.base (file, read-only)
+    Cache mode:       writeback, ignore flushes
+(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K
+ide0-hd0: TEST_DIR/t.qcow2 (qcow2)
+    Cache mode:       writethrough
+    Backing file:     TEST_DIR/t.qcow2.base (chain depth: 1)
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block f^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block fi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block fil^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block file^[[K
+
+file: TEST_DIR/t.qcow2 (file)
+    Cache mode:       writeback
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block b^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ba^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block bac^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block back^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backin^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing^[[K
+backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
+    Cache mode:       writeback, ignore flushes
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block b^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ba^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block bac^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block back^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backin^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-f^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-fi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D!
 ^[[D^[[Dinfo block backing-fil^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-file^[[K
+
+backing-file: TEST_DIR/t.qcow2.base (file, read-only)
+    Cache mode:       writeback, ignore flushes
+(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K
+ide0-hd0: TEST_DIR/t.qcow2 (qcow2)
+    Cache mode:       writeback, ignore flushes
+    Backing file:     TEST_DIR/t.qcow2.base (chain depth: 1)
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block f^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block fi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block fil^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block file^[[K
+
+file: TEST_DIR/t.qcow2 (file)
+    Cache mode:       writeback, ignore flushes
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block b^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ba^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block bac^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block back^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backin^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing^[[K
+backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
+    Cache mode:       writeback, ignore flushes
+(qemu) i^[[K^[[Din^[[K^[[D^[[Dinf^[[K^[[D^[[D^[[Dinfo^[[K^[[D^[[D^[[D^[[Dinfo ^[[K^[[D^[[D^[[D^[[D^[[Dinfo b^[[K^[[D^[[D^[[D^[[D^[[D^[[Dinfo bl^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo blo^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo bloc^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block b^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block ba^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block bac^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block back^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backin^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-f^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-fi^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D!
 ^[[D^[[Dinfo block backing-fil^[[K^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[D^[[Dinfo block backing-file^[[K
+
+backing-file: TEST_DIR/t.qcow2.base (file, read-only)
+    Cache mode:       writeback, ignore flushes
+(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file: invalid cache option
+
+
 === Specifying the protocol layer ===
 
 Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 33/34] qemu-iotests: Test cache mode option inheritance
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (31 preceding siblings ...)
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 32/34] qemu-iotests: Try setting cache mode for children Kevin Wolf
@ 2015-05-08 17:22 ` Kevin Wolf
  2015-05-15 19:16   ` Max Reitz
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 34/34] qemu-iotests: Test reopen with node-name/driver options Kevin Wolf
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:22 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

This is doing a more complete test on setting cache modes both while
opening an image (i.e. in a -drive command line) and in reopen
situations. It checks that reopen can specify options for child nodes
and that cache modes are correctly inherited from parent nodes where
they are not specified.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 tests/qemu-iotests/132     | 336 ++++++++++++++++++++
 tests/qemu-iotests/132.out | 767 +++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/group   |   1 +
 3 files changed, 1104 insertions(+)
 create mode 100755 tests/qemu-iotests/132
 create mode 100644 tests/qemu-iotests/132.out

diff --git a/tests/qemu-iotests/132 b/tests/qemu-iotests/132
new file mode 100755
index 0000000..dd0de16
--- /dev/null
+++ b/tests/qemu-iotests/132
@@ -0,0 +1,336 @@
+#!/bin/bash
+#
+# Test for configuring cache modes of arbitrary nodes (requires O_DIRECT)
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+_cleanup()
+{
+    _cleanup_test_img
+    rm -f $TEST_IMG.snap
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+# We test all cache modes anyway, but O_DIRECT needs to be supported
+_default_cache_mode none
+_supported_cache_modes none directsync
+
+function do_run_qemu()
+{
+    echo Testing: "$@"
+    (
+        if ! test -t 0; then
+            while read cmd; do
+                echo $cmd
+            done
+        fi
+        echo quit
+    ) | $QEMU -nographic -monitor stdio -nodefaults "$@"
+    echo
+}
+
+function run_qemu()
+{
+    do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu
+}
+
+size=128M
+
+TEST_IMG="$TEST_IMG.base" _make_test_img $size
+TEST_IMG="$TEST_IMG.snap" _make_test_img $size
+_make_test_img -b "$TEST_IMG.base" $size
+
+echo
+echo === Simple test for all cache modes ===
+echo
+
+run_qemu -drive file="$TEST_IMG",cache=none
+run_qemu -drive file="$TEST_IMG",cache=directsync
+run_qemu -drive file="$TEST_IMG",cache=writeback
+run_qemu -drive file="$TEST_IMG",cache=writethrough
+run_qemu -drive file="$TEST_IMG",cache=unsafe
+run_qemu -drive file="$TEST_IMG",cache=invalid_value
+
+echo
+echo === Check inheritance of cache modes ===
+echo
+
+files="file=$TEST_IMG,backing.file.filename=$TEST_IMG.base"
+ids="node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file"
+
+function check_cache_all()
+{
+    # cache.direct is supposed to be inherited by both bs->file and
+    # bs->backing_hd
+
+    echo -e "cache.direct=on on ide0-hd0"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.direct=on | grep "Cache"
+    echo -e "\ncache.direct=on on file"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.direct=on | grep "Cache"
+    echo -e "\ncache.direct=on on backing"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.direct=on | grep "Cache"
+    echo -e "\ncache.direct=on on backing-file"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.direct=on | grep "Cache"
+
+    # cache.writeback is supposed to be inherited by bs->backing_hd; bs->file
+    # always gets cache.writeback=on
+
+    echo -e "\n\ncache.writeback=off on ide0-hd0"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.writeback=off | grep "Cache"
+    echo -e "\ncache.writeback=off on file"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.writeback=off | grep "Cache"
+    echo -e "\ncache.writeback=off on backing"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.writeback=off | grep "Cache"
+    echo -e "\ncache.writeback=off on backing-file"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.writeback=off | grep "Cache"
+
+    # cache.no-flush is supposed to be inherited by both bs->file and bs->backing_hd
+
+    echo -e "\n\ncache.no-flush=on on ide0-hd0"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.no-flush=on | grep "Cache"
+    echo -e "\ncache.no-flush=on on file"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.no-flush=on | grep "Cache"
+    echo -e "\ncache.no-flush=on on backing"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.no-flush=on | grep "Cache"
+    echo -e "\ncache.no-flush=on on backing-file"
+    echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.no-flush=on | grep "Cache"
+}
+
+echo
+echo "--- Configure cache modes on the command line ---"
+echo
+
+# First check the inherited cache mode after opening the image.
+
+hmp_cmds="info block image
+info block file
+info block backing
+info block backing-file"
+
+check_cache_all
+
+echo
+echo "--- Cache modes after reopen (live snapshot) ---"
+echo
+
+# Then trigger a reopen and check that the cache modes are still the same.
+
+hmp_cmds="snapshot_blkdev -n ide0-hd0 $TEST_IMG.snap $IMGFMT
+info block
+info block image
+info block file
+info block backing
+info block backing-file"
+
+check_cache_all
+
+echo
+echo "--- Change cache modes with reopen (qemu-io command, flags) ---"
+echo
+
+# This one actually changes the cache mode with the reopen. For this test, the
+# new cache mode is specified in the flags, not as an option.
+
+hmp_cmds='qemu-io ide0-hd0 "reopen -c none"
+info block image
+info block file
+info block backing
+info block backing-file'
+
+check_cache_all
+
+echo
+echo "--- Change cache modes with reopen (qemu-io command, options) ---"
+echo
+
+# This one actually changes the cache mode with the reopen. For this test, the
+# new cache mode is specified as an option, not in the flags.
+
+hmp_cmds='qemu-io ide0-hd0 "reopen -o cache.direct=on"
+info block image
+info block file
+info block backing
+info block backing-file'
+
+check_cache_all
+
+echo
+echo "--- Change cache modes after snapshot ---"
+echo
+
+# This checks that the original image doesn't inherit from the snapshot
+
+hmp_cmds="snapshot_blkdev -n ide0-hd0 $TEST_IMG.snap $IMGFMT
+qemu-io ide0-hd0 \"reopen -c none\"
+info block ide0-hd0
+info block image
+info block file
+info block backing
+info block backing-file"
+
+check_cache_all
+
+echo
+echo "=== Check that referenced BDSes don't inherit ==="
+echo
+
+drv_bkfile="if=none,driver=file,filename=$TEST_IMG.base,node-name=backing-file"
+drv_bk="if=none,file=json:{'driver':'$IMGFMT',,'file':'backing-file',,'node-name':'backing'}"
+drv_file="if=none,driver=file,filename=$TEST_IMG,node-name=file"
+drv_img="file=json:{'driver':'$IMGFMT',,'file':'file',,'backing':'backing',,'node-name':'image'}"
+
+function check_cache_all_separate()
+{
+    # Check cache.direct
+
+    echo -e "cache.direct=on on ide0-hd0"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.direct=on | grep "Cache"
+    echo -e "\ncache.direct=on on file"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.direct=on -drive "$drv_img" | grep "Cache"
+    echo -e "\ncache.direct=on on backing"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.direct=on -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+    echo -e "\ncache.direct=on on backing-file"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.direct=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+
+    # Check cache.writeback
+
+    echo -e "\n\ncache.writeback=off on ide0-hd0"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.writeback=off | grep "Cache"
+    echo -e "\ncache.writeback=off on file"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.writeback=off -drive "$drv_img" | grep "Cache"
+    echo -e "\ncache.writeback=off on backing"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.writeback=off -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+    echo -e "\ncache.writeback=off on backing-file"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.writeback=off -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+
+    # Check cache.no-flush
+
+    echo -e "\n\ncache.no-flush=on on ide0-hd0"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.no-flush=on | grep "Cache"
+    echo -e "\ncache.no-flush=on on file"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.no-flush=on -drive "$drv_img" | grep "Cache"
+    echo -e "\ncache.no-flush=on on backing"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.no-flush=on -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+    echo -e "\ncache.no-flush=on on backing-file"
+    echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.no-flush=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache"
+}
+
+echo
+echo "--- Configure cache modes on the command line ---"
+echo
+
+# First check the inherited cache mode after opening the image.
+
+hmp_cmds="info block image
+info block file
+info block backing
+info block backing-file"
+
+check_cache_all_separate
+
+echo
+echo "--- Cache modes after reopen (live snapshot) ---"
+echo
+
+# Then trigger a reopen and check that the cache modes are still the same.
+
+hmp_cmds="snapshot_blkdev -n ide0-hd0 $TEST_IMG.snap $IMGFMT
+info block ide0-hd0
+info block image
+info block file
+info block backing
+info block backing-file"
+
+check_cache_all_separate
+
+echo
+echo "--- Change cache modes with reopen (qemu-io command, flags) ---"
+echo
+
+# This one actually changes the cache mode with the reopen. For this test, the
+# new cache mode is specified as flags, not as option.
+
+hmp_cmds='qemu-io ide0-hd0 "reopen -c none"
+info block image
+info block file
+info block backing
+info block backing-file'
+
+check_cache_all_separate
+
+
+echo
+echo "=== Reopening children instead of the root ==="
+echo
+
+files="file=$TEST_IMG,backing.file.filename=$TEST_IMG.base"
+ids="node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file"
+
+echo
+echo "--- Basic reopen ---"
+echo
+
+hmp_cmds='qemu-io ide0-hd0 "reopen -o backing.cache.direct=on"
+info block image
+info block file
+info block backing
+info block backing-file'
+
+check_cache_all
+
+echo
+echo "--- Change cache mode after reopening child ---"
+echo
+
+# This checks that children with options explicitly set with reopen don't
+# inherit these options from their parents any more
+
+# TODO Implement node-name support for 'qemu-io' HMP command for -c
+# Can use only -o to access child node options for now
+
+hmp_cmds="qemu-io ide0-hd0 \"reopen -o file.cache.writeback=off,file.cache.direct=off,file.cache.no-flush=off\"
+qemu-io ide0-hd0 \"reopen -o backing.file.cache.writeback=on,backing.file.cache.direct=off,backing.file.cache.no-flush=on\"
+qemu-io ide0-hd0 \"reopen -c none\"
+info block image
+info block file
+info block backing
+info block backing-file"
+
+echo "$hmp_cmds" | run_qemu -drive "$files","$ids" | grep "Cache"
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/132.out b/tests/qemu-iotests/132.out
new file mode 100644
index 0000000..691a7b4
--- /dev/null
+++ b/tests/qemu-iotests/132.out
@@ -0,0 +1,767 @@
+QA output created by 132
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT.snap', fmt=IMGFMT size=134217728
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR/t.IMGFMT.base'
+
+=== Simple test for all cache modes ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=none
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=directsync
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) q^[[K^[[Dqu^[[K^[[D^[[Dqui^[[K^[[D^[[D^[[Dquit^[[K
+
+Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value: invalid cache option
+
+
+=== Check inheritance of cache modes ===
+
+
+--- Configure cache modes on the command line ---
+
+cache.direct=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on file
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.direct=on on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+
+
+cache.writeback=off on ide0-hd0
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+
+cache.writeback=off on file
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.writeback=off on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+
+cache.writeback=off on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+
+
+cache.no-flush=on on ide0-hd0
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+
+cache.no-flush=on on file
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.no-flush=on on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+
+cache.no-flush=on on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+
+--- Cache modes after reopen (live snapshot) ---
+
+cache.direct=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.direct=on on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+
+
+cache.writeback=off on ide0-hd0
+    Cache mode:       writethrough
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+
+cache.writeback=off on file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.writeback=off on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+
+cache.writeback=off on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+
+
+cache.no-flush=on on ide0-hd0
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+
+cache.no-flush=on on file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.no-flush=on on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+
+cache.no-flush=on on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+
+--- Change cache modes with reopen (qemu-io command, flags) ---
+
+cache.direct=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+
+cache.writeback=off on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.writeback=off on file
+    Cache mode:       writeback, direct
+    Cache mode:       writethrough, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.writeback=off on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writethrough, direct
+    Cache mode:       writeback, direct
+
+cache.writeback=off on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writethrough, direct
+
+
+cache.no-flush=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.no-flush=on on file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct, ignore flushes
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.no-flush=on on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct, ignore flushes
+    Cache mode:       writeback, direct, ignore flushes
+
+cache.no-flush=on on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct, ignore flushes
+
+--- Change cache modes with reopen (qemu-io command, options) ---
+
+cache.direct=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+
+cache.writeback=off on ide0-hd0
+    Cache mode:       writethrough, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writethrough, direct
+    Cache mode:       writeback, direct
+
+cache.writeback=off on file
+    Cache mode:       writeback, direct
+    Cache mode:       writethrough, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.writeback=off on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writethrough, direct
+    Cache mode:       writeback, direct
+
+cache.writeback=off on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writethrough, direct
+
+
+cache.no-flush=on on ide0-hd0
+    Cache mode:       writeback, direct, ignore flushes
+    Cache mode:       writeback, direct, ignore flushes
+    Cache mode:       writeback, direct, ignore flushes
+    Cache mode:       writeback, direct, ignore flushes
+
+cache.no-flush=on on file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct, ignore flushes
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.no-flush=on on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct, ignore flushes
+    Cache mode:       writeback, direct, ignore flushes
+
+cache.no-flush=on on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct, ignore flushes
+
+--- Change cache modes after snapshot ---
+
+cache.direct=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.direct=on on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+
+
+cache.writeback=off on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+
+cache.writeback=off on file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.writeback=off on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+
+cache.writeback=off on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+
+
+cache.no-flush=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+
+cache.no-flush=on on file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.no-flush=on on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+
+cache.no-flush=on on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+
+=== Check that referenced BDSes don't inherit ===
+
+
+--- Configure cache modes on the command line ---
+
+cache.direct=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.direct=on on file
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.direct=on on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+
+cache.direct=on on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+
+
+cache.writeback=off on ide0-hd0
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.writeback=off on file
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.writeback=off on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+
+cache.writeback=off on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+
+
+cache.no-flush=on on ide0-hd0
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.no-flush=on on file
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.no-flush=on on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback
+
+cache.no-flush=on on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+
+--- Cache modes after reopen (live snapshot) ---
+
+cache.direct=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.direct=on on file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.direct=on on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+
+cache.direct=on on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+
+
+cache.writeback=off on ide0-hd0
+    Cache mode:       writethrough
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.writeback=off on file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.writeback=off on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+
+cache.writeback=off on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+
+
+cache.no-flush=on on ide0-hd0
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.no-flush=on on file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.no-flush=on on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback
+
+cache.no-flush=on on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+
+--- Change cache modes with reopen (qemu-io command, flags) ---
+
+cache.direct=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.direct=on on file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.direct=on on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+
+cache.direct=on on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+
+
+cache.writeback=off on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.writeback=off on file
+    Cache mode:       writeback, direct
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.writeback=off on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback
+
+cache.writeback=off on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough
+
+
+cache.no-flush=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.no-flush=on on file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback
+    Cache mode:       writeback
+
+cache.no-flush=on on backing
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback
+
+cache.no-flush=on on backing-file
+    Cache mode:       writeback, direct
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+
+=== Reopening children instead of the root ===
+
+
+--- Basic reopen ---
+
+cache.direct=on on ide0-hd0
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on file
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.direct=on on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+
+cache.writeback=off on ide0-hd0
+    Cache mode:       writethrough
+    Cache mode:       writeback
+    Cache mode:       writethrough, direct
+    Cache mode:       writeback, direct
+
+cache.writeback=off on file
+    Cache mode:       writeback
+    Cache mode:       writethrough
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.writeback=off on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writethrough, direct
+    Cache mode:       writeback, direct
+
+cache.writeback=off on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writethrough, direct
+
+
+cache.no-flush=on on ide0-hd0
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, direct, ignore flushes
+    Cache mode:       writeback, direct, ignore flushes
+
+cache.no-flush=on on file
+    Cache mode:       writeback
+    Cache mode:       writeback, ignore flushes
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct
+
+cache.no-flush=on on backing
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct, ignore flushes
+    Cache mode:       writeback, direct, ignore flushes
+
+cache.no-flush=on on backing-file
+    Cache mode:       writeback
+    Cache mode:       writeback
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, direct, ignore flushes
+
+--- Change cache mode after reopening child ---
+
+    Cache mode:       writeback, direct
+    Cache mode:       writethrough
+    Cache mode:       writeback, direct
+    Cache mode:       writeback, ignore flushes
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 6ca3466..25f4f71 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -128,3 +128,4 @@
 128 rw auto quick
 129 rw auto quick
 130 rw auto quick
+132 auto
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* [Qemu-devel] [PATCH 34/34] qemu-iotests: Test reopen with node-name/driver options
  2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
                   ` (32 preceding siblings ...)
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 33/34] qemu-iotests: Test cache mode option inheritance Kevin Wolf
@ 2015-05-08 17:22 ` Kevin Wolf
  2015-05-15 19:19   ` Max Reitz
  33 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-08 17:22 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, armbru, mreitz

'node-name' and 'driver' should not be changed during a reopen
operation. It is, however, valid to specify them with the same value as
they already had.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 tests/qemu-iotests/133     | 90 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/133.out | 22 ++++++++++++
 tests/qemu-iotests/group   |  1 +
 3 files changed, 113 insertions(+)
 create mode 100755 tests/qemu-iotests/133
 create mode 100644 tests/qemu-iotests/133.out

diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133
new file mode 100755
index 0000000..8587102
--- /dev/null
+++ b/tests/qemu-iotests/133
@@ -0,0 +1,90 @@
+#!/bin/bash
+#
+# Test for reopen
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+_cleanup()
+{
+    _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+TEST_IMG="$TEST_IMG.base" _make_test_img 64M
+_make_test_img -b "$TEST_IMG.base"
+
+echo
+echo "=== Check that node-name can't be changed ==="
+echo
+
+$QEMU_IO -c 'reopen -o node-name=foo' $TEST_IMG
+$QEMU_IO -c 'reopen -o file.node-name=foo' $TEST_IMG
+$QEMU_IO -c 'reopen -o backing.node-name=foo' $TEST_IMG
+
+echo
+echo "=== Check that unchanged node-name is okay ==="
+echo
+
+# Explicitly repeated
+$QEMU_IO -c "open -o node-name=foo $TEST_IMG" -c 'reopen -o node-name=foo'
+$QEMU_IO -c "open -o file.node-name=foo $TEST_IMG" -c 'reopen -o file.node-name=foo'
+$QEMU_IO -c "open -o backing.node-name=foo $TEST_IMG" -c 'reopen -o backing.node-name=foo'
+
+# Implicitly retained
+$QEMU_IO -c "open -o node-name=foo $TEST_IMG" -c 'reopen'
+$QEMU_IO -c "open -o file.node-name=foo $TEST_IMG" -c 'reopen'
+$QEMU_IO -c "open -o backing.node-name=foo $TEST_IMG" -c 'reopen'
+
+echo
+echo "=== Check that driver can't be changed ==="
+echo
+
+$QEMU_IO -c 'reopen -o driver=raw' $TEST_IMG
+$QEMU_IO -c 'reopen -o file.driver=qcow2' $TEST_IMG
+$QEMU_IO -c 'reopen -o backing.driver=file' $TEST_IMG
+
+echo
+echo "=== Check that unchanged driver is okay ==="
+echo
+
+# Explicitly repeated (implicit case is covered in node-name test)
+$QEMU_IO -c 'reopen -o driver=qcow2' $TEST_IMG
+$QEMU_IO -c 'reopen -o file.driver=file' $TEST_IMG
+$QEMU_IO -c 'reopen -o backing.driver=qcow2' $TEST_IMG
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/133.out b/tests/qemu-iotests/133.out
new file mode 100644
index 0000000..682406f
--- /dev/null
+++ b/tests/qemu-iotests/133.out
@@ -0,0 +1,22 @@
+QA output created by 133
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+
+=== Check that node-name can't be changed ===
+
+Cannot change the option 'node-name'
+Cannot change the option 'node-name'
+Cannot change the option 'node-name'
+
+=== Check that unchanged node-name is okay ===
+
+
+=== Check that driver can't be changed ===
+
+Cannot change the option 'driver'
+Cannot change the option 'driver'
+Cannot change the option 'driver'
+
+=== Check that unchanged driver is okay ===
+
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 25f4f71..7282358 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -129,3 +129,4 @@
 129 rw auto quick
 130 rw auto quick
 132 auto
+133 auto quick
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries() Kevin Wolf
@ 2015-05-08 20:06   ` Eric Blake
  2015-05-08 21:22     ` Eric Blake
                       ` (2 more replies)
  2015-05-11 13:56   ` [Qemu-devel] " Max Reitz
  1 sibling, 3 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-08 20:06 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 2326 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---

Might want to include mention of what it will be used for in the commit
body.

>  include/qapi/qmp/qdict.h |  1 +
>  qobject/qdict.c          | 68 +++++++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 65 insertions(+), 4 deletions(-)
> 

> @@ -646,7 +647,7 @@ void qdict_array_split(QDict *src, QList **dst)
>          snprintf_ret = snprintf(prefix, 32, "%u.", i);
>          assert(snprintf_ret < 32);
>  
> -        is_subqdict = qdict_has_prefixed_entries(src, prefix);
> +        is_subqdict = qdict_count_prefixed_entries(src, prefix);

Good thing we require a C99 compiler, where 'bool = int' does the right
thing for integers > 1.

>  /**
> + * qdict_array_valid(): Returns the number of direct array entries if the
> + * sub-QDict of src specified by the prefix in subqdict (or src itself for
> + * prefix == "") is valid as an array, i.e. the length of the created list if
> + * the sub-QDict would become empty after calling qdict_array_split() on it. If
> + * the array is not valid, -1 is returned.
> + */
> +int qdict_array_entries(QDict *src, const char *subqdict)

Comment doesn't match function name.

> +{
> +    const QDictEntry *entry;
> +    unsigned i;
> +    unsigned entries = 0;
> +    size_t subqdict_len = strlen(subqdict);
> +
> +    assert(!subqdict_len || subqdict[subqdict_len - 1] == '.');
> +
> +    for (i = 0; i < UINT_MAX; i++) {
> +        QObject *subqobj;
> +        int subqdict_entries;
> +        size_t slen = 32 + subqdict_len;
> +        char indexstr[slen], prefix[slen];

And more dependence on a working C99 compiler, thanks to variable length
array (VLA).

> +        size_t snprintf_ret;
> +
> +        snprintf_ret = snprintf(indexstr, slen, "%s%u", subqdict, i);
> +        assert(snprintf_ret < slen);

Since gcc may compile the allocation of indexstr into a malloc()
anyways, would it be any simpler to just use g_strdup_printf() directly,
instead of futzing around with VLA and snprintf() ourselves?  It might
mean less code, as some of the error checking is taken care of on your
behalf.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries()
  2015-05-08 20:06   ` Eric Blake
@ 2015-05-08 21:22     ` Eric Blake
  2015-05-11 14:40     ` Kevin Wolf
  2015-05-20 14:19     ` [Qemu-devel] [Qemu-block] " Alberto Garcia
  2 siblings, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-08 21:22 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel, mreitz

[-- Attachment #1: Type: text/plain, Size: 633 bytes --]

On 05/08/2015 02:06 PM, Eric Blake wrote:
> On 05/08/2015 11:21 AM, Kevin Wolf wrote:
>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>> ---
> 
> Might want to include mention of what it will be used for in the commit
> body.
> 
>>  include/qapi/qmp/qdict.h |  1 +
>>  qobject/qdict.c          | 68 +++++++++++++++++++++++++++++++++++++++++++++---
>>  2 files changed, 65 insertions(+), 4 deletions(-)
>>

Oh, and I meant to mention: shouldn't the testsuite also be enhanced to
cover the new functionality?

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set, copy}_default()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set,copy}_default() Kevin Wolf
@ 2015-05-08 21:30   ` Eric Blake
  2015-05-11 14:06     ` Kevin Wolf
  2015-05-11 14:16   ` Max Reitz
  1 sibling, 1 reply; 130+ messages in thread
From: Eric Blake @ 2015-05-08 21:30 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 1366 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> In the block layer functions that determine options for a child block
> device, it's a common pattern to either copy options from the parent's
> options or to set a default string if the option isn't explicitly set
> yet for the child. Provide convenience functions so that it becomes a
> one-liner for each option.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  include/qapi/qmp/qdict.h |  3 +++
>  qobject/qdict.c          | 34 ++++++++++++++++++++++++++++++++++
>  2 files changed, 37 insertions(+)
> 

> +/**
> + * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet,
> + * 'val' is put there, with the QDict taking the reference. Otherwise, the
> + * refcount of 'val' is decreased.
> + */
> +void qdict_set_default_str(QDict *dst, const char *key, const char *val)

Huh? Since when does 'const char *val' have a refcount that needs
decreasing?

> +{
> +    if (qdict_haskey(dst, key)) {
> +        return;
> +    }
> +
> +    qdict_put(dst, key, qstring_from_str(val));
> +}

I'm wondering if you wrote that comment at a point where you were
passing qstrings around, and then changed your mind by using C strings
for the implementation.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 03/34] quorum: Use bdrv_open_image()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 03/34] quorum: Use bdrv_open_image() Kevin Wolf
@ 2015-05-08 21:33   ` Eric Blake
  2015-05-11 14:27   ` Max Reitz
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-08 21:33 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 609 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Besides standardising on a single interface for opening child nodes,
> this simplifies the .bdrv_open() implementation of the quorum block
> driver by using block layer functionality for handling BlockdevRefs.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/quorum.c | 51 +++++++++++----------------------------------------
>  1 file changed, 11 insertions(+), 40 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 04/34] vmdk: Use bdrv_open_image()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 04/34] vmdk: " Kevin Wolf
@ 2015-05-08 22:00   ` Eric Blake
  2015-05-11 14:35   ` Max Reitz
  2015-05-12 19:12   ` [Qemu-devel] [Qemu-block] " Jeff Cody
  2 siblings, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-08 22:00 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 639 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Besides standardising on a single interface for opening child nodes,
> this patch allows the user to specify options to individual extent
> nodes. Overriding file names isn't possible with this yet, so it's of
> limited usefulness, but still a step forward.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/vmdk.c | 34 +++++++++++++++++++++-------------
>  1 file changed, 21 insertions(+), 13 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names Kevin Wolf
@ 2015-05-08 22:54   ` Eric Blake
  2015-05-11 14:40   ` Max Reitz
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-08 22:54 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 411 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  blockdev.c            | 24 ++++++++++++------------
>  include/block/block.h |  8 ++++++++
>  2 files changed, 20 insertions(+), 12 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 06/34] block: Use QemuOpts in bdrv_open_common()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 06/34] block: Use QemuOpts in bdrv_open_common() Kevin Wolf
@ 2015-05-08 22:57   ` Eric Blake
  2015-05-11 14:57   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-08 22:57 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 685 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Instead of manually parsing options and then deleting them from the
> options QDict, just use QemuOpts like most other places that deal with
> block device options.
> 
> More options will be added there and then QemuOpts is a lot more
> managable than open-coding everything.

s/managable/manageable/

> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c | 37 ++++++++++++++++++++++++++++++++-----
>  1 file changed, 32 insertions(+), 5 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 07/34] block: Move flag inheritance to bdrv_open_inherited()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 07/34] block: Move flag inheritance to bdrv_open_inherited() Kevin Wolf
@ 2015-05-08 23:20   ` Eric Blake
  2015-05-11 15:20   ` Max Reitz
  2015-05-28 11:10   ` Wen Congyang
  2 siblings, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-08 23:20 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 958 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Instead of letting every caller of bdrv_open() determine the right flags
> for its child node manually and pass them to the function, pass the
> parent node and the role of the newly opened child (like backing file,
> protocol layer, etc.).
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c                   | 74 ++++++++++++++++++++++++++++++++++++++---------
>  block/blkdebug.c          |  2 +-
>  block/blkverify.c         |  4 +--
>  block/quorum.c            |  4 +--
>  block/vmdk.c              |  5 ++--
>  include/block/block.h     |  4 ++-
>  include/block/block_int.h |  7 +++++
>  7 files changed, 78 insertions(+), 22 deletions(-)
> 

Took me a while to follow the flow of information, but looks correct.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState Kevin Wolf
@ 2015-05-08 23:34   ` Eric Blake
  2015-05-11 15:45   ` Max Reitz
  2015-05-27 11:30   ` Kevin Wolf
  2 siblings, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-08 23:34 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 801 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> This allows iterating over all children of a given BDS, not only
> including bs->file and bs->backing_hd, but also driver-specific
> ones like VMDK extents or Quorum children.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c                   | 27 +++++++++++++++++++++++++++
>  include/block/block_int.h |  8 ++++++++
>  2 files changed, 35 insertions(+)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

and now I'm starting to see why you passed a well-named instance of a
struct that contains only a single function pointer, rather than the
function pointer directly, when creating BdrvChildRole in patch 7.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 09/34] block: Add BlockDriverState.inherits_from
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 09/34] block: Add BlockDriverState.inherits_from Kevin Wolf
@ 2015-05-08 23:39   ` Eric Blake
  2015-05-11 15:50   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-08 23:39 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 917 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Currently, the block layer assumes that any block node can have only one
> parent, and if it has a parent, that it inherits some options/flags from
> this parent.
> 
> This is not true any more: With references used in block device
> creation, a single node can be used by multiple parents, or it can be
> created separately and not inherit flags from any parent.
> 
> To handle reopens correctly, a node must know from which parent it
> inherited options. This patch adds the information to BlockDriverState.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c                   | 17 +++++++++++++++++
>  include/block/block_int.h |  4 ++++
>  2 files changed, 21 insertions(+)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries() Kevin Wolf
  2015-05-08 20:06   ` Eric Blake
@ 2015-05-11 13:56   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 13:56 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   include/qapi/qmp/qdict.h |  1 +
>   qobject/qdict.c          | 68 +++++++++++++++++++++++++++++++++++++++++++++---
>   2 files changed, 65 insertions(+), 4 deletions(-)
>
> diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
> index d68f4eb..d20db94 100644
> --- a/include/qapi/qmp/qdict.h
> +++ b/include/qapi/qmp/qdict.h
> @@ -70,6 +70,7 @@ void qdict_flatten(QDict *qdict);
>   
>   void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
>   void qdict_array_split(QDict *src, QList **dst);
> +int qdict_array_entries(QDict *src, const char *subqdict);
>   
>   void qdict_join(QDict *dest, QDict *src, bool overwrite);
>   
> diff --git a/qobject/qdict.c b/qobject/qdict.c
> index ea239f0..2fcb7fe 100644
> --- a/qobject/qdict.c
> +++ b/qobject/qdict.c
> @@ -597,17 +597,18 @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start)
>       }
>   }
>   
> -static bool qdict_has_prefixed_entries(const QDict *src, const char *start)
> +static int qdict_count_prefixed_entries(const QDict *src, const char *start)
>   {
>       const QDictEntry *entry;
> +    int count = 0;
>   
>       for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
>           if (strstart(entry->key, start, NULL)) {
> -            return true;
> +            count++;

On one hand a dumb question, but on the other hand we probably do need 
to consider it: What about overflows? I think we can avoid thinking 
about them by using size_t for all the counters.

>           }
>       }
>   
> -    return false;
> +    return count;
>   }
>   
>   /**
> @@ -646,7 +647,7 @@ void qdict_array_split(QDict *src, QList **dst)
>           snprintf_ret = snprintf(prefix, 32, "%u.", i);
>           assert(snprintf_ret < 32);
>   
> -        is_subqdict = qdict_has_prefixed_entries(src, prefix);
> +        is_subqdict = qdict_count_prefixed_entries(src, prefix);
>   
>           // There may be either a single subordinate object (named "%u") or
>           // multiple objects (each with a key prefixed "%u."), but not both.
> @@ -667,6 +668,65 @@ void qdict_array_split(QDict *src, QList **dst)
>   }
>   
>   /**
> + * qdict_array_valid(): Returns the number of direct array entries if the

(As Eric said, should be "qdict_array_entries():")

> + * sub-QDict of src specified by the prefix in subqdict (or src itself for
> + * prefix == "") is valid as an array, i.e. the length of the created list if
> + * the sub-QDict would become empty after calling qdict_array_split() on it. If
> + * the array is not valid, -1 is returned.
> + */
> +int qdict_array_entries(QDict *src, const char *subqdict)
> +{
> +    const QDictEntry *entry;
> +    unsigned i;
> +    unsigned entries = 0;
> +    size_t subqdict_len = strlen(subqdict);
> +
> +    assert(!subqdict_len || subqdict[subqdict_len - 1] == '.');
> +
> +    for (i = 0; i < UINT_MAX; i++) {
> +        QObject *subqobj;
> +        int subqdict_entries;
> +        size_t slen = 32 + subqdict_len;
> +        char indexstr[slen], prefix[slen];
> +        size_t snprintf_ret;
> +
> +        snprintf_ret = snprintf(indexstr, slen, "%s%u", subqdict, i);
> +        assert(snprintf_ret < slen);
> +
> +        subqobj = qdict_get(src, indexstr);
> +
> +        snprintf_ret = snprintf(prefix, slen, "%s%u.", subqdict, i);
> +        assert(snprintf_ret < slen);
> +
> +        subqdict_entries = qdict_count_prefixed_entries(src, prefix);
> +
> +        /* There may be either a single subordinate object (named "%u") or
> +         * multiple objects (each with a key prefixed "%u."), but not both. */
> +        if (subqobj && subqdict_entries) {
> +            return -1;
> +        } else if (!subqobj && !subqdict_entries) {
> +            break;
> +        }
> +
> +        entries += subqdict_entries ? subqdict_entries : 1;
> +    }
> +
> +    /* Consider everything handled that isn't part of the given sub-QDict */
> +    for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
> +        if (!strstart(qdict_entry_key(entry), subqdict, NULL)) {
> +            entries++;
> +        }
> +    }
> +
> +    /* Anything left in the sub-QDict that wasn't handled? */
> +    if (qdict_size(src) != entries) {
> +        return -1;
> +    }
> +
> +    return i;

Again, possible overflow that can be avoided by returning size_t.

Max

> +}
> +
> +/**
>    * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
>    * elements from src to dest.
>    *

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set, copy}_default()
  2015-05-08 21:30   ` [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set, copy}_default() Eric Blake
@ 2015-05-11 14:06     ` Kevin Wolf
  0 siblings, 0 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-11 14:06 UTC (permalink / raw)
  To: Eric Blake; +Cc: mreitz, qemu-devel, qemu-block, armbru

[-- Attachment #1: Type: text/plain, Size: 1458 bytes --]

Am 08.05.2015 um 23:30 hat Eric Blake geschrieben:
> On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> > In the block layer functions that determine options for a child block
> > device, it's a common pattern to either copy options from the parent's
> > options or to set a default string if the option isn't explicitly set
> > yet for the child. Provide convenience functions so that it becomes a
> > one-liner for each option.
> > 
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > ---
> >  include/qapi/qmp/qdict.h |  3 +++
> >  qobject/qdict.c          | 34 ++++++++++++++++++++++++++++++++++
> >  2 files changed, 37 insertions(+)
> > 
> 
> > +/**
> > + * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet,
> > + * 'val' is put there, with the QDict taking the reference. Otherwise, the
> > + * refcount of 'val' is decreased.
> > + */
> > +void qdict_set_default_str(QDict *dst, const char *key, const char *val)
> 
> Huh? Since when does 'const char *val' have a refcount that needs
> decreasing?
> 
> > +{
> > +    if (qdict_haskey(dst, key)) {
> > +        return;
> > +    }
> > +
> > +    qdict_put(dst, key, qstring_from_str(val));
> > +}
> 
> I'm wondering if you wrote that comment at a point where you were
> passing qstrings around, and then changed your mind by using C strings
> for the implementation.

Indeed, I think this is what happened. Thanks, I'll fix the comment.

Kevin

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set, copy}_default()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set,copy}_default() Kevin Wolf
  2015-05-08 21:30   ` [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set, copy}_default() Eric Blake
@ 2015-05-11 14:16   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 14:16 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> In the block layer functions that determine options for a child block
> device, it's a common pattern to either copy options from the parent's
> options or to set a default string if the option isn't explicitly set
> yet for the child. Provide convenience functions so that it becomes a
> one-liner for each option.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   include/qapi/qmp/qdict.h |  3 +++
>   qobject/qdict.c          | 34 ++++++++++++++++++++++++++++++++++
>   2 files changed, 37 insertions(+)
>
> diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
> index d20db94..9fbf68e 100644
> --- a/include/qapi/qmp/qdict.h
> +++ b/include/qapi/qmp/qdict.h
> @@ -65,6 +65,9 @@ int64_t qdict_get_try_int(const QDict *qdict, const char *key,
>   int qdict_get_try_bool(const QDict *qdict, const char *key, int def_value);
>   const char *qdict_get_try_str(const QDict *qdict, const char *key);
>   
> +void qdict_copy_default(QDict *dst, QDict *src, const char *key);
> +void qdict_set_default_str(QDict *dst, const char *key, const char *val);
> +
>   QDict *qdict_clone_shallow(const QDict *src);
>   void qdict_flatten(QDict *qdict);
>   
> diff --git a/qobject/qdict.c b/qobject/qdict.c
> index 2fcb7fe..45ba42c 100644
> --- a/qobject/qdict.c
> +++ b/qobject/qdict.c
> @@ -477,6 +477,40 @@ static void qdict_destroy_obj(QObject *obj)
>       g_free(qdict);
>   }
>   
> +/**
> + * qdict_copy_default(): If no entry mapped by 'key' exists in 'dst' yet, the
> + * value of 'key' in 'src' is copied there (and the refcount increased
> + * accordingly).
> + */
> +void qdict_copy_default(QDict *dst, QDict *src, const char *key)
> +{
> +    QObject *val;
> +
> +    if (qdict_haskey(dst, key)) {
> +        return;
> +    }
> +
> +    val = qdict_get(src, key);
> +    if (val) {
> +        qobject_incref(val);
> +        qdict_put_obj(dst, key, val);
> +    }
> +}
> +
> +/**
> + * qdict_set_default_str(): If no entry mapped by 'key' exists in 'dst' yet,
> + * 'val' is put there, with the QDict taking the reference. Otherwise, the
> + * refcount of 'val' is decreased.

With the comment fixed:

Reviewed-by: Max Reitz <mreitz@redhat.com>

> + */
> +void qdict_set_default_str(QDict *dst, const char *key, const char *val)
> +{
> +    if (qdict_haskey(dst, key)) {
> +        return;
> +    }
> +
> +    qdict_put(dst, key, qstring_from_str(val));
> +}
> +
>   static void qdict_flatten_qdict(QDict *qdict, QDict *target,
>                                   const char *prefix);
>   

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 03/34] quorum: Use bdrv_open_image()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 03/34] quorum: Use bdrv_open_image() Kevin Wolf
  2015-05-08 21:33   ` Eric Blake
@ 2015-05-11 14:27   ` Max Reitz
  2015-05-12 19:07   ` [Qemu-devel] [Qemu-block] " Jeff Cody
  2015-05-20 14:46   ` Alberto Garcia
  3 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 14:27 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Besides standardising on a single interface for opening child nodes,
> this simplifies the .bdrv_open() implementation of the quorum block
> driver by using block layer functionality for handling BlockdevRefs.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block/quorum.c | 51 +++++++++++----------------------------------------
>   1 file changed, 11 insertions(+), 40 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 04/34] vmdk: Use bdrv_open_image()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 04/34] vmdk: " Kevin Wolf
  2015-05-08 22:00   ` Eric Blake
@ 2015-05-11 14:35   ` Max Reitz
  2015-05-12 19:12   ` [Qemu-devel] [Qemu-block] " Jeff Cody
  2 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 14:35 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Besides standardising on a single interface for opening child nodes,
> this patch allows the user to specify options to individual extent
> nodes. Overriding file names isn't possible with this yet, so it's of
> limited usefulness, but still a step forward.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block/vmdk.c | 34 +++++++++++++++++++++-------------
>   1 file changed, 21 insertions(+), 13 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names Kevin Wolf
  2015-05-08 22:54   ` Eric Blake
@ 2015-05-11 14:40   ` Max Reitz
  2015-05-11 14:51     ` Kevin Wolf
  2015-05-11 15:00   ` Max Reitz
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 130+ messages in thread
From: Max Reitz @ 2015-05-11 14:40 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   blockdev.c            | 24 ++++++++++++------------
>   include/block/block.h |  8 ++++++++
>   2 files changed, 20 insertions(+), 12 deletions(-)

Any reason for not making it part of the BLOCK_OPT_* macros in block_int.h?

Max

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries()
  2015-05-08 20:06   ` Eric Blake
  2015-05-08 21:22     ` Eric Blake
@ 2015-05-11 14:40     ` Kevin Wolf
  2015-05-11 15:28       ` Eric Blake
  2015-05-20 14:19     ` [Qemu-devel] [Qemu-block] " Alberto Garcia
  2 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-11 14:40 UTC (permalink / raw)
  To: Eric Blake; +Cc: mreitz, qemu-devel, qemu-block, armbru

[-- Attachment #1: Type: text/plain, Size: 3210 bytes --]

Am 08.05.2015 um 22:06 hat Eric Blake geschrieben:
> On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > ---
> 
> Might want to include mention of what it will be used for in the commit
> body.

You're right. This is the new commit message:

    This counts the entries in a flattened array in a QDict without
    actually splitting the QDict into a QList.

    bdrv_open_image() doesn't take a QList, but rather a QDict and a key
    prefix string, so this is more convenient for block drivers which have a
    dynamically sized list of child nodes (e.g. Quorum) and are to be
    converted to using bdrv_open_image() as the standard interface for
    opening child nodes.

> >  include/qapi/qmp/qdict.h |  1 +
> >  qobject/qdict.c          | 68 +++++++++++++++++++++++++++++++++++++++++++++---
> >  2 files changed, 65 insertions(+), 4 deletions(-)
> > 
> 
> > @@ -646,7 +647,7 @@ void qdict_array_split(QDict *src, QList **dst)
> >          snprintf_ret = snprintf(prefix, 32, "%u.", i);
> >          assert(snprintf_ret < 32);
> >  
> > -        is_subqdict = qdict_has_prefixed_entries(src, prefix);
> > +        is_subqdict = qdict_count_prefixed_entries(src, prefix);
> 
> Good thing we require a C99 compiler, where 'bool = int' does the right
> thing for integers > 1.
> 
> >  /**
> > + * qdict_array_valid(): Returns the number of direct array entries if the
> > + * sub-QDict of src specified by the prefix in subqdict (or src itself for
> > + * prefix == "") is valid as an array, i.e. the length of the created list if
> > + * the sub-QDict would become empty after calling qdict_array_split() on it. If
> > + * the array is not valid, -1 is returned.
> > + */
> > +int qdict_array_entries(QDict *src, const char *subqdict)
> 
> Comment doesn't match function name.

Thanks, fixed.

> > +{
> > +    const QDictEntry *entry;
> > +    unsigned i;
> > +    unsigned entries = 0;
> > +    size_t subqdict_len = strlen(subqdict);
> > +
> > +    assert(!subqdict_len || subqdict[subqdict_len - 1] == '.');
> > +
> > +    for (i = 0; i < UINT_MAX; i++) {
> > +        QObject *subqobj;
> > +        int subqdict_entries;
> > +        size_t slen = 32 + subqdict_len;
> > +        char indexstr[slen], prefix[slen];
> 
> And more dependence on a working C99 compiler, thanks to variable length
> array (VLA).
> 
> > +        size_t snprintf_ret;
> > +
> > +        snprintf_ret = snprintf(indexstr, slen, "%s%u", subqdict, i);
> > +        assert(snprintf_ret < slen);
> 
> Since gcc may compile the allocation of indexstr into a malloc()
> anyways, would it be any simpler to just use g_strdup_printf() directly,
> instead of futzing around with VLA and snprintf() ourselves?  It might
> mean less code, as some of the error checking is taken care of on your
> behalf.

This code parallels the code in qdict_array_split(), which looks almos
the same, except that the latter doesn't support subqict and therefore
has a fixed-size array rather than a VLA.

If you think that g_strdup_printf() is preferable, I would do that on
top of this series and change both functions.

Kevin

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names
  2015-05-11 14:40   ` Max Reitz
@ 2015-05-11 14:51     ` Kevin Wolf
  2015-05-11 14:59       ` Max Reitz
  0 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-11 14:51 UTC (permalink / raw)
  To: Max Reitz; +Cc: armbru, qemu-block, qemu-devel

Am 11.05.2015 um 16:40 hat Max Reitz geschrieben:
> On 08.05.2015 19:21, Kevin Wolf wrote:
> >Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> >---
> >  blockdev.c            | 24 ++++++++++++------------
> >  include/block/block.h |  8 ++++++++
> >  2 files changed, 20 insertions(+), 12 deletions(-)
> 
> Any reason for not making it part of the BLOCK_OPT_* macros in block_int.h?

Those aren't bdrv_open(), but bdrv_create() options, which should be
abundantly clear from the fact that they start in BLOCK instead of BDRV.
*cough*

I guess I can move the new options to block_int.h indeed, but when it
comes to renaming to make the difference clearer, I think I'd prefer
renaming the create options.

Any opinions on that?

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 06/34] block: Use QemuOpts in bdrv_open_common()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 06/34] block: Use QemuOpts in bdrv_open_common() Kevin Wolf
  2015-05-08 22:57   ` Eric Blake
@ 2015-05-11 14:57   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 14:57 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Instead of manually parsing options and then deleting them from the
> options QDict, just use QemuOpts like most other places that deal with
> block device options.
>
> More options will be added there and then QemuOpts is a lot more
> managable than open-coding everything.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c | 37 ++++++++++++++++++++++++++++++++-----
>   1 file changed, 32 insertions(+), 5 deletions(-)
>
> diff --git a/block.c b/block.c
> index 7904098..cea022f 100644
> --- a/block.c
> +++ b/block.c
> @@ -757,6 +757,19 @@ static void bdrv_assign_node_name(BlockDriverState *bs,
>       QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list);
>   }
>   
> +static QemuOptsList bdrv_runtime_opts = {
> +    .name = "bdrv_common",
> +    .head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head),
> +    .desc = {
> +        {
> +            .name = "node-name",
> +            .type = QEMU_OPT_STRING,
> +            .help = "Node name of the block device node",
> +        },
> +        { /* end of list */ }
> +    },
> +};
> +
>   /*
>    * Common part for opening disk images and files
>    *
> @@ -768,6 +781,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
>       int ret, open_flags;
>       const char *filename;
>       const char *node_name = NULL;
> +    QemuOpts *opts;
>       Error *local_err = NULL;
>   
>       assert(drv != NULL);
> @@ -788,19 +802,28 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
>   
>       trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
>   
> -    node_name = qdict_get_try_str(options, "node-name");
> +    opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
> +    qemu_opts_absorb_qdict(opts, options, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        ret = -EINVAL;
> +        goto fail_opts;
> +    }
> +
> +    node_name = qemu_opt_get(opts, "node-name");
>       bdrv_assign_node_name(bs, node_name, &local_err);
>       if (local_err) {
>           error_propagate(errp, local_err);
> -        return -EINVAL;
> +        ret = -EINVAL;
> +        goto fail_opts;
>       }
> -    qdict_del(options, "node-name");
>   
>       /* bdrv_open() with directly using a protocol as drv. This layer is already
>        * opened, so assign it to bs (while file becomes a closed BlockDriverState)
>        * and return immediately. */
>       if (file != NULL && drv->bdrv_file_open) {
>           bdrv_swap(file, bs);
> +        qemu_opts_del(opts);
>           return 0;
>       }
>   
> @@ -817,7 +840,8 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
>                           ? "Driver '%s' can only be used for read-only devices"
>                           : "Driver '%s' is not whitelisted",
>                      drv->format_name);
> -        return -ENOTSUP;
> +        ret = -ENOTSUP;
> +        goto fail_opts;
>       }
>   
>       assert(bs->copy_on_read == 0); /* bdrv_new() and bdrv_close() make it so */
> @@ -826,7 +850,8 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
>               bdrv_enable_copy_on_read(bs);
>           } else {
>               error_setg(errp, "Can't use copy-on-read on read-only device");
> -            return -EINVAL;
> +            ret = -EINVAL;
> +            goto fail_opts;
>           }
>       }
>   
> @@ -898,6 +923,8 @@ free_and_fail:

"opts" seems to be leaked in case of success.

Max

>       g_free(bs->opaque);
>       bs->opaque = NULL;
>       bs->drv = NULL;
> +fail_opts:
> +    qemu_opts_del(opts);
>       return ret;
>   }
>   

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names
  2015-05-11 14:51     ` Kevin Wolf
@ 2015-05-11 14:59       ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 14:59 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: armbru, qemu-block, qemu-devel

On 11.05.2015 16:51, Kevin Wolf wrote:
> Am 11.05.2015 um 16:40 hat Max Reitz geschrieben:
>> On 08.05.2015 19:21, Kevin Wolf wrote:
>>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>>> ---
>>>   blockdev.c            | 24 ++++++++++++------------
>>>   include/block/block.h |  8 ++++++++
>>>   2 files changed, 20 insertions(+), 12 deletions(-)
>> Any reason for not making it part of the BLOCK_OPT_* macros in block_int.h?
> Those aren't bdrv_open(), but bdrv_create() options, which should be
> abundantly clear from the fact that they start in BLOCK instead of BDRV.
> *cough*

Oh, right, how could I have missed that. *cough cough*

> I guess I can move the new options to block_int.h indeed, but when it
> comes to renaming to make the difference clearer, I think I'd prefer
> renaming the create options.

Sounds good to me. Also, block.h is a more appropriate place, 
considering this is not an internal option of the block layer, but 
something for the outer interface.

Max

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names Kevin Wolf
  2015-05-08 22:54   ` Eric Blake
  2015-05-11 14:40   ` Max Reitz
@ 2015-05-11 15:00   ` Max Reitz
  2015-05-12 19:14   ` [Qemu-devel] [Qemu-block] " Jeff Cody
  2015-05-20 14:49   ` Alberto Garcia
  4 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 15:00 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   blockdev.c            | 24 ++++++++++++------------
>   include/block/block.h |  8 ++++++++
>   2 files changed, 20 insertions(+), 12 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 07/34] block: Move flag inheritance to bdrv_open_inherited()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 07/34] block: Move flag inheritance to bdrv_open_inherited() Kevin Wolf
  2015-05-08 23:20   ` Eric Blake
@ 2015-05-11 15:20   ` Max Reitz
  2015-05-12 13:32     ` Kevin Wolf
  2015-05-28 11:10   ` Wen Congyang
  2 siblings, 1 reply; 130+ messages in thread
From: Max Reitz @ 2015-05-11 15:20 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Instead of letting every caller of bdrv_open() determine the right flags
> for its child node manually and pass them to the function, pass the
> parent node and the role of the newly opened child (like backing file,
> protocol layer, etc.).
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c                   | 74 ++++++++++++++++++++++++++++++++++++++---------
>   block/blkdebug.c          |  2 +-
>   block/blkverify.c         |  4 +--
>   block/quorum.c            |  4 +--
>   block/vmdk.c              |  5 ++--
>   include/block/block.h     |  4 ++-
>   include/block/block_int.h |  7 +++++
>   7 files changed, 78 insertions(+), 22 deletions(-)
>
> diff --git a/block.c b/block.c
> index cea022f..c4f0fb4 100644
> --- a/block.c
> +++ b/block.c
> @@ -79,6 +79,12 @@ static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
>   static QLIST_HEAD(, BlockDriver) bdrv_drivers =
>       QLIST_HEAD_INITIALIZER(bdrv_drivers);
>   
> +static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
> +                             const char *reference, QDict *options, int flags,
> +                             BlockDriverState* parent,

Stern zur Variable!

> +                             const BdrvChildRole *child_role,
> +                             BlockDriver *drv, Error **errp);
> +
>   static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
>   /* If non-zero, use only whitelisted block drivers */
>   static int use_bdrv_whitelist;
> @@ -672,8 +678,8 @@ static int bdrv_temp_snapshot_flags(int flags)
>   }
>   
>   /*
> - * Returns the flags that bs->file should get, based on the given flags for
> - * the parent BDS
> + * Returns the flags that bs->file should get if a protocol driver is expected,
> + * based on the given flags for the parent BDS
>    */
>   static int bdrv_inherited_flags(int flags)
>   {
> @@ -690,6 +696,25 @@ static int bdrv_inherited_flags(int flags)
>       return flags;
>   }
>   
> +const BdrvChildRole child_file = {
> +    .inherit_flags = bdrv_inherited_flags,
> +};
> +
> +/*
> + * Returns the flags that bs->file should get if the use of formats (and not
> + * only protocols) is permitted for it, based on the given flags for the parent
> + * BDS
> + */
> +static int bdrv_inherited_fmt_flags(int parent_flags)
> +{
> +    int flags = child_file.inherit_flags(parent_flags);
> +    return flags & ~BDRV_O_PROTOCOL;
> +}
> +
> +const BdrvChildRole child_format = {
> +    .inherit_flags = bdrv_inherited_fmt_flags,
> +};
> +
>   /*
>    * Returns the flags that bs->backing_hd should get, based on the given flags
>    * for the parent BDS
> @@ -705,6 +730,10 @@ static int bdrv_backing_flags(int flags)
>       return flags;
>   }
>   
> +static const BdrvChildRole child_backing = {
> +    .inherit_flags = bdrv_backing_flags,
> +};
> +
>   static int bdrv_open_flags(BlockDriverState *bs, int flags)
>   {
>       int open_flags = flags | BDRV_O_CACHE_WB;
> @@ -827,7 +856,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
>           return 0;
>       }
>   
> -    bs->open_flags = flags;
>       bs->guest_block_size = 512;
>       bs->request_alignment = 512;
>       bs->zero_beyond_eof = true;
> @@ -1134,9 +1162,10 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
>       }
>   
>       assert(bs->backing_hd == NULL);
> -    ret = bdrv_open(&backing_hd,
> -                    *backing_filename ? backing_filename : NULL, NULL, options,
> -                    bdrv_backing_flags(bs->open_flags), NULL, &local_err);
> +    ret = bdrv_open_inherit(&backing_hd,
> +                            *backing_filename ? backing_filename : NULL,
> +                            NULL, options, 0, bs, &child_backing,
> +                            NULL, &local_err);
>       if (ret < 0) {
>           bdrv_unref(backing_hd);
>           backing_hd = NULL;
> @@ -1170,7 +1199,8 @@ free_exit:
>    * To conform with the behavior of bdrv_open(), *pbs has to be NULL.
>    */
>   int bdrv_open_image(BlockDriverState **pbs, const char *filename,
> -                    QDict *options, const char *bdref_key, int flags,
> +                    QDict *options, const char *bdref_key,
> +                    BlockDriverState* parent, const BdrvChildRole *child_role,

!

>                       bool allow_none, Error **errp)
>   {
>       QDict *image_options;
> @@ -1198,7 +1228,8 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
>           goto done;
>       }
>   
> -    ret = bdrv_open(pbs, filename, reference, image_options, flags, NULL, errp);
> +    ret = bdrv_open_inherit(pbs, filename, reference, image_options, 0,
> +                            parent, child_role, NULL, errp);
>   
>   done:
>       qdict_del(options, bdref_key);
> @@ -1285,9 +1316,11 @@ out:
>    * should be opened. If specified, neither options nor a filename may be given,
>    * nor can an existing BDS be reused (that is, *pbs has to be NULL).
>    */
> -int bdrv_open(BlockDriverState **pbs, const char *filename,
> -              const char *reference, QDict *options, int flags,
> -              BlockDriver *drv, Error **errp)
> +static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
> +                             const char *reference, QDict *options, int flags,
> +                             BlockDriverState* parent,

Faithfully following the forward declaration, so the same issue here.

Other than these nitpicks:

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries()
  2015-05-11 14:40     ` Kevin Wolf
@ 2015-05-11 15:28       ` Eric Blake
  0 siblings, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-11 15:28 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: mreitz, qemu-devel, qemu-block, armbru

[-- Attachment #1: Type: text/plain, Size: 1302 bytes --]

On 05/11/2015 08:40 AM, Kevin Wolf wrote:

>>> +        char indexstr[slen], prefix[slen];
>>
>> And more dependence on a working C99 compiler, thanks to variable length
>> array (VLA).
>>
>>> +        size_t snprintf_ret;
>>> +
>>> +        snprintf_ret = snprintf(indexstr, slen, "%s%u", subqdict, i);
>>> +        assert(snprintf_ret < slen);
>>
>> Since gcc may compile the allocation of indexstr into a malloc()
>> anyways, would it be any simpler to just use g_strdup_printf() directly,
>> instead of futzing around with VLA and snprintf() ourselves?  It might
>> mean less code, as some of the error checking is taken care of on your
>> behalf.
> 
> This code parallels the code in qdict_array_split(), which looks almos
> the same, except that the latter doesn't support subqict and therefore
> has a fixed-size array rather than a VLA.
> 
> If you think that g_strdup_printf() is preferable, I would do that on
> top of this series and change both functions.

I'm not strongly opposed to keeping snprintf, but agree that if you want
to clean it up to g_strdup_printf(), a separate patch hitting multiple
uses would be cleaner than respinning this patch.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState Kevin Wolf
  2015-05-08 23:34   ` Eric Blake
@ 2015-05-11 15:45   ` Max Reitz
  2015-05-12 14:23     ` Kevin Wolf
  2015-06-10 12:09     ` Kevin Wolf
  2015-05-27 11:30   ` Kevin Wolf
  2 siblings, 2 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 15:45 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> This allows iterating over all children of a given BDS, not only
> including bs->file and bs->backing_hd, but also driver-specific
> ones like VMDK extents or Quorum children.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c                   | 27 +++++++++++++++++++++++++++
>   include/block/block_int.h |  8 ++++++++
>   2 files changed, 35 insertions(+)
>
> diff --git a/block.c b/block.c
> index c4f0fb4..59f54ed 100644
> --- a/block.c
> +++ b/block.c
> @@ -1301,6 +1301,19 @@ out:
>       return ret;
>   }
>   
> +static void bdrv_attach_child(BlockDriverState *parent_bs,
> +                              BlockDriverState *child_bs,
> +                              const BdrvChildRole *child_role)
> +{
> +    BdrvChild *child = g_new(BdrvChild, 1);
> +    *child = (BdrvChild) {
> +        .bs     = child_bs,
> +        .role   = child_role,
> +    };
> +
> +    QLIST_INSERT_HEAD(&parent_bs->children, child, next);
> +}
> +
>   /*
>    * Opens a disk image (raw, qcow2, vmdk, ...)
>    *
> @@ -1353,6 +1366,9 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>               return -ENODEV;
>           }
>           bdrv_ref(bs);
> +        if (child_role) {
> +            bdrv_attach_child(parent, bs, child_role);
> +        }
>           *pbs = bs;
>           return 0;
>       }
> @@ -1495,6 +1511,10 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>           goto close_and_fail;
>       }
>   
> +    if (child_role) {
> +        bdrv_attach_child(parent, bs, child_role);
> +    }
> +
>       QDECREF(options);
>       *pbs = bs;
>       return 0;
> @@ -1789,6 +1809,12 @@ void bdrv_close(BlockDriverState *bs)
>       notifier_list_notify(&bs->close_notifiers, bs);
>   
>       if (bs->drv) {
> +        BdrvChild *child, *next;
> +
> +        QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
> +            g_free(child);
> +        }
> +

Not considering the case where the child is closed before the parent 
assumes all children are reference-counted from the parent and they 
won't be closed (and maybe replaced with another BDS) on purpose. The 
first seems reasonable, the second one I'm not so sure about. It works 
for now, but I could imagine that we want to modify children of a Quorum 
instance at runtime.

But I can't imagine any case where this would break right now, so I 
guess I'm fine with it.

>           if (bs->backing_hd) {
>               BlockDriverState *backing_hd = bs->backing_hd;
>               bdrv_set_backing_hd(bs, NULL);
> @@ -1999,6 +2025,7 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
>       /* The contents of 'tmp' will become bs_top, as we are
>        * swapping bs_new and bs_top contents. */
>       bdrv_set_backing_hd(bs_top, bs_new);
> +    bdrv_attach_child(bs_top, bs_new, &child_backing);
>   }
>   
>   static void bdrv_delete(BlockDriverState *bs)

Using a mirror block job, we can force bdrv_swap() on arbitrary nodes, 
right? What happens if you swap e.g. a VMDK and a quorum node? Well, 
maybe one simply cannot swap a quorum node due to blockers, but I guess 
one can swap a VMDK node with some non-VMDK node. It is actually correct 
to leave the extents behind; but the other node cannot do anything with 
them, so because they are part of the opaque VMDK structure, they will 
de-facto remain with VMDK, while being counted as children of the other 
node. But I try to keep so far away from bdrv_swap() that I don't even 
know whether this case is even possible.

Max

> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index eb01ea2..12c7fb3 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -334,6 +334,12 @@ struct BdrvChildRole {
>   extern const BdrvChildRole child_file;
>   extern const BdrvChildRole child_format;
>   
> +typedef struct BdrvChild {
> +    BlockDriverState *bs;
> +    const BdrvChildRole *role;
> +    QLIST_ENTRY(BdrvChild) next;
> +} BdrvChild;
> +
>   /*
>    * Note: the function bdrv_append() copies and swaps contents of
>    * BlockDriverStates, so if you add new fields to this struct, please
> @@ -428,6 +434,8 @@ struct BlockDriverState {
>       /* long-running background operation */
>       BlockJob *job;
>   
> +    QLIST_HEAD(, BdrvChild) children;
> +
>       QDict *options;
>       BlockdevDetectZeroesOptions detect_zeroes;
>   

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 09/34] block: Add BlockDriverState.inherits_from
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 09/34] block: Add BlockDriverState.inherits_from Kevin Wolf
  2015-05-08 23:39   ` Eric Blake
@ 2015-05-11 15:50   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 15:50 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Currently, the block layer assumes that any block node can have only one
> parent, and if it has a parent, that it inherits some options/flags from
> this parent.
>
> This is not true any more: With references used in block device
> creation, a single node can be used by multiple parents, or it can be
> created separately and not inherit flags from any parent.
>
> To handle reopens correctly, a node must know from which parent it
> inherited options. This patch adds the information to BlockDriverState.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c                   | 17 +++++++++++++++++
>   include/block/block_int.h |  4 ++++
>   2 files changed, 21 insertions(+)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 10/34] block: Fix reopen flag inheritance
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 10/34] block: Fix reopen flag inheritance Kevin Wolf
@ 2015-05-11 16:04   ` Max Reitz
  2015-05-12 14:32   ` Eric Blake
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 16:04 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> When reopening an image, the block layer already takes care to reopen
> bs->file as well with recalculated inherited flags. The same must happen
> for any other child (most notably missing before this patch: backing
> files).
>
> If bs->file (or any other child) didn't originally inherit from bs, e.g.
> because it was created separately and then only referenced, it must not
> inherit flags on reopen either, so check the inherited_from field before
> propagation the reopen down.
>
> VMDK already reopened its extents manually; this code can now be
> dropped.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c      | 13 +++++++++++--
>   block/vmdk.c | 28 ++--------------------------
>   2 files changed, 13 insertions(+), 28 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 11/34] block: Allow references for backing files
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 11/34] block: Allow references for backing files Kevin Wolf
@ 2015-05-11 16:19   ` Max Reitz
  2015-05-12 14:46   ` Eric Blake
  2015-05-21  5:47   ` Wen Congyang
  2 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 16:19 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> For bs->file, using references to existing BDSes has been possible for a
> while already. This patch enables the same for bs->backing_hd.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c               | 42 ++++++++++++++++++++++++------------------
>   block/mirror.c        |  2 +-
>   include/block/block.h |  3 ++-
>   3 files changed, 27 insertions(+), 20 deletions(-)
>
> diff --git a/block.c b/block.c
> index e93bf63..95dc51e 100644
> --- a/block.c
> +++ b/block.c
> @@ -1109,30 +1109,41 @@ out:
>   /*
>    * Opens the backing file for a BlockDriverState if not yet open
>    *
> - * options is a QDict of options to pass to the block drivers, or NULL for an
> - * empty set of options. The reference to the QDict is transferred to this
> - * function (even on failure), so if the caller intends to reuse the dictionary,
> - * it needs to use QINCREF() before calling bdrv_file_open.
> + * bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
> + * That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
> + * itself, all options starting with "${bdref_key}." are considered part of the
> + * BlockdevRef.
> + *
> + * TODO Can this be unified with bdrv_open_image()?
>    */
> -int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
> +int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
> +                           const char *bdref_key, Error **errp)
>   {
>       char *backing_filename = g_malloc0(PATH_MAX);
> +    char *bdref_key_dot;
> +    const char *reference = NULL;
>       int ret = 0;
>       BlockDriverState *backing_hd;
> +    QDict *options;
>       Error *local_err = NULL;
>   
>       if (bs->backing_hd != NULL) {
> -        QDECREF(options);
>           goto free_exit;
>       }
>   
>       /* NULL means an empty set of options */
> -    if (options == NULL) {
> -        options = qdict_new();
> +    if (parent_options == NULL) {
> +        parent_options = qdict_new();

If parent_options is created here, it's leaked.

Max

>       }
>   
>       bs->open_flags &= ~BDRV_O_NO_BACKING;
> -    if (qdict_haskey(options, "file.filename")) {
> +
> +    bdref_key_dot = g_strdup_printf("%s.", bdref_key);
> +    qdict_extract_subqdict(parent_options, &options, bdref_key_dot);
> +    g_free(bdref_key_dot);
> +
> +    reference = qdict_get_try_str(parent_options, bdref_key);
> +    if (reference || qdict_haskey(options, "file.filename")) {
>           backing_filename[0] = '\0';
>       } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
>           QDECREF(options);
> @@ -1155,20 +1166,17 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
>           goto free_exit;
>       }
>   
> -    backing_hd = bdrv_new();
> -
>       if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
>           qdict_put(options, "driver", qstring_from_str(bs->backing_format));
>       }
>   
>       assert(bs->backing_hd == NULL);
> +    backing_hd = NULL;
>       ret = bdrv_open_inherit(&backing_hd,
>                               *backing_filename ? backing_filename : NULL,
> -                            NULL, options, 0, bs, &child_backing,
> +                            reference, options, 0, bs, &child_backing,
>                               NULL, &local_err);
>       if (ret < 0) {
> -        bdrv_unref(backing_hd);
> -        backing_hd = NULL;
>           bs->open_flags |= BDRV_O_NO_BACKING;
>           error_setg(errp, "Could not open backing file: %s",
>                      error_get_pretty(local_err));
> @@ -1176,6 +1184,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
>           goto free_exit;
>       }
>       bdrv_set_backing_hd(bs, backing_hd);
> +    qdict_del(parent_options, bdref_key);
>   
>   free_exit:
>       g_free(backing_filename);
> @@ -1463,10 +1472,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>   
>       /* If there is a backing file, use it */
>       if ((flags & BDRV_O_NO_BACKING) == 0) {
> -        QDict *backing_options;
> -
> -        qdict_extract_subqdict(options, &backing_options, "backing.");
> -        ret = bdrv_open_backing_file(bs, backing_options, &local_err);
> +        ret = bdrv_open_backing_file(bs, options, "backing", &local_err);
>           if (ret < 0) {
>               goto close_and_fail;
>           }
> diff --git a/block/mirror.c b/block/mirror.c
> index 58f391a..f1bc342 100644
> --- a/block/mirror.c
> +++ b/block/mirror.c
> @@ -592,7 +592,7 @@ static void mirror_complete(BlockJob *job, Error **errp)
>       Error *local_err = NULL;
>       int ret;
>   
> -    ret = bdrv_open_backing_file(s->target, NULL, &local_err);
> +    ret = bdrv_open_backing_file(s->target, NULL, "backing", &local_err);
>       if (ret < 0) {
>           error_propagate(errp, local_err);
>           return;
> diff --git a/include/block/block.h b/include/block/block.h
> index 27ab2c8..341a551 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -208,7 +208,8 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
>                       BlockDriverState* parent, const BdrvChildRole *child_role,
>                       bool allow_none, Error **errp);
>   void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
> -int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
> +int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
> +                           const char *bdref_key, Error **errp);
>   int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp);
>   int bdrv_open(BlockDriverState **pbs, const char *filename,
>                 const char *reference, QDict *options, int flags,

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 12/34] block: Allow specifying driver-specific options to reopen
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 12/34] block: Allow specifying driver-specific options to reopen Kevin Wolf
@ 2015-05-11 16:35   ` Max Reitz
  2015-05-12 14:59   ` Eric Blake
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 16:35 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c               | 42 +++++++++++++++++++++++++++++++++++++++---
>   block/commit.c        |  4 ++--
>   include/block/block.h |  4 +++-
>   3 files changed, 44 insertions(+), 6 deletions(-)
>
> diff --git a/block.c b/block.c
> index 95dc51e..561cefd 100644
> --- a/block.c
> +++ b/block.c
> @@ -1584,6 +1584,9 @@ typedef struct BlockReopenQueueEntry {
>    *
>    * bs is the BlockDriverState to add to the reopen queue.
>    *
> + * options contains the changed options for the associated bs
> + * (the BlockReopenQueue takes the ownership)
> + *
>    * flags contains the open flags for the associated bs
>    *
>    * returns a pointer to bs_queue, which is either the newly allocated
> @@ -1591,18 +1594,28 @@ typedef struct BlockReopenQueueEntry {
>    *
>    */
>   BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
> -                                    BlockDriverState *bs, int flags)
> +                                    BlockDriverState *bs,
> +                                    QDict *options, int flags)
>   {
>       assert(bs != NULL);
>   
>       BlockReopenQueueEntry *bs_entry;
>       BdrvChild *child;
> +    QDict *old_options;
>   
>       if (bs_queue == NULL) {
>           bs_queue = g_new0(BlockReopenQueue, 1);
>           QSIMPLEQ_INIT(bs_queue);
>       }
>   
> +    if (!options) {
> +        options = qdict_new();
> +    }
> +
> +    old_options = qdict_clone_shallow(bs->options);
> +    qdict_join(options, old_options, false);
> +    QDECREF(old_options);
> +
>       /* bdrv_open() masks this flag out */
>       flags &= ~BDRV_O_PROTOCOL;
>   
> @@ -1614,13 +1627,15 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
>           }
>   
>           child_flags = child->role->inherit_flags(flags);
> -        bdrv_reopen_queue(bs_queue, child->bs, child_flags);
> +        /* TODO Pass down child flags (backing.*, extents.*, ...) */
> +        bdrv_reopen_queue(bs_queue, child->bs, NULL, child_flags);
>       }
>   
>       bs_entry = g_new0(BlockReopenQueueEntry, 1);
>       QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry);
>   
>       bs_entry->state.bs = bs;
> +    bs_entry->state.options = options;
>       bs_entry->state.flags = flags;
>   
>       return bs_queue;
> @@ -1673,6 +1688,7 @@ cleanup:
>           if (ret && bs_entry->prepared) {
>               bdrv_reopen_abort(&bs_entry->state);
>           }
> +        QDECREF(bs_entry->state.options);
>           g_free(bs_entry);
>       }
>       g_free(bs_queue);
> @@ -1685,7 +1701,7 @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
>   {
>       int ret = -1;
>       Error *local_err = NULL;
> -    BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, bdrv_flags);
> +    BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
>   
>       ret = bdrv_reopen_multiple(queue, &local_err);
>       if (local_err != NULL) {
> @@ -1761,6 +1777,26 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
>           goto error;
>       }
>   
> +    /* Options that are not handled are only okay if they are unchanged
> +     * compared to the old state. It is expected that some options are only
> +     * used for the initial open, but not reopen (e.g. filename) */
> +    if (qdict_size(reopen_state->options)) {
> +        const QDictEntry *entry = qdict_first(reopen_state->options);
> +
> +        do {
> +            QString *new_obj = qobject_to_qstring(entry->value);

Maybe add an assert(new_obj)? If it's NULL, the next qstring_get_str() 
will dereference NULL which is basically just as good, but well...

> +            const char *new = qstring_get_str(new_obj);
> +            const char *old = qdict_get_try_str(reopen_state->bs->options,
> +                                                entry->key);
> +
> +            if (!new != !old || strcmp(new, old)) {

This form implies to me that you expect !new might be true. However, 
assuming that, we might get !new && !old, thus !new == !old and thus 
strcmp(NULL, NULL), which would be bad.

I think !new will never be true. Therefore, I'd rather put this as "if 
(!old || strcmp(new, old))".

> +                error_setg(errp, "Cannot change the option '%s'", entry->key);
> +                ret = -EINVAL;

Hm, well, so far this function generally returned -1 on error, but okay...

I don't see anything truly wrong, though, so with or without assert() 
and the different condition:

Reviewed-by: Max Reitz <mreitz@redhat.com>

> +                goto error;
> +            }
> +        } while ((entry = qdict_next(reopen_state->options, entry)));
> +    }
> +
>       ret = 0;
>   
>   error:
> diff --git a/block/commit.c b/block/commit.c
> index cfa2bbe..2c07d12 100644
> --- a/block/commit.c
> +++ b/block/commit.c
> @@ -235,11 +235,11 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
>   
>       /* convert base & overlay_bs to r/w, if necessary */
>       if (!(orig_base_flags & BDRV_O_RDWR)) {
> -        reopen_queue = bdrv_reopen_queue(reopen_queue, base,
> +        reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
>                                            orig_base_flags | BDRV_O_RDWR);
>       }
>       if (!(orig_overlay_flags & BDRV_O_RDWR)) {
> -        reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs,
> +        reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL,
>                                            orig_overlay_flags | BDRV_O_RDWR);
>       }
>       if (reopen_queue) {
> diff --git a/include/block/block.h b/include/block/block.h
> index 341a551..1287013 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -146,6 +146,7 @@ typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue;
>   typedef struct BDRVReopenState {
>       BlockDriverState *bs;
>       int flags;
> +    QDict *options;
>       void *opaque;
>   } BDRVReopenState;
>   
> @@ -215,7 +216,8 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
>                 const char *reference, QDict *options, int flags,
>                 BlockDriver *drv, Error **errp);
>   BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
> -                                    BlockDriverState *bs, int flags);
> +                                    BlockDriverState *bs,
> +                                    QDict *options, int flags);
>   int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
>   int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp);
>   int bdrv_reopen_prepare(BDRVReopenState *reopen_state,

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 13/34] qemu-io: Add command 'reopen'
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 13/34] qemu-io: Add command 'reopen' Kevin Wolf
@ 2015-05-11 16:50   ` Max Reitz
  2015-05-12 15:05   ` Eric Blake
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-11 16:50 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   qemu-io-cmds.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 71 insertions(+)
>
> diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
> index 1afcfc0..ef8f3fd 100644
> --- a/qemu-io-cmds.c
> +++ b/qemu-io-cmds.c
> @@ -1978,6 +1978,76 @@ static const cmdinfo_t map_cmd = {
>          .oneline        = "prints the allocated areas of a file",
>   };
>   
> +static int reopen_f(BlockBackend *blk, int argc, char **argv);
> +
> +static QemuOptsList reopen_opts = {
> +    .name = "reopen",
> +    .merge_lists = true,
> +    .head = QTAILQ_HEAD_INITIALIZER(reopen_opts.head),
> +    .desc = {
> +        /* no elements => accept any params */
> +        { /* end of list */ }
> +    },
> +};
> +
> +static const cmdinfo_t reopen_cmd = {
> +       .name           = "reopen",
> +       .argmin         = 0,
> +       .argmax         = -1,
> +       .cfunc          = reopen_f,
> +       .args           = "",

Why none? "[-c cache] [-o options] [-r]" would be pretty helpful, I reckon.

> +       .oneline        = "reopens an image with new options",

No .help? Awww. (Fine, as long as .args isn't empty)

> +};
> +
> +static int reopen_f(BlockBackend *blk, int argc, char **argv)
> +{
> +    BlockDriverState *bs = blk_bs(blk);
> +    QemuOpts *qopts;
> +    QDict *opts;
> +    int c;
> +    int flags = bs->open_flags;
> +
> +    BlockReopenQueue *brq;
> +    Error *local_err = NULL;
> +
> +    while ((c = getopt(argc, argv, "c:o:r")) != EOF) {
> +        switch (c) {
> +        case 'c':
> +            if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
> +                error_report("Invalid cache option: %s", optarg);
> +                return 0;
> +            }
> +            break;
> +        case 'o':
> +            if (!qemu_opts_parse(&reopen_opts, optarg, 0)) {
> +                printf("could not parse option list -- %s\n", optarg);
> +                qemu_opts_reset(&reopen_opts);
> +                return 0;
> +            }
> +            break;
> +        case 'r':
> +            flags &= ~BDRV_O_RDWR;
> +            break;
> +        default:
> +            qemu_opts_reset(&reopen_opts);
> +            return qemuio_command_usage(&reopen_cmd);
> +        }
> +    }

Should I be getting an error for "reopen foo", that is, excess arguments?

> +
> +    qopts = qemu_opts_find(&reopen_opts, NULL);
> +    opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
> +    qemu_opts_reset(&reopen_opts);
> +
> +    brq = bdrv_reopen_queue(NULL, bs, opts, flags);
> +    bdrv_reopen_multiple(brq, &local_err);
> +    if (local_err) {
> +        qerror_report_err(local_err);
> +        error_free(local_err);

How about error_report_err() instead?

Max

> +    }
> +
> +    return 0;
> +}
> +
>   static int break_f(BlockBackend *blk, int argc, char **argv)
>   {
>       int ret;
> @@ -2265,6 +2335,7 @@ static void __attribute((constructor)) init_qemuio_commands(void)
>       qemuio_add_command(&discard_cmd);
>       qemuio_add_command(&alloc_cmd);
>       qemuio_add_command(&map_cmd);
> +    qemuio_add_command(&reopen_cmd);
>       qemuio_add_command(&break_cmd);
>       qemuio_add_command(&remove_break_cmd);
>       qemuio_add_command(&resume_cmd);

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 07/34] block: Move flag inheritance to bdrv_open_inherited()
  2015-05-11 15:20   ` Max Reitz
@ 2015-05-12 13:32     ` Kevin Wolf
  0 siblings, 0 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-12 13:32 UTC (permalink / raw)
  To: Max Reitz; +Cc: armbru, qemu-block, qemu-devel

Am 11.05.2015 um 17:20 hat Max Reitz geschrieben:
> On 08.05.2015 19:21, Kevin Wolf wrote:
> >Instead of letting every caller of bdrv_open() determine the right flags
> >for its child node manually and pass them to the function, pass the
> >parent node and the role of the newly opened child (like backing file,
> >protocol layer, etc.).
> >
> >Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> >---
> >  block.c                   | 74 ++++++++++++++++++++++++++++++++++++++---------
> >  block/blkdebug.c          |  2 +-
> >  block/blkverify.c         |  4 +--
> >  block/quorum.c            |  4 +--
> >  block/vmdk.c              |  5 ++--
> >  include/block/block.h     |  4 ++-
> >  include/block/block_int.h |  7 +++++
> >  7 files changed, 78 insertions(+), 22 deletions(-)
> >
> >diff --git a/block.c b/block.c
> >index cea022f..c4f0fb4 100644
> >--- a/block.c
> >+++ b/block.c
> >@@ -79,6 +79,12 @@ static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
> >  static QLIST_HEAD(, BlockDriver) bdrv_drivers =
> >      QLIST_HEAD_INITIALIZER(bdrv_drivers);
> >+static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
> >+                             const char *reference, QDict *options, int flags,
> >+                             BlockDriverState* parent,
> 
> Stern zur Variable!

Okay, now that we're in nitpicking mode:

Zur Variablen, wenn schon.

(Sorry for starting a discussion about German grammar on qemu-devel, but
I just have to...)

> >+                             const BdrvChildRole *child_role,
> >+                             BlockDriver *drv, Error **errp);
> >+
> >  static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
> >  /* If non-zero, use only whitelisted block drivers */
> >  static int use_bdrv_whitelist;
> >@@ -672,8 +678,8 @@ static int bdrv_temp_snapshot_flags(int flags)
> >  }
> >  /*
> >- * Returns the flags that bs->file should get, based on the given flags for
> >- * the parent BDS
> >+ * Returns the flags that bs->file should get if a protocol driver is expected,
> >+ * based on the given flags for the parent BDS
> >   */
> >  static int bdrv_inherited_flags(int flags)
> >  {
> >@@ -690,6 +696,25 @@ static int bdrv_inherited_flags(int flags)
> >      return flags;
> >  }
> >+const BdrvChildRole child_file = {
> >+    .inherit_flags = bdrv_inherited_flags,
> >+};
> >+
> >+/*
> >+ * Returns the flags that bs->file should get if the use of formats (and not
> >+ * only protocols) is permitted for it, based on the given flags for the parent
> >+ * BDS
> >+ */
> >+static int bdrv_inherited_fmt_flags(int parent_flags)
> >+{
> >+    int flags = child_file.inherit_flags(parent_flags);
> >+    return flags & ~BDRV_O_PROTOCOL;
> >+}
> >+
> >+const BdrvChildRole child_format = {
> >+    .inherit_flags = bdrv_inherited_fmt_flags,
> >+};
> >+
> >  /*
> >   * Returns the flags that bs->backing_hd should get, based on the given flags
> >   * for the parent BDS
> >@@ -705,6 +730,10 @@ static int bdrv_backing_flags(int flags)
> >      return flags;
> >  }
> >+static const BdrvChildRole child_backing = {
> >+    .inherit_flags = bdrv_backing_flags,
> >+};
> >+
> >  static int bdrv_open_flags(BlockDriverState *bs, int flags)
> >  {
> >      int open_flags = flags | BDRV_O_CACHE_WB;
> >@@ -827,7 +856,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
> >          return 0;
> >      }
> >-    bs->open_flags = flags;
> >      bs->guest_block_size = 512;
> >      bs->request_alignment = 512;
> >      bs->zero_beyond_eof = true;
> >@@ -1134,9 +1162,10 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
> >      }
> >      assert(bs->backing_hd == NULL);
> >-    ret = bdrv_open(&backing_hd,
> >-                    *backing_filename ? backing_filename : NULL, NULL, options,
> >-                    bdrv_backing_flags(bs->open_flags), NULL, &local_err);
> >+    ret = bdrv_open_inherit(&backing_hd,
> >+                            *backing_filename ? backing_filename : NULL,
> >+                            NULL, options, 0, bs, &child_backing,
> >+                            NULL, &local_err);
> >      if (ret < 0) {
> >          bdrv_unref(backing_hd);
> >          backing_hd = NULL;
> >@@ -1170,7 +1199,8 @@ free_exit:
> >   * To conform with the behavior of bdrv_open(), *pbs has to be NULL.
> >   */
> >  int bdrv_open_image(BlockDriverState **pbs, const char *filename,
> >-                    QDict *options, const char *bdref_key, int flags,
> >+                    QDict *options, const char *bdref_key,
> >+                    BlockDriverState* parent, const BdrvChildRole *child_role,
> 
> !
> 
> >                      bool allow_none, Error **errp)
> >  {
> >      QDict *image_options;
> >@@ -1198,7 +1228,8 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
> >          goto done;
> >      }
> >-    ret = bdrv_open(pbs, filename, reference, image_options, flags, NULL, errp);
> >+    ret = bdrv_open_inherit(pbs, filename, reference, image_options, 0,
> >+                            parent, child_role, NULL, errp);
> >  done:
> >      qdict_del(options, bdref_key);
> >@@ -1285,9 +1316,11 @@ out:
> >   * should be opened. If specified, neither options nor a filename may be given,
> >   * nor can an existing BDS be reused (that is, *pbs has to be NULL).
> >   */
> >-int bdrv_open(BlockDriverState **pbs, const char *filename,
> >-              const char *reference, QDict *options, int flags,
> >-              BlockDriver *drv, Error **errp)
> >+static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
> >+                             const char *reference, QDict *options, int flags,
> >+                             BlockDriverState* parent,
> 
> Faithfully following the forward declaration, so the same issue here.
> 
> Other than these nitpicks:
> 
> Reviewed-by: Max Reitz <mreitz@redhat.com>

Thanks, will fix.

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState
  2015-05-11 15:45   ` Max Reitz
@ 2015-05-12 14:23     ` Kevin Wolf
  2015-06-10 12:09     ` Kevin Wolf
  1 sibling, 0 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-12 14:23 UTC (permalink / raw)
  To: Max Reitz; +Cc: armbru, qemu-block, qemu-devel

Am 11.05.2015 um 17:45 hat Max Reitz geschrieben:
> On 08.05.2015 19:21, Kevin Wolf wrote:
> >This allows iterating over all children of a given BDS, not only
> >including bs->file and bs->backing_hd, but also driver-specific
> >ones like VMDK extents or Quorum children.
> >
> >Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> >---
> >  block.c                   | 27 +++++++++++++++++++++++++++
> >  include/block/block_int.h |  8 ++++++++
> >  2 files changed, 35 insertions(+)
> >
> >diff --git a/block.c b/block.c
> >index c4f0fb4..59f54ed 100644
> >--- a/block.c
> >+++ b/block.c
> >@@ -1301,6 +1301,19 @@ out:
> >      return ret;
> >  }
> >+static void bdrv_attach_child(BlockDriverState *parent_bs,
> >+                              BlockDriverState *child_bs,
> >+                              const BdrvChildRole *child_role)
> >+{
> >+    BdrvChild *child = g_new(BdrvChild, 1);
> >+    *child = (BdrvChild) {
> >+        .bs     = child_bs,
> >+        .role   = child_role,
> >+    };
> >+
> >+    QLIST_INSERT_HEAD(&parent_bs->children, child, next);
> >+}
> >+
> >  /*
> >   * Opens a disk image (raw, qcow2, vmdk, ...)
> >   *
> >@@ -1353,6 +1366,9 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
> >              return -ENODEV;
> >          }
> >          bdrv_ref(bs);
> >+        if (child_role) {
> >+            bdrv_attach_child(parent, bs, child_role);
> >+        }
> >          *pbs = bs;
> >          return 0;
> >      }
> >@@ -1495,6 +1511,10 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
> >          goto close_and_fail;
> >      }
> >+    if (child_role) {
> >+        bdrv_attach_child(parent, bs, child_role);
> >+    }
> >+
> >      QDECREF(options);
> >      *pbs = bs;
> >      return 0;
> >@@ -1789,6 +1809,12 @@ void bdrv_close(BlockDriverState *bs)
> >      notifier_list_notify(&bs->close_notifiers, bs);
> >      if (bs->drv) {
> >+        BdrvChild *child, *next;
> >+
> >+        QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
> >+            g_free(child);
> >+        }
> >+
> 
> Not considering the case where the child is closed before the parent
> assumes all children are reference-counted from the parent and they
> won't be closed (and maybe replaced with another BDS) on purpose.
> The first seems reasonable, the second one I'm not so sure about. It
> works for now, but I could imagine that we want to modify children
> of a Quorum instance at runtime.
> 
> But I can't imagine any case where this would break right now, so I
> guess I'm fine with it.

We don't have that yet, but I suppose to remove a child you would modify
the Quorum node to drop the child reference, which should at the same
time remove it from the children list.

What we currently can do (I think) is replacing a node with another
node. In that case, I thought bdrv_swap() would do the right thing, but
maybe it doesn't.

> >          if (bs->backing_hd) {
> >              BlockDriverState *backing_hd = bs->backing_hd;
> >              bdrv_set_backing_hd(bs, NULL);
> >@@ -1999,6 +2025,7 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
> >      /* The contents of 'tmp' will become bs_top, as we are
> >       * swapping bs_new and bs_top contents. */
> >      bdrv_set_backing_hd(bs_top, bs_new);
> >+    bdrv_attach_child(bs_top, bs_new, &child_backing);
> >  }
> >  static void bdrv_delete(BlockDriverState *bs)
> 
> Using a mirror block job, we can force bdrv_swap() on arbitrary
> nodes, right? What happens if you swap e.g. a VMDK and a quorum
> node? Well, maybe one simply cannot swap a quorum node due to
> blockers, but I guess one can swap a VMDK node with some non-VMDK
> node. It is actually correct to leave the extents behind; but the
> other node cannot do anything with them, so because they are part of
> the opaque VMDK structure, they will de-facto remain with VMDK,
> while being counted as children of the other node. But I try to keep
> so far away from bdrv_swap() that I don't even know whether this
> case is even possible.

I suspect that instead of doing bdrv_attach_child() here, the child list
must be handled in bdrv_move_feature_fields(), so that the swapped BDSes
effectively swap their roles.

bs->inherits_from (next patch) might be similar. I'm not completely sure
yet what the ideal behaviour would be there. Or perhaps just set it to
NULL for both swapped BDSes.

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 10/34] block: Fix reopen flag inheritance
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 10/34] block: Fix reopen flag inheritance Kevin Wolf
  2015-05-11 16:04   ` Max Reitz
@ 2015-05-12 14:32   ` Eric Blake
  1 sibling, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-12 14:32 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 985 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> When reopening an image, the block layer already takes care to reopen
> bs->file as well with recalculated inherited flags. The same must happen
> for any other child (most notably missing before this patch: backing
> files).
> 
> If bs->file (or any other child) didn't originally inherit from bs, e.g.
> because it was created separately and then only referenced, it must not
> inherit flags on reopen either, so check the inherited_from field before
> propagation the reopen down.
> 
> VMDK already reopened its extents manually; this code can now be
> dropped.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c      | 13 +++++++++++--
>  block/vmdk.c | 28 ++--------------------------
>  2 files changed, 13 insertions(+), 28 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 11/34] block: Allow references for backing files
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 11/34] block: Allow references for backing files Kevin Wolf
  2015-05-11 16:19   ` Max Reitz
@ 2015-05-12 14:46   ` Eric Blake
  2015-05-21  5:47   ` Wen Congyang
  2 siblings, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-12 14:46 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 1897 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> For bs->file, using references to existing BDSes has been possible for a
> while already. This patch enables the same for bs->backing_hd.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c               | 42 ++++++++++++++++++++++++------------------
>  block/mirror.c        |  2 +-
>  include/block/block.h |  3 ++-
>  3 files changed, 27 insertions(+), 20 deletions(-)
> 
> diff --git a/block.c b/block.c
> index e93bf63..95dc51e 100644
> --- a/block.c
> +++ b/block.c
> @@ -1109,30 +1109,41 @@ out:
>  /*
>   * Opens the backing file for a BlockDriverState if not yet open
>   *
> - * options is a QDict of options to pass to the block drivers, or NULL for an
> - * empty set of options. The reference to the QDict is transferred to this
> - * function (even on failure), so if the caller intends to reuse the dictionary,
> - * it needs to use QINCREF() before calling bdrv_file_open.
> + * bdrev_key specifies the key for the image's BlockdevRef in the options QDict.

s/bdrev/bdref/

> + * That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
> + * itself, all options starting with "${bdref_key}." are considered part of the
> + * BlockdevRef.
> + *

>  
>      bs->open_flags &= ~BDRV_O_NO_BACKING;
> -    if (qdict_haskey(options, "file.filename")) {
> +
> +    bdref_key_dot = g_strdup_printf("%s.", bdref_key);
> +    qdict_extract_subqdict(parent_options, &options, bdref_key_dot);
> +    g_free(bdref_key_dot);

I wonder if we have a pattern like this frequently enough to make a
wrapper that concatenates the argument for us, instead of having every
caller have to form a temporary concatenation string.  But not something
that affects this patch.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 12/34] block: Allow specifying driver-specific options to reopen
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 12/34] block: Allow specifying driver-specific options to reopen Kevin Wolf
  2015-05-11 16:35   ` Max Reitz
@ 2015-05-12 14:59   ` Eric Blake
  1 sibling, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-12 14:59 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 856 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c               | 42 +++++++++++++++++++++++++++++++++++++++---
>  block/commit.c        |  4 ++--
>  include/block/block.h |  4 +++-
>  3 files changed, 44 insertions(+), 6 deletions(-)
> 
> diff --git a/block.c b/block.c
> index 95dc51e..561cefd 100644
> --- a/block.c
> +++ b/block.c
> @@ -1584,6 +1584,9 @@ typedef struct BlockReopenQueueEntry {
>   *
>   * bs is the BlockDriverState to add to the reopen queue.
>   *
> + * options contains the changed options for the associated bs
> + * (the BlockReopenQueue takes the ownership)

'takes ownership' reads a bit more idiomatically, but what you have is
not wrong.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 13/34] qemu-io: Add command 'reopen'
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 13/34] qemu-io: Add command 'reopen' Kevin Wolf
  2015-05-11 16:50   ` Max Reitz
@ 2015-05-12 15:05   ` Eric Blake
  2015-05-13  8:37     ` Kevin Wolf
  1 sibling, 1 reply; 130+ messages in thread
From: Eric Blake @ 2015-05-12 15:05 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 1406 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  qemu-io-cmds.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 71 insertions(+)
> 

> +
> +    while ((c = getopt(argc, argv, "c:o:r")) != EOF) {

POSIX says getopt() returns -1 at conclusion, and allows EOF to have a
value different than -1.  Thus, this could inf-loop on weird platforms
(does anyone know such a platform?)  But I see you are copying from
other bad examples in the file; so I'll post a trivial patch to fix all
those in one go.

http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html

> +        switch (c) {
> +        case 'c':
> +            if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
> +                error_report("Invalid cache option: %s", optarg);
> +                return 0;
> +            }
> +            break;
> +        case 'o':
> +            if (!qemu_opts_parse(&reopen_opts, optarg, 0)) {
> +                printf("could not parse option list -- %s\n", optarg);

Messages usually have ':', not ' --', when displaying details about the
message on the left.

We aren't very consistent on whether to start messages with lower or
upper case, so you added one of each :)

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 03/34] quorum: Use bdrv_open_image()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 03/34] quorum: Use bdrv_open_image() Kevin Wolf
  2015-05-08 21:33   ` Eric Blake
  2015-05-11 14:27   ` Max Reitz
@ 2015-05-12 19:07   ` Jeff Cody
  2015-05-20 14:46   ` Alberto Garcia
  3 siblings, 0 replies; 130+ messages in thread
From: Jeff Cody @ 2015-05-12 19:07 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: mreitz, qemu-devel, qemu-block, armbru

On Fri, May 08, 2015 at 07:21:35PM +0200, Kevin Wolf wrote:
> Besides standardising on a single interface for opening child nodes,
> this simplifies the .bdrv_open() implementation of the quorum block
> driver by using block layer functionality for handling BlockdevRefs.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/quorum.c | 51 +++++++++++----------------------------------------
>  1 file changed, 11 insertions(+), 40 deletions(-)
> 
> diff --git a/block/quorum.c b/block/quorum.c
> index f91ef75..a33881a 100644
> --- a/block/quorum.c
> +++ b/block/quorum.c
> @@ -866,25 +866,18 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
>      Error *local_err = NULL;
>      QemuOpts *opts = NULL;
>      bool *opened;
> -    QDict *sub = NULL;
> -    QList *list = NULL;
> -    const QListEntry *lentry;
>      int i;
>      int ret = 0;
>  
>      qdict_flatten(options);
> -    qdict_extract_subqdict(options, &sub, "children.");
> -    qdict_array_split(sub, &list);
>  
> -    if (qdict_size(sub)) {
> -        error_setg(&local_err, "Invalid option children.%s",
> -                   qdict_first(sub)->key);
> +    /* count how many different children are present */
> +    s->num_children = qdict_array_entries(options, "children.");
> +    if (s->num_children < 0) {
> +        error_setg(&local_err, "Option children is not a valid array");
>          ret = -EINVAL;
>          goto exit;
>      }
> -
> -    /* count how many different children are present */
> -    s->num_children = qlist_size(list);
>      if (s->num_children < 2) {
>          error_setg(&local_err,
>                     "Number of provided children must be greater than 1");
> @@ -937,37 +930,17 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
>      s->bs = g_new0(BlockDriverState *, s->num_children);
>      opened = g_new0(bool, s->num_children);
>  
> -    for (i = 0, lentry = qlist_first(list); lentry;
> -         lentry = qlist_next(lentry), i++) {
> -        QDict *d;
> -        QString *string;
> -
> -        switch (qobject_type(lentry->value))
> -        {
> -            /* List of options */
> -            case QTYPE_QDICT:
> -                d = qobject_to_qdict(lentry->value);
> -                QINCREF(d);
> -                ret = bdrv_open(&s->bs[i], NULL, NULL, d, flags, NULL,
> -                                &local_err);
> -                break;
> -
> -            /* QMP reference */
> -            case QTYPE_QSTRING:
> -                string = qobject_to_qstring(lentry->value);
> -                ret = bdrv_open(&s->bs[i], NULL, qstring_get_str(string), NULL,
> -                                flags, NULL, &local_err);
> -                break;
> -
> -            default:
> -                error_setg(&local_err, "Specification of child block device %i "
> -                           "is invalid", i);
> -                ret = -EINVAL;
> -        }
> +    for (i = 0; i < s->num_children; i++) {
> +        char indexstr[32];
> +        ret = snprintf(indexstr, 32, "children.%d", i);
> +        assert(ret < 32);
>  
> +        ret = bdrv_open_image(&s->bs[i], NULL, options, indexstr, flags,
> +                              false, &local_err);
>          if (ret < 0) {
>              goto close_exit;
>          }
> +
>          opened[i] = true;
>      }
>  
> @@ -990,8 +963,6 @@ exit:
>      if (local_err) {
>          error_propagate(errp, local_err);
>      }
> -    QDECREF(list);
> -    QDECREF(sub);
>      return ret;
>  }
>  
> -- 
> 1.8.3.1
> 
>

Reviewed-by: Jeff Cody <jcody@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 04/34] vmdk: Use bdrv_open_image()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 04/34] vmdk: " Kevin Wolf
  2015-05-08 22:00   ` Eric Blake
  2015-05-11 14:35   ` Max Reitz
@ 2015-05-12 19:12   ` Jeff Cody
  2 siblings, 0 replies; 130+ messages in thread
From: Jeff Cody @ 2015-05-12 19:12 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: mreitz, qemu-devel, qemu-block, armbru

On Fri, May 08, 2015 at 07:21:36PM +0200, Kevin Wolf wrote:
> Besides standardising on a single interface for opening child nodes,
> this patch allows the user to specify options to individual extent
> nodes. Overriding file names isn't possible with this yet, so it's of
> limited usefulness, but still a step forward.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/vmdk.c | 34 +++++++++++++++++++++-------------
>  1 file changed, 21 insertions(+), 13 deletions(-)
> 
> diff --git a/block/vmdk.c b/block/vmdk.c
> index b66745d..641e026 100644
> --- a/block/vmdk.c
> +++ b/block/vmdk.c
> @@ -543,7 +543,7 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs,
>  }
>  
>  static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
> -                               Error **errp);
> +                               QDict *options, Error **errp);
>  
>  static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset,
>                              Error **errp)
> @@ -582,7 +582,7 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset,
>  
>  static int vmdk_open_vmdk4(BlockDriverState *bs,
>                             BlockDriverState *file,
> -                           int flags, Error **errp)
> +                           int flags, QDict *options, Error **errp)
>  {
>      int ret;
>      uint32_t magic;
> @@ -606,7 +606,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
>              if (!buf) {
>                  return -EINVAL;
>              }
> -            ret = vmdk_open_desc_file(bs, flags, buf, errp);
> +            ret = vmdk_open_desc_file(bs, flags, buf, options, errp);
>              g_free(buf);
>              return ret;
>          }
> @@ -763,7 +763,7 @@ static int vmdk_parse_description(const char *desc, const char *opt_name,
>  /* Open an extent file and append to bs array */
>  static int vmdk_open_sparse(BlockDriverState *bs,
>                              BlockDriverState *file, int flags,
> -                            char *buf, Error **errp)
> +                            char *buf, QDict *options, Error **errp)
>  {
>      uint32_t magic;
>  
> @@ -773,7 +773,7 @@ static int vmdk_open_sparse(BlockDriverState *bs,
>              return vmdk_open_vmfs_sparse(bs, file, flags, errp);
>              break;
>          case VMDK4_MAGIC:
> -            return vmdk_open_vmdk4(bs, file, flags, errp);
> +            return vmdk_open_vmdk4(bs, file, flags, options, errp);
>              break;
>          default:
>              error_setg(errp, "Image not in VMDK format");
> @@ -783,7 +783,8 @@ static int vmdk_open_sparse(BlockDriverState *bs,
>  }
>  
>  static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
> -                              const char *desc_file_path, Error **errp)
> +                              const char *desc_file_path, QDict *options,
> +                              Error **errp)
>  {
>      int ret;
>      int matches;
> @@ -797,6 +798,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
>      BlockDriverState *extent_file;
>      BDRVVmdkState *s = bs->opaque;
>      VmdkExtent *extent;
> +    char extent_opt_prefix[32];
>  
>      while (*p) {
>          /* parse extent line in one of below formats:
> @@ -846,8 +848,13 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
>          extent_path = g_malloc0(PATH_MAX);
>          path_combine(extent_path, PATH_MAX, desc_file_path, fname);
>          extent_file = NULL;
> -        ret = bdrv_open(&extent_file, extent_path, NULL, NULL,
> -                        bs->open_flags | BDRV_O_PROTOCOL, NULL, errp);
> +
> +        ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents);
> +        assert(ret < 32);
> +
> +        ret = bdrv_open_image(&extent_file, extent_path,
> +                              options, extent_opt_prefix,
> +                              bs->open_flags | BDRV_O_PROTOCOL, false, errp);
>          g_free(extent_path);
>          if (ret) {
>              return ret;
> @@ -870,7 +877,8 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
>              if (!buf) {
>                  ret = -EINVAL;
>              } else {
> -                ret = vmdk_open_sparse(bs, extent_file, bs->open_flags, buf, errp);
> +                ret = vmdk_open_sparse(bs, extent_file, bs->open_flags, buf,
> +                                       options, errp);
>              }
>              g_free(buf);
>              if (ret) {
> @@ -898,7 +906,7 @@ next_line:
>  }
>  
>  static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
> -                               Error **errp)
> +                               QDict *options, Error **errp)
>  {
>      int ret;
>      char ct[128];
> @@ -920,7 +928,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
>      }
>      s->create_type = g_strdup(ct);
>      s->desc_offset = 0;
> -    ret = vmdk_parse_extents(buf, bs, bs->file->exact_filename, errp);
> +    ret = vmdk_parse_extents(buf, bs, bs->file->exact_filename, options, errp);
>  exit:
>      return ret;
>  }
> @@ -942,11 +950,11 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
>      switch (magic) {
>          case VMDK3_MAGIC:
>          case VMDK4_MAGIC:
> -            ret = vmdk_open_sparse(bs, bs->file, flags, buf, errp);
> +            ret = vmdk_open_sparse(bs, bs->file, flags, buf, options, errp);
>              s->desc_offset = 0x200;
>              break;
>          default:
> -            ret = vmdk_open_desc_file(bs, flags, buf, errp);
> +            ret = vmdk_open_desc_file(bs, flags, buf, options, errp);
>              break;
>      }
>      if (ret) {
> -- 
> 1.8.3.1
> 
>

Reviewed-by: Jeff Cody <jcody@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 05/34] block: Use macro for cache option names
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names Kevin Wolf
                     ` (2 preceding siblings ...)
  2015-05-11 15:00   ` Max Reitz
@ 2015-05-12 19:14   ` Jeff Cody
  2015-05-20 14:49   ` Alberto Garcia
  4 siblings, 0 replies; 130+ messages in thread
From: Jeff Cody @ 2015-05-12 19:14 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: mreitz, qemu-devel, qemu-block, armbru

On Fri, May 08, 2015 at 07:21:37PM +0200, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  blockdev.c            | 24 ++++++++++++------------
>  include/block/block.h |  8 ++++++++
>  2 files changed, 20 insertions(+), 12 deletions(-)
> 
> diff --git a/blockdev.c b/blockdev.c
> index 5eaf77e..77cbe72 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -391,13 +391,13 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
>          }
>      }
>  
> -    if (qemu_opt_get_bool(opts, "cache.writeback", true)) {
> +    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true)) {
>          bdrv_flags |= BDRV_O_CACHE_WB;
>      }
> -    if (qemu_opt_get_bool(opts, "cache.direct", false)) {
> +    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
>          bdrv_flags |= BDRV_O_NOCACHE;
>      }
> -    if (qemu_opt_get_bool(opts, "cache.no-flush", false)) {
> +    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
>          bdrv_flags |= BDRV_O_NO_FLUSH;
>      }
>  
> @@ -733,16 +733,16 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
>          }
>  
>          /* Specific options take precedence */
> -        if (!qemu_opt_get(all_opts, "cache.writeback")) {
> -            qemu_opt_set_bool(all_opts, "cache.writeback",
> +        if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_WB)) {
> +            qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_WB,
>                                !!(flags & BDRV_O_CACHE_WB), &error_abort);
>          }
> -        if (!qemu_opt_get(all_opts, "cache.direct")) {
> -            qemu_opt_set_bool(all_opts, "cache.direct",
> +        if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_DIRECT)) {
> +            qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_DIRECT,
>                                !!(flags & BDRV_O_NOCACHE), &error_abort);
>          }
> -        if (!qemu_opt_get(all_opts, "cache.no-flush")) {
> -            qemu_opt_set_bool(all_opts, "cache.no-flush",
> +        if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_NO_FLUSH)) {
> +            qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_NO_FLUSH,
>                                !!(flags & BDRV_O_NO_FLUSH), &error_abort);
>          }
>          qemu_opt_unset(all_opts, "cache");
> @@ -3106,15 +3106,15 @@ QemuOptsList qemu_common_drive_opts = {
>              .type = QEMU_OPT_STRING,
>              .help = "discard operation (ignore/off, unmap/on)",
>          },{
> -            .name = "cache.writeback",
> +            .name = BDRV_OPT_CACHE_WB,
>              .type = QEMU_OPT_BOOL,
>              .help = "enables writeback mode for any caches",
>          },{
> -            .name = "cache.direct",
> +            .name = BDRV_OPT_CACHE_DIRECT,
>              .type = QEMU_OPT_BOOL,
>              .help = "enables use of O_DIRECT (bypass the host page cache)",
>          },{
> -            .name = "cache.no-flush",
> +            .name = BDRV_OPT_CACHE_NO_FLUSH,
>              .type = QEMU_OPT_BOOL,
>              .help = "ignore any flush requests for the device",
>          },{
> diff --git a/include/block/block.h b/include/block/block.h
> index 7d1a717..86bdac8 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -90,6 +90,14 @@ typedef struct HDGeometry {
>  
>  #define BDRV_O_CACHE_MASK  (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
>  
> +
> +/* Option names of options parsed by the block layer */
> +
> +#define BDRV_OPT_CACHE_WB       "cache.writeback"
> +#define BDRV_OPT_CACHE_DIRECT   "cache.direct"
> +#define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush"
> +
> +
>  #define BDRV_SECTOR_BITS   9
>  #define BDRV_SECTOR_SIZE   (1ULL << BDRV_SECTOR_BITS)
>  #define BDRV_SECTOR_MASK   ~(BDRV_SECTOR_SIZE - 1)
> -- 
> 1.8.3.1
> 
>

Reviewed-by: Jeff Cody <jcody@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options() Kevin Wolf
@ 2015-05-12 20:04   ` Eric Blake
  2015-05-13  9:11     ` Kevin Wolf
  2015-05-13 11:21   ` Max Reitz
  2015-05-13 11:28   ` Max Reitz
  2 siblings, 1 reply; 130+ messages in thread
From: Eric Blake @ 2015-05-12 20:04 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 914 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Eventually we want to be able to change options at runtime. As a first
> step towards that goal, separate some option handling code from the
> general initialisation code in qcow2_open().
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/qcow2.c | 135 +++++++++++++++++++++++++++++++++-------------------------
>  1 file changed, 76 insertions(+), 59 deletions(-)
> 
> +    } else {
> +        error_setg(errp, "Unsupported value '%s' for qcow2 option "
> +                   "'overlap-check'. Allowed are either of the following: "
> +                   "none, constant, cached, all", opt_overlap_check);

Pre-existing due to code motion, but I find s/either/any/ easier to read.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 15/34] qcow2: Move qcow2_update_options() call up
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 15/34] qcow2: Move qcow2_update_options() call up Kevin Wolf
@ 2015-05-12 20:15   ` Eric Blake
  2015-05-13 11:25   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-12 20:15 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 614 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> qcow2_update_options() only updates some variables in BDRVQcowState and
> doesn't really depend on other parts of it being initialised yet, so it
> can be moved so that it immediately follows the other half of option
> handling code in qcow2_open().
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/qcow2.c | 18 +++++++++---------
>  1 file changed, 9 insertions(+), 9 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 16/34] qcow2: Move rest of option handling to qcow2_update_options()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 16/34] qcow2: Move rest of option handling to qcow2_update_options() Kevin Wolf
@ 2015-05-12 20:47   ` Eric Blake
  2015-05-13 11:38   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-12 20:47 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 538 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> With this commit, the handling of driver-specific options in
> qcow2_open() is completely separated out into qcow2_update_options().
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/qcow2.c | 109 +++++++++++++++++++++++++++++-----------------------------
>  1 file changed, 55 insertions(+), 54 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 17/34] qcow2: Leave s unchanged on qcow2_update_options() failure
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 17/34] qcow2: Leave s unchanged on qcow2_update_options() failure Kevin Wolf
@ 2015-05-12 20:57   ` Eric Blake
  2015-05-13 11:47   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-12 20:57 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 568 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> On return, either all new options should be applied to BDRVQcowState (on
> success), or all of the old setting should be preserved (on failure).

s/setting/settings/

> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/qcow2.c | 52 ++++++++++++++++++++++++++++++++--------------------
>  1 file changed, 32 insertions(+), 20 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 18/34] qcow2: Fix memory leak in qcow2_update_options() error path
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 18/34] qcow2: Fix memory leak in qcow2_update_options() error path Kevin Wolf
@ 2015-05-12 21:26   ` Eric Blake
  2015-05-13 11:52   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-12 21:26 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 349 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/qcow2.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 19/34] qcow2: Make qcow2_update_options() suitable for transactions
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 19/34] qcow2: Make qcow2_update_options() suitable for transactions Kevin Wolf
@ 2015-05-12 21:40   ` Eric Blake
  2015-05-13  9:21     ` Kevin Wolf
  2015-05-13 12:06   ` Max Reitz
  1 sibling, 1 reply; 130+ messages in thread
From: Eric Blake @ 2015-05-12 21:40 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 842 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> Before we can allow updating options at runtime with bdrv_reopen(), we
> need to split the function into prepare/commit/abort parts.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/qcow2.c | 101 ++++++++++++++++++++++++++++++++++++++--------------------
>  1 file changed, 67 insertions(+), 34 deletions(-)
> 

In isolation, it looks like a valid conversion, so:

Reviewed-by: Eric Blake <eblake@redhat.com>

However, given that we are having a conversation on another thread about
semantics for prepare vs. commit being the action that actually changes
the in-memory representation, is this the correct split for however we
end up resolving that bug?

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 20/34] qcow2: Support updating driver-specific options in reopen
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 20/34] qcow2: Support updating driver-specific options in reopen Kevin Wolf
@ 2015-05-12 21:47   ` Eric Blake
  2015-05-13  9:26     ` Kevin Wolf
  0 siblings, 1 reply; 130+ messages in thread
From: Eric Blake @ 2015-05-12 21:47 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 1975 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> For updating the cache sizes or disabling lazy refcounts there is a bit
> more to do than just changing the variables, but otherwise we're all set
> for changing options during bdrv_reopen().
> 
> Just implement the missing pieces and hook the functions up in
> bdrv_reopen().
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/qcow2.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 64 insertions(+), 6 deletions(-)
> 

> -/* We have no actual commit/abort logic for qcow2, but we need to write out any
> - * unwritten data if we reopen read-only. */
>  static int qcow2_reopen_prepare(BDRVReopenState *state,
>                                  BlockReopenQueue *queue, Error **errp)
>  {
> +    Qcow2ReopenState *r;
>      int ret;
>  
> +    r = g_new0(Qcow2ReopenState, 1);
> +    state->opaque = r;
> +
> +    ret = qcow2_update_options_prepare(state->bs, r, state->options,
> +                                       state->flags, errp);
> +    if (ret < 0) {
> +        goto fail;
> +    }
> +
> +    /* We need to write out any unwritten data if we reopen read-only. */
>      if ((state->flags & BDRV_O_RDWR) == 0) {
>          ret = bdrv_flush(state->bs);
>          if (ret < 0) {
> -            return ret;
> +            goto fail;
>          }
>  
>          ret = qcow2_mark_clean(state->bs);
>          if (ret < 0) {
> -            return ret;
> +            goto fail;
>          }
>      }
>  
>      return 0;
> +
> +fail:
> +    qcow2_update_options_abort(state->bs, r);
> +    return ret;

Doesn't this leak r?  That is, you only free r if _commit or _abort is
reached, but my understanding of transaction semantics is that we only
guarantee that one of those is reached if _prepare succeeded.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 21/34] block: Consider all block layer options in append_open_options
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 21/34] block: Consider all block layer options in append_open_options Kevin Wolf
@ 2015-05-12 21:59   ` Eric Blake
  2015-05-13 12:26   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-12 21:59 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

[-- Attachment #1: Type: text/plain, Size: 2072 bytes --]

On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> The code already special-cased "node-name", which is currently the only
> option passed in the QDict that isn't driver-specific. Generalise the
> code to take all general block layer options into consideration.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c | 26 ++++++++++++++++++--------
>  1 file changed, 18 insertions(+), 8 deletions(-)
> 

>  
>      for (entry = qdict_first(bs->options); entry;
>           entry = qdict_next(bs->options, entry))
>      {
> -        /* Only take options for this level and exclude all non-driver-specific
> -         * options */
> -        if (!strchr(qdict_entry_key(entry), '.') &&
> -            strcmp(qdict_entry_key(entry), "node-name"))
> -        {
> -            qobject_incref(qdict_entry_value(entry));
> -            qdict_put_obj(d, qdict_entry_key(entry), qdict_entry_value(entry));
> -            found_any = true;
> +        /* Only take options for this level */
> +        if (strchr(qdict_entry_key(entry), '.')) {
> +            continue;
>          }
> +
> +        /* And exclude all non-driver-specific options */
> +        for (desc = bdrv_runtime_opts.desc; desc->name; desc++) {
> +            if (!strcmp(qdict_entry_key(entry), desc->name)) {
> +                break;
> +            }
> +        }
> +        if (desc->name) {
> +            continue;

If only C had Java's "continue label" notation, which makes it cleaner
to jump out of nested loops :)  At least you didn't do a backwards "goto".

Looks like it will be O(n^2), but since our set of recognized option
names is still rather small, I don't think the performance hit will
reach a point where scaling matters.  If it does, we could switch to
binary search for O(n log n) or hash table lookups for O(n) amortized
cost, at the cost of code complexity, at a future date.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 13/34] qemu-io: Add command 'reopen'
  2015-05-12 15:05   ` Eric Blake
@ 2015-05-13  8:37     ` Kevin Wolf
  0 siblings, 0 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-13  8:37 UTC (permalink / raw)
  To: Eric Blake; +Cc: mreitz, qemu-devel, qemu-block, armbru

[-- Attachment #1: Type: text/plain, Size: 1611 bytes --]

Am 12.05.2015 um 17:05 hat Eric Blake geschrieben:
> On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > ---
> >  qemu-io-cmds.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 71 insertions(+)
> > 
> 
> > +
> > +    while ((c = getopt(argc, argv, "c:o:r")) != EOF) {
> 
> POSIX says getopt() returns -1 at conclusion, and allows EOF to have a
> value different than -1.  Thus, this could inf-loop on weird platforms
> (does anyone know such a platform?)  But I see you are copying from
> other bad examples in the file; so I'll post a trivial patch to fix all
> those in one go.

Thanks. And yes, almost everything in this patch is just copied from
elsewhere.

> > +        switch (c) {
> > +        case 'c':
> > +            if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
> > +                error_report("Invalid cache option: %s", optarg);
> > +                return 0;
> > +            }
> > +            break;
> > +        case 'o':
> > +            if (!qemu_opts_parse(&reopen_opts, optarg, 0)) {
> > +                printf("could not parse option list -- %s\n", optarg);
> 
> Messages usually have ':', not ' --', when displaying details about the
> message on the left.
> 
> We aren't very consistent on whether to start messages with lower or
> upper case, so you added one of each :)

Indeed. Copied from open_f() in qemu-io.c, Max is to blame. :-)

I'll add a patch fixing qemu-io.c first to use upper case, colon and
error_report() and then do the same here.

Kevin

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options()
  2015-05-12 20:04   ` Eric Blake
@ 2015-05-13  9:11     ` Kevin Wolf
  2015-05-13 17:04       ` Eric Blake
  0 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-13  9:11 UTC (permalink / raw)
  To: Eric Blake; +Cc: mreitz, qemu-devel, qemu-block, armbru

[-- Attachment #1: Type: text/plain, Size: 966 bytes --]

Am 12.05.2015 um 22:04 hat Eric Blake geschrieben:
> On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> > Eventually we want to be able to change options at runtime. As a first
> > step towards that goal, separate some option handling code from the
> > general initialisation code in qcow2_open().
> > 
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > ---
> >  block/qcow2.c | 135 +++++++++++++++++++++++++++++++++-------------------------
> >  1 file changed, 76 insertions(+), 59 deletions(-)
> > 
> > +    } else {
> > +        error_setg(errp, "Unsupported value '%s' for qcow2 option "
> > +                   "'overlap-check'. Allowed are either of the following: "
> > +                   "none, constant, cached, all", opt_overlap_check);
> 
> Pre-existing due to code motion, but I find s/either/any/ easier to read.

Isn't "either" only for a choice between two things anyway?

The series isn't long enough yet, I'll fix it. :-)

Kevin

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 19/34] qcow2: Make qcow2_update_options() suitable for transactions
  2015-05-12 21:40   ` Eric Blake
@ 2015-05-13  9:21     ` Kevin Wolf
  0 siblings, 0 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-13  9:21 UTC (permalink / raw)
  To: Eric Blake; +Cc: mreitz, qemu-devel, qemu-block, armbru

[-- Attachment #1: Type: text/plain, Size: 1054 bytes --]

Am 12.05.2015 um 23:40 hat Eric Blake geschrieben:
> On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> > Before we can allow updating options at runtime with bdrv_reopen(), we
> > need to split the function into prepare/commit/abort parts.
> > 
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > ---
> >  block/qcow2.c | 101 ++++++++++++++++++++++++++++++++++++++--------------------
> >  1 file changed, 67 insertions(+), 34 deletions(-)
> > 
> 
> In isolation, it looks like a valid conversion, so:
> 
> Reviewed-by: Eric Blake <eblake@redhat.com>
> 
> However, given that we are having a conversation on another thread about
> semantics for prepare vs. commit being the action that actually changes
> the in-memory representation, is this the correct split for however we
> end up resolving that bug?

Reopen transactions are a different thing than QMP transactions, so I
hope that they are not affected by that discussion. Generally, my
assumption with reopen transactions is that the change only takes effect
in commit.

Kevin

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 20/34] qcow2: Support updating driver-specific options in reopen
  2015-05-12 21:47   ` Eric Blake
@ 2015-05-13  9:26     ` Kevin Wolf
  0 siblings, 0 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-13  9:26 UTC (permalink / raw)
  To: Eric Blake; +Cc: mreitz, qemu-devel, qemu-block, armbru

[-- Attachment #1: Type: text/plain, Size: 2078 bytes --]

Am 12.05.2015 um 23:47 hat Eric Blake geschrieben:
> On 05/08/2015 11:21 AM, Kevin Wolf wrote:
> > For updating the cache sizes or disabling lazy refcounts there is a bit
> > more to do than just changing the variables, but otherwise we're all set
> > for changing options during bdrv_reopen().
> > 
> > Just implement the missing pieces and hook the functions up in
> > bdrv_reopen().
> > 
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > ---
> >  block/qcow2.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
> >  1 file changed, 64 insertions(+), 6 deletions(-)
> > 
> 
> > -/* We have no actual commit/abort logic for qcow2, but we need to write out any
> > - * unwritten data if we reopen read-only. */
> >  static int qcow2_reopen_prepare(BDRVReopenState *state,
> >                                  BlockReopenQueue *queue, Error **errp)
> >  {
> > +    Qcow2ReopenState *r;
> >      int ret;
> >  
> > +    r = g_new0(Qcow2ReopenState, 1);
> > +    state->opaque = r;
> > +
> > +    ret = qcow2_update_options_prepare(state->bs, r, state->options,
> > +                                       state->flags, errp);
> > +    if (ret < 0) {
> > +        goto fail;
> > +    }
> > +
> > +    /* We need to write out any unwritten data if we reopen read-only. */
> >      if ((state->flags & BDRV_O_RDWR) == 0) {
> >          ret = bdrv_flush(state->bs);
> >          if (ret < 0) {
> > -            return ret;
> > +            goto fail;
> >          }
> >  
> >          ret = qcow2_mark_clean(state->bs);
> >          if (ret < 0) {
> > -            return ret;
> > +            goto fail;
> >          }
> >      }
> >  
> >      return 0;
> > +
> > +fail:
> > +    qcow2_update_options_abort(state->bs, r);
> > +    return ret;
> 
> Doesn't this leak r?  That is, you only free r if _commit or _abort is
> reached, but my understanding of transaction semantics is that we only
> guarantee that one of those is reached if _prepare succeeded.

Yes, it does. Thanks for catching that.

Kevin

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options() Kevin Wolf
  2015-05-12 20:04   ` Eric Blake
@ 2015-05-13 11:21   ` Max Reitz
  2015-05-13 11:28   ` Max Reitz
  2 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 11:21 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Eventually we want to be able to change options at runtime. As a first
> step towards that goal, separate some option handling code from the
> general initialisation code in qcow2_open().
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block/qcow2.c | 135 +++++++++++++++++++++++++++++++++-------------------------
>   1 file changed, 76 insertions(+), 59 deletions(-)
>
> diff --git a/block/qcow2.c b/block/qcow2.c
> index b9a72e3..db535d4 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c

[snip]

> @@ -549,8 +623,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
>       Error *local_err = NULL;
>       uint64_t ext_end;
>       uint64_t l1_vm_state_index;
> -    const char *opt_overlap_check, *opt_overlap_check_template;
> -    int overlap_check_template = 0;
>       uint64_t l2_cache_size, refcount_cache_size;
>   
>       ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
> @@ -924,69 +996,14 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
>       }
>   
>       /* Enable lazy_refcounts according to image and command line options */

[...]

> +    ret = qcow2_update_options(bs, opts, flags, errp);
> +    if (ret < 0) {

The comment looks a bit strange now, because qcow2_update_options() 
doesn't update just lazy_refcounts.

Max

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 15/34] qcow2: Move qcow2_update_options() call up
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 15/34] qcow2: Move qcow2_update_options() call up Kevin Wolf
  2015-05-12 20:15   ` Eric Blake
@ 2015-05-13 11:25   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 11:25 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> qcow2_update_options() only updates some variables in BDRVQcowState and
> doesn't really depend on other parts of it being initialised yet, so it
> can be moved so that it immediately follows the other half of option
> handling code in qcow2_open().
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block/qcow2.c | 18 +++++++++---------
>   1 file changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/block/qcow2.c b/block/qcow2.c
> index db535d4..761ba30 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -911,6 +911,15 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
>           goto fail;
>       }
>   
> +    /* Enable lazy_refcounts according to image and command line options */

Again, I find the comment not very fitting. But the motion itself is 
okay, so regardless of what comment you are moving here:

Reviewed-by: Max Reitz <mreitz@redhat.com>

> +    ret = qcow2_update_options(bs, opts, flags, errp);
> +    if (ret < 0) {
> +        goto fail;
> +    }
> +
> +    qemu_opts_del(opts);
> +    opts = NULL;
> +
>       s->cluster_cache = g_malloc(s->cluster_size);
>       /* one more sector for decompressed data alignment */
>       s->cluster_data = qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
> @@ -995,15 +1004,6 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
>           }
>       }
>   
> -    /* Enable lazy_refcounts according to image and command line options */
> -    ret = qcow2_update_options(bs, opts, flags, errp);
> -    if (ret < 0) {
> -        goto fail;
> -    }
> -
> -    qemu_opts_del(opts);
> -    opts = NULL;
> -
>   #ifdef DEBUG_ALLOC
>       {
>           BdrvCheckResult result = {0};

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options() Kevin Wolf
  2015-05-12 20:04   ` Eric Blake
  2015-05-13 11:21   ` Max Reitz
@ 2015-05-13 11:28   ` Max Reitz
  2 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 11:28 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Eventually we want to be able to change options at runtime. As a first
> step towards that goal, separate some option handling code from the
> general initialisation code in qcow2_open().
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block/qcow2.c | 135 +++++++++++++++++++++++++++++++++-------------------------
>   1 file changed, 76 insertions(+), 59 deletions(-)

Now seeing that the comment I was complaining about is removed in patch 16:

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 16/34] qcow2: Move rest of option handling to qcow2_update_options()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 16/34] qcow2: Move rest of option handling to qcow2_update_options() Kevin Wolf
  2015-05-12 20:47   ` Eric Blake
@ 2015-05-13 11:38   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 11:38 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> With this commit, the handling of driver-specific options in
> qcow2_open() is completely separated out into qcow2_update_options().
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block/qcow2.c | 109 +++++++++++++++++++++++++++++-----------------------------
>   1 file changed, 55 insertions(+), 54 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 17/34] qcow2: Leave s unchanged on qcow2_update_options() failure
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 17/34] qcow2: Leave s unchanged on qcow2_update_options() failure Kevin Wolf
  2015-05-12 20:57   ` Eric Blake
@ 2015-05-13 11:47   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 11:47 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> On return, either all new options should be applied to BDRVQcowState (on
> success), or all of the old setting should be preserved (on failure).
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block/qcow2.c | 52 ++++++++++++++++++++++++++++++++--------------------
>   1 file changed, 32 insertions(+), 20 deletions(-)
>
> diff --git a/block/qcow2.c b/block/qcow2.c
> index a4a267d..abe22f3 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -546,6 +546,9 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
>       const char *opt_overlap_check, *opt_overlap_check_template;
>       int overlap_check_template = 0;
>       uint64_t l2_cache_size, refcount_cache_size;
> +    Qcow2Cache* l2_table_cache;
> +    Qcow2Cache* refcount_block_cache;

;-)

Because patch 18 exists:

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 18/34] qcow2: Fix memory leak in qcow2_update_options() error path
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 18/34] qcow2: Fix memory leak in qcow2_update_options() error path Kevin Wolf
  2015-05-12 21:26   ` Eric Blake
@ 2015-05-13 11:52   ` Max Reitz
  2015-05-13 12:02     ` Kevin Wolf
  1 sibling, 1 reply; 130+ messages in thread
From: Max Reitz @ 2015-05-13 11:52 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block/qcow2.c | 12 ++++++++++--
>   1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/block/qcow2.c b/block/qcow2.c
> index abe22f3..84d6e0f 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -546,8 +546,8 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
>       const char *opt_overlap_check, *opt_overlap_check_template;
>       int overlap_check_template = 0;
>       uint64_t l2_cache_size, refcount_cache_size;
> -    Qcow2Cache* l2_table_cache;
> -    Qcow2Cache* refcount_block_cache;
> +    Qcow2Cache* l2_table_cache = NULL;
> +    Qcow2Cache* refcount_block_cache = NULL;
>       bool use_lazy_refcounts;
>       int i;
>       Error *local_err = NULL;
> @@ -670,6 +670,14 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
>   
>       ret = 0;
>   fail:
> +    if (ret < 0) {
> +        if (l2_table_cache) {
> +            qcow2_cache_destroy(bs, l2_table_cache);
> +        }
> +        if (refcount_block_cache) {
> +            qcow2_cache_destroy(bs, refcount_block_cache);
> +        }
> +    }
>       qemu_opts_del(opts);
>       opts = NULL;

Why don't you squash this into patch 17 (I guess there is a reason, but 
I fail to see it)?

Also, I think it might make sense to either set 
{l2_table,refcount_block}_cache to NULL once they have been moved to 
s->{l2_table,refcount_block}_cache, or, even better, exchange them with 
their respective field in *s. Thus, you could drop the "if (ret < 0)", I 
think I'd find the code easier to read, and with the transation, we'd 
even be safe if the options had been set before and are now to be updated.

But since nothing is wrong:

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 18/34] qcow2: Fix memory leak in qcow2_update_options() error path
  2015-05-13 11:52   ` Max Reitz
@ 2015-05-13 12:02     ` Kevin Wolf
  2015-05-13 12:04       ` Max Reitz
  0 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-13 12:02 UTC (permalink / raw)
  To: Max Reitz; +Cc: armbru, qemu-block, qemu-devel

Am 13.05.2015 um 13:52 hat Max Reitz geschrieben:
> On 08.05.2015 19:21, Kevin Wolf wrote:
> >Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> >---
> >  block/qcow2.c | 12 ++++++++++--
> >  1 file changed, 10 insertions(+), 2 deletions(-)
> >
> >diff --git a/block/qcow2.c b/block/qcow2.c
> >index abe22f3..84d6e0f 100644
> >--- a/block/qcow2.c
> >+++ b/block/qcow2.c
> >@@ -546,8 +546,8 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
> >      const char *opt_overlap_check, *opt_overlap_check_template;
> >      int overlap_check_template = 0;
> >      uint64_t l2_cache_size, refcount_cache_size;
> >-    Qcow2Cache* l2_table_cache;
> >-    Qcow2Cache* refcount_block_cache;
> >+    Qcow2Cache* l2_table_cache = NULL;
> >+    Qcow2Cache* refcount_block_cache = NULL;
> >      bool use_lazy_refcounts;
> >      int i;
> >      Error *local_err = NULL;
> >@@ -670,6 +670,14 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
> >      ret = 0;
> >  fail:
> >+    if (ret < 0) {
> >+        if (l2_table_cache) {
> >+            qcow2_cache_destroy(bs, l2_table_cache);
> >+        }
> >+        if (refcount_block_cache) {
> >+            qcow2_cache_destroy(bs, refcount_block_cache);
> >+        }
> >+    }
> >      qemu_opts_del(opts);
> >      opts = NULL;
> 
> Why don't you squash this into patch 17 (I guess there is a reason,
> but I fail to see it)?

It's a preexisting bug and its fix is unrelated to any of the
refactoring or preparation for reopen. So I think it deserves its own
commit, and if it doesn't, it's not clear to me why it should belong to
patch 17 of all patches.

> Also, I think it might make sense to either set
> {l2_table,refcount_block}_cache to NULL once they have been moved to
> s->{l2_table,refcount_block}_cache, or, even better, exchange them
> with their respective field in *s. Thus, you could drop the "if (ret
> < 0)", I think I'd find the code easier to read, and with the
> transation, we'd even be safe if the options had been set before and
> are now to be updated.

The if (ret < 0) disappears shortly after this patch when this is moved
into the abort part of a transaction.

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 18/34] qcow2: Fix memory leak in qcow2_update_options() error path
  2015-05-13 12:02     ` Kevin Wolf
@ 2015-05-13 12:04       ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 12:04 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: armbru, qemu-block, qemu-devel

On 13.05.2015 14:02, Kevin Wolf wrote:
> Am 13.05.2015 um 13:52 hat Max Reitz geschrieben:
>> On 08.05.2015 19:21, Kevin Wolf wrote:
>>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>>> ---
>>>   block/qcow2.c | 12 ++++++++++--
>>>   1 file changed, 10 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/block/qcow2.c b/block/qcow2.c
>>> index abe22f3..84d6e0f 100644
>>> --- a/block/qcow2.c
>>> +++ b/block/qcow2.c
>>> @@ -546,8 +546,8 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
>>>       const char *opt_overlap_check, *opt_overlap_check_template;
>>>       int overlap_check_template = 0;
>>>       uint64_t l2_cache_size, refcount_cache_size;
>>> -    Qcow2Cache* l2_table_cache;
>>> -    Qcow2Cache* refcount_block_cache;
>>> +    Qcow2Cache* l2_table_cache = NULL;
>>> +    Qcow2Cache* refcount_block_cache = NULL;
>>>       bool use_lazy_refcounts;
>>>       int i;
>>>       Error *local_err = NULL;
>>> @@ -670,6 +670,14 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
>>>       ret = 0;
>>>   fail:
>>> +    if (ret < 0) {
>>> +        if (l2_table_cache) {
>>> +            qcow2_cache_destroy(bs, l2_table_cache);
>>> +        }
>>> +        if (refcount_block_cache) {
>>> +            qcow2_cache_destroy(bs, refcount_block_cache);
>>> +        }
>>> +    }
>>>       qemu_opts_del(opts);
>>>       opts = NULL;
>> Why don't you squash this into patch 17 (I guess there is a reason,
>> but I fail to see it)?
> It's a preexisting bug and its fix is unrelated to any of the
> refactoring or preparation for reopen. So I think it deserves its own
> commit, and if it doesn't, it's not clear to me why it should belong to
> patch 17 of all patches.

Because patch 17 is introducing the {l2_table,refcount_block}_cache as 
local variables.

>> Also, I think it might make sense to either set
>> {l2_table,refcount_block}_cache to NULL once they have been moved to
>> s->{l2_table,refcount_block}_cache, or, even better, exchange them
>> with their respective field in *s. Thus, you could drop the "if (ret
>> < 0)", I think I'd find the code easier to read, and with the
>> transation, we'd even be safe if the options had been set before and
>> are now to be updated.
> The if (ret < 0) disappears shortly after this patch when this is moved
> into the abort part of a transaction.

Right, I just saw this. :-)

Max

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 19/34] qcow2: Make qcow2_update_options() suitable for transactions
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 19/34] qcow2: Make qcow2_update_options() suitable for transactions Kevin Wolf
  2015-05-12 21:40   ` Eric Blake
@ 2015-05-13 12:06   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 12:06 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Before we can allow updating options at runtime with bdrv_reopen(), we
> need to split the function into prepare/commit/abort parts.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block/qcow2.c | 101 ++++++++++++++++++++++++++++++++++++++--------------------
>   1 file changed, 67 insertions(+), 34 deletions(-)
>
> diff --git a/block/qcow2.c b/block/qcow2.c
> index 84d6e0f..fc9375e 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -538,17 +538,24 @@ static void read_cache_sizes(QemuOpts *opts, uint64_t *l2_cache_size,
>       }
>   }
>   
> -static int qcow2_update_options(BlockDriverState *bs, QDict *options,
> -                                int flags, Error **errp)
> +typedef struct Qcow2ReopenState {
> +    Qcow2Cache* l2_table_cache;
> +    Qcow2Cache* refcount_block_cache;

*cough*

> +    bool use_lazy_refcounts;
> +    int overlap_check;
> +    bool discard_passthrough[QCOW2_DISCARD_MAX];
> +} Qcow2ReopenState;
> +
> +static int qcow2_update_options_prepare(BlockDriverState *bs,
> +                                        Qcow2ReopenState *r,
> +                                        QDict *options, int flags,
> +                                        Error **errp)
>   {
>       BDRVQcowState *s = bs->opaque;
>       QemuOpts *opts = NULL;
>       const char *opt_overlap_check, *opt_overlap_check_template;
>       int overlap_check_template = 0;
>       uint64_t l2_cache_size, refcount_cache_size;
> -    Qcow2Cache* l2_table_cache = NULL;
> -    Qcow2Cache* refcount_block_cache = NULL;
> -    bool use_lazy_refcounts;
>       int i;
>       Error *local_err = NULL;
>       int ret;
> @@ -590,18 +597,18 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
>       }
>   
>       /* alloc L2 table/refcount block cache */
> -    l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
> -    refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
> -    if (l2_table_cache == NULL || refcount_block_cache == NULL) {
> +    r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
> +    r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
> +    if (r->l2_table_cache == NULL || r->refcount_block_cache == NULL) {
>           error_setg(errp, "Could not allocate metadata caches");
>           ret = -ENOMEM;
>           goto fail;
>       }
>   
>       /* Enable lazy_refcounts according to image and command line options */
> -    use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
> +    r->use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
>           (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS));
> -    if (use_lazy_refcounts && s->qcow_version < 3) {
> +    if (r->use_lazy_refcounts && s->qcow_version < 3) {
>           error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
>                      "qemu 1.1 compatibility level");
>           ret = -EINVAL;
> @@ -640,46 +647,72 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
>           goto fail;
>       }
>   
> -    /*
> -     * Start updating fields in BDRVQcowState.
> -     * After this point no failure is allowed any more.
> -     */
> -    s->overlap_check = 0;
> +    r->overlap_check = 0;
>       for (i = 0; i < QCOW2_OL_MAX_BITNR; i++) {
>           /* overlap-check defines a template bitmask, but every flag may be
>            * overwritten through the associated boolean option */
> -        s->overlap_check |=
> +        r->overlap_check |=
>               qemu_opt_get_bool(opts, overlap_bool_option_names[i],
>                                 overlap_check_template & (1 << i)) << i;
>       }
>   
> -    s->l2_table_cache = l2_table_cache;
> -    s->refcount_block_cache = refcount_block_cache;
> -
> -    s->use_lazy_refcounts = use_lazy_refcounts;
> -
> -    s->discard_passthrough[QCOW2_DISCARD_NEVER] = false;
> -    s->discard_passthrough[QCOW2_DISCARD_ALWAYS] = true;
> -    s->discard_passthrough[QCOW2_DISCARD_REQUEST] =
> +    r->discard_passthrough[QCOW2_DISCARD_NEVER] = false;
> +    r->discard_passthrough[QCOW2_DISCARD_ALWAYS] = true;
> +    r->discard_passthrough[QCOW2_DISCARD_REQUEST] =
>           qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_REQUEST,
>                             flags & BDRV_O_UNMAP);
> -    s->discard_passthrough[QCOW2_DISCARD_SNAPSHOT] =
> +    r->discard_passthrough[QCOW2_DISCARD_SNAPSHOT] =
>           qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_SNAPSHOT, true);
> -    s->discard_passthrough[QCOW2_DISCARD_OTHER] =
> +    r->discard_passthrough[QCOW2_DISCARD_OTHER] =
>           qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
>   
>       ret = 0;
>   fail:
> -    if (ret < 0) {
> -        if (l2_table_cache) {
> -            qcow2_cache_destroy(bs, l2_table_cache);
> -        }
> -        if (refcount_block_cache) {
> -            qcow2_cache_destroy(bs, refcount_block_cache);
> -        }
> -    }
>       qemu_opts_del(opts);
>       opts = NULL;
> +    return ret;
> +}
> +
> +static void qcow2_update_options_commit(BlockDriverState *bs,
> +                                        Qcow2ReopenState *r)
> +{
> +    BDRVQcowState *s = bs->opaque;
> +    int i;
> +
> +    s->l2_table_cache = r->l2_table_cache;
> +    s->refcount_block_cache = r->refcount_block_cache;
> +
> +    s->overlap_check = r->overlap_check;
> +    s->use_lazy_refcounts = r->use_lazy_refcounts;
> +
> +    for (i = 0; i < QCOW2_DISCARD_MAX; i++) {
> +        s->discard_passthrough[i] = r->discard_passthrough[i];
> +    }
> +}
> +
> +static void qcow2_update_options_abort(BlockDriverState *bs,
> +                                       Qcow2ReopenState *r)
> +{
> +    if (r->l2_table_cache) {
> +        qcow2_cache_destroy(bs, r->l2_table_cache);
> +    }
> +    if (r->refcount_block_cache) {
> +        qcow2_cache_destroy(bs, r->refcount_block_cache);
> +    }
> +}

Okay, now it makes sense not to set {l2_table,refcount_block}_cache to 
NULL in patch 18 after they've been moved to *s.

Reviewed-by: Max Reitz <mreitz@redhat.com>

> +
> +static int qcow2_update_options(BlockDriverState *bs, QDict *options,
> +                                int flags, Error **errp)
> +{
> +    Qcow2ReopenState r = {};
> +    int ret;
> +
> +    ret = qcow2_update_options_prepare(bs, &r, options, flags, errp);
> +    if (ret >= 0) {
> +        qcow2_update_options_commit(bs, &r);
> +    } else {
> +        qcow2_update_options_abort(bs, &r);
> +    }
>   
>       return ret;
>   }

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 21/34] block: Consider all block layer options in append_open_options
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 21/34] block: Consider all block layer options in append_open_options Kevin Wolf
  2015-05-12 21:59   ` Eric Blake
@ 2015-05-13 12:26   ` Max Reitz
  1 sibling, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 12:26 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> The code already special-cased "node-name", which is currently the only
> option passed in the QDict that isn't driver-specific. Generalise the
> code to take all general block layer options into consideration.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c | 26 ++++++++++++++++++--------
>   1 file changed, 18 insertions(+), 8 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 22/34] block: Exclude nested options only for children in append_open_options()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 22/34] block: Exclude nested options only for children in append_open_options() Kevin Wolf
@ 2015-05-13 12:49   ` Max Reitz
  2015-05-13 12:50     ` Max Reitz
  0 siblings, 1 reply; 130+ messages in thread
From: Max Reitz @ 2015-05-13 12:49 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Some drivers have nested options (e.g. blkdebug rule arrays), which
> don't belong to a child node and shouldn't be removed. Don't remove all
> options with "." in their name, but check for the complete prefixes of
> actually existing child nodes.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c                   | 30 +++++++++++++++++++-----------
>   include/block/block_int.h |  1 +
>   2 files changed, 20 insertions(+), 11 deletions(-)
>
> diff --git a/block.c b/block.c
> index e329a47..e9a1d76 100644
> --- a/block.c
> +++ b/block.c
> @@ -81,7 +81,7 @@ static QLIST_HEAD(, BlockDriver) bdrv_drivers =
>   
>   static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>                                const char *reference, QDict *options, int flags,
> -                             BlockDriverState* parent,
> +                             BlockDriverState* parent, const char *child_name,
>                                const BdrvChildRole *child_role,
>                                BlockDriver *drv, Error **errp);
>   
> @@ -1174,8 +1174,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
>       backing_hd = NULL;
>       ret = bdrv_open_inherit(&backing_hd,
>                               *backing_filename ? backing_filename : NULL,
> -                            reference, options, 0, bs, &child_backing,
> -                            NULL, &local_err);
> +                            reference, options, 0, bs, "backing",
> +                            &child_backing, NULL, &local_err);
>       if (ret < 0) {
>           bs->open_flags |= BDRV_O_NO_BACKING;
>           error_setg(errp, "Could not open backing file: %s",
> @@ -1238,7 +1238,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
>       }
>   
>       ret = bdrv_open_inherit(pbs, filename, reference, image_options, 0,
> -                            parent, child_role, NULL, errp);
> +                            parent, bdref_key, child_role, NULL, errp);
>   
>   done:
>       qdict_del(options, bdref_key);
> @@ -1312,11 +1312,13 @@ out:
>   
>   static void bdrv_attach_child(BlockDriverState *parent_bs,
>                                 BlockDriverState *child_bs,
> +                              const char *child_name,
>                                 const BdrvChildRole *child_role)
>   {
>       BdrvChild *child = g_new(BdrvChild, 1);
>       *child = (BdrvChild) {
>           .bs     = child_bs,
> +        .name   = child_name,
>           .role   = child_role,
>       };
>   
> @@ -1340,7 +1342,7 @@ static void bdrv_attach_child(BlockDriverState *parent_bs,
>    */
>   static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>                                const char *reference, QDict *options, int flags,
> -                             BlockDriverState* parent,
> +                             BlockDriverState* parent, const char *child_name,
>                                const BdrvChildRole *child_role,
>                                BlockDriver *drv, Error **errp)
>   {
> @@ -1376,7 +1378,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>           }
>           bdrv_ref(bs);
>           if (child_role) {
> -            bdrv_attach_child(parent, bs, child_role);
> +            bdrv_attach_child(parent, bs, child_name, child_role);
>           }
>           *pbs = bs;
>           return 0;
> @@ -1519,7 +1521,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>       }
>   
>       if (child_role) {
> -        bdrv_attach_child(parent, bs, child_role);
> +        bdrv_attach_child(parent, bs, child_name, child_role);
>       }
>   
>       QDECREF(options);
> @@ -1563,7 +1565,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
>                 BlockDriver *drv, Error **errp)
>   {
>       return bdrv_open_inherit(pbs, filename, reference, options, flags, NULL,
> -                             NULL, drv, errp);
> +                             NULL, NULL, drv, errp);
>   }
>   
>   typedef struct BlockReopenQueueEntry {
> @@ -2093,7 +2095,7 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
>       /* The contents of 'tmp' will become bs_top, as we are
>        * swapping bs_new and bs_top contents. */
>       bdrv_set_backing_hd(bs_top, bs_new);
> -    bdrv_attach_child(bs_top, bs_new, &child_backing);
> +    bdrv_attach_child(bs_top, bs_new, "backing", &child_backing);
>   }
>   
>   static void bdrv_delete(BlockDriverState *bs)
> @@ -4037,13 +4039,19 @@ static bool append_open_options(QDict *d, BlockDriverState *bs)
>   {
>       const QDictEntry *entry;
>       QemuOptDesc *desc;
> +    BdrvChild *child;
>       bool found_any = false;
>   
>       for (entry = qdict_first(bs->options); entry;
>            entry = qdict_next(bs->options, entry))
>       {
> -        /* Only take options for this level */
> -        if (strchr(qdict_entry_key(entry), '.')) {
> +        /* Exclude options for children */
> +        QLIST_FOREACH(child, &bs->children, next) {
> +            if (strstart(qdict_entry_key(entry), child->name, NULL)) {

I think the prefix should be "#{child->name}.", tested like "if 
(strstart(..., &ptr) && *ptr == '.')".

It doesn't matter now, so I'm not sure whether I can give an R-b 
anyway... I guess when in doubt, back out. So I won't. :-)

Max

> +                break;
> +            }
> +        }
> +        if (child) {
>               continue;
>           }
>   
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index 2fad5f8..90da3f7 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -336,6 +336,7 @@ extern const BdrvChildRole child_format;
>   
>   typedef struct BdrvChild {
>       BlockDriverState *bs;
> +    const char *name;
>       const BdrvChildRole *role;
>       QLIST_ENTRY(BdrvChild) next;
>   } BdrvChild;

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 22/34] block: Exclude nested options only for children in append_open_options()
  2015-05-13 12:49   ` Max Reitz
@ 2015-05-13 12:50     ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 12:50 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 13.05.2015 14:49, Max Reitz wrote:
> On 08.05.2015 19:21, Kevin Wolf wrote:
>> Some drivers have nested options (e.g. blkdebug rule arrays), which
>> don't belong to a child node and shouldn't be removed. Don't remove all
>> options with "." in their name, but check for the complete prefixes of
>> actually existing child nodes.
>>
>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>> ---
>>   block.c                   | 30 +++++++++++++++++++-----------
>>   include/block/block_int.h |  1 +
>>   2 files changed, 20 insertions(+), 11 deletions(-)
>>
>> diff --git a/block.c b/block.c
>> index e329a47..e9a1d76 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -81,7 +81,7 @@ static QLIST_HEAD(, BlockDriver) bdrv_drivers =
>>     static int bdrv_open_inherit(BlockDriverState **pbs, const char 
>> *filename,
>>                                const char *reference, QDict *options, 
>> int flags,
>> -                             BlockDriverState* parent,
>> +                             BlockDriverState* parent, const char 
>> *child_name,
>>                                const BdrvChildRole *child_role,
>>                                BlockDriver *drv, Error **errp);
>>   @@ -1174,8 +1174,8 @@ int bdrv_open_backing_file(BlockDriverState 
>> *bs, QDict *parent_options,
>>       backing_hd = NULL;
>>       ret = bdrv_open_inherit(&backing_hd,
>>                               *backing_filename ? backing_filename : 
>> NULL,
>> -                            reference, options, 0, bs, &child_backing,
>> -                            NULL, &local_err);
>> +                            reference, options, 0, bs, "backing",
>> +                            &child_backing, NULL, &local_err);
>>       if (ret < 0) {
>>           bs->open_flags |= BDRV_O_NO_BACKING;
>>           error_setg(errp, "Could not open backing file: %s",
>> @@ -1238,7 +1238,7 @@ int bdrv_open_image(BlockDriverState **pbs, 
>> const char *filename,
>>       }
>>         ret = bdrv_open_inherit(pbs, filename, reference, 
>> image_options, 0,
>> -                            parent, child_role, NULL, errp);
>> +                            parent, bdref_key, child_role, NULL, errp);
>>     done:
>>       qdict_del(options, bdref_key);
>> @@ -1312,11 +1312,13 @@ out:
>>     static void bdrv_attach_child(BlockDriverState *parent_bs,
>>                                 BlockDriverState *child_bs,
>> +                              const char *child_name,
>>                                 const BdrvChildRole *child_role)
>>   {
>>       BdrvChild *child = g_new(BdrvChild, 1);
>>       *child = (BdrvChild) {
>>           .bs     = child_bs,
>> +        .name   = child_name,
>>           .role   = child_role,
>>       };
>>   @@ -1340,7 +1342,7 @@ static void 
>> bdrv_attach_child(BlockDriverState *parent_bs,
>>    */
>>   static int bdrv_open_inherit(BlockDriverState **pbs, const char 
>> *filename,
>>                                const char *reference, QDict *options, 
>> int flags,
>> -                             BlockDriverState* parent,
>> +                             BlockDriverState* parent, const char 
>> *child_name,
>>                                const BdrvChildRole *child_role,
>>                                BlockDriver *drv, Error **errp)
>>   {
>> @@ -1376,7 +1378,7 @@ static int bdrv_open_inherit(BlockDriverState 
>> **pbs, const char *filename,
>>           }
>>           bdrv_ref(bs);
>>           if (child_role) {
>> -            bdrv_attach_child(parent, bs, child_role);
>> +            bdrv_attach_child(parent, bs, child_name, child_role);
>>           }
>>           *pbs = bs;
>>           return 0;
>> @@ -1519,7 +1521,7 @@ static int bdrv_open_inherit(BlockDriverState 
>> **pbs, const char *filename,
>>       }
>>         if (child_role) {
>> -        bdrv_attach_child(parent, bs, child_role);
>> +        bdrv_attach_child(parent, bs, child_name, child_role);
>>       }
>>         QDECREF(options);
>> @@ -1563,7 +1565,7 @@ int bdrv_open(BlockDriverState **pbs, const 
>> char *filename,
>>                 BlockDriver *drv, Error **errp)
>>   {
>>       return bdrv_open_inherit(pbs, filename, reference, options, 
>> flags, NULL,
>> -                             NULL, drv, errp);
>> +                             NULL, NULL, drv, errp);
>>   }
>>     typedef struct BlockReopenQueueEntry {
>> @@ -2093,7 +2095,7 @@ void bdrv_append(BlockDriverState *bs_new, 
>> BlockDriverState *bs_top)
>>       /* The contents of 'tmp' will become bs_top, as we are
>>        * swapping bs_new and bs_top contents. */
>>       bdrv_set_backing_hd(bs_top, bs_new);
>> -    bdrv_attach_child(bs_top, bs_new, &child_backing);
>> +    bdrv_attach_child(bs_top, bs_new, "backing", &child_backing);
>>   }
>>     static void bdrv_delete(BlockDriverState *bs)
>> @@ -4037,13 +4039,19 @@ static bool append_open_options(QDict *d, 
>> BlockDriverState *bs)
>>   {
>>       const QDictEntry *entry;
>>       QemuOptDesc *desc;
>> +    BdrvChild *child;
>>       bool found_any = false;
>>         for (entry = qdict_first(bs->options); entry;
>>            entry = qdict_next(bs->options, entry))
>>       {
>> -        /* Only take options for this level */
>> -        if (strchr(qdict_entry_key(entry), '.')) {
>> +        /* Exclude options for children */
>> +        QLIST_FOREACH(child, &bs->children, next) {
>> +            if (strstart(qdict_entry_key(entry), child->name, NULL)) {
>
> I think the prefix should be "#{child->name}.", tested like "if 
> (strstart(..., &ptr) && *ptr == '.')".

Make that "(*ptr == '.' || !*ptr)", I think.

> It doesn't matter now, so I'm not sure whether I can give an R-b 
> anyway... I guess when in doubt, back out. So I won't. :-)
>
> Max
>
>> +                break;
>> +            }
>> +        }
>> +        if (child) {
>>               continue;
>>           }
>>   diff --git a/include/block/block_int.h b/include/block/block_int.h
>> index 2fad5f8..90da3f7 100644
>> --- a/include/block/block_int.h
>> +++ b/include/block/block_int.h
>> @@ -336,6 +336,7 @@ extern const BdrvChildRole child_format;
>>     typedef struct BdrvChild {
>>       BlockDriverState *bs;
>> +    const char *name;
>>       const BdrvChildRole *role;
>>       QLIST_ENTRY(BdrvChild) next;
>>   } BdrvChild;
>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 23/34] block: Pass driver-specific options to .bdrv_refresh_filename()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 23/34] block: Pass driver-specific options to .bdrv_refresh_filename() Kevin Wolf
@ 2015-05-13 12:57   ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 12:57 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> In order to decide whether a blkdebug: filename can be produced or a
> json: one is necessary, blkdebug checked whether bs->options had more
> options than just "config", "x-image" or "image" (the latter including
> nested options). That doesn't work well when generic block layer options
> are present.
>
> This patch passes an option QDict to the driver that contains only
> driver-specific options, i.e. the options for the general block layer as
> well as child nodes are already filtered out. Works much better this
> way.

Indeed. :-)

> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c                   |  5 ++++-
>   block/blkdebug.c          | 17 ++++++-----------
>   block/blkverify.c         |  2 +-
>   block/nbd.c               | 10 +++++-----
>   block/quorum.c            |  2 +-
>   include/block/block_int.h |  2 +-
>   6 files changed, 18 insertions(+), 20 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 24/34] block: Keep "driver" in bs->options
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 24/34] block: Keep "driver" in bs->options Kevin Wolf
@ 2015-05-13 13:22   ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 13:22 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Instead of passing a separate drv argument to bdrv_open_common(), just
> make sure that a "driver" option is set in the QDict. This also means
> that a "driver" entry is consistently present in bs->options now.
>
> This is another step towards keeping all options in the QDict (which is
> the represenation of the blockdev-add QMP command).
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c | 54 ++++++++++++++++++++++++++++++++++++++----------------
>   1 file changed, 38 insertions(+), 16 deletions(-)
>
> diff --git a/block.c b/block.c
> index 7c0c9db..ef39c74 100644
> --- a/block.c
> +++ b/block.c
> @@ -795,6 +795,11 @@ static QemuOptsList bdrv_runtime_opts = {
>               .type = QEMU_OPT_STRING,
>               .help = "Node name of the block device node",
>           },
> +        {
> +            .name = "driver",
> +            .type = QEMU_OPT_STRING,
> +            .help = "Block driver to use for the node",
> +        },
>           { /* end of list */ }
>       },
>   };
> @@ -805,18 +810,31 @@ static QemuOptsList bdrv_runtime_opts = {
>    * Removes all processed options from *options.
>    */
>   static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
> -    QDict *options, int flags, BlockDriver *drv, Error **errp)
> +                            QDict *options, int flags, Error **errp)
>   {
>       int ret, open_flags;
>       const char *filename;
> +    const char *driver_name = NULL;
>       const char *node_name = NULL;
>       QemuOpts *opts;
> +    BlockDriver *drv;
>       Error *local_err = NULL;
>   
> -    assert(drv != NULL);
>       assert(bs->file == NULL);
>       assert(options != NULL && bs->options != options);
>   
> +    opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
> +    qemu_opts_absorb_qdict(opts, options, &local_err);
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        ret = -EINVAL;
> +        goto fail_opts;
> +    }
> +
> +    driver_name = qemu_opt_get(opts, "driver");
> +    drv = bdrv_find_format(driver_name);
> +    assert(drv != NULL);
> +
>       if (file != NULL) {
>           filename = file->filename;
>       } else {

The "return -EINVAL" in "if (drv->bdrv_needs_filename && !filename) {" 
should be changed to "ret = -EINVAL; goto fail_opts;" now.

With that changed:

Reviewed-by: Max Reitz <mreitz@redhat.com>

> @@ -831,14 +849,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
>   
>       trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
>   
> -    opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
> -    qemu_opts_absorb_qdict(opts, options, &local_err);
> -    if (local_err) {
> -        error_propagate(errp, local_err);
> -        ret = -EINVAL;
> -        goto fail_opts;
> -    }
> -
>       node_name = qemu_opt_get(opts, "node-name");
>       bdrv_assign_node_name(bs, node_name, &local_err);
>       if (local_err) {
> @@ -1405,12 +1415,15 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>           goto fail;
>       }
>   
> +    bs->open_flags = flags;
> +    bs->options = options;
> +    options = qdict_clone_shallow(options);
> +
>       /* Find the right image format driver */
>       drv = NULL;
>       drvname = qdict_get_try_str(options, "driver");
>       if (drvname) {
>           drv = bdrv_find_format(drvname);
> -        qdict_del(options, "driver");
>           if (!drv) {
>               error_setg(errp, "Unknown driver: '%s'", drvname);
>               ret = -EINVAL;
> @@ -1425,10 +1438,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>           flags &= ~BDRV_O_PROTOCOL;
>       }
>   
> -    bs->open_flags = flags;
> -    bs->options = options;
> -    options = qdict_clone_shallow(options);
> -
>       /* Open image file without format layer */
>       if ((flags & BDRV_O_PROTOCOL) == 0) {
>           if (flags & BDRV_O_RDWR) {
> @@ -1455,6 +1464,19 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>           if (ret < 0) {
>               goto fail;
>           }
> +        /*
> +         * This option update would logically belong in bdrv_fill_options(),
> +         * but we first need to open bs->file for the probing to work, while
> +         * opening bs->file already requires the (mostly) final set of options
> +         * so that cache mode etc. can be inherited.
> +         *
> +         * Adding the driver later is somewhat ugly, but it's not an option
> +         * that would ever be inherited, so it's correct. We just need to make
> +         * sure to update both bs->options (which has the full effective
> +         * options for bs) and options (which has file.* already removed).
> +         */
> +        qdict_put(bs->options, "driver", qstring_from_str(drv->format_name));
> +        qdict_put(options, "driver", qstring_from_str(drv->format_name));
>       } else if (!drv) {
>           error_setg(errp, "Must specify either driver or file");
>           ret = -EINVAL;
> @@ -1462,7 +1484,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>       }
>   
>       /* Open the image */
> -    ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
> +    ret = bdrv_open_common(bs, file, options, flags, &local_err);
>       if (ret < 0) {
>           goto fail;
>       }

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 25/34] block: Allow specifying child options in reopen
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 25/34] block: Allow specifying child options in reopen Kevin Wolf
@ 2015-05-13 13:41   ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 13:41 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> If the child was defined in the same context (-drive argument or
> blockdev-add QMP command) as its parent, a reopen of the parent should
> work the same and allow changing options of the child.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c | 12 ++++++++++--
>   1 file changed, 10 insertions(+), 2 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 26/34] block: reopen: Document option precedence and refactor accordingly
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 26/34] block: reopen: Document option precedence and refactor accordingly Kevin Wolf
@ 2015-05-13 14:47   ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-13 14:47 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> The interesting part of reopening an image is from which sources the
> effective options should be taken, i.e. which options take precedence
> over which other options. This patch documents the precedence that will
> be implemented in the following patches.
>
> It also refactors bdrv_reopen_queue(), so that the top-level reopened
> node is handled the same way as children are. Option/flag inheritance
> from the parent becomes just one item in the list and is done at the
> beginning of the function, similar to how the other items are/will be
> handled.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c | 39 +++++++++++++++++++++++++++++++++------
>   1 file changed, 33 insertions(+), 6 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 27/34] block: Add infrastructure for option inheritance
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 27/34] block: Add infrastructure for option inheritance Kevin Wolf
@ 2015-05-13 15:10   ` Max Reitz
  2015-05-13 15:28     ` Kevin Wolf
  0 siblings, 1 reply; 130+ messages in thread
From: Max Reitz @ 2015-05-13 15:10 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:21, Kevin Wolf wrote:
> Options are not actually inherited from the parent node yet, but this
> commit lays the grounds for doing so.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c                   | 51 ++++++++++++++++++++++++++---------------------
>   include/block/block_int.h |  3 ++-
>   2 files changed, 30 insertions(+), 24 deletions(-)
>
> diff --git a/block.c b/block.c
> index 1e5625f..9259b42 100644
> --- a/block.c
> +++ b/block.c
> @@ -678,11 +678,14 @@ static int bdrv_temp_snapshot_flags(int flags)
>   }
>   
>   /*
> - * Returns the flags that bs->file should get if a protocol driver is expected,
> - * based on the given flags for the parent BDS
> + * Returns the options and flags that bs->file should get if a protocol driver
> + * is expected, based on the given flags for the parent BDS
>    */
> -static int bdrv_inherited_flags(int flags)
> +static void bdrv_inherited_options(int *child_flags, QDict *child_options,
> +                                   int parent_flags, QDict *parent_options)
>   {
> +    int flags = parent_flags;
> +
>       /* Enable protocol handling, disable format probing for bs->file */
>       flags |= BDRV_O_PROTOCOL;
>   
> @@ -693,45 +696,46 @@ static int bdrv_inherited_flags(int flags)
>       /* Clear flags that only apply to the top layer */
>       flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
>   
> -    return flags;
> +    *child_flags = flags;
>   }
>   
>   const BdrvChildRole child_file = {
> -    .inherit_flags = bdrv_inherited_flags,
> +    .inherit_options = bdrv_inherited_options,
>   };
>   
> -/*
> - * Returns the flags that bs->file should get if the use of formats (and not
> - * only protocols) is permitted for it, based on the given flags for the parent
> - * BDS
> - */

Is removing this comment intentional?

The rest looks fine.

Max

> -static int bdrv_inherited_fmt_flags(int parent_flags)
> +static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options,
> +                                       int parent_flags, QDict *parent_options)
>   {
> -    int flags = child_file.inherit_flags(parent_flags);
> -    return flags & ~BDRV_O_PROTOCOL;
> +    child_file.inherit_options(child_flags, child_options,
> +                               parent_flags, parent_options);
> +
> +    *child_flags &= ~BDRV_O_PROTOCOL;
>   }
>   
>   const BdrvChildRole child_format = {
> -    .inherit_flags = bdrv_inherited_fmt_flags,
> +    .inherit_options = bdrv_inherited_fmt_options,
>   };
>   
>   /*
> - * Returns the flags that bs->backing_hd should get, based on the given flags
> - * for the parent BDS
> + * Returns the options and flags that bs->backing_hd should get, based on the
> + * given options and flags for the parent BDS
>    */
> -static int bdrv_backing_flags(int flags)
> +static void bdrv_backing_options(int *child_flags, QDict *child_options,
> +                                 int parent_flags, QDict *parent_options)
>   {
> +    int flags = parent_flags;
> +
>       /* backing files always opened read-only */
>       flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
>   
>       /* snapshot=on is handled on the top layer */
>       flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
>   
> -    return flags;
> +    *child_flags = flags;
>   }
>   
>   static const BdrvChildRole child_backing = {
> -    .inherit_flags = bdrv_backing_flags,
> +    .inherit_options = bdrv_backing_options,
>   };
>   
>   static int bdrv_open_flags(BlockDriverState *bs, int flags)
> @@ -1407,7 +1411,8 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>   
>       if (child_role) {
>           bs->inherits_from = parent;
> -        flags = child_role->inherit_flags(parent->open_flags);
> +        child_role->inherit_options(&flags, options,
> +                                    parent->open_flags, parent->options);
>       }
>   
>       ret = bdrv_fill_options(&options, &filename, flags, drv, &local_err);
> @@ -1445,7 +1450,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>           }
>           if (flags & BDRV_O_SNAPSHOT) {
>               snapshot_flags = bdrv_temp_snapshot_flags(flags);
> -            flags = bdrv_backing_flags(flags);
> +            bdrv_backing_options(&flags, options, flags, options);
>           }
>   
>           assert(file == NULL);
> @@ -1645,14 +1650,14 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
>        * 1. Explicitly passed in options (highest)
>        * 2. TODO Set in flags (only for top level)
>        * 3. TODO Retained from explicitly set options of bs
> -     * 4. TODO Inherited from parent node
> +     * 4. Inherited from parent node
>        * 5. Retained from effective options of bs
>        */
>   
>       /* Inherit from parent node */
>       if (parent_options) {
>           assert(!flags);
> -        flags = role->inherit_flags(parent_flags);
> +        role->inherit_options(&flags, options, parent_flags, parent_options);
>       }
>   
>       /* Old values are used for options that aren't set yet */
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index c9333b2..1cae8d4 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -328,7 +328,8 @@ typedef struct BdrvAioNotifier {
>   } BdrvAioNotifier;
>   
>   struct BdrvChildRole {
> -    int (*inherit_flags)(int parent_flags);
> +    void (*inherit_options)(int *child_flags, QDict *child_options,
> +                            int parent_flags, QDict *parent_options);
>   };
>   
>   extern const BdrvChildRole child_file;

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 27/34] block: Add infrastructure for option inheritance
  2015-05-13 15:10   ` Max Reitz
@ 2015-05-13 15:28     ` Kevin Wolf
  0 siblings, 0 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-13 15:28 UTC (permalink / raw)
  To: Max Reitz; +Cc: armbru, qemu-block, qemu-devel

Am 13.05.2015 um 17:10 hat Max Reitz geschrieben:
> On 08.05.2015 19:21, Kevin Wolf wrote:
> >Options are not actually inherited from the parent node yet, but this
> >commit lays the grounds for doing so.
> >
> >Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> >---
> >  block.c                   | 51 ++++++++++++++++++++++++++---------------------
> >  include/block/block_int.h |  3 ++-
> >  2 files changed, 30 insertions(+), 24 deletions(-)
> >
> >diff --git a/block.c b/block.c
> >index 1e5625f..9259b42 100644
> >--- a/block.c
> >+++ b/block.c
> >@@ -678,11 +678,14 @@ static int bdrv_temp_snapshot_flags(int flags)
> >  }
> >  /*
> >- * Returns the flags that bs->file should get if a protocol driver is expected,
> >- * based on the given flags for the parent BDS
> >+ * Returns the options and flags that bs->file should get if a protocol driver
> >+ * is expected, based on the given flags for the parent BDS
> >   */
> >-static int bdrv_inherited_flags(int flags)
> >+static void bdrv_inherited_options(int *child_flags, QDict *child_options,
> >+                                   int parent_flags, QDict *parent_options)
> >  {
> >+    int flags = parent_flags;
> >+
> >      /* Enable protocol handling, disable format probing for bs->file */
> >      flags |= BDRV_O_PROTOCOL;
> >@@ -693,45 +696,46 @@ static int bdrv_inherited_flags(int flags)
> >      /* Clear flags that only apply to the top layer */
> >      flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
> >-    return flags;
> >+    *child_flags = flags;
> >  }
> >  const BdrvChildRole child_file = {
> >-    .inherit_flags = bdrv_inherited_flags,
> >+    .inherit_options = bdrv_inherited_options,
> >  };
> >-/*
> >- * Returns the flags that bs->file should get if the use of formats (and not
> >- * only protocols) is permitted for it, based on the given flags for the parent
> >- * BDS
> >- */
> 
> Is removing this comment intentional?

Looks like a mismerge, thanks.

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options()
  2015-05-13  9:11     ` Kevin Wolf
@ 2015-05-13 17:04       ` Eric Blake
  0 siblings, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-13 17:04 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: mreitz, qemu-devel, qemu-block, armbru

[-- Attachment #1: Type: text/plain, Size: 1584 bytes --]

On 05/13/2015 03:11 AM, Kevin Wolf wrote:
> Am 12.05.2015 um 22:04 hat Eric Blake geschrieben:
>> On 05/08/2015 11:21 AM, Kevin Wolf wrote:
>>> Eventually we want to be able to change options at runtime. As a first
>>> step towards that goal, separate some option handling code from the
>>> general initialisation code in qcow2_open().
>>>
>>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>>> ---
>>>  block/qcow2.c | 135 +++++++++++++++++++++++++++++++++-------------------------
>>>  1 file changed, 76 insertions(+), 59 deletions(-)
>>>
>>> +    } else {
>>> +        error_setg(errp, "Unsupported value '%s' for qcow2 option "
>>> +                   "'overlap-check'. Allowed are either of the following: "
>>> +                   "none, constant, cached, all", opt_overlap_check);
>>
>> Pre-existing due to code motion, but I find s/either/any/ easier to read.
> 
> Isn't "either" only for a choice between two things anyway?

Exactly. And since there are four things, that's why I found it easier
to read.

> 
> The series isn't long enough yet, I'll fix it. :-)

If you want conciseness, this would also work:

"Unsupported value '%s' for qcow2 option 'overlap-check'; expecting one
of: none, constant, cached, all"

or even omitting the list of valid options altogether (which in the long
run is easier to maintain if we anticipate extending the list - as there
are fewer places where copies of the list need to be kept in sync)

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 28/34] block: Introduce bs->explicit_options
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 28/34] block: Introduce bs->explicit_options Kevin Wolf
@ 2015-05-15 17:47   ` Max Reitz
  2015-10-29 11:38     ` Kevin Wolf
  0 siblings, 1 reply; 130+ messages in thread
From: Max Reitz @ 2015-05-15 17:47 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:22, Kevin Wolf wrote:
> bs->options doesn't only contain options that the user explicitly
> requested, but also option that were derived from flags, the filename or
> inherited from the parent node.
>
> For reopen, it is important to know the difference because reopening the
> parent can change inherited values in child nodes, but it shouldn't
> change any options that were explicitly specified for the child.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c                   | 20 ++++++++++++++++++--
>   include/block/block.h     |  1 +
>   include/block/block_int.h |  1 +
>   3 files changed, 20 insertions(+), 2 deletions(-)

This patch is not that easy to review because we have to make sure that 
bs->explicit_options really does not include any derived options, so we 
have to make sure that any @options QDict given to bdrv_open_inherit() 
does not contain any derived options:


1) In bdrv_open_backing_file():
The QDict is generated by extracting the sub-QDict from @parent_options 
with the prefix "#{bdref_key}.". Maybe good, we'll have to find out. 
"driver" is put into the QDict if not explicitly overridden and if 
provided by the BDS format driver as the backing file format: Okay.
So is @parent_options good?

1a) bdrv_open_backing_file() call from bdrv_open_inherit():
@options is a QDict which we assume (our induction hypothesis) to be 
void of derived options when bdrv_open_inherit() was called. @bdref_key 
is "backing". Which calls can modify @options on the way to the 
bdrv_open_backing_file() call?
1a I) child_role->inherit_options(): None so far. But this is very 
deeply nested, and there is no notice of this whatsoever. It's fine, but 
it's not good.
1a II) bdrv_fill_options(): If @filename is a JSON filename, anything 
can happen, but this is okay because these are user-supplied options (or 
are they not? see note below). "filename" and "driver" can be set, but 
they do not match /^backing\./, so it's good.
1a III) bdrv_backing_options(): Special case of 1a I.
1a IV) bdrv_open_image(): Only removes entries from @options, so it's good.
1a V) Once again, "driver" may be set; it's fine (see 1a II).
1a VI) bdrv_open_common() only removes entries from @options, too, so 
it's good as well.
Therefore, no auto-generated options matching /^backing\./ are passed to 
bdrv_open_backing_file() here.

1b) bdrv_open_backing_file() call from mirror_complete(): 
@parent_options is NULL, everything's good.

Thus, the bdrv_open_inherit() call from bdrv_open_backing_file() is safe.


2) In bdrv_open_image():
The QDict is generated by extracting the sub-QDict from @options with 
the prefix "#{bdref_key}.". Whether that's okay again depends on the 
callers of bdrv_open_image():

2a) bdrv_open_image() call from bdrv_open_inherit():
Same problem as for 1a, @bdref_key is "file". No option set that matches 
/^file\./.

2b) bdrv_open_image() call from blkdebug_open():
@options is a QDict which is both supplied to blkdebug_open() and may be 
filled from a config file (the latter one of which is definitely okay), 
all blkdebug-specific options have been removed (none of which match 
/^image\./ anyway). @bdref_key is "image". The question is whether any 
option can be autogenerated for blkdebug_open() which matches /^image\./:
2b I) drv->bdrv_file_open() call in bdrv_open_common(): Basically the 
same problem as for 1a. No option set that matches /^image\./ either, so 
it's good.

2c) First bdrv_open_image() call from blkverify_open():
@options is a QDict which is supplied to blkverify_open() where all 
blkverify-specific options (x-raw and x-image) have been removed. 
@bdref_key is "raw". Essentially the same as 2b, no option set that 
matches /^raw\./ before the drv->bdrv_file_open() call, so it's good.

2d) Second bdrv_open_image() call from blkverify_open():
Same as 2c with @bdref_key being "test". No option set that matches 
/^test\./ before the drv->bdrv_file_open() call, so it's good.

2e) bdrv_open_image() call from quorum_open():
@options is a QDict which is supplied to quorum_open() where all 
quorum-specific options have been removed. @bdref_key is "children.%d". 
Same as 2b, 2c, 2d: No option set that matches /^children\.\d+\./ before 
the drv->bdrv_file_open() call in bdrv_open_common(), so it's good.

2f) bdrv_open_image() call from vmdk_parse_extents():
@options is supplied directly to this function; it originally comes 
directly from vmdk_open(), without any modification. vmdk_open() is 
called as drv->bdrv_open() in bdrv_open_common(); so it's again 
essentially the same as 2b to 2e, with @bdref_key being "extents.%d". No 
option set that matches /^extents\.\d+\./ before said call, so it's good.

That's all. As a recurring pattern, we can see that as long as nothing 
in bdrv_open_inherit() sets any option with a dot in it, we're good.


3) In bdrv_open():
The QDict is just the one given to bdrv_open().

3a) bdrv_open() call from bdrv_append_temp_snapshot():
"file.driver" and "file.filename" are set, and these are the only 
options in the whole QDict. Well... I'd argue that these are options 
supplied are supplied from the flags (BDRV_O_SNAPSHOT, to be exact), but 
I guess I can turn a blind eye to this case.

3b) bdrv_open() call from blk_new_open():
@options is just the one given to blk_new_open().
3b I) blk_new_open() call from blockdev_init(): Some options are removed 
from @bs_opts, "driver" is set if "format" is set (and "driver" isn't), 
okay. No further modifications, good. (@bs_opts in turn comes from 
drive_new() and blockdev_add(), therefore those really are options 
coming from the user)
3b II) blk_new_open() call from blk_connect() (Xen): @options is empty 
or will contain "driver" if that's enforced by Xen. Basically as correct 
as setting "driver" based on the backing file format for backing files, 
so it's good.
3b III) blk_new_open() call from img_open() (qemu-img): @options is 
empty or will contain the driver set by the user. Good.
3b IV) First blk_new_open() call from img_rebase() (qemu-img): Same as 
above. Good.
3b V) Second blk_new_open() call from img_rebase() (qemu-img): Same as 
above. Good.
3b VI) blk_new_open() call from openfile() (qemu-io): @opts is generated 
from user-supplied options. Good.
3b VII) blk_new_open() call from main() (qemu-nbd): Same as in qemu-img. 
Good.

3c, 3d, 3e, 3f, 3g, 3h, 3i, 3j, 3k, 3l, 3m, 3n, 3o, 3p, 3q) bdrv_open() 
call from qcow_create(), qcow2_create2(), qcow2_create2(), qed_create(), 
sd_prealloc(), sd_create(), vdi_create(), vhdx_create(), 
vmdk_create_extent(), vmdk_create(), vpc_create(), enable_write_target() 
(vvfat), bdrv_image_create(), qmp_bdrv_open_encrypted(), and 
qmp_drive_backup():
@options is NULL. Good.

3r, 3s) bdrv_open() call from external_snapshot_prepare() and 
qmp_drive_mirror():
@options only contains a node-name, and that one is user-supplied. Good.

In total, 3a looks a bit fishy, but I guess it's alright.


Concluding, I can say that setting bs->explicit_options at that point 
will not result in automatically derived options being included there 
(except for 3a). A problem I do see is that as can be seen above, 
deriving this is not trivial, and keeping this the case isn't either. We 
have to make sure that bdrv_open_inherit() will never set any option in 
@options which contains a dot, neither may any of the functions it calls 
(do we need appropriate documentation for child_role->inherit_options()?).

As noted above in point 1a II, @filename may be a JSON filename in 
bdrv_open_inherit(). I think these would be user-supplied options, so 
they should be put into bs->explicit_options, too. If they are not, 1a 
II is invalid and we have to make sure that none of the options supplied 
there can end up in any bs->explicit_options of any child BDS.

Also note that above I did not check whether bs->explicit_options will 
contain all user-specified options. I only made sure that it doesn't 
contain automatically derived options. But as long as blkdebug doesn't 
absorb options like "image.filename", it should be fine (no options 
prefixed with a bdref_key matching a BDS child role we are still 
intending to open may be removed, but I don't think that's the case, ever).


Oh, and also we have to make sure that setting 
reopen_state->bs->explicit_options does not result in derived options 
being set. It's generated from @options given to 
bdrv_reopen_queue_child(), joined with bs->explicit_options (induction 
hypothesis: bs->explicit_options is good). Is @options good, too? So far 
yes, because it's always empty (except for qemu-io, where it comes 
directly from the user).

> diff --git a/block.c b/block.c
> index 9259b42..d76e385 100644
> --- a/block.c
> +++ b/block.c
> @@ -1408,6 +1408,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>       if (options == NULL) {
>           options = qdict_new();
>       }
> +    bs->explicit_options = qdict_clone_shallow(options);
>   
>       if (child_role) {
>           bs->inherits_from = parent;
> @@ -1559,6 +1560,7 @@ fail:
>       if (file != NULL) {
>           bdrv_unref(file);
>       }
> +    QDECREF(bs->explicit_options);
>       QDECREF(bs->options);
>       QDECREF(options);
>       bs->options = NULL;
> @@ -1634,7 +1636,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
>   
>       BlockReopenQueueEntry *bs_entry;
>       BdrvChild *child;
> -    QDict *old_options;
> +    QDict *old_options, *explicit_options;
>   
>       if (bs_queue == NULL) {
>           bs_queue = g_new0(BlockReopenQueue, 1);
> @@ -1649,11 +1651,18 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
>        * Precedence of options:
>        * 1. Explicitly passed in options (highest)
>        * 2. TODO Set in flags (only for top level)
> -     * 3. TODO Retained from explicitly set options of bs
> +     * 3. Retained from explicitly set options of bs
>        * 4. Inherited from parent node
>        * 5. Retained from effective options of bs
>        */
>   
> +    /* Old explicitly set values (don't overwrite by inherited value) */
> +    old_options = qdict_clone_shallow(bs->explicit_options);
> +    qdict_join(options, old_options, false);
> +    QDECREF(old_options);
> +
> +    explicit_options = qdict_clone_shallow(options);
> +
>       /* Inherit from parent node */
>       if (parent_options) {
>           assert(!flags);
> @@ -1692,6 +1701,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
>   
>       bs_entry->state.bs = bs;
>       bs_entry->state.options = options;
> +    bs_entry->state.explicit_options = explicit_options;
>       bs_entry->state.flags = flags;
>   
>       return bs_queue;
> @@ -1886,6 +1896,9 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
>       }
>   
>       /* set BDS specific flags now */
> +    QDECREF(reopen_state->bs->explicit_options);
> +
> +    reopen_state->bs->explicit_options   = reopen_state->explicit_options;
>       reopen_state->bs->open_flags         = reopen_state->flags;
>       reopen_state->bs->enable_write_cache = !!(reopen_state->flags &
>                                                 BDRV_O_CACHE_WB);
> @@ -1909,6 +1922,8 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
>       if (drv->bdrv_reopen_abort) {
>           drv->bdrv_reopen_abort(reopen_state);
>       }
> +
> +    QDECREF(reopen_state->explicit_options);

I think this must be done in bdrv_reopen_multiple(). Otherwise, 
reopen_state->explicit_options is leaked for the one BDS where 
bdrv_reopen_prepare() failed.

>   }
>   
>   
> @@ -1952,6 +1967,7 @@ void bdrv_close(BlockDriverState *bs)
>           bs->sg = 0;
>           bs->zero_beyond_eof = false;
>           QDECREF(bs->options);
> +        QDECREF(bs->explicit_options);
>           bs->options = NULL;
>           QDECREF(bs->full_open_options);
>           bs->full_open_options = NULL;
> diff --git a/include/block/block.h b/include/block/block.h
> index 1287013..08bd0fe 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -147,6 +147,7 @@ typedef struct BDRVReopenState {
>       BlockDriverState *bs;
>       int flags;
>       QDict *options;
> +    QDict *explicit_options;
>       void *opaque;
>   } BDRVReopenState;
>   
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index 1cae8d4..a2e96bb 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -443,6 +443,7 @@ struct BlockDriverState {
>       QLIST_HEAD(, BdrvChild) children;
>   
>       QDict *options;
> +    QDict *explicit_options;
>       BlockdevDetectZeroesOptions detect_zeroes;
>   
>       /* The error object in use for blocking operations on backing_hd */

What I'd like to have for a R-b: No leak of 
reopen_state->explicit_options, and an answer to the question whether 
options coming from a JSON filename should be part of 
bs->explicit_options (right now, they are for all child BDSs, but not 
for the top BDS, because bdrv_fill_options() is called after 
bs->explicit_options is set).

Max

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 29/34] qemu-iotests: Remove cache mode test without medium
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 29/34] qemu-iotests: Remove cache mode test without medium Kevin Wolf
@ 2015-05-15 17:53   ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-15 17:53 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:22, Kevin Wolf wrote:
> Specifying the cache mode for a driver without a medium is not a useful
> thing to do: As long as there is no medium, the cache mode doesn't make
> a difference, and once the 'change' command is used to insert a medium,
> it ignores the old cache mode and makes the new medium use
> cache=writethrough.
>
> Later patches will make it an error to specify the cache mode for an
> empty drive. Remove the corresponding test case.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   tests/qemu-iotests/051     | 14 --------------
>   tests/qemu-iotests/051.out | 26 --------------------------
>   2 files changed, 40 deletions(-)

Well, you could have changed it to format=null-co or something...

But it's your test so it's your call whether to remove it or not.

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 30/34] block: reopen: Extract QemuOpts for generic block layer options
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 30/34] block: reopen: Extract QemuOpts for generic block layer options Kevin Wolf
@ 2015-05-15 18:07   ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-15 18:07 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:22, Kevin Wolf wrote:
> This patch adds a QemuOpts for generic block layer options to
> bdrv_reopen_prepare(). The only two options that exist currently
> (node-name and driver) cannot be changed

And I don't suppose we want them to be changed at some point.

(changing node-name doesn't really make sense, because it's not really 
meant for human usage anyway, and tools don't need to change it once 
it's set, they just need a unique name; and I can't think of a useful 
use case for changing the driver)

> , so the only thing we do is
> putting them right back into the QDict so that we check at the end that
> they are indeed unchanged.
>
> We will add new options soon that can actually be changed.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c | 24 ++++++++++++++++++++++++
>   1 file changed, 24 insertions(+)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 31/34] block: Move cache options into options QDict
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 31/34] block: Move cache options into options QDict Kevin Wolf
@ 2015-05-15 18:43   ` Max Reitz
  2015-05-15 19:44     ` Eric Blake
  0 siblings, 1 reply; 130+ messages in thread
From: Max Reitz @ 2015-05-15 18:43 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:22, Kevin Wolf wrote:
> This adds the cache mode options to the QDict, so that they can be
> specified for child nodes (e.g. backing.cache.direct=off).
>
> The cache modes are not removed from the flags at this point; instead,
> options and flags are kept in sync. If the user specifies both flags and
> options, the options take precedence.
>
> Child node inherit cache modes as options now, they don't use flags any
> more.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c    | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
>   blockdev.c | 27 +++++---------------
>   2 files changed, 88 insertions(+), 24 deletions(-)
>
> diff --git a/block.c b/block.c
> index 8faa5ce..2430070 100644
> --- a/block.c
> +++ b/block.c
> @@ -27,6 +27,7 @@
>   #include "block/block_int.h"
>   #include "block/blockjob.h"
>   #include "qemu/module.h"
> +#include "qapi/qmp/qbool.h"
>   #include "qapi/qmp/qjson.h"
>   #include "sysemu/block-backend.h"
>   #include "sysemu/sysemu.h"
> @@ -689,9 +690,15 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
>       /* Enable protocol handling, disable format probing for bs->file */
>       flags |= BDRV_O_PROTOCOL;
>   
> +    /* If the cache mode isn't explicitly set, inherit direct and no-flush from
> +     * the parent. */
> +    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
> +    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
> +

Well, this directly violates what I wanted these functions to guarantee: 
Not set any option with a dot in them. It's fine anyway because "cache" 
is never used as the bdref_key for child BDS.

>       /* Our block drivers take care to send flushes and respect unmap policy,
>        * so we can enable both unconditionally on lower layers. */

The comment reads a bit strange now (because it's referring to two 
heterogenous lines instead of one line with two flags on it), and also 
WB is no longer "unconditionally" enabled.

> -    flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP;
> +    qdict_set_default_str(child_options, BDRV_OPT_CACHE_WB, "on");
> +    flags |= BDRV_O_UNMAP;
>   
>       /* Clear flags that only apply to the top layer */
>       flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
> @@ -725,6 +732,11 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
>   {
>       int flags = parent_flags;
>   
> +    /* The cache mode is inherited unmodified for backing files */
> +    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_WB);
> +    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
> +    qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
> +
>       /* backing files always opened read-only */
>       flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
>   
> @@ -758,6 +770,42 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
>       return open_flags;
>   }
>   
> +static void update_flags_from_options(int *flags, QemuOpts *opts)
> +{
> +    *flags &= ~BDRV_O_CACHE_MASK;
> +
> +    assert(qemu_opt_find(opts, BDRV_OPT_CACHE_WB));
> +    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, false)) {
> +        *flags |= BDRV_O_CACHE_WB;
> +    }
> +
> +    assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH));
> +    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
> +        *flags |= BDRV_O_NO_FLUSH;
> +    }
> +
> +    assert(qemu_opt_find(opts, BDRV_OPT_CACHE_DIRECT));
> +    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
> +        *flags |= BDRV_O_NOCACHE;
> +    }
> +}
> +
> +static void update_options_from_flags(QDict *options, int flags)
> +{
> +    if (!qdict_haskey(options, BDRV_OPT_CACHE_WB)) {
> +        qdict_put(options, BDRV_OPT_CACHE_WB,
> +                  qbool_from_int(flags & BDRV_O_CACHE_WB));

Urgh, qbool_from_int() doesn't cast the int to bool? :-/



> +    }
> +    if (!qdict_haskey(options, BDRV_OPT_CACHE_DIRECT)) {
> +        qdict_put(options, BDRV_OPT_CACHE_DIRECT,
> +                  qbool_from_int(flags & BDRV_O_NOCACHE));
> +    }
> +    if (!qdict_haskey(options, BDRV_OPT_CACHE_NO_FLUSH)) {
> +        qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH,
> +                  qbool_from_int(flags & BDRV_O_NO_FLUSH));
> +    }
> +}
> +
>   static void bdrv_assign_node_name(BlockDriverState *bs,
>                                     const char *node_name,
>                                     Error **errp)
> @@ -804,6 +852,20 @@ static QemuOptsList bdrv_runtime_opts = {
>               .type = QEMU_OPT_STRING,
>               .help = "Block driver to use for the node",
>           },
> +        {
> +            .name = BDRV_OPT_CACHE_WB,
> +            .type = QEMU_OPT_BOOL,
> +            .help = "Enable writeback mode",
> +        },
> +        {
> +            .name = BDRV_OPT_CACHE_DIRECT,
> +            .type = QEMU_OPT_BOOL,

Why no .help?

> +        },
> +        {
> +            .name = BDRV_OPT_CACHE_NO_FLUSH,
> +            .type = QEMU_OPT_BOOL,
> +            .help = "Ignore flush requests",
> +        },
>           { /* end of list */ }
>       },
>   };
> @@ -907,7 +969,9 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
>       bs->drv = drv;
>       bs->opaque = g_malloc0(drv->instance_size);
>   
> -    bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
> +    /* Apply cache mode options */
> +    update_flags_from_options(&bs->open_flags, opts);
> +    bdrv_set_enable_write_cache(bs, bs->open_flags & BDRV_O_CACHE_WB);
>   
>       /* Open the image, either directly or using a protocol */
>       if (drv->bdrv_file_open) {
> @@ -1025,6 +1089,9 @@ static int bdrv_fill_options(QDict **options, const char **pfilename, int flags,
>           *pfilename = filename = NULL;
>       }
>   
> +    /* Translate cache options from flags into options */
> +    update_options_from_flags(*options, flags);
> +
>       /* Fetch the file name from the options QDict if necessary */
>       if (protocol && filename) {
>           if (!qdict_haskey(*options, "filename")) {
> @@ -1650,12 +1717,22 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
>       /*
>        * Precedence of options:
>        * 1. Explicitly passed in options (highest)
> -     * 2. TODO Set in flags (only for top level)
> +     * 2. Set in flags (only for top level)
>        * 3. Retained from explicitly set options of bs
>        * 4. Inherited from parent node
>        * 5. Retained from effective options of bs
>        */
>   
> +    if (!parent_options) {
> +        /*
> +         * Any setting represented by flags is always updated. If the
> +         * corresponding QDict option is set, it takes precedence. Otherwise
> +         * the flag is translated into a QDict option. The old setting of bs is
> +         * not considered.
> +         */
> +        update_options_from_flags(options, flags);
> +    }
> +
>       /* Old explicitly set values (don't overwrite by inherited value) */
>       old_options = qdict_clone_shallow(bs->explicit_options);
>       qdict_join(options, old_options, false);
> @@ -1824,6 +1901,8 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
>           goto error;
>       }
>   
> +    update_flags_from_options(&reopen_state->flags, opts);
> +
>       /* node-name and driver must be unchanged. Put them back into the QDict, so
>        * that they are checked at the end of this function. */
>       value = qemu_opt_get(opts, "node-name");
> diff --git a/blockdev.c b/blockdev.c
> index 77cbe72..90853aa 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -391,15 +391,12 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
>           }
>       }
>   
> -    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true)) {
> -        bdrv_flags |= BDRV_O_CACHE_WB;
> -    }
> -    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
> -        bdrv_flags |= BDRV_O_NOCACHE;
> -    }
> -    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
> -        bdrv_flags |= BDRV_O_NO_FLUSH;
> -    }
> +    /* bdrv_open() defaults to the values in bdrv_flags (for compatibility with
> +     * other callers) rather than what we want as the real defaults. Apply the
> +     * defaults here instead. */
> +    qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_WB, "on");
> +    qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off");
> +    qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
>   
>   #ifdef CONFIG_LINUX_AIO
>       if ((buf = qemu_opt_get(opts, "aio")) != NULL) {
> @@ -3106,18 +3103,6 @@ QemuOptsList qemu_common_drive_opts = {
>               .type = QEMU_OPT_STRING,
>               .help = "discard operation (ignore/off, unmap/on)",
>           },{
> -            .name = BDRV_OPT_CACHE_WB,
> -            .type = QEMU_OPT_BOOL,
> -            .help = "enables writeback mode for any caches",
> -        },{
> -            .name = BDRV_OPT_CACHE_DIRECT,
> -            .type = QEMU_OPT_BOOL,
> -            .help = "enables use of O_DIRECT (bypass the host page cache)",
> -        },{
> -            .name = BDRV_OPT_CACHE_NO_FLUSH,
> -            .type = QEMU_OPT_BOOL,
> -            .help = "ignore any flush requests for the device",
> -        },{
>               .name = "aio",
>               .type = QEMU_OPT_STRING,
>               .help = "host AIO implementation (threads, native)",

Question: bdrv_set_enable_write_cache() changes bs->open_flags so the 
option (BDRV_O_CACHE_WB) is preserved beyond a reopen (according to the 
comment there). Is this still the case? Or should it instead modify 
bs->options now?

Max

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 32/34] qemu-iotests: Try setting cache mode for children
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 32/34] qemu-iotests: Try setting cache mode for children Kevin Wolf
@ 2015-05-15 18:52   ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-15 18:52 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:22, Kevin Wolf wrote:
> This is a basic test for specifying cache modes for child nodes on the
> command line. It doesn't take much time and works without O_DIRECT
> support.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   tests/qemu-iotests/051     | 12 +++++++++
>   tests/qemu-iotests/051.out | 63 ++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 75 insertions(+)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 33/34] qemu-iotests: Test cache mode option inheritance
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 33/34] qemu-iotests: Test cache mode option inheritance Kevin Wolf
@ 2015-05-15 19:16   ` Max Reitz
  2015-05-18 14:39     ` Kevin Wolf
  0 siblings, 1 reply; 130+ messages in thread
From: Max Reitz @ 2015-05-15 19:16 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:22, Kevin Wolf wrote:
> This is doing a more complete test on setting cache modes both while
> opening an image (i.e. in a -drive command line) and in reopen
> situations. It checks that reopen can specify options for child nodes
> and that cache modes are correctly inherited from parent nodes where
> they are not specified.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   tests/qemu-iotests/132     | 336 ++++++++++++++++++++
>   tests/qemu-iotests/132.out | 767 +++++++++++++++++++++++++++++++++++++++++++++
>   tests/qemu-iotests/group   |   1 +
>   3 files changed, 1104 insertions(+)
>   create mode 100755 tests/qemu-iotests/132
>   create mode 100644 tests/qemu-iotests/132.out


So starting from now I once again need to specify -c writethrough for 
running tests in tmpfs... Welp.

("Welp" because there is no actual strict requirement to have O_DIRECT, 
because we don't actually use it but only check the configuration; so 
using null-co would be fine, too, but we can only use that with raw as 
the format driver, and raw doesn't support backing files...)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 34/34] qemu-iotests: Test reopen with node-name/driver options
  2015-05-08 17:22 ` [Qemu-devel] [PATCH 34/34] qemu-iotests: Test reopen with node-name/driver options Kevin Wolf
@ 2015-05-15 19:19   ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-15 19:19 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

On 08.05.2015 19:22, Kevin Wolf wrote:
> 'node-name' and 'driver' should not be changed during a reopen
> operation. It is, however, valid to specify them with the same value as
> they already had.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   tests/qemu-iotests/133     | 90 ++++++++++++++++++++++++++++++++++++++++++++++
>   tests/qemu-iotests/133.out | 22 ++++++++++++
>   tests/qemu-iotests/group   |  1 +
>   3 files changed, 113 insertions(+)
>   create mode 100755 tests/qemu-iotests/133
>   create mode 100644 tests/qemu-iotests/133.out

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 31/34] block: Move cache options into options QDict
  2015-05-15 18:43   ` Max Reitz
@ 2015-05-15 19:44     ` Eric Blake
  0 siblings, 0 replies; 130+ messages in thread
From: Eric Blake @ 2015-05-15 19:44 UTC (permalink / raw)
  To: Max Reitz, Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1223 bytes --]

On 05/15/2015 12:43 PM, Max Reitz wrote:
> On 08.05.2015 19:22, Kevin Wolf wrote:
>> This adds the cache mode options to the QDict, so that they can be
>> specified for child nodes (e.g. backing.cache.direct=off).
>>
>> The cache modes are not removed from the flags at this point; instead,
>> options and flags are kept in sync. If the user specifies both flags and
>> options, the options take precedence.
>>
>> Child node inherit cache modes as options now, they don't use flags any
>> more.
>>
>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

>> +
>> +static void update_options_from_flags(QDict *options, int flags)
>> +{
>> +    if (!qdict_haskey(options, BDRV_OPT_CACHE_WB)) {
>> +        qdict_put(options, BDRV_OPT_CACHE_WB,
>> +                  qbool_from_int(flags & BDRV_O_CACHE_WB));
> 
> Urgh, qbool_from_int() doesn't cast the int to bool? :-/

No, it's a horrible interface at the moment. But it's on my to-do plate
to see how hard it would be to modernize a bit, since I've already been
touching in that area (the recent addition of qnull copied heavily from
qbool).

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 33/34] qemu-iotests: Test cache mode option inheritance
  2015-05-15 19:16   ` Max Reitz
@ 2015-05-18 14:39     ` Kevin Wolf
  2015-05-18 15:32       ` Max Reitz
  0 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-18 14:39 UTC (permalink / raw)
  To: Max Reitz; +Cc: armbru, qemu-block, qemu-devel

Am 15.05.2015 um 21:16 hat Max Reitz geschrieben:
> On 08.05.2015 19:22, Kevin Wolf wrote:
> >This is doing a more complete test on setting cache modes both while
> >opening an image (i.e. in a -drive command line) and in reopen
> >situations. It checks that reopen can specify options for child nodes
> >and that cache modes are correctly inherited from parent nodes where
> >they are not specified.
> >
> >Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> >---
> >  tests/qemu-iotests/132     | 336 ++++++++++++++++++++
> >  tests/qemu-iotests/132.out | 767 +++++++++++++++++++++++++++++++++++++++++++++
> >  tests/qemu-iotests/group   |   1 +
> >  3 files changed, 1104 insertions(+)
> >  create mode 100755 tests/qemu-iotests/132
> >  create mode 100644 tests/qemu-iotests/132.out
> 
> 
> So starting from now I once again need to specify -c writethrough
> for running tests in tmpfs... Welp.
> 
> ("Welp" because there is no actual strict requirement to have
> O_DIRECT, because we don't actually use it but only check the
> configuration; so using null-co would be fine, too, but we can only
> use that with raw as the format driver, and raw doesn't support
> backing files...)

Perhaps we should add a switch to tell qemu-iotests to skip test cases
that would require cache.direct=on? Or create a group 'direct' so you
can use '-x direct'?

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 33/34] qemu-iotests: Test cache mode option inheritance
  2015-05-18 14:39     ` Kevin Wolf
@ 2015-05-18 15:32       ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-05-18 15:32 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: armbru, qemu-block, qemu-devel

On 18.05.2015 16:39, Kevin Wolf wrote:
> Am 15.05.2015 um 21:16 hat Max Reitz geschrieben:
>> On 08.05.2015 19:22, Kevin Wolf wrote:
>>> This is doing a more complete test on setting cache modes both while
>>> opening an image (i.e. in a -drive command line) and in reopen
>>> situations. It checks that reopen can specify options for child nodes
>>> and that cache modes are correctly inherited from parent nodes where
>>> they are not specified.
>>>
>>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>>> ---
>>>   tests/qemu-iotests/132     | 336 ++++++++++++++++++++
>>>   tests/qemu-iotests/132.out | 767 +++++++++++++++++++++++++++++++++++++++++++++
>>>   tests/qemu-iotests/group   |   1 +
>>>   3 files changed, 1104 insertions(+)
>>>   create mode 100755 tests/qemu-iotests/132
>>>   create mode 100644 tests/qemu-iotests/132.out
>>
>> So starting from now I once again need to specify -c writethrough
>> for running tests in tmpfs... Welp.
>>
>> ("Welp" because there is no actual strict requirement to have
>> O_DIRECT, because we don't actually use it but only check the
>> configuration; so using null-co would be fine, too, but we can only
>> use that with raw as the format driver, and raw doesn't support
>> backing files...)
> Perhaps we should add a switch to tell qemu-iotests to skip test cases
> that would require cache.direct=on? Or create a group 'direct' so you
> can use '-x direct'?

Well, it would be 'non-direct', and in this case it's not better than -c 
writethrough. ;-)

I was lucky I got away without specifying the cache mode until now, and 
now I'll just have to live with it. If we (I) would want to make it 
easier, we'd have to probe (in ./check) whether $TEST_DIR supports 
O_DIRECT or not.

Max

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 01/34] qdict: Add qdict_array_entries()
  2015-05-08 20:06   ` Eric Blake
  2015-05-08 21:22     ` Eric Blake
  2015-05-11 14:40     ` Kevin Wolf
@ 2015-05-20 14:19     ` Alberto Garcia
  2 siblings, 0 replies; 130+ messages in thread
From: Alberto Garcia @ 2015-05-20 14:19 UTC (permalink / raw)
  To: Eric Blake, Kevin Wolf, qemu-block; +Cc: armbru, qemu-devel, mreitz

On Fri 08 May 2015 10:06:35 PM CEST, Eric Blake wrote:

>> +    for (i = 0; i < UINT_MAX; i++) {
>> +        QObject *subqobj;
>> +        int subqdict_entries;
>> +        size_t slen = 32 + subqdict_len;
>> +        char indexstr[slen], prefix[slen];
>
> And more dependence on a working C99 compiler, thanks to variable
> length array (VLA).
>
>> +        size_t snprintf_ret;
>> +
>> +        snprintf_ret = snprintf(indexstr, slen, "%s%u", subqdict, i);
>> +        assert(snprintf_ret < slen);
>
> Since gcc may compile the allocation of indexstr into a malloc()
> anyways, would it be any simpler to just use g_strdup_printf()
> directly, instead of futzing around with VLA and snprintf() ourselves?
> It might mean less code, as some of the error checking is taken care
> of on your behalf.

Since the only difference between the two strings you are allocating is
the trailing dot, you could also save one malloc() by reusing the same
string and stripping the dot.

Alternatively you could allocate the memory outside the loop instead of
having to do it in every iteration. The size is always the same after
all.

Berto

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 03/34] quorum: Use bdrv_open_image()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 03/34] quorum: Use bdrv_open_image() Kevin Wolf
                     ` (2 preceding siblings ...)
  2015-05-12 19:07   ` [Qemu-devel] [Qemu-block] " Jeff Cody
@ 2015-05-20 14:46   ` Alberto Garcia
  3 siblings, 0 replies; 130+ messages in thread
From: Alberto Garcia @ 2015-05-20 14:46 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

On Fri 08 May 2015 07:21:35 PM CEST, Kevin Wolf wrote:

> Besides standardising on a single interface for opening child nodes,
> this simplifies the .bdrv_open() implementation of the quorum block
> driver by using block layer functionality for handling BlockdevRefs.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Reviewed-by: Alberto Garcia <berto@igalia.com>

Berto

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 05/34] block: Use macro for cache option names
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names Kevin Wolf
                     ` (3 preceding siblings ...)
  2015-05-12 19:14   ` [Qemu-devel] [Qemu-block] " Jeff Cody
@ 2015-05-20 14:49   ` Alberto Garcia
  4 siblings, 0 replies; 130+ messages in thread
From: Alberto Garcia @ 2015-05-20 14:49 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

On Fri 08 May 2015 07:21:37 PM CEST, Kevin Wolf wrote:

> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Reviewed-by: Alberto Garcia <berto@igalia.com>

Berto

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 11/34] block: Allow references for backing files
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 11/34] block: Allow references for backing files Kevin Wolf
  2015-05-11 16:19   ` Max Reitz
  2015-05-12 14:46   ` Eric Blake
@ 2015-05-21  5:47   ` Wen Congyang
  2015-05-27 12:31     ` Kevin Wolf
  2 siblings, 1 reply; 130+ messages in thread
From: Wen Congyang @ 2015-05-21  5:47 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

On 05/09/2015 01:21 AM, Kevin Wolf wrote:
> For bs->file, using references to existing BDSes has been possible for a
> while already. This patch enables the same for bs->backing_hd.

1. We reference to an existing BDSes, and some disk uses this blk. Do
we allow this?
2. bs->backing_hd->blk can be not NULL now? If we do an active commit
to this backing file(use mirror job), we will call bdrv_swap() in
mirror_exit(), and the function bdrv_swap() doesn't allow that
new_bs->blk(here is bs->backing_hd) is not NULL.

Thanks
Wen Congyang

> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c               | 42 ++++++++++++++++++++++++------------------
>  block/mirror.c        |  2 +-
>  include/block/block.h |  3 ++-
>  3 files changed, 27 insertions(+), 20 deletions(-)
> 
> diff --git a/block.c b/block.c
> index e93bf63..95dc51e 100644
> --- a/block.c
> +++ b/block.c
> @@ -1109,30 +1109,41 @@ out:
>  /*
>   * Opens the backing file for a BlockDriverState if not yet open
>   *
> - * options is a QDict of options to pass to the block drivers, or NULL for an
> - * empty set of options. The reference to the QDict is transferred to this
> - * function (even on failure), so if the caller intends to reuse the dictionary,
> - * it needs to use QINCREF() before calling bdrv_file_open.
> + * bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
> + * That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
> + * itself, all options starting with "${bdref_key}." are considered part of the
> + * BlockdevRef.
> + *
> + * TODO Can this be unified with bdrv_open_image()?
>   */
> -int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
> +int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
> +                           const char *bdref_key, Error **errp)
>  {
>      char *backing_filename = g_malloc0(PATH_MAX);
> +    char *bdref_key_dot;
> +    const char *reference = NULL;
>      int ret = 0;
>      BlockDriverState *backing_hd;
> +    QDict *options;
>      Error *local_err = NULL;
>  
>      if (bs->backing_hd != NULL) {
> -        QDECREF(options);
>          goto free_exit;
>      }
>  
>      /* NULL means an empty set of options */
> -    if (options == NULL) {
> -        options = qdict_new();
> +    if (parent_options == NULL) {
> +        parent_options = qdict_new();
>      }
>  
>      bs->open_flags &= ~BDRV_O_NO_BACKING;
> -    if (qdict_haskey(options, "file.filename")) {
> +
> +    bdref_key_dot = g_strdup_printf("%s.", bdref_key);
> +    qdict_extract_subqdict(parent_options, &options, bdref_key_dot);
> +    g_free(bdref_key_dot);
> +
> +    reference = qdict_get_try_str(parent_options, bdref_key);
> +    if (reference || qdict_haskey(options, "file.filename")) {
>          backing_filename[0] = '\0';
>      } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
>          QDECREF(options);
> @@ -1155,20 +1166,17 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
>          goto free_exit;
>      }
>  
> -    backing_hd = bdrv_new();
> -
>      if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
>          qdict_put(options, "driver", qstring_from_str(bs->backing_format));
>      }
>  
>      assert(bs->backing_hd == NULL);
> +    backing_hd = NULL;
>      ret = bdrv_open_inherit(&backing_hd,
>                              *backing_filename ? backing_filename : NULL,
> -                            NULL, options, 0, bs, &child_backing,
> +                            reference, options, 0, bs, &child_backing,
>                              NULL, &local_err);
>      if (ret < 0) {
> -        bdrv_unref(backing_hd);
> -        backing_hd = NULL;
>          bs->open_flags |= BDRV_O_NO_BACKING;
>          error_setg(errp, "Could not open backing file: %s",
>                     error_get_pretty(local_err));
> @@ -1176,6 +1184,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
>          goto free_exit;
>      }
>      bdrv_set_backing_hd(bs, backing_hd);
> +    qdict_del(parent_options, bdref_key);
>  
>  free_exit:
>      g_free(backing_filename);
> @@ -1463,10 +1472,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>  
>      /* If there is a backing file, use it */
>      if ((flags & BDRV_O_NO_BACKING) == 0) {
> -        QDict *backing_options;
> -
> -        qdict_extract_subqdict(options, &backing_options, "backing.");
> -        ret = bdrv_open_backing_file(bs, backing_options, &local_err);
> +        ret = bdrv_open_backing_file(bs, options, "backing", &local_err);
>          if (ret < 0) {
>              goto close_and_fail;
>          }
> diff --git a/block/mirror.c b/block/mirror.c
> index 58f391a..f1bc342 100644
> --- a/block/mirror.c
> +++ b/block/mirror.c
> @@ -592,7 +592,7 @@ static void mirror_complete(BlockJob *job, Error **errp)
>      Error *local_err = NULL;
>      int ret;
>  
> -    ret = bdrv_open_backing_file(s->target, NULL, &local_err);
> +    ret = bdrv_open_backing_file(s->target, NULL, "backing", &local_err);
>      if (ret < 0) {
>          error_propagate(errp, local_err);
>          return;
> diff --git a/include/block/block.h b/include/block/block.h
> index 27ab2c8..341a551 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -208,7 +208,8 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
>                      BlockDriverState* parent, const BdrvChildRole *child_role,
>                      bool allow_none, Error **errp);
>  void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
> -int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
> +int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
> +                           const char *bdref_key, Error **errp);
>  int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp);
>  int bdrv_open(BlockDriverState **pbs, const char *filename,
>                const char *reference, QDict *options, int flags,
> 

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState Kevin Wolf
  2015-05-08 23:34   ` Eric Blake
  2015-05-11 15:45   ` Max Reitz
@ 2015-05-27 11:30   ` Kevin Wolf
  2 siblings, 0 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-27 11:30 UTC (permalink / raw)
  To: qemu-block; +Cc: qemu-devel, armbru, mreitz

Am 08.05.2015 um 19:21 hat Kevin Wolf geschrieben:
> This allows iterating over all children of a given BDS, not only
> including bs->file and bs->backing_hd, but also driver-specific
> ones like VMDK extents or Quorum children.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c                   | 27 +++++++++++++++++++++++++++
>  include/block/block_int.h |  8 ++++++++
>  2 files changed, 35 insertions(+)
> 
> diff --git a/block.c b/block.c
> index c4f0fb4..59f54ed 100644
> --- a/block.c
> +++ b/block.c
> @@ -1301,6 +1301,19 @@ out:
>      return ret;
>  }
>  
> +static void bdrv_attach_child(BlockDriverState *parent_bs,
> +                              BlockDriverState *child_bs,
> +                              const BdrvChildRole *child_role)
> +{
> +    BdrvChild *child = g_new(BdrvChild, 1);
> +    *child = (BdrvChild) {
> +        .bs     = child_bs,
> +        .role   = child_role,
> +    };
> +
> +    QLIST_INSERT_HEAD(&parent_bs->children, child, next);
> +}
> +
>  /*
>   * Opens a disk image (raw, qcow2, vmdk, ...)
>   *
> @@ -1353,6 +1366,9 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>              return -ENODEV;
>          }
>          bdrv_ref(bs);
> +        if (child_role) {
> +            bdrv_attach_child(parent, bs, child_role);
> +        }
>          *pbs = bs;
>          return 0;
>      }
> @@ -1495,6 +1511,10 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>          goto close_and_fail;
>      }
>  
> +    if (child_role) {
> +        bdrv_attach_child(parent, bs, child_role);
> +    }
> +
>      QDECREF(options);
>      *pbs = bs;
>      return 0;
> @@ -1789,6 +1809,12 @@ void bdrv_close(BlockDriverState *bs)
>      notifier_list_notify(&bs->close_notifiers, bs);
>  
>      if (bs->drv) {
> +        BdrvChild *child, *next;
> +
> +        QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
> +            g_free(child);
> +        }

Max already pointed out this place, but we both didn't see the real bug
here: Without a QLIST_REMOVE(), we get use after free on the next open
of this BDS.

After the latest rebase, the floppy media change qtest ended up failing
because of this. Who said that time invested in fdc is wasted? ;-)

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 11/34] block: Allow references for backing files
  2015-05-21  5:47   ` Wen Congyang
@ 2015-05-27 12:31     ` Kevin Wolf
  2015-05-27 13:30       ` [Qemu-devel] [Qemu-block] " Kevin Wolf
                         ` (2 more replies)
  0 siblings, 3 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-05-27 12:31 UTC (permalink / raw)
  To: Wen Congyang; +Cc: jcody, mreitz, qemu-devel, qemu-block, armbru

Am 21.05.2015 um 07:47 hat Wen Congyang geschrieben:
> On 05/09/2015 01:21 AM, Kevin Wolf wrote:
> > For bs->file, using references to existing BDSes has been possible for a
> > while already. This patch enables the same for bs->backing_hd.
> 
> 1. We reference to an existing BDSes, and some disk uses this blk. Do
> we allow this?

Currently yes. If it breaks, you get to keep both pieces.

As long as your guest device is read-only, it should just work. It would
be a very bad idea, though, to write to a backing file.

Op blockers should eventually prevent this from happening (Jeff, you may
want to take a note ;-))

> 2. bs->backing_hd->blk can be not NULL now? If we do an active commit
> to this backing file(use mirror job), we will call bdrv_swap() in
> mirror_exit(), and the function bdrv_swap() doesn't allow that
> new_bs->blk(here is bs->backing_hd) is not NULL.

You're right.

I can remove this patch from the series for now, but of course that
doesn't solve the problem. I'm not sure what to do about it. Making
bdrv_swap() work with BDSes that have BB attached is probably another
item in the list of "dynamic reconfiguration" problems.

Markus, any ideas?

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 11/34] block: Allow references for backing files
  2015-05-27 12:31     ` Kevin Wolf
@ 2015-05-27 13:30       ` Kevin Wolf
  2015-05-27 13:44         ` Paolo Bonzini
  2015-05-28  0:59       ` [Qemu-devel] " Wen Congyang
  2015-06-01  2:01       ` Wen Congyang
  2 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-27 13:30 UTC (permalink / raw)
  To: Wen Congyang; +Cc: armbru, pbonzini, qemu-devel, qemu-block, mreitz

Am 27.05.2015 um 14:31 hat Kevin Wolf geschrieben:
> Am 21.05.2015 um 07:47 hat Wen Congyang geschrieben:
> > On 05/09/2015 01:21 AM, Kevin Wolf wrote:
> > > For bs->file, using references to existing BDSes has been possible for a
> > > while already. This patch enables the same for bs->backing_hd.
> > 
> > 1. We reference to an existing BDSes, and some disk uses this blk. Do
> > we allow this?
> 
> Currently yes. If it breaks, you get to keep both pieces.
> 
> As long as your guest device is read-only, it should just work. It would
> be a very bad idea, though, to write to a backing file.
> 
> Op blockers should eventually prevent this from happening (Jeff, you may
> want to take a note ;-))
> 
> > 2. bs->backing_hd->blk can be not NULL now? If we do an active commit
> > to this backing file(use mirror job), we will call bdrv_swap() in
> > mirror_exit(), and the function bdrv_swap() doesn't allow that
> > new_bs->blk(here is bs->backing_hd) is not NULL.
> 
> You're right.
> 
> I can remove this patch from the series for now, but of course that
> doesn't solve the problem.

On second thought, I don't want to remove the patch from the series
because then I don't have test cases for backing files that don't
inherit option from their parents. (Also, it would lead to some
conflicts through the series.)

> I'm not sure what to do about it. Making
> bdrv_swap() work with BDSes that have BB attached is probably another
> item in the list of "dynamic reconfiguration" problems.
> 
> Markus, any ideas?

So it would be even more important to figure out what to do with
bdrv_swap().

Paolo, you added that bunch of assertions to bdrv_swap() when you
introduced it in commit 4ddc07ca. Did you just add them because they
were true at the time, or is anything actually relying on these
invariants?

What do we actually want to happen? Let's assume a small chain of
backing files:

        +---------- A-BlockBackend
        |
        |    +----- B-BlockBackend
        |    |
base <- A <- B

After completing the commit operation, what we want to have for the BB
of B is clear:

        +---------- B-BlockBackend
        |
base <- A

If we just remove the assertions that are currently present in
bdrv_swap(), I think we'd end up with this:

             +----- A-BlockBackend
             |
        +---------- B-BlockBackend
        |    |
base <- A <- B

This is probably surprising for the user if they ever look at
A-BlockBackend again. It's also surprising because (unlike the case
without a BB for A) B is actually still referenced and therefore the
file stays opened.

I suspect what we really want is this (which is not swapping):

        +---------- A-BlockBackend
        |
        +---------- B-BlockBackend
        |
base <- A

Both BBs point to the same BDS now and B is actually closed.

Any opinions on this?

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 11/34] block: Allow references for backing files
  2015-05-27 13:30       ` [Qemu-devel] [Qemu-block] " Kevin Wolf
@ 2015-05-27 13:44         ` Paolo Bonzini
  0 siblings, 0 replies; 130+ messages in thread
From: Paolo Bonzini @ 2015-05-27 13:44 UTC (permalink / raw)
  To: Kevin Wolf, Wen Congyang; +Cc: armbru, qemu-devel, qemu-block, mreitz



On 27/05/2015 15:30, Kevin Wolf wrote:
> So it would be even more important to figure out what to do with
> bdrv_swap().
> 
> Paolo, you added that bunch of assertions to bdrv_swap() when you
> introduced it in commit 4ddc07ca. Did you just add them because they
> were true at the time, or is anything actually relying on these
> invariants?

When I added bdrv_swap, the idea was to bs_new was either being closed
afterwards,  or (for bdrv_append) it would be the backing file of bs_top.

In either case, the assertions would make sure that nothing would break
when further manipulating bs_new.

Are they being relied on?  Probably not, but some violations would be
just weird, such as a device attached to a non-topmost BDS, or a job
attached to the old version of a mirrored disk.

> What do we actually want to happen? Let's assume a small chain of
> backing files:
> 
>         +---------- A-BlockBackend
>         |
>         |    +----- B-BlockBackend
>         |    |
> base <- A <- B
> 
> After completing the commit operation, what we want to have for the BB
> of B is clear:
> 
>         +---------- B-BlockBackend
>         |
> base <- A
> 
> If we just remove the assertions that are currently present in
> bdrv_swap(), I think we'd end up with this:
> 
>              +----- A-BlockBackend
>              |
>         +---------- B-BlockBackend
>         |    |
> base <- A <- B
> 
> This is probably surprising for the user if they ever look at
> A-BlockBackend again. It's also surprising because (unlike the case
> without a BB for A) B is actually still referenced and therefore the
> file stays opened.
> 
> I suspect what we really want is this (which is not swapping):
> 
>         +---------- A-BlockBackend
>         |
>         +---------- B-BlockBackend
>         |
> base <- A
> 
> Both BBs point to the same BDS now and B is actually closed.

Correct.  Swapping was just a trick to do things underneath the device's
feet, effectively emulating BlockBackends.

Since I'm not very much up-to-date with the block device graph stuff, do
BDSes have a list of BlockBackends that point to them, so that they can
redirect all those BlockBackends to the backing file?

Paolo

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 11/34] block: Allow references for backing files
  2015-05-27 12:31     ` Kevin Wolf
  2015-05-27 13:30       ` [Qemu-devel] [Qemu-block] " Kevin Wolf
@ 2015-05-28  0:59       ` Wen Congyang
  2015-05-28  9:48         ` Kevin Wolf
  2015-06-01  2:01       ` Wen Congyang
  2 siblings, 1 reply; 130+ messages in thread
From: Wen Congyang @ 2015-05-28  0:59 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: jcody, mreitz, qemu-devel, qemu-block, armbru

On 05/27/2015 08:31 PM, Kevin Wolf wrote:
> Am 21.05.2015 um 07:47 hat Wen Congyang geschrieben:
>> On 05/09/2015 01:21 AM, Kevin Wolf wrote:
>>> For bs->file, using references to existing BDSes has been possible for a
>>> while already. This patch enables the same for bs->backing_hd.
>>
>> 1. We reference to an existing BDSes, and some disk uses this blk. Do
>> we allow this?
> 
> Currently yes. If it breaks, you get to keep both pieces.
> 
> As long as your guest device is read-only, it should just work. It would
> be a very bad idea, though, to write to a backing file.
> 
> Op blockers should eventually prevent this from happening (Jeff, you may
> want to take a note ;-))
> 
>> 2. bs->backing_hd->blk can be not NULL now? If we do an active commit
>> to this backing file(use mirror job), we will call bdrv_swap() in
>> mirror_exit(), and the function bdrv_swap() doesn't allow that
>> new_bs->blk(here is bs->backing_hd) is not NULL.
> 
> You're right.
> 
> I can remove this patch from the series for now, but of course that
> doesn't solve the problem. I'm not sure what to do about it. Making
> bdrv_swap() work with BDSes that have BB attached is probably another
> item in the list of "dynamic reconfiguration" problems.

What does "dynamic reconfiguration" mean? Allow to change drive's option
when guest is running?

Thanks
Wen Congyang

> 
> Markus, any ideas?
> 
> Kevin
> .
> 

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 11/34] block: Allow references for backing files
  2015-05-28  0:59       ` [Qemu-devel] " Wen Congyang
@ 2015-05-28  9:48         ` Kevin Wolf
  2015-05-28  9:58           ` Wen Congyang
  0 siblings, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-05-28  9:48 UTC (permalink / raw)
  To: Wen Congyang; +Cc: jcody, mreitz, qemu-devel, qemu-block, armbru

Am 28.05.2015 um 02:59 hat Wen Congyang geschrieben:
> On 05/27/2015 08:31 PM, Kevin Wolf wrote:
> > Am 21.05.2015 um 07:47 hat Wen Congyang geschrieben:
> >> On 05/09/2015 01:21 AM, Kevin Wolf wrote:
> >>> For bs->file, using references to existing BDSes has been possible for a
> >>> while already. This patch enables the same for bs->backing_hd.
> >>
> >> 1. We reference to an existing BDSes, and some disk uses this blk. Do
> >> we allow this?
> > 
> > Currently yes. If it breaks, you get to keep both pieces.
> > 
> > As long as your guest device is read-only, it should just work. It would
> > be a very bad idea, though, to write to a backing file.
> > 
> > Op blockers should eventually prevent this from happening (Jeff, you may
> > want to take a note ;-))
> > 
> >> 2. bs->backing_hd->blk can be not NULL now? If we do an active commit
> >> to this backing file(use mirror job), we will call bdrv_swap() in
> >> mirror_exit(), and the function bdrv_swap() doesn't allow that
> >> new_bs->blk(here is bs->backing_hd) is not NULL.
> > 
> > You're right.
> > 
> > I can remove this patch from the series for now, but of course that
> > doesn't solve the problem. I'm not sure what to do about it. Making
> > bdrv_swap() work with BDSes that have BB attached is probably another
> > item in the list of "dynamic reconfiguration" problems.
> 
> What does "dynamic reconfiguration" mean? Allow to change drive's option
> when guest is running?

Sorry, I should have been more specific for those of you who haven't
been part of previous discussions.

In this context, I'm talking about dynamic reconfiguration of the
BlockDriverState graph, i.e. any operation that changes the relationship
between different BDSes (essentially add/remove/change pointers to other
BDSes).

An example for that is changing the backing file of an opened image
after having merged external snapshots with block-commit, or inserting a
new active layer for taking a live snapshot.

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 11/34] block: Allow references for backing files
  2015-05-28  9:48         ` Kevin Wolf
@ 2015-05-28  9:58           ` Wen Congyang
  0 siblings, 0 replies; 130+ messages in thread
From: Wen Congyang @ 2015-05-28  9:58 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: jcody, mreitz, qemu-devel, qemu-block, armbru

On 05/28/2015 05:48 PM, Kevin Wolf wrote:
> Am 28.05.2015 um 02:59 hat Wen Congyang geschrieben:
>> On 05/27/2015 08:31 PM, Kevin Wolf wrote:
>>> Am 21.05.2015 um 07:47 hat Wen Congyang geschrieben:
>>>> On 05/09/2015 01:21 AM, Kevin Wolf wrote:
>>>>> For bs->file, using references to existing BDSes has been possible for a
>>>>> while already. This patch enables the same for bs->backing_hd.
>>>>
>>>> 1. We reference to an existing BDSes, and some disk uses this blk. Do
>>>> we allow this?
>>>
>>> Currently yes. If it breaks, you get to keep both pieces.
>>>
>>> As long as your guest device is read-only, it should just work. It would
>>> be a very bad idea, though, to write to a backing file.
>>>
>>> Op blockers should eventually prevent this from happening (Jeff, you may
>>> want to take a note ;-))
>>>
>>>> 2. bs->backing_hd->blk can be not NULL now? If we do an active commit
>>>> to this backing file(use mirror job), we will call bdrv_swap() in
>>>> mirror_exit(), and the function bdrv_swap() doesn't allow that
>>>> new_bs->blk(here is bs->backing_hd) is not NULL.
>>>
>>> You're right.
>>>
>>> I can remove this patch from the series for now, but of course that
>>> doesn't solve the problem. I'm not sure what to do about it. Making
>>> bdrv_swap() work with BDSes that have BB attached is probably another
>>> item in the list of "dynamic reconfiguration" problems.
>>
>> What does "dynamic reconfiguration" mean? Allow to change drive's option
>> when guest is running?
> 
> Sorry, I should have been more specific for those of you who haven't
> been part of previous discussions.
> 
> In this context, I'm talking about dynamic reconfiguration of the
> BlockDriverState graph, i.e. any operation that changes the relationship
> between different BDSes (essentially add/remove/change pointers to other
> BDSes).
> 
> An example for that is changing the backing file of an opened image
> after having merged external snapshots with block-commit, or inserting a
> new active layer for taking a live snapshot.

Thanks for your explanation. I understand it now.

Wen Congyang

> 
> Kevin
> .
> 

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 07/34] block: Move flag inheritance to bdrv_open_inherited()
  2015-05-08 17:21 ` [Qemu-devel] [PATCH 07/34] block: Move flag inheritance to bdrv_open_inherited() Kevin Wolf
  2015-05-08 23:20   ` Eric Blake
  2015-05-11 15:20   ` Max Reitz
@ 2015-05-28 11:10   ` Wen Congyang
  2 siblings, 0 replies; 130+ messages in thread
From: Wen Congyang @ 2015-05-28 11:10 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: mreitz, qemu-devel, armbru

On 05/09/2015 01:21 AM, Kevin Wolf wrote:
> Instead of letting every caller of bdrv_open() determine the right flags
> for its child node manually and pass them to the function, pass the
> parent node and the role of the newly opened child (like backing file,
> protocol layer, etc.).
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c                   | 74 ++++++++++++++++++++++++++++++++++++++---------
>  block/blkdebug.c          |  2 +-
>  block/blkverify.c         |  4 +--
>  block/quorum.c            |  4 +--
>  block/vmdk.c              |  5 ++--
>  include/block/block.h     |  4 ++-
>  include/block/block_int.h |  7 +++++
>  7 files changed, 78 insertions(+), 22 deletions(-)
> 
> diff --git a/block.c b/block.c
> index cea022f..c4f0fb4 100644
> --- a/block.c
> +++ b/block.c
> @@ -79,6 +79,12 @@ static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
>  static QLIST_HEAD(, BlockDriver) bdrv_drivers =
>      QLIST_HEAD_INITIALIZER(bdrv_drivers);
>  
> +static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
> +                             const char *reference, QDict *options, int flags,
> +                             BlockDriverState* parent,
> +                             const BdrvChildRole *child_role,
> +                             BlockDriver *drv, Error **errp);

The function name in patch title is wrong.

Thanks
Wen Congyang

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 11/34] block: Allow references for backing files
  2015-05-27 12:31     ` Kevin Wolf
  2015-05-27 13:30       ` [Qemu-devel] [Qemu-block] " Kevin Wolf
  2015-05-28  0:59       ` [Qemu-devel] " Wen Congyang
@ 2015-06-01  2:01       ` Wen Congyang
  2 siblings, 0 replies; 130+ messages in thread
From: Wen Congyang @ 2015-06-01  2:01 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: jcody, mreitz, qemu-devel, qemu-block, armbru

On 05/27/2015 08:31 PM, Kevin Wolf wrote:
> Am 21.05.2015 um 07:47 hat Wen Congyang geschrieben:
>> On 05/09/2015 01:21 AM, Kevin Wolf wrote:
>>> For bs->file, using references to existing BDSes has been possible for a
>>> while already. This patch enables the same for bs->backing_hd.
>>
>> 1. We reference to an existing BDSes, and some disk uses this blk. Do
>> we allow this?
> 
> Currently yes. If it breaks, you get to keep both pieces.
> 
> As long as your guest device is read-only, it should just work. It would
> be a very bad idea, though, to write to a backing file.
> 
> Op blockers should eventually prevent this from happening (Jeff, you may
> want to take a note ;-))
> 
>> 2. bs->backing_hd->blk can be not NULL now? If we do an active commit
>> to this backing file(use mirror job), we will call bdrv_swap() in
>> mirror_exit(), and the function bdrv_swap() doesn't allow that
>> new_bs->blk(here is bs->backing_hd) is not NULL.
> 
> You're right.
> 
> I can remove this patch from the series for now, but of course that
> doesn't solve the problem. I'm not sure what to do about it. Making
> bdrv_swap() work with BDSes that have BB attached is probably another
> item in the list of "dynamic reconfiguration" problems.

Hmm, add a new API to check if the BDSes have BB attached. If not, we can
allow this operation. So we can also mirror to an existing BDSes that don't
have BB attached.

Thanks
Wen Congyang

> 
> Markus, any ideas?
> 
> Kevin
> .
> 

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState
  2015-05-11 15:45   ` Max Reitz
  2015-05-12 14:23     ` Kevin Wolf
@ 2015-06-10 12:09     ` Kevin Wolf
  2015-06-10 13:48       ` Max Reitz
  1 sibling, 1 reply; 130+ messages in thread
From: Kevin Wolf @ 2015-06-10 12:09 UTC (permalink / raw)
  To: Max Reitz; +Cc: armbru, qemu-block, qemu-devel

Am 11.05.2015 um 17:45 hat Max Reitz geschrieben:
> On 08.05.2015 19:21, Kevin Wolf wrote:
> >This allows iterating over all children of a given BDS, not only
> >including bs->file and bs->backing_hd, but also driver-specific
> >ones like VMDK extents or Quorum children.
> >
> >Signed-off-by: Kevin Wolf <kwolf@redhat.com>

> >@@ -1789,6 +1809,12 @@ void bdrv_close(BlockDriverState *bs)
> >      notifier_list_notify(&bs->close_notifiers, bs);
> >      if (bs->drv) {
> >+        BdrvChild *child, *next;
> >+
> >+        QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
> >+            g_free(child);
> >+        }
> >+
> 
> Not considering the case where the child is closed before the parent
> assumes all children are reference-counted from the parent and they
> won't be closed (and maybe replaced with another BDS) on purpose.
> The first seems reasonable, the second one I'm not so sure about. It
> works for now, but I could imagine that we want to modify children
> of a Quorum instance at runtime.
> 
> But I can't imagine any case where this would break right now, so I
> guess I'm fine with it.
> 
> >          if (bs->backing_hd) {
> >              BlockDriverState *backing_hd = bs->backing_hd;
> >              bdrv_set_backing_hd(bs, NULL);
> >@@ -1999,6 +2025,7 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
> >      /* The contents of 'tmp' will become bs_top, as we are
> >       * swapping bs_new and bs_top contents. */
> >      bdrv_set_backing_hd(bs_top, bs_new);
> >+    bdrv_attach_child(bs_top, bs_new, &child_backing);
> >  }
> >  static void bdrv_delete(BlockDriverState *bs)
> 
> Using a mirror block job, we can force bdrv_swap() on arbitrary
> nodes, right? What happens if you swap e.g. a VMDK and a quorum
> node? Well, maybe one simply cannot swap a quorum node due to
> blockers, but I guess one can swap a VMDK node with some non-VMDK
> node. It is actually correct to leave the extents behind; but the
> other node cannot do anything with them, so because they are part of
> the opaque VMDK structure, they will de-facto remain with VMDK,
> while being counted as children of the other node. But I try to keep
> so far away from bdrv_swap() that I don't even know whether this
> case is even possible.

While trying to fix up this part of the series so I can send out a v2,
I noticed that I'm not sure what exactly you mean.

You are aware that bdrv_swap() doesn't change any pointers between
BDSes, but just swaps the _contents_ of them, right? That is, the extent
BDS is changed under the feet of VMDK, without it having code for it.
This is what makes bdrv_swap() work at all, and also what makes it so
ugly.

Do you think that there is still something left that would refer from
VMDK to the removed extent BDS? Where would that pointer come from?

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState
  2015-06-10 12:09     ` Kevin Wolf
@ 2015-06-10 13:48       ` Max Reitz
  0 siblings, 0 replies; 130+ messages in thread
From: Max Reitz @ 2015-06-10 13:48 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: armbru, qemu-block, qemu-devel

On 10.06.2015 14:09, Kevin Wolf wrote:
> Am 11.05.2015 um 17:45 hat Max Reitz geschrieben:
>> On 08.05.2015 19:21, Kevin Wolf wrote:
>>> This allows iterating over all children of a given BDS, not only
>>> including bs->file and bs->backing_hd, but also driver-specific
>>> ones like VMDK extents or Quorum children.
>>>
>>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>>> @@ -1789,6 +1809,12 @@ void bdrv_close(BlockDriverState *bs)
>>>       notifier_list_notify(&bs->close_notifiers, bs);
>>>       if (bs->drv) {
>>> +        BdrvChild *child, *next;
>>> +
>>> +        QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
>>> +            g_free(child);
>>> +        }
>>> +
>> Not considering the case where the child is closed before the parent
>> assumes all children are reference-counted from the parent and they
>> won't be closed (and maybe replaced with another BDS) on purpose.
>> The first seems reasonable, the second one I'm not so sure about. It
>> works for now, but I could imagine that we want to modify children
>> of a Quorum instance at runtime.
>>
>> But I can't imagine any case where this would break right now, so I
>> guess I'm fine with it.
>>
>>>           if (bs->backing_hd) {
>>>               BlockDriverState *backing_hd = bs->backing_hd;
>>>               bdrv_set_backing_hd(bs, NULL);
>>> @@ -1999,6 +2025,7 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
>>>       /* The contents of 'tmp' will become bs_top, as we are
>>>        * swapping bs_new and bs_top contents. */
>>>       bdrv_set_backing_hd(bs_top, bs_new);
>>> +    bdrv_attach_child(bs_top, bs_new, &child_backing);
>>>   }
>>>   static void bdrv_delete(BlockDriverState *bs)
>> Using a mirror block job, we can force bdrv_swap() on arbitrary
>> nodes, right? What happens if you swap e.g. a VMDK and a quorum
>> node? Well, maybe one simply cannot swap a quorum node due to
>> blockers, but I guess one can swap a VMDK node with some non-VMDK
>> node. It is actually correct to leave the extents behind; but the
>> other node cannot do anything with them, so because they are part of
>> the opaque VMDK structure, they will de-facto remain with VMDK,
>> while being counted as children of the other node. But I try to keep
>> so far away from bdrv_swap() that I don't even know whether this
>> case is even possible.
> While trying to fix up this part of the series so I can send out a v2,
> I noticed that I'm not sure what exactly you mean.
>
> You are aware that bdrv_swap() doesn't change any pointers between
> BDSes, but just swaps the _contents_ of them, right? That is, the extent
> BDS is changed under the feet of VMDK, without it having code for it.
> This is what makes bdrv_swap() work at all, and also what makes it so
> ugly.
>
> Do you think that there is still something left that would refer from
> VMDK to the removed extent BDS? Where would that pointer come from?

My point wasn't about switching the extent BDS, but the VMDK BDS itself, 
which has multiple extent BDSs as children.

My mistake was somehow assuming this list of children would not be moved 
during bdrv_swap() (what I meant by "to leave the extents behind"), but 
of course it is. So on bdrv_swap(), all the children get swapped, too 
(which is correct: protocol and backing BDS, as well as all BDSs 
referred to through the opaque structure, are indeed swapped).

So, no objections remaining.

Max

^ permalink raw reply	[flat|nested] 130+ messages in thread

* Re: [Qemu-devel] [PATCH 28/34] block: Introduce bs->explicit_options
  2015-05-15 17:47   ` Max Reitz
@ 2015-10-29 11:38     ` Kevin Wolf
  0 siblings, 0 replies; 130+ messages in thread
From: Kevin Wolf @ 2015-10-29 11:38 UTC (permalink / raw)
  To: Max Reitz; +Cc: armbru, qemu-block, qemu-devel

Am 15.05.2015 um 19:47 hat Max Reitz geschrieben:
> 3) In bdrv_open():
> The QDict is just the one given to bdrv_open().
> 
> 3a) bdrv_open() call from bdrv_append_temp_snapshot():
> "file.driver" and "file.filename" are set, and these are the only
> options in the whole QDict. Well... I'd argue that these are options
> supplied are supplied from the flags (BDRV_O_SNAPSHOT, to be exact),
> but I guess I can turn a blind eye to this case.
> [...]
> In total, 3a looks a bit fishy, but I guess it's alright.

In fact, not only the options are derived from a flag, but the whole BDS
is, so I think this is a different case anywy. Might prove rather hard
to create a working qcow2 BDS without setting any child options. :-)

Anyway, I think we'll eventually move this to drive_init(), and at that
point I'd definitely consider it provided by the user, even if he used a
syntax that doesn't make obvious what exact options he provided.

> Concluding, I can say that setting bs->explicit_options at that
> point will not result in automatically derived options being
> included there (except for 3a). A problem I do see is that as can be
> seen above, deriving this is not trivial, and keeping this the case
> isn't either. We have to make sure that bdrv_open_inherit() will
> never set any option in @options which contains a dot, neither may
> any of the functions it calls (do we need appropriate documentation
> for child_role->inherit_options()?).

Yes, we need to ensure that. But in fact, I don't think that's very
hard to maintain. On the contrary, it's just common sense that
bdrv_open_inherit() only tinkers with "local" options. Especially in the
.inherit_options() functions, which don't even know if the node has any
children, it seems unlikely that an option for children is set.

I mean, why would any of these functions even _want_ to add an option
with a dot in it?

But if you prefer, I can put a comment at the inherit_options function
pointer declaration.

> As noted above in point 1a II, @filename may be a JSON filename in
> bdrv_open_inherit(). I think these would be user-supplied options,
> so they should be put into bs->explicit_options, too. If they are
> not, 1a II is invalid and we have to make sure that none of the
> options supplied there can end up in any bs->explicit_options of any
> child BDS.

Yes, I would agree that json: objects should be treated exactly the same
as if the options were already contained in the QDict.

> Also note that above I did not check whether bs->explicit_options
> will contain all user-specified options. I only made sure that it
> doesn't contain automatically derived options. But as long as
> blkdebug doesn't absorb options like "image.filename", it should be
> fine (no options prefixed with a bdref_key matching a BDS child role
> we are still intending to open may be removed, but I don't think
> that's the case, ever).

Actually, even if blkdebug absorbed "image.filename" (which would be a
stupid thing to do because it breaks a useful option naming convention),
it would be an explicit option to blkdebug, but not to raw-posix,
because raw-posix would never even see it. So the code should do the
right thing there.

Or phrased differently: If explicit_options isn't a subset of options,
something went wrong.

> Oh, and also we have to make sure that setting
> reopen_state->bs->explicit_options does not result in derived
> options being set. It's generated from @options given to
> bdrv_reopen_queue_child(), joined with bs->explicit_options
> (induction hypothesis: bs->explicit_options is good). Is @options
> good, too? So far yes, because it's always empty (except for
> qemu-io, where it comes directly from the user).

In my book, the callers of bdrv_reopen_*() are users. ;-)

Or less sloppily: They are triggered by user actions. A guest or an NBD
client can't reopen an image.

> >@@ -1886,6 +1896,9 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
> >      }
> >      /* set BDS specific flags now */
> >+    QDECREF(reopen_state->bs->explicit_options);
> >+
> >+    reopen_state->bs->explicit_options   = reopen_state->explicit_options;
> >      reopen_state->bs->open_flags         = reopen_state->flags;
> >      reopen_state->bs->enable_write_cache = !!(reopen_state->flags &
> >                                                BDRV_O_CACHE_WB);
> >@@ -1909,6 +1922,8 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
> >      if (drv->bdrv_reopen_abort) {
> >          drv->bdrv_reopen_abort(reopen_state);
> >      }
> >+
> >+    QDECREF(reopen_state->explicit_options);
> 
> I think this must be done in bdrv_reopen_multiple(). Otherwise,
> reopen_state->explicit_options is leaked for the one BDS where
> bdrv_reopen_prepare() failed.

And actually for all of the following BDSes as well.

I'll leave it in abort for symmetry with commit, but add a QDECREF for
yet unprepared BDSes.

> What I'd like to have for a R-b: No leak of
> reopen_state->explicit_options, and an answer to the question
> whether options coming from a JSON filename should be part of
> bs->explicit_options (right now, they are for all child BDSs, but
> not for the top BDS, because bdrv_fill_options() is called after
> bs->explicit_options is set).

Oh. I guess this should be fixed so that they are considered
explicit even for the top level. But we don't want the rest of
bdrv_fill_options() to be considered explicit, so it seems I'll have
to split it.

Kevin

^ permalink raw reply	[flat|nested] 130+ messages in thread

end of thread, other threads:[~2015-10-29 11:38 UTC | newest]

Thread overview: 130+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-08 17:21 [Qemu-devel] [PATCH 00/34] block: Cache mode for children, reopen overhaul and more Kevin Wolf
2015-05-08 17:21 ` [Qemu-devel] [PATCH 01/34] qdict: Add qdict_array_entries() Kevin Wolf
2015-05-08 20:06   ` Eric Blake
2015-05-08 21:22     ` Eric Blake
2015-05-11 14:40     ` Kevin Wolf
2015-05-11 15:28       ` Eric Blake
2015-05-20 14:19     ` [Qemu-devel] [Qemu-block] " Alberto Garcia
2015-05-11 13:56   ` [Qemu-devel] " Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set,copy}_default() Kevin Wolf
2015-05-08 21:30   ` [Qemu-devel] [PATCH 02/34] qdict: Add qdict_{set, copy}_default() Eric Blake
2015-05-11 14:06     ` Kevin Wolf
2015-05-11 14:16   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 03/34] quorum: Use bdrv_open_image() Kevin Wolf
2015-05-08 21:33   ` Eric Blake
2015-05-11 14:27   ` Max Reitz
2015-05-12 19:07   ` [Qemu-devel] [Qemu-block] " Jeff Cody
2015-05-20 14:46   ` Alberto Garcia
2015-05-08 17:21 ` [Qemu-devel] [PATCH 04/34] vmdk: " Kevin Wolf
2015-05-08 22:00   ` Eric Blake
2015-05-11 14:35   ` Max Reitz
2015-05-12 19:12   ` [Qemu-devel] [Qemu-block] " Jeff Cody
2015-05-08 17:21 ` [Qemu-devel] [PATCH 05/34] block: Use macro for cache option names Kevin Wolf
2015-05-08 22:54   ` Eric Blake
2015-05-11 14:40   ` Max Reitz
2015-05-11 14:51     ` Kevin Wolf
2015-05-11 14:59       ` Max Reitz
2015-05-11 15:00   ` Max Reitz
2015-05-12 19:14   ` [Qemu-devel] [Qemu-block] " Jeff Cody
2015-05-20 14:49   ` Alberto Garcia
2015-05-08 17:21 ` [Qemu-devel] [PATCH 06/34] block: Use QemuOpts in bdrv_open_common() Kevin Wolf
2015-05-08 22:57   ` Eric Blake
2015-05-11 14:57   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 07/34] block: Move flag inheritance to bdrv_open_inherited() Kevin Wolf
2015-05-08 23:20   ` Eric Blake
2015-05-11 15:20   ` Max Reitz
2015-05-12 13:32     ` Kevin Wolf
2015-05-28 11:10   ` Wen Congyang
2015-05-08 17:21 ` [Qemu-devel] [PATCH 08/34] block: Add list of children to BlockDriverState Kevin Wolf
2015-05-08 23:34   ` Eric Blake
2015-05-11 15:45   ` Max Reitz
2015-05-12 14:23     ` Kevin Wolf
2015-06-10 12:09     ` Kevin Wolf
2015-06-10 13:48       ` Max Reitz
2015-05-27 11:30   ` Kevin Wolf
2015-05-08 17:21 ` [Qemu-devel] [PATCH 09/34] block: Add BlockDriverState.inherits_from Kevin Wolf
2015-05-08 23:39   ` Eric Blake
2015-05-11 15:50   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 10/34] block: Fix reopen flag inheritance Kevin Wolf
2015-05-11 16:04   ` Max Reitz
2015-05-12 14:32   ` Eric Blake
2015-05-08 17:21 ` [Qemu-devel] [PATCH 11/34] block: Allow references for backing files Kevin Wolf
2015-05-11 16:19   ` Max Reitz
2015-05-12 14:46   ` Eric Blake
2015-05-21  5:47   ` Wen Congyang
2015-05-27 12:31     ` Kevin Wolf
2015-05-27 13:30       ` [Qemu-devel] [Qemu-block] " Kevin Wolf
2015-05-27 13:44         ` Paolo Bonzini
2015-05-28  0:59       ` [Qemu-devel] " Wen Congyang
2015-05-28  9:48         ` Kevin Wolf
2015-05-28  9:58           ` Wen Congyang
2015-06-01  2:01       ` Wen Congyang
2015-05-08 17:21 ` [Qemu-devel] [PATCH 12/34] block: Allow specifying driver-specific options to reopen Kevin Wolf
2015-05-11 16:35   ` Max Reitz
2015-05-12 14:59   ` Eric Blake
2015-05-08 17:21 ` [Qemu-devel] [PATCH 13/34] qemu-io: Add command 'reopen' Kevin Wolf
2015-05-11 16:50   ` Max Reitz
2015-05-12 15:05   ` Eric Blake
2015-05-13  8:37     ` Kevin Wolf
2015-05-08 17:21 ` [Qemu-devel] [PATCH 14/34] qcow2: Factor out qcow2_update_options() Kevin Wolf
2015-05-12 20:04   ` Eric Blake
2015-05-13  9:11     ` Kevin Wolf
2015-05-13 17:04       ` Eric Blake
2015-05-13 11:21   ` Max Reitz
2015-05-13 11:28   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 15/34] qcow2: Move qcow2_update_options() call up Kevin Wolf
2015-05-12 20:15   ` Eric Blake
2015-05-13 11:25   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 16/34] qcow2: Move rest of option handling to qcow2_update_options() Kevin Wolf
2015-05-12 20:47   ` Eric Blake
2015-05-13 11:38   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 17/34] qcow2: Leave s unchanged on qcow2_update_options() failure Kevin Wolf
2015-05-12 20:57   ` Eric Blake
2015-05-13 11:47   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 18/34] qcow2: Fix memory leak in qcow2_update_options() error path Kevin Wolf
2015-05-12 21:26   ` Eric Blake
2015-05-13 11:52   ` Max Reitz
2015-05-13 12:02     ` Kevin Wolf
2015-05-13 12:04       ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 19/34] qcow2: Make qcow2_update_options() suitable for transactions Kevin Wolf
2015-05-12 21:40   ` Eric Blake
2015-05-13  9:21     ` Kevin Wolf
2015-05-13 12:06   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 20/34] qcow2: Support updating driver-specific options in reopen Kevin Wolf
2015-05-12 21:47   ` Eric Blake
2015-05-13  9:26     ` Kevin Wolf
2015-05-08 17:21 ` [Qemu-devel] [PATCH 21/34] block: Consider all block layer options in append_open_options Kevin Wolf
2015-05-12 21:59   ` Eric Blake
2015-05-13 12:26   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 22/34] block: Exclude nested options only for children in append_open_options() Kevin Wolf
2015-05-13 12:49   ` Max Reitz
2015-05-13 12:50     ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 23/34] block: Pass driver-specific options to .bdrv_refresh_filename() Kevin Wolf
2015-05-13 12:57   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 24/34] block: Keep "driver" in bs->options Kevin Wolf
2015-05-13 13:22   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 25/34] block: Allow specifying child options in reopen Kevin Wolf
2015-05-13 13:41   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 26/34] block: reopen: Document option precedence and refactor accordingly Kevin Wolf
2015-05-13 14:47   ` Max Reitz
2015-05-08 17:21 ` [Qemu-devel] [PATCH 27/34] block: Add infrastructure for option inheritance Kevin Wolf
2015-05-13 15:10   ` Max Reitz
2015-05-13 15:28     ` Kevin Wolf
2015-05-08 17:22 ` [Qemu-devel] [PATCH 28/34] block: Introduce bs->explicit_options Kevin Wolf
2015-05-15 17:47   ` Max Reitz
2015-10-29 11:38     ` Kevin Wolf
2015-05-08 17:22 ` [Qemu-devel] [PATCH 29/34] qemu-iotests: Remove cache mode test without medium Kevin Wolf
2015-05-15 17:53   ` Max Reitz
2015-05-08 17:22 ` [Qemu-devel] [PATCH 30/34] block: reopen: Extract QemuOpts for generic block layer options Kevin Wolf
2015-05-15 18:07   ` Max Reitz
2015-05-08 17:22 ` [Qemu-devel] [PATCH 31/34] block: Move cache options into options QDict Kevin Wolf
2015-05-15 18:43   ` Max Reitz
2015-05-15 19:44     ` Eric Blake
2015-05-08 17:22 ` [Qemu-devel] [PATCH 32/34] qemu-iotests: Try setting cache mode for children Kevin Wolf
2015-05-15 18:52   ` Max Reitz
2015-05-08 17:22 ` [Qemu-devel] [PATCH 33/34] qemu-iotests: Test cache mode option inheritance Kevin Wolf
2015-05-15 19:16   ` Max Reitz
2015-05-18 14:39     ` Kevin Wolf
2015-05-18 15:32       ` Max Reitz
2015-05-08 17:22 ` [Qemu-devel] [PATCH 34/34] qemu-iotests: Test reopen with node-name/driver options Kevin Wolf
2015-05-15 19:19   ` Max Reitz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.