Add a new function called bdrv_open_backing_chain_until.
This is used to open a block up until a specified backing chain.

Modified bdrv_open_inherit to accept a new arg 'open_backing' to force
to to no open the next backing. Adjusting all references to keep the
existing behaviour.

Signed-off-by: Jean-Louis Dupond <[email protected]>
---
 block.c                            | 65 +++++++++++++++++++++++++-----
 block/mirror.c                     |  2 +-
 include/block/block-global-state.h |  7 +++-
 3 files changed, 62 insertions(+), 12 deletions(-)

diff --git a/block.c b/block.c
index f0a6042e61..a4f4ce1c21 100644
--- a/block.c
+++ b/block.c
@@ -83,6 +83,7 @@ static QLIST_HEAD(, BlockDriver) bdrv_drivers =
 static BlockDriverState *bdrv_open_inherit(const char *filename,
                                            const char *reference,
                                            QDict *options, int flags,
+                                           bool open_backing,
                                            BlockDriverState *parent,
                                            const BdrvChildClass *child_class,
                                            BdrvChildRole child_role,
@@ -3617,6 +3618,7 @@ out:
  * TODO Can this be unified with bdrv_open_image()?
  */
 int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
+                           bool open_backing,
                            const char *bdref_key, Error **errp)
 {
     ERRP_GUARD();
@@ -3695,9 +3697,9 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict 
*parent_options,
         qdict_put_str(options, "driver", bs->backing_format);
     }
 
-    backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0, bs,
-                                   &child_of_bds, bdrv_backing_role(bs), true,
-                                   errp);
+    backing_hd = bdrv_open_inherit(backing_filename, reference, options, 0,
+                                   open_backing, bs, &child_of_bds,
+                                   bdrv_backing_role(bs), true, errp);
     if (!backing_hd) {
         bs->open_flags |= BDRV_O_NO_BACKING;
         error_prepend(errp, "Could not open backing file: ");
@@ -3733,6 +3735,48 @@ free_exit:
     return ret;
 }
 
+int
+bdrv_open_backing_chain_until(BlockDriverState *top_bs,
+                              const char *base_filename,
+                              Error **errp)
+{
+    BlockDriverState *base_bs = NULL;
+    BlockDriverState *curr = top_bs;
+    int ret;
+
+    GLOBAL_STATE_CODE();
+
+    if (!base_filename) {
+        return 0;
+    }
+
+    while (!(base_bs = bdrv_find_backing_image(top_bs, base_filename))) {
+        QDict *options;
+
+        options = qdict_clone_shallow(curr->options);
+        ret = bdrv_open_backing_file(curr, options, false, "backing", errp);
+        qobject_unref(options);
+        if (ret < 0) {
+            return ret;
+        }
+
+        bdrv_graph_rdlock_main_loop();
+        if (!curr->backing) {
+            bdrv_graph_rdunlock_main_loop();
+            error_setg(errp,
+                       "Did not find '%s' in the backing chain of '%s'",
+                       base_filename, top_bs->filename);
+            return -ENOENT;
+        }
+
+        /* Switch to the next layer */
+        curr = curr->backing->bs;
+        bdrv_graph_rdunlock_main_loop();
+    }
+
+    return 0;
+}
+
 static BlockDriverState *
 bdrv_open_child_bs(const char *filename, QDict *options, const char *bdref_key,
                    BlockDriverState *parent, const BdrvChildClass *child_class,
@@ -3767,7 +3811,7 @@ bdrv_open_child_bs(const char *filename, QDict *options, 
const char *bdref_key,
         goto done;
     }
 
-    bs = bdrv_open_inherit(filename, reference, image_options, 0,
+    bs = bdrv_open_inherit(filename, reference, image_options, 0, true,
                            parent, child_class, child_role, parse_filename,
                            errp);
     if (!bs) {
@@ -3897,8 +3941,8 @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef 
*ref, Error **errp)
 
     }
 
-    bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, 0, false,
-                           errp);
+    bs = bdrv_open_inherit(NULL, reference, qdict, 0, true, NULL, NULL, 0,
+                           false, errp);
     obj = NULL;
     qobject_unref(obj);
     visit_free(v);
@@ -3986,7 +4030,7 @@ out:
  */
 static BlockDriverState * no_coroutine_fn
 bdrv_open_inherit(const char *filename, const char *reference, QDict *options,
-                  int flags, BlockDriverState *parent,
+                  int flags, bool open_backing, BlockDriverState *parent,
                   const BdrvChildClass *child_class, BdrvChildRole child_role,
                   bool parse_filename, Error **errp)
 {
@@ -4199,8 +4243,9 @@ bdrv_open_inherit(const char *filename, const char 
*reference, QDict *options,
     }
 
     /* If there is a backing file, use it */
-    if ((flags & BDRV_O_NO_BACKING) == 0) {
-        ret = bdrv_open_backing_file(bs, options, "backing", &local_err);
+    if ((flags & BDRV_O_NO_BACKING) == 0 && open_backing) {
+        ret = bdrv_open_backing_file(bs, options, open_backing, "backing",
+                                     &local_err);
         if (ret < 0) {
             goto close_and_fail;
         }
@@ -4283,7 +4328,7 @@ BlockDriverState *bdrv_open(const char *filename, const 
char *reference,
 {
     GLOBAL_STATE_CODE();
 
-    return bdrv_open_inherit(filename, reference, options, flags, NULL,
+    return bdrv_open_inherit(filename, reference, options, flags, true, NULL,
                              NULL, 0, true, errp);
 }
 
diff --git a/block/mirror.c b/block/mirror.c
index 089856f4a8..a4dde5d36d 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -785,7 +785,7 @@ static int mirror_exit_common(Job *job)
         bdrv_graph_rdlock_main_loop();
         assert(!bdrv_backing_chain_next(target_bs));
         ret = bdrv_open_backing_file(bdrv_skip_filters(target_bs), NULL,
-                                     "backing", &local_err);
+                                     true, "backing", &local_err);
         bdrv_graph_rdunlock_main_loop();
         if (ret < 0) {
             error_report_err(local_err);
diff --git a/include/block/block-global-state.h 
b/include/block/block-global-state.h
index ed89999f0f..c7becd9d73 100644
--- a/include/block/block-global-state.h
+++ b/include/block/block-global-state.h
@@ -110,7 +110,12 @@ bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState 
*backing_hd,
                     Error **errp);
 
 int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
-                           const char *bdref_key, Error **errp);
+                           bool open_backing, const char *bdref_key,
+                           Error **errp);
+
+int bdrv_open_backing_chain_until(BlockDriverState *top_bs,
+                                  const char *base_filename,
+                                  Error **errp);
 
 BlockDriverState * no_coroutine_fn
 bdrv_open(const char *filename, const char *reference, QDict *options,
-- 
2.54.0


Reply via email to