diff mbox

[v2,11/13] block: Add list of children to BlockDriverState

Message ID 1433944027-28533-12-git-send-email-kwolf@redhat.com
State New
Headers show

Commit Message

Kevin Wolf June 10, 2015, 1:47 p.m. UTC
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(+)

Comments

Eric Blake June 10, 2015, 11:26 p.m. UTC | #1
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>
Max Reitz June 12, 2015, 2:23 p.m. UTC | #2
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>
diff mbox

Patch

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;