qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1
@ 2015-06-10 13:46 Kevin Wolf
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 01/13] qdict: Add qdict_array_entries() Kevin Wolf
                   ` (12 more replies)
  0 siblings, 13 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:46 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, qemu-devel, armbru, mreitz

This is v2 of the first part of the series "[PATCH 00/34] block: Cache
mode for children, reopen overhaul and more". Review of v1 turned up
some larger issues that need to be addressed as a prerequisite for some
patches (essentially bdrv_swap() removal is needed), so I decided to
split the series in multiple parts, even if this means that we commit
series with no immediate effect. This series is almost like that.

>From the items in the original cover letter, this series still 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)

Left for part 2 and 3 of the split series are:

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


Changes in v2:
- Patch 1:
  Added a real commit message [Eric]
  Fixed function comment [Eric]
  Handle overflows [Max]

- Patch 2: Fixed function comment [Eric]

- New patch 3: Added test cases for new QDict functions [Eric]

- Patch 7 (was 6): Fixed opts leak [Max]

- Patch 8 (was 7):
  Improved comment [Eric]
  Fixed coding style [Max]

- New patches 9 and 10: bdrv_swap() needs to fix up all list heads of
  non-empty lists in BlockDriverState. Add bdrv_drain() to ensure that
  the tracked requests list is empty; add a macro for fixing up
  non-empty lists.

- Patch 11 (was 8):
  Fixed bdrv_swap() for bs->children (fix up list head)
  Remove entries from bs->children list before free()ing them

=== git-backport-diff against v1 ===

Key:
[----] : patches are identical
[####] : number of functional differences between upstream/downstream patch
[down] : patch is downstream-only
The flags [FC] indicate (F)unctional and (C)ontextual differences, respectively

001/13:[0020] [FC] 'qdict: Add qdict_array_entries()'
002/13:[0005] [FC] 'qdict: Add qdict_{set,copy}_default()'
003/13:[down] 'check-qdict: Test cases for new functions'
004/13:[----] [--] 'quorum: Use bdrv_open_image()'
005/13:[----] [--] 'vmdk: Use bdrv_open_image()'
006/13:[----] [--] 'block: Use macro for cache option names'
007/13:[0002] [FC] 'block: Use QemuOpts in bdrv_open_common()'
008/13:[down] 'block: Move flag inheritance to bdrv_open_inherit()'
009/13:[down] 'block: Drain requests before swapping nodes in bdrv_swap()'
010/13:[down] 'queue.h: Add QLIST_FIX_HEAD_PTR()'
011/13:[0010] [FC] 'block: Add list of children to BlockDriverState'
012/13:[----] [-C] 'block: Add BlockDriverState.inherits_from'
013/13:[----] [--] 'block: Fix reopen flag inheritance'

(Patch 8 was present before, but the subject line changed.)


Kevin Wolf (13):
  qdict: Add qdict_array_entries()
  qdict: Add qdict_{set,copy}_default()
  check-qdict: Test cases for new functions
  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_inherit()
  block: Drain requests before swapping nodes in bdrv_swap()
  queue.h: Add QLIST_FIX_HEAD_PTR()
  block: Add list of children to BlockDriverState
  block: Add BlockDriverState.inherits_from
  block: Fix reopen flag inheritance

 block.c                   | 186 +++++++++++++++++++++++++++++++++++++++++-----
 block/blkdebug.c          |   2 +-
 block/blkverify.c         |   4 +-
 block/quorum.c            |  51 +++----------
 block/vmdk.c              |  61 ++++++---------
 blockdev.c                |  24 +++---
 include/block/block.h     |  12 ++-
 include/block/block_int.h |  19 +++++
 include/qapi/qmp/qdict.h  |   4 +
 include/qemu/queue.h      |   6 ++
 qobject/qdict.c           | 111 ++++++++++++++++++++++++++-
 tests/check-qdict.c       |  67 +++++++++++++++++
 12 files changed, 428 insertions(+), 119 deletions(-)

-- 
1.8.3.1

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

* [Qemu-devel] [PATCH v2 01/13] qdict: Add qdict_array_entries()
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
@ 2015-06-10 13:46 ` Kevin Wolf
  2015-06-10 20:50   ` Eric Blake
  2015-06-12 14:07   ` Max Reitz
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 02/13] qdict: Add qdict_{set, copy}_default() Kevin Wolf
                   ` (11 subsequent siblings)
  12 siblings, 2 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:46 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, qemu-devel, armbru, mreitz

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.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/qapi/qmp/qdict.h |  1 +
 qobject/qdict.c          | 78 +++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 75 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..50c0ab3 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -597,17 +597,21 @@ 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;
+            if (count == INT_MAX) {
+                return -ERANGE;
+            }
+            count++;
         }
     }
 
-    return false;
+    return count;
 }
 
 /**
@@ -646,7 +650,8 @@ 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);
+        /* Overflow is the same as positive non-zero results */
+        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 +672,71 @@ void qdict_array_split(QDict *src, QList **dst)
 }
 
 /**
+ * qdict_array_entries(): 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, -EINVAL 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] == '.');
+
+    /* qdict_array_split() loops until UINT_MAX, but as we want to return
+     * negative errors, we only have a signed return value here. Any additional
+     * entries will lead to -EINVAL. */
+    for (i = 0; i < INT_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);
+        if (subqdict_entries < 0) {
+            return subqdict_entries;
+        }
+
+        /* 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 -EINVAL;
+        } 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 -EINVAL;
+    }
+
+    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] 27+ messages in thread

* [Qemu-devel] [PATCH v2 02/13] qdict: Add qdict_{set, copy}_default()
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 01/13] qdict: Add qdict_array_entries() Kevin Wolf
@ 2015-06-10 13:46 ` Kevin Wolf
  2015-06-10 21:29   ` Eric Blake
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 03/13] check-qdict: Test cases for new functions Kevin Wolf
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:46 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, 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>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 include/qapi/qmp/qdict.h |  3 +++
 qobject/qdict.c          | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 36 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 50c0ab3..190791b 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -477,6 +477,39 @@ 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, a
+ * new QString initialised by 'val' is put there.
+ */
+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] 27+ messages in thread

* [Qemu-devel] [PATCH v2 03/13] check-qdict: Test cases for new functions
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 01/13] qdict: Add qdict_array_entries() Kevin Wolf
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 02/13] qdict: Add qdict_{set, copy}_default() Kevin Wolf
@ 2015-06-10 13:46 ` Kevin Wolf
  2015-06-10 21:34   ` Eric Blake
  2015-06-12 14:12   ` Max Reitz
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 04/13] quorum: Use bdrv_open_image() Kevin Wolf
                   ` (9 subsequent siblings)
  12 siblings, 2 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:46 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, qemu-devel, armbru, mreitz

This adds test cases for the following new QDict functions:

* qdict_array_entries()
* qdict_set_default_str()
* qdict_copy_default()

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 tests/check-qdict.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/tests/check-qdict.c b/tests/check-qdict.c
index a9296f0..a136f2a 100644
--- a/tests/check-qdict.c
+++ b/tests/check-qdict.c
@@ -152,6 +152,28 @@ static void qdict_get_try_str_test(void)
     QDECREF(tests_dict);
 }
 
+static void qdict_defaults_test(void)
+{
+    QDict *dict, *copy;
+
+    dict = qdict_new();
+    copy = qdict_new();
+
+    qdict_set_default_str(dict, "foo", "abc");
+    qdict_set_default_str(dict, "foo", "def");
+    g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "abc");
+    qdict_set_default_str(dict, "bar", "ghi");
+
+    qdict_copy_default(copy, dict, "foo");
+    g_assert_cmpstr(qdict_get_str(copy, "foo"), ==, "abc");
+    qdict_set_default_str(copy, "bar", "xyz");
+    qdict_copy_default(copy, dict, "bar");
+    g_assert_cmpstr(qdict_get_str(copy, "bar"), ==, "xyz");
+
+    QDECREF(copy);
+    QDECREF(dict);
+}
+
 static void qdict_haskey_not_test(void)
 {
     QDict *tests_dict = qdict_new();
@@ -444,6 +466,49 @@ static void qdict_array_split_test(void)
     QDECREF(test_dict);
 }
 
+static void qdict_array_entries_test(void)
+{
+    QDict *dict = qdict_new();
+
+    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
+
+    qdict_put(dict, "bar", qint_from_int(0));
+    qdict_put(dict, "baz.0", qint_from_int(0));
+    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
+
+    qdict_put(dict, "foo.1", qint_from_int(0));
+    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
+    qdict_put(dict, "foo.0", qint_from_int(0));
+    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2);
+    qdict_put(dict, "foo.bar", qint_from_int(0));
+    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
+    qdict_del(dict, "foo.bar");
+
+    qdict_put(dict, "foo.2.a", qint_from_int(0));
+    qdict_put(dict, "foo.2.b", qint_from_int(0));
+    qdict_put(dict, "foo.2.c", qint_from_int(0));
+    g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3);
+    g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
+
+    QDECREF(dict);
+
+    dict = qdict_new();
+    qdict_put(dict, "1", qint_from_int(0));
+    g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
+    qdict_put(dict, "0", qint_from_int(0));
+    g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2);
+    qdict_put(dict, "bar", qint_from_int(0));
+    g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
+    qdict_del(dict, "bar");
+
+    qdict_put(dict, "2.a", qint_from_int(0));
+    qdict_put(dict, "2.b", qint_from_int(0));
+    qdict_put(dict, "2.c", qint_from_int(0));
+    g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3);
+
+    QDECREF(dict);
+}
+
 static void qdict_join_test(void)
 {
     QDict *dict1, *dict2;
@@ -663,6 +728,7 @@ int main(int argc, char **argv)
     g_test_add_func("/public/get_try_int", qdict_get_try_int_test);
     g_test_add_func("/public/get_str", qdict_get_str_test);
     g_test_add_func("/public/get_try_str", qdict_get_try_str_test);
+    g_test_add_func("/public/defaults", qdict_defaults_test);
     g_test_add_func("/public/haskey_not", qdict_haskey_not_test);
     g_test_add_func("/public/haskey", qdict_haskey_test);
     g_test_add_func("/public/del", qdict_del_test);
@@ -670,6 +736,7 @@ int main(int argc, char **argv)
     g_test_add_func("/public/iterapi", qdict_iterapi_test);
     g_test_add_func("/public/flatten", qdict_flatten_test);
     g_test_add_func("/public/array_split", qdict_array_split_test);
+    g_test_add_func("/public/array_entries", qdict_array_entries_test);
     g_test_add_func("/public/join", qdict_join_test);
 
     g_test_add_func("/errors/put_exists", qdict_put_exists_test);
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH v2 04/13] quorum: Use bdrv_open_image()
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
                   ` (2 preceding siblings ...)
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 03/13] check-qdict: Test cases for new functions Kevin Wolf
@ 2015-06-10 13:46 ` Kevin Wolf
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 05/13] vmdk: " Kevin Wolf
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:46 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, 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>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Jeff Cody <jcody@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.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] 27+ messages in thread

* [Qemu-devel] [PATCH v2 05/13] vmdk: Use bdrv_open_image()
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
                   ` (3 preceding siblings ...)
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 04/13] quorum: Use bdrv_open_image() Kevin Wolf
@ 2015-06-10 13:46 ` Kevin Wolf
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 06/13] block: Use macro for cache option names Kevin Wolf
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:46 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, 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>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Jeff Cody <jcody@redhat.com>
---
 block/vmdk.c | 34 +++++++++++++++++++++-------------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/block/vmdk.c b/block/vmdk.c
index 56626b0..aad051b 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] 27+ messages in thread

* [Qemu-devel] [PATCH v2 06/13] block: Use macro for cache option names
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
                   ` (4 preceding siblings ...)
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 05/13] vmdk: " Kevin Wolf
@ 2015-06-10 13:47 ` Kevin Wolf
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 07/13] block: Use QemuOpts in bdrv_open_common() Kevin Wolf
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:47 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, qemu-devel, armbru, mreitz

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Jeff Cody <jcody@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.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 de94a8b..fffc9b5 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");
@@ -3105,15 +3105,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 f7680b6..5f3c2de 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] 27+ messages in thread

* [Qemu-devel] [PATCH v2 07/13] block: Use QemuOpts in bdrv_open_common()
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
                   ` (5 preceding siblings ...)
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 06/13] block: Use macro for cache option names Kevin Wolf
@ 2015-06-10 13:47 ` Kevin Wolf
  2015-06-10 21:42   ` Eric Blake
  2015-06-12 14:15   ` Max Reitz
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 08/13] block: Move flag inheritance to bdrv_open_inherit() Kevin Wolf
                   ` (5 subsequent siblings)
  12 siblings, 2 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:47 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, 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 | 39 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/block.c b/block.c
index 2786e47..7b466cf 100644
--- a/block.c
+++ b/block.c
@@ -767,6 +767,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
  *
@@ -778,6 +791,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);
@@ -798,19 +812,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;
     }
 
@@ -827,7 +850,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 */
@@ -836,7 +860,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;
         }
     }
 
@@ -902,6 +927,8 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
     assert(bdrv_opt_mem_align(bs) != 0);
     assert(bdrv_min_mem_align(bs) != 0);
     assert((bs->request_alignment != 0) || bs->sg);
+
+    qemu_opts_del(opts);
     return 0;
 
 free_and_fail:
@@ -909,6 +936,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] 27+ messages in thread

* [Qemu-devel] [PATCH v2 08/13] block: Move flag inheritance to bdrv_open_inherit()
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
                   ` (6 preceding siblings ...)
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 07/13] block: Use QemuOpts in bdrv_open_common() Kevin Wolf
@ 2015-06-10 13:47 ` Kevin Wolf
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 09/13] block: Drain requests before swapping nodes in bdrv_swap() Kevin Wolf
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:47 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, 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>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@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 7b466cf..7ba0edd 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;
@@ -682,8 +688,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)
 {
@@ -700,6 +706,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
@@ -715,6 +740,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;
@@ -837,7 +866,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;
@@ -1147,9 +1175,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;
@@ -1183,7 +1212,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;
@@ -1211,7 +1241,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);
@@ -1298,9 +1329,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;
@@ -1309,6 +1342,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;
@@ -1346,6 +1381,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;
@@ -1371,6 +1410,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);
 
@@ -1385,9 +1425,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;
         }
@@ -1504,6 +1544,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 1e92607..bc247f4 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -429,7 +429,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 aad051b..3284bec 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 5f3c2de..45e2340 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 f004378..662dd56 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -330,6 +330,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] 27+ messages in thread

* [Qemu-devel] [PATCH v2 09/13] block: Drain requests before swapping nodes in bdrv_swap()
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
                   ` (7 preceding siblings ...)
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 08/13] block: Move flag inheritance to bdrv_open_inherit() Kevin Wolf
@ 2015-06-10 13:47 ` Kevin Wolf
  2015-06-10 23:17   ` Eric Blake
  2015-06-12 14:16   ` Max Reitz
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 10/13] queue.h: Add QLIST_FIX_HEAD_PTR() Kevin Wolf
                   ` (3 subsequent siblings)
  12 siblings, 2 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:47 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, qemu-devel, armbru, mreitz

bdrv_swap() requires that there are no requests in flight on either of
the two devices. The request coroutine would work on the wrong
BlockDriverState object (with bs->opaque even being interpreted as a
different type potentially) and all sorts of bad things would result
from this.

The currently existing callers mostly ensure that there is no I/O
pending on nodes that are swapped. In detail, this is:

1. Live snapshots. This goes through qmp_transaction(), which calls
   bdrv_drain_all() before doing anything. The command is executed
   synchronously, so no new I/O can be issued concurrently.

2. snapshot=on in bdrv_open(). We're in the middle of opening the image
   (both the original image and its temporary overlay), so there can't
   be any I/O in flight yet.

3. Mirroring. bdrv_drain() is already used on the source device so that
   the mirror doesn't miss anything. However, the main loop runs between
   that and the bdrv_swap() (which is actually a bug, being addressed in
   another series), so there is a small window in which new I/O might be
   issued that would be in flight during bdrv_swap().

It is safer to just drain the request queue of both devices in
bdrv_swap() instead of relying on callers to do the right thing.

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

diff --git a/block.c b/block.c
index 7ba0edd..f1ceb26 100644
--- a/block.c
+++ b/block.c
@@ -1947,6 +1947,9 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
 {
     BlockDriverState tmp;
 
+    bdrv_drain(bs_new);
+    bdrv_drain(bs_old);
+
     /* 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
      * insert them back if needed.
@@ -1990,6 +1993,9 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
         QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_old, node_list);
     }
 
+    assert(QLIST_EMPTY(&bs_old->tracked_requests));
+    assert(QLIST_EMPTY(&bs_new->tracked_requests));
+
     bdrv_rebind(bs_new);
     bdrv_rebind(bs_old);
 }
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH v2 10/13] queue.h: Add QLIST_FIX_HEAD_PTR()
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
                   ` (8 preceding siblings ...)
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 09/13] block: Drain requests before swapping nodes in bdrv_swap() Kevin Wolf
@ 2015-06-10 13:47 ` Kevin Wolf
  2015-06-10 23:19   ` Eric Blake
  2015-06-12 14:19   ` Max Reitz
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 11/13] block: Add list of children to BlockDriverState Kevin Wolf
                   ` (2 subsequent siblings)
  12 siblings, 2 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:47 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, qemu-devel, armbru, mreitz

If the head of a list has been moved to a different memory location, the
le_prev link in the first list entry has to be fixed up. Provide a macro
that implements this fixup.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/qemu/queue.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/qemu/queue.h b/include/qemu/queue.h
index f781aa2..a8d3cb8 100644
--- a/include/qemu/queue.h
+++ b/include/qemu/queue.h
@@ -117,6 +117,12 @@ struct {                                                                \
         }                                                               \
 } while (/*CONSTCOND*/0)
 
+#define QLIST_FIX_HEAD_PTR(head, field) do {                            \
+        if ((head)->lh_first != NULL) {                                 \
+            (head)->lh_first->field.le_prev = &(head)->lh_first;        \
+        }                                                               \
+} while (/*CONSTCOND*/0)
+
 #define QLIST_INSERT_AFTER(listelm, elm, field) do {                    \
         if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)  \
                 (listelm)->field.le_next->field.le_prev =               \
-- 
1.8.3.1

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

* [Qemu-devel] [PATCH v2 11/13] block: Add list of children to BlockDriverState
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
                   ` (9 preceding siblings ...)
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 10/13] queue.h: Add QLIST_FIX_HEAD_PTR() Kevin Wolf
@ 2015-06-10 13:47 ` Kevin Wolf
  2015-06-10 23:26   ` Eric Blake
  2015-06-12 14:23   ` Max Reitz
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 12/13] block: Add BlockDriverState.inherits_from Kevin Wolf
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 13/13] block: Fix reopen flag inheritance Kevin Wolf
  12 siblings, 2 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:47 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, 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.

For bdrv_swap(), the list of children of the swapped BDS stays at that
BDS (because that's where the pointers stay as well). The list head
moves and pointers to it must be fixed up therefore.

The list of children in the parent of the swapped BDS is not affected by
the swap. The contents of the BDS objects is swapped, so the existing
pointer in the parent automatically points to the newly swapped in BDS.

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

diff --git a/block.c b/block.c
index f1ceb26..e2236c3 100644
--- a/block.c
+++ b/block.c
@@ -1314,6 +1314,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, ...)
  *
@@ -1366,6 +1379,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;
     }
@@ -1508,6 +1524,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;
@@ -1802,6 +1822,13 @@ 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) {
+            QLIST_REMOVE(child, next);
+            g_free(child);
+        }
+
         if (bs->backing_hd) {
             BlockDriverState *backing_hd = bs->backing_hd;
             bdrv_set_backing_hd(bs, NULL);
@@ -1993,9 +2020,18 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
         QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_old, node_list);
     }
 
+    /*
+     * Update lh_first.le_prev for non-empty lists.
+     *
+     * The head of the op blocker list doesn't change because it is moved back
+     * in bdrv_move_feature_fields().
+     */
     assert(QLIST_EMPTY(&bs_old->tracked_requests));
     assert(QLIST_EMPTY(&bs_new->tracked_requests));
 
+    QLIST_FIX_HEAD_PTR(&bs_new->children, next);
+    QLIST_FIX_HEAD_PTR(&bs_old->children, next);
+
     bdrv_rebind(bs_new);
     bdrv_rebind(bs_old);
 }
@@ -2018,6 +2054,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 662dd56..4ae5860 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -337,6 +337,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
@@ -431,6 +437,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] 27+ messages in thread

* [Qemu-devel] [PATCH v2 12/13] block: Add BlockDriverState.inherits_from
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
                   ` (10 preceding siblings ...)
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 11/13] block: Add list of children to BlockDriverState Kevin Wolf
@ 2015-06-10 13:47 ` Kevin Wolf
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 13/13] block: Fix reopen flag inheritance Kevin Wolf
  12 siblings, 0 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:47 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, 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>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@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 e2236c3..fa89410 100644
--- a/block.c
+++ b/block.c
@@ -1398,6 +1398,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);
     }
 
@@ -1825,6 +1826,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;
+            }
             QLIST_REMOVE(child, next);
             g_free(child);
         }
@@ -1973,6 +1977,7 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
 void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
 {
     BlockDriverState tmp;
+    BdrvChild *child;
 
     bdrv_drain(bs_new);
     bdrv_drain(bs_old);
@@ -2032,6 +2037,18 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
     QLIST_FIX_HEAD_PTR(&bs_new->children, next);
     QLIST_FIX_HEAD_PTR(&bs_old->children, next);
 
+    /* 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 4ae5860..2732ccd 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -437,6 +437,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] 27+ messages in thread

* [Qemu-devel] [PATCH v2 13/13] block: Fix reopen flag inheritance
  2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
                   ` (11 preceding siblings ...)
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 12/13] block: Add BlockDriverState.inherits_from Kevin Wolf
@ 2015-06-10 13:47 ` Kevin Wolf
  12 siblings, 0 replies; 27+ messages in thread
From: Kevin Wolf @ 2015-06-10 13:47 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, berto, 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>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@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 fa89410..54fedfc 100644
--- a/block.c
+++ b/block.c
@@ -1603,6 +1603,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);
@@ -1611,8 +1613,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 3284bec..be9263a 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] 27+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/13] qdict: Add qdict_array_entries()
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 01/13] qdict: Add qdict_array_entries() Kevin Wolf
@ 2015-06-10 20:50   ` Eric Blake
  2015-06-12 14:07   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Eric Blake @ 2015-06-10 20:50 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: qemu-devel, berto, armbru, mreitz

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

On 06/10/2015 07:46 AM, Kevin Wolf wrote:
> 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.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  include/qapi/qmp/qdict.h |  1 +
>  qobject/qdict.c          | 78 +++++++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 75 insertions(+), 4 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] 27+ messages in thread

* Re: [Qemu-devel] [PATCH v2 02/13] qdict: Add qdict_{set, copy}_default()
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 02/13] qdict: Add qdict_{set, copy}_default() Kevin Wolf
@ 2015-06-10 21:29   ` Eric Blake
  0 siblings, 0 replies; 27+ messages in thread
From: Eric Blake @ 2015-06-10 21:29 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: qemu-devel, berto, armbru, mreitz

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

On 06/10/2015 07:46 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>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> ---
>  include/qapi/qmp/qdict.h |  3 +++
>  qobject/qdict.c          | 33 +++++++++++++++++++++++++++++++++
>  2 files changed, 36 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] 27+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/13] check-qdict: Test cases for new functions
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 03/13] check-qdict: Test cases for new functions Kevin Wolf
@ 2015-06-10 21:34   ` Eric Blake
  2015-06-12 14:12   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Eric Blake @ 2015-06-10 21:34 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: qemu-devel, berto, armbru, mreitz

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

On 06/10/2015 07:46 AM, Kevin Wolf wrote:
> This adds test cases for the following new QDict functions:
> 
> * qdict_array_entries()
> * qdict_set_default_str()
> * qdict_copy_default()
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  tests/check-qdict.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 67 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] 27+ messages in thread

* Re: [Qemu-devel] [PATCH v2 07/13] block: Use QemuOpts in bdrv_open_common()
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 07/13] block: Use QemuOpts in bdrv_open_common() Kevin Wolf
@ 2015-06-10 21:42   ` Eric Blake
  2015-06-12 14:15   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Eric Blake @ 2015-06-10 21:42 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: qemu-devel, berto, armbru, mreitz

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

On 06/10/2015 07:47 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 | 39 ++++++++++++++++++++++++++++++++++-----
>  1 file changed, 34 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] 27+ messages in thread

* Re: [Qemu-devel] [PATCH v2 09/13] block: Drain requests before swapping nodes in bdrv_swap()
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 09/13] block: Drain requests before swapping nodes in bdrv_swap() Kevin Wolf
@ 2015-06-10 23:17   ` Eric Blake
  2015-06-12 14:16   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Eric Blake @ 2015-06-10 23:17 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: qemu-devel, berto, armbru, mreitz

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

On 06/10/2015 07:47 AM, Kevin Wolf wrote:
> bdrv_swap() requires that there are no requests in flight on either of
> the two devices. The request coroutine would work on the wrong
> BlockDriverState object (with bs->opaque even being interpreted as a
> different type potentially) and all sorts of bad things would result
> from this.
> 
> The currently existing callers mostly ensure that there is no I/O
> pending on nodes that are swapped. In detail, this is:
> 
> 1. Live snapshots. This goes through qmp_transaction(), which calls
>    bdrv_drain_all() before doing anything. The command is executed
>    synchronously, so no new I/O can be issued concurrently.
> 
> 2. snapshot=on in bdrv_open(). We're in the middle of opening the image
>    (both the original image and its temporary overlay), so there can't
>    be any I/O in flight yet.
> 
> 3. Mirroring. bdrv_drain() is already used on the source device so that
>    the mirror doesn't miss anything. However, the main loop runs between
>    that and the bdrv_swap() (which is actually a bug, being addressed in
>    another series), so there is a small window in which new I/O might be
>    issued that would be in flight during bdrv_swap().
> 
> It is safer to just drain the request queue of both devices in
> bdrv_swap() instead of relying on callers to do the right thing.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c | 6 ++++++
>  1 file changed, 6 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] 27+ messages in thread

* Re: [Qemu-devel] [PATCH v2 10/13] queue.h: Add QLIST_FIX_HEAD_PTR()
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 10/13] queue.h: Add QLIST_FIX_HEAD_PTR() Kevin Wolf
@ 2015-06-10 23:19   ` Eric Blake
  2015-06-12 14:19   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Eric Blake @ 2015-06-10 23:19 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: qemu-devel, berto, armbru, mreitz

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

On 06/10/2015 07:47 AM, Kevin Wolf wrote:
> If the head of a list has been moved to a different memory location, the
> le_prev link in the first list entry has to be fixed up. Provide a macro
> that implements this fixup.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  include/qemu/queue.h | 6 ++++++
>  1 file changed, 6 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] 27+ messages in thread

* Re: [Qemu-devel] [PATCH v2 11/13] block: Add list of children to BlockDriverState
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 11/13] block: Add list of children to BlockDriverState Kevin Wolf
@ 2015-06-10 23:26   ` Eric Blake
  2015-06-12 14:23   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Eric Blake @ 2015-06-10 23:26 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: qemu-devel, berto, armbru, mreitz

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

On 06/10/2015 07:47 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.
> 
> For bdrv_swap(), the list of children of the swapped BDS stays at that
> BDS (because that's where the pointers stay as well). The list head
> moves and pointers to it must be fixed up therefore.
> 
> The list of children in the parent of the swapped BDS is not affected by
> the swap. The contents of the BDS objects is swapped, so the existing
> pointer in the parent automatically points to the newly swapped in BDS.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c                   | 37 +++++++++++++++++++++++++++++++++++++
>  include/block/block_int.h |  8 ++++++++
>  2 files changed, 45 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] 27+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/13] qdict: Add qdict_array_entries()
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 01/13] qdict: Add qdict_array_entries() Kevin Wolf
  2015-06-10 20:50   ` Eric Blake
@ 2015-06-12 14:07   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Max Reitz @ 2015-06-12 14:07 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: berto, armbru, qemu-devel

On 10.06.2015 15:46, Kevin Wolf wrote:
> 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.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   include/qapi/qmp/qdict.h |  1 +
>   qobject/qdict.c          | 78 +++++++++++++++++++++++++++++++++++++++++++++---
>   2 files changed, 75 insertions(+), 4 deletions(-)

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

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

* Re: [Qemu-devel] [PATCH v2 03/13] check-qdict: Test cases for new functions
  2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 03/13] check-qdict: Test cases for new functions Kevin Wolf
  2015-06-10 21:34   ` Eric Blake
@ 2015-06-12 14:12   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Max Reitz @ 2015-06-12 14:12 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: berto, armbru, qemu-devel

On 10.06.2015 15:46, Kevin Wolf wrote:
> This adds test cases for the following new QDict functions:
>
> * qdict_array_entries()
> * qdict_set_default_str()
> * qdict_copy_default()
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   tests/check-qdict.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 67 insertions(+)

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

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

* Re: [Qemu-devel] [PATCH v2 07/13] block: Use QemuOpts in bdrv_open_common()
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 07/13] block: Use QemuOpts in bdrv_open_common() Kevin Wolf
  2015-06-10 21:42   ` Eric Blake
@ 2015-06-12 14:15   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Max Reitz @ 2015-06-12 14:15 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: berto, armbru, qemu-devel

On 10.06.2015 15:47, 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 | 39 ++++++++++++++++++++++++++++++++++-----
>   1 file changed, 34 insertions(+), 5 deletions(-)

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

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

* Re: [Qemu-devel] [PATCH v2 09/13] block: Drain requests before swapping nodes in bdrv_swap()
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 09/13] block: Drain requests before swapping nodes in bdrv_swap() Kevin Wolf
  2015-06-10 23:17   ` Eric Blake
@ 2015-06-12 14:16   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Max Reitz @ 2015-06-12 14:16 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: berto, armbru, qemu-devel

On 10.06.2015 15:47, Kevin Wolf wrote:
> bdrv_swap() requires that there are no requests in flight on either of
> the two devices. The request coroutine would work on the wrong
> BlockDriverState object (with bs->opaque even being interpreted as a
> different type potentially) and all sorts of bad things would result
> from this.
>
> The currently existing callers mostly ensure that there is no I/O
> pending on nodes that are swapped. In detail, this is:
>
> 1. Live snapshots. This goes through qmp_transaction(), which calls
>     bdrv_drain_all() before doing anything. The command is executed
>     synchronously, so no new I/O can be issued concurrently.
>
> 2. snapshot=on in bdrv_open(). We're in the middle of opening the image
>     (both the original image and its temporary overlay), so there can't
>     be any I/O in flight yet.
>
> 3. Mirroring. bdrv_drain() is already used on the source device so that
>     the mirror doesn't miss anything. However, the main loop runs between
>     that and the bdrv_swap() (which is actually a bug, being addressed in
>     another series), so there is a small window in which new I/O might be
>     issued that would be in flight during bdrv_swap().
>
> It is safer to just drain the request queue of both devices in
> bdrv_swap() instead of relying on callers to do the right thing.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c | 6 ++++++
>   1 file changed, 6 insertions(+)

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

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

* Re: [Qemu-devel] [PATCH v2 10/13] queue.h: Add QLIST_FIX_HEAD_PTR()
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 10/13] queue.h: Add QLIST_FIX_HEAD_PTR() Kevin Wolf
  2015-06-10 23:19   ` Eric Blake
@ 2015-06-12 14:19   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Max Reitz @ 2015-06-12 14:19 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: berto, armbru, qemu-devel

On 10.06.2015 15:47, Kevin Wolf wrote:
> If the head of a list has been moved to a different memory location, the
> le_prev link in the first list entry has to be fixed up. Provide a macro
> that implements this fixup.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   include/qemu/queue.h | 6 ++++++
>   1 file changed, 6 insertions(+)

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

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

* Re: [Qemu-devel] [PATCH v2 11/13] block: Add list of children to BlockDriverState
  2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 11/13] block: Add list of children to BlockDriverState Kevin Wolf
  2015-06-10 23:26   ` Eric Blake
@ 2015-06-12 14:23   ` Max Reitz
  1 sibling, 0 replies; 27+ messages in thread
From: Max Reitz @ 2015-06-12 14:23 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: berto, armbru, qemu-devel

On 10.06.2015 15:47, 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.
>
> For bdrv_swap(), the list of children of the swapped BDS stays at that
> BDS (because that's where the pointers stay as well). The list head
> moves and pointers to it must be fixed up therefore.
>
> The list of children in the parent of the swapped BDS is not affected by
> the swap. The contents of the BDS objects is swapped, so the existing
> pointer in the parent automatically points to the newly swapped in BDS.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block.c                   | 37 +++++++++++++++++++++++++++++++++++++
>   include/block/block_int.h |  8 ++++++++
>   2 files changed, 45 insertions(+)

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

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

end of thread, other threads:[~2015-06-12 14:24 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-06-10 13:46 [Qemu-devel] [PATCH v2 00/13] bdrv_reopen() overhaul, part 1 Kevin Wolf
2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 01/13] qdict: Add qdict_array_entries() Kevin Wolf
2015-06-10 20:50   ` Eric Blake
2015-06-12 14:07   ` Max Reitz
2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 02/13] qdict: Add qdict_{set, copy}_default() Kevin Wolf
2015-06-10 21:29   ` Eric Blake
2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 03/13] check-qdict: Test cases for new functions Kevin Wolf
2015-06-10 21:34   ` Eric Blake
2015-06-12 14:12   ` Max Reitz
2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 04/13] quorum: Use bdrv_open_image() Kevin Wolf
2015-06-10 13:46 ` [Qemu-devel] [PATCH v2 05/13] vmdk: " Kevin Wolf
2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 06/13] block: Use macro for cache option names Kevin Wolf
2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 07/13] block: Use QemuOpts in bdrv_open_common() Kevin Wolf
2015-06-10 21:42   ` Eric Blake
2015-06-12 14:15   ` Max Reitz
2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 08/13] block: Move flag inheritance to bdrv_open_inherit() Kevin Wolf
2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 09/13] block: Drain requests before swapping nodes in bdrv_swap() Kevin Wolf
2015-06-10 23:17   ` Eric Blake
2015-06-12 14:16   ` Max Reitz
2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 10/13] queue.h: Add QLIST_FIX_HEAD_PTR() Kevin Wolf
2015-06-10 23:19   ` Eric Blake
2015-06-12 14:19   ` Max Reitz
2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 11/13] block: Add list of children to BlockDriverState Kevin Wolf
2015-06-10 23:26   ` Eric Blake
2015-06-12 14:23   ` Max Reitz
2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 12/13] block: Add BlockDriverState.inherits_from Kevin Wolf
2015-06-10 13:47 ` [Qemu-devel] [PATCH v2 13/13] block: Fix reopen flag inheritance Kevin Wolf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).