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
