Commit 54e26900 authored by Jeff Cody's avatar Jeff Cody Committed by Stefan Hajnoczi
Browse files

block: extend block-commit to accept a string for the backing file



On some image chains, QEMU may not always be able to resolve the
filenames properly, when updating the backing file of an image
after a block commit.

For instance, certain relative pathnames may fail, or drives may
have been specified originally by file descriptor (e.g. /dev/fd/???),
or a relative protocol pathname may have been used.

In these instances, QEMU may lack the information to be able to make
the correct choice, but the user or management layer most likely does
have that knowledge.

With this extension to the block-commit api, the user is able to change
the backing file of the overlay image as part of the block-commit
operation.

This allows the change to be 'safe', in the sense that if the attempt
to write the overlay image metadata fails, then the block-commit
operation returns failure, without disrupting the guest.

If the commit top is the active layer, then specifying the backing
file string will be treated as an error (there is no overlay image
to modify in that case).

If a backing file string is not specified in the command, the backing
file string to use is determined in the same manner as it was
previously.

Reviewed-by: default avatarEric Blake <eblake@redhat.com>
Signed-off-by: default avatarJeff Cody <jcody@redhat.com>
Reviewed-by: default avatarKevin Wolf <kwolf@redhat.com>
Signed-off-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
parent 5a6684d2
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -2555,12 +2555,15 @@ typedef struct BlkIntermediateStates {
 *
 * base <- active
 *
 * If backing_file_str is non-NULL, it will be used when modifying top's
 * overlay image metadata.
 *
 * Error conditions:
 *  if active == top, that is considered an error
 *
 */
int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
                           BlockDriverState *base)
                           BlockDriverState *base, const char *backing_file_str)
{
    BlockDriverState *intermediate;
    BlockDriverState *base_bs = NULL;
@@ -2612,7 +2615,8 @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
    }

    /* success - we can delete the intermediate states, and link top->base */
    ret = bdrv_change_backing_file(new_top_bs, base_bs->filename,
    backing_file_str = backing_file_str ? backing_file_str : base_bs->filename;
    ret = bdrv_change_backing_file(new_top_bs, backing_file_str,
                                   base_bs->drv ? base_bs->drv->format_name : "");
    if (ret) {
        goto exit;
+6 −3
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ typedef struct CommitBlockJob {
    BlockdevOnError on_error;
    int base_flags;
    int orig_overlay_flags;
    char *backing_file_str;
} CommitBlockJob;

static int coroutine_fn commit_populate(BlockDriverState *bs,
@@ -141,7 +142,7 @@ wait:

    if (!block_job_is_cancelled(&s->common) && sector_num == end) {
        /* success */
        ret = bdrv_drop_intermediate(active, top, base);
        ret = bdrv_drop_intermediate(active, top, base, s->backing_file_str);
    }

exit_free_buf:
@@ -158,7 +159,7 @@ exit_restore_reopen:
    if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) {
        bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL);
    }

    g_free(s->backing_file_str);
    block_job_completed(&s->common, ret);
}

@@ -182,7 +183,7 @@ static const BlockJobDriver commit_job_driver = {
void commit_start(BlockDriverState *bs, BlockDriverState *base,
                  BlockDriverState *top, int64_t speed,
                  BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
                  void *opaque, Error **errp)
                  void *opaque, const char *backing_file_str, Error **errp)
{
    CommitBlockJob *s;
    BlockReopenQueue *reopen_queue = NULL;
@@ -244,6 +245,8 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
    s->base_flags          = orig_base_flags;
    s->orig_overlay_flags  = orig_overlay_flags;

    s->backing_file_str = g_strdup(backing_file_str);

    s->on_error = on_error;
    s->common.co = qemu_coroutine_create(commit_run);

+7 −1
Original line number Diff line number Diff line
@@ -1915,6 +1915,7 @@ void qmp_block_stream(const char *device, bool has_base,
void qmp_block_commit(const char *device,
                      bool has_base, const char *base,
                      bool has_top, const char *top,
                      bool has_backing_file, const char *backing_file,
                      bool has_speed, int64_t speed,
                      Error **errp)
{
@@ -1980,11 +1981,16 @@ void qmp_block_commit(const char *device,
    }

    if (top_bs == bs) {
        if (has_backing_file) {
            error_setg(errp, "'backing-file' specified,"
                             " but 'top' is the active layer");
            return;
        }
        commit_active_start(bs, base_bs, speed, on_error, block_job_cb,
                            bs, &local_err);
    } else {
        commit_start(bs, base_bs, top_bs, speed, on_error, block_job_cb, bs,
                    &local_err);
                     has_backing_file ? backing_file : NULL, &local_err);
    }
    if (local_err != NULL) {
        error_propagate(errp, local_err);
+2 −1
Original line number Diff line number Diff line
@@ -285,7 +285,8 @@ int bdrv_change_backing_file(BlockDriverState *bs,
    const char *backing_file, const char *backing_fmt);
void bdrv_register(BlockDriver *bdrv);
int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
                           BlockDriverState *base);
                           BlockDriverState *base,
                           const char *backing_file_str);
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
                                    BlockDriverState *bs);
BlockDriverState *bdrv_find_base(BlockDriverState *bs);
+2 −1
Original line number Diff line number Diff line
@@ -463,13 +463,14 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base,
 * @on_error: The action to take upon error.
 * @cb: Completion function for the job.
 * @opaque: Opaque pointer value passed to @cb.
 * @backing_file_str: String to use as the backing file in @top's overlay
 * @errp: Error object.
 *
 */
void commit_start(BlockDriverState *bs, BlockDriverState *base,
                 BlockDriverState *top, int64_t speed,
                 BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
                 void *opaque, Error **errp);
                 void *opaque, const char *backing_file_str, Error **errp);
/**
 * commit_active_start:
 * @bs: Active block device to be committed.
Loading