X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/9f0355b590ac523d0c4e67c416c3f9cf7af3d574..29d72431ef7a68977a809727988285654887263f:/block/stream.c diff --git a/block/stream.c b/block/stream.c index 91d18a2db7..25af7eff62 100644 --- a/block/stream.c +++ b/block/stream.c @@ -14,7 +14,9 @@ #include "trace.h" #include "block/block_int.h" #include "block/blockjob.h" +#include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" +#include "sysemu/block-backend.h" enum { /* @@ -32,7 +34,7 @@ typedef struct StreamBlockJob { RateLimit limit; BlockDriverState *base; BlockdevOnError on_error; - char backing_file_id[1024]; + char *backing_file_str; } StreamBlockJob; static int coroutine_fn stream_populate(BlockDriverState *bs, @@ -51,37 +53,39 @@ static int coroutine_fn stream_populate(BlockDriverState *bs, return bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, &qiov); } -static void close_unused_images(BlockDriverState *top, BlockDriverState *base, - const char *base_id) -{ - BlockDriverState *intermediate; - intermediate = top->backing_hd; - - /* Must assign before bdrv_delete() to prevent traversing dangling pointer - * while we delete backing image instances. - */ - bdrv_set_backing_hd(top, base); +typedef struct { + int ret; + bool reached_end; +} StreamCompleteData; - while (intermediate) { - BlockDriverState *unused; +static void stream_complete(BlockJob *job, void *opaque) +{ + StreamBlockJob *s = container_of(job, StreamBlockJob, common); + StreamCompleteData *data = opaque; + BlockDriverState *base = s->base; - /* reached base */ - if (intermediate == base) { - break; + if (!block_job_is_cancelled(&s->common) && data->reached_end && + data->ret == 0) { + const char *base_id = NULL, *base_fmt = NULL; + if (base) { + base_id = s->backing_file_str; + if (base->drv) { + base_fmt = base->drv->format_name; + } } - - unused = intermediate; - intermediate = intermediate->backing_hd; - bdrv_set_backing_hd(unused, NULL); - bdrv_unref(unused); + data->ret = bdrv_change_backing_file(job->bs, base_id, base_fmt); + bdrv_set_backing_hd(job->bs, base); } - bdrv_refresh_limits(top); + g_free(s->backing_file_str); + block_job_completed(&s->common, data->ret); + g_free(data); } static void coroutine_fn stream_run(void *opaque) { StreamBlockJob *s = opaque; + StreamCompleteData *data; BlockDriverState *bs = s->common.bs; BlockDriverState *base = s->base; int64_t sector_num, end; @@ -90,7 +94,7 @@ static void coroutine_fn stream_run(void *opaque) int n = 0; void *buf; - if (!bs->backing_hd) { + if (!bs->backing) { block_job_completed(&s->common, 0); return; } @@ -135,7 +139,7 @@ wait: } else if (ret >= 0) { /* Copy if allocated in the intermediate images. Limit to the * known-unallocated area [sector_num, sector_num+n). */ - ret = bdrv_is_allocated_above(bs->backing_hd, base, + ret = bdrv_is_allocated_above(backing_bs(bs), base, sector_num, n, &n); /* Finish early if end of backing file has been reached */ @@ -159,14 +163,14 @@ wait: BlockErrorAction action = block_job_error_action(&s->common, s->common.bs, s->on_error, true, -ret); - if (action == BDRV_ACTION_STOP) { + if (action == BLOCK_ERROR_ACTION_STOP) { n = 0; continue; } if (error == 0) { error = ret; } - if (action == BDRV_ACTION_REPORT) { + if (action == BLOCK_ERROR_ACTION_REPORT) { break; } } @@ -183,20 +187,13 @@ wait: /* Do not remove the backing file if an error was there but ignored. */ ret = error; - if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) { - const char *base_id = NULL, *base_fmt = NULL; - if (base) { - base_id = s->backing_file_id; - if (base->drv) { - base_fmt = base->drv->format_name; - } - } - ret = bdrv_change_backing_file(bs, base_id, base_fmt); - close_unused_images(bs, base, base_id); - } - qemu_vfree(buf); - block_job_completed(&s->common, ret); + + /* Modify backing chain and close BDSes in main loop */ + data = g_malloc(sizeof(*data)); + data->ret = ret; + data->reached_end = sector_num == end; + block_job_defer_to_main_loop(&s->common, stream_complete, data); } static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp) @@ -204,7 +201,7 @@ static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp) StreamBlockJob *s = container_of(job, StreamBlockJob, common); if (speed < 0) { - error_set(errp, QERR_INVALID_PARAMETER, "speed"); + error_setg(errp, QERR_INVALID_PARAMETER, "speed"); return; } ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME); @@ -217,17 +214,17 @@ static const BlockJobDriver stream_job_driver = { }; void stream_start(BlockDriverState *bs, BlockDriverState *base, - const char *base_id, int64_t speed, + const char *backing_file_str, int64_t speed, BlockdevOnError on_error, - BlockDriverCompletionFunc *cb, + BlockCompletionFunc *cb, void *opaque, Error **errp) { StreamBlockJob *s; if ((on_error == BLOCKDEV_ON_ERROR_STOP || on_error == BLOCKDEV_ON_ERROR_ENOSPC) && - !bdrv_iostatus_is_enabled(bs)) { - error_set(errp, QERR_INVALID_PARAMETER, "on-error"); + (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) { + error_setg(errp, QERR_INVALID_PARAMETER, "on-error"); return; } @@ -237,9 +234,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base, } s->base = base; - if (base_id) { - pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id); - } + s->backing_file_str = g_strdup(backing_file_str); s->on_error = on_error; s->common.co = qemu_coroutine_create(stream_run);