diff --git a/block.c b/block.c index dbce7bc181..e28a32a201 100644 --- a/block.c +++ b/block.c @@ -257,7 +257,6 @@ BlockDriverState *bdrv_new(void) for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) { QLIST_INIT(&bs->op_blockers[i]); } - bdrv_iostatus_disable(bs); notifier_list_init(&bs->close_notifiers); notifier_with_return_list_init(&bs->before_write_notifiers); qemu_co_queue_init(&bs->throttled_reqs[0]); @@ -2005,14 +2004,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest, bs_dest->enable_write_cache = bs_src->enable_write_cache; - /* r/w error */ - bs_dest->on_read_error = bs_src->on_read_error; - bs_dest->on_write_error = bs_src->on_write_error; - - /* i/o status */ - bs_dest->iostatus_enabled = bs_src->iostatus_enabled; - bs_dest->iostatus = bs_src->iostatus; - /* dirty bitmap */ bs_dest->dirty_bitmaps = bs_src->dirty_bitmaps; } @@ -2499,82 +2490,6 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr) *nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors; } -void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error, - BlockdevOnError on_write_error) -{ - bs->on_read_error = on_read_error; - bs->on_write_error = on_write_error; -} - -BlockdevOnError bdrv_get_on_error(BlockDriverState *bs, bool is_read) -{ - return is_read ? bs->on_read_error : bs->on_write_error; -} - -BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int error) -{ - BlockdevOnError on_err = is_read ? bs->on_read_error : bs->on_write_error; - - switch (on_err) { - case BLOCKDEV_ON_ERROR_ENOSPC: - return (error == ENOSPC) ? - BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT; - case BLOCKDEV_ON_ERROR_STOP: - return BLOCK_ERROR_ACTION_STOP; - case BLOCKDEV_ON_ERROR_REPORT: - return BLOCK_ERROR_ACTION_REPORT; - case BLOCKDEV_ON_ERROR_IGNORE: - return BLOCK_ERROR_ACTION_IGNORE; - default: - abort(); - } -} - -static void send_qmp_error_event(BlockDriverState *bs, - BlockErrorAction action, - bool is_read, int error) -{ - IoOperationType optype; - - optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE; - qapi_event_send_block_io_error(bdrv_get_device_name(bs), optype, action, - bdrv_iostatus_is_enabled(bs), - error == ENOSPC, strerror(error), - &error_abort); -} - -/* This is done by device models because, while the block layer knows - * about the error, it does not know whether an operation comes from - * the device or the block layer (from a job, for example). - */ -void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action, - bool is_read, int error) -{ - assert(error >= 0); - - if (action == BLOCK_ERROR_ACTION_STOP) { - /* First set the iostatus, so that "info block" returns an iostatus - * that matches the events raised so far (an additional error iostatus - * is fine, but not a lost one). - */ - bdrv_iostatus_set_err(bs, error); - - /* Then raise the request to stop the VM and the event. - * qemu_system_vmstop_request_prepare has two effects. First, - * it ensures that the STOP event always comes after the - * BLOCK_IO_ERROR event. Second, it ensures that even if management - * can observe the STOP event and do a "cont" before the STOP - * event is issued, the VM will not stop. In this case, vm_start() - * also ensures that the STOP/RESUME pair of events is emitted. - */ - qemu_system_vmstop_request_prepare(); - send_qmp_error_event(bs, action, is_read, error); - qemu_system_vmstop_request(RUN_STATE_IO_ERROR); - } else { - send_qmp_error_event(bs, action, is_read, error); - } -} - int bdrv_is_read_only(BlockDriverState *bs) { return bs->read_only; @@ -3602,46 +3517,6 @@ bool bdrv_op_blocker_is_empty(BlockDriverState *bs) return true; } -void bdrv_iostatus_enable(BlockDriverState *bs) -{ - bs->iostatus_enabled = true; - bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK; -} - -/* The I/O status is only enabled if the drive explicitly - * enables it _and_ the VM is configured to stop on errors */ -bool bdrv_iostatus_is_enabled(const BlockDriverState *bs) -{ - return (bs->iostatus_enabled && - (bs->on_write_error == BLOCKDEV_ON_ERROR_ENOSPC || - bs->on_write_error == BLOCKDEV_ON_ERROR_STOP || - bs->on_read_error == BLOCKDEV_ON_ERROR_STOP)); -} - -void bdrv_iostatus_disable(BlockDriverState *bs) -{ - bs->iostatus_enabled = false; -} - -void bdrv_iostatus_reset(BlockDriverState *bs) -{ - if (bdrv_iostatus_is_enabled(bs)) { - bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK; - if (bs->job) { - block_job_iostatus_reset(bs->job); - } - } -} - -void bdrv_iostatus_set_err(BlockDriverState *bs, int error) -{ - assert(bdrv_iostatus_is_enabled(bs)); - if (bs->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { - bs->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE : - BLOCK_DEVICE_IO_STATUS_FAILED; - } -} - void bdrv_img_create(const char *filename, const char *fmt, const char *base_filename, const char *base_fmt, char *options, uint64_t img_size, int flags, diff --git a/block/backup.c b/block/backup.c index 5696431711..ec01db8eff 100644 --- a/block/backup.c +++ b/block/backup.c @@ -21,6 +21,7 @@ #include "block/blockjob.h" #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" +#include "sysemu/block-backend.h" #define BACKUP_CLUSTER_BITS 16 #define BACKUP_CLUSTER_SIZE (1 << BACKUP_CLUSTER_BITS) @@ -215,7 +216,9 @@ static void backup_iostatus_reset(BlockJob *job) { BackupBlockJob *s = container_of(job, BackupBlockJob, common); - bdrv_iostatus_reset(s->target); + if (s->target->blk) { + blk_iostatus_reset(s->target->blk); + } } static const BlockJobDriver backup_job_driver = { @@ -360,8 +363,10 @@ static void coroutine_fn backup_run(void *opaque) job->bitmap = hbitmap_alloc(end, 0); bdrv_set_enable_write_cache(target, true); - bdrv_set_on_error(target, on_target_error, on_target_error); - bdrv_iostatus_enable(target); + if (target->blk) { + blk_set_on_error(target->blk, on_target_error, on_target_error); + blk_iostatus_enable(target->blk); + } bdrv_add_before_write_notifier(bs, &before_write); @@ -451,7 +456,9 @@ static void coroutine_fn backup_run(void *opaque) } hbitmap_free(job->bitmap); - bdrv_iostatus_disable(target); + if (target->blk) { + blk_iostatus_disable(target->blk); + } bdrv_op_unblock_all(target, job->common.blocker); data = g_malloc(sizeof(*data)); @@ -480,7 +487,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target, if ((on_source_error == BLOCKDEV_ON_ERROR_STOP || on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) && - !bdrv_iostatus_is_enabled(bs)) { + (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) { error_setg(errp, QERR_INVALID_PARAMETER, "on-source-error"); return; } diff --git a/block/block-backend.c b/block/block-backend.c index a52037b418..2708ad146c 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -12,7 +12,9 @@ #include "sysemu/block-backend.h" #include "block/block_int.h" +#include "block/blockjob.h" #include "sysemu/blockdev.h" +#include "sysemu/sysemu.h" #include "qapi-event.h" /* Number of coroutines to reserve per attached device model */ @@ -37,6 +39,10 @@ struct BlockBackend { /* I/O stats (display with "info blockstats"). */ BlockAcctStats stats; + + BlockdevOnError on_read_error, on_write_error; + bool iostatus_enabled; + BlockDeviceIoStatus iostatus; }; typedef struct BlockBackendAIOCB { @@ -330,7 +336,7 @@ int blk_attach_dev(BlockBackend *blk, void *dev) } blk_ref(blk); blk->dev = dev; - bdrv_iostatus_reset(blk->bs); + blk_iostatus_reset(blk); return 0; } @@ -462,7 +468,47 @@ void blk_dev_resize_cb(BlockBackend *blk) void blk_iostatus_enable(BlockBackend *blk) { - bdrv_iostatus_enable(blk->bs); + blk->iostatus_enabled = true; + blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK; +} + +/* The I/O status is only enabled if the drive explicitly + * enables it _and_ the VM is configured to stop on errors */ +bool blk_iostatus_is_enabled(const BlockBackend *blk) +{ + return (blk->iostatus_enabled && + (blk->on_write_error == BLOCKDEV_ON_ERROR_ENOSPC || + blk->on_write_error == BLOCKDEV_ON_ERROR_STOP || + blk->on_read_error == BLOCKDEV_ON_ERROR_STOP)); +} + +BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk) +{ + return blk->iostatus; +} + +void blk_iostatus_disable(BlockBackend *blk) +{ + blk->iostatus_enabled = false; +} + +void blk_iostatus_reset(BlockBackend *blk) +{ + if (blk_iostatus_is_enabled(blk)) { + blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK; + if (blk->bs && blk->bs->job) { + block_job_iostatus_reset(blk->bs->job); + } + } +} + +void blk_iostatus_set_err(BlockBackend *blk, int error) +{ + assert(blk_iostatus_is_enabled(blk)); + if (blk->iostatus == BLOCK_DEVICE_IO_STATUS_OK) { + blk->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE : + BLOCK_DEVICE_IO_STATUS_FAILED; + } } static int blk_check_byte_request(BlockBackend *blk, int64_t offset, @@ -738,21 +784,81 @@ void blk_drain_all(void) bdrv_drain_all(); } +void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, + BlockdevOnError on_write_error) +{ + blk->on_read_error = on_read_error; + blk->on_write_error = on_write_error; +} + BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read) { - return bdrv_get_on_error(blk->bs, is_read); + return is_read ? blk->on_read_error : blk->on_write_error; } BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, int error) { - return bdrv_get_error_action(blk->bs, is_read, error); + BlockdevOnError on_err = blk_get_on_error(blk, is_read); + + switch (on_err) { + case BLOCKDEV_ON_ERROR_ENOSPC: + return (error == ENOSPC) ? + BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT; + case BLOCKDEV_ON_ERROR_STOP: + return BLOCK_ERROR_ACTION_STOP; + case BLOCKDEV_ON_ERROR_REPORT: + return BLOCK_ERROR_ACTION_REPORT; + case BLOCKDEV_ON_ERROR_IGNORE: + return BLOCK_ERROR_ACTION_IGNORE; + default: + abort(); + } } +static void send_qmp_error_event(BlockBackend *blk, + BlockErrorAction action, + bool is_read, int error) +{ + IoOperationType optype; + + optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE; + qapi_event_send_block_io_error(blk_name(blk), optype, action, + blk_iostatus_is_enabled(blk), + error == ENOSPC, strerror(error), + &error_abort); +} + +/* This is done by device models because, while the block layer knows + * about the error, it does not know whether an operation comes from + * the device or the block layer (from a job, for example). + */ void blk_error_action(BlockBackend *blk, BlockErrorAction action, bool is_read, int error) { - bdrv_error_action(blk->bs, action, is_read, error); + assert(error >= 0); + + if (action == BLOCK_ERROR_ACTION_STOP) { + /* First set the iostatus, so that "info block" returns an iostatus + * that matches the events raised so far (an additional error iostatus + * is fine, but not a lost one). + */ + blk_iostatus_set_err(blk, error); + + /* Then raise the request to stop the VM and the event. + * qemu_system_vmstop_request_prepare has two effects. First, + * it ensures that the STOP event always comes after the + * BLOCK_IO_ERROR event. Second, it ensures that even if management + * can observe the STOP event and do a "cont" before the STOP + * event is issued, the VM will not stop. In this case, vm_start() + * also ensures that the STOP/RESUME pair of events is emitted. + */ + qemu_system_vmstop_request_prepare(); + send_qmp_error_event(blk, action, is_read, error); + qemu_system_vmstop_request(RUN_STATE_IO_ERROR); + } else { + send_qmp_error_event(blk, action, is_read, error); + } } int blk_is_read_only(BlockBackend *blk) diff --git a/block/commit.c b/block/commit.c index d12e26fab6..fdebe87c16 100644 --- a/block/commit.c +++ b/block/commit.c @@ -17,6 +17,7 @@ #include "block/blockjob.h" #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" +#include "sysemu/block-backend.h" enum { /* @@ -213,7 +214,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, if ((on_error == BLOCKDEV_ON_ERROR_STOP || on_error == BLOCKDEV_ON_ERROR_ENOSPC) && - !bdrv_iostatus_is_enabled(bs)) { + (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) { error_setg(errp, "Invalid parameter combination"); return; } diff --git a/block/mirror.c b/block/mirror.c index 7e43511832..b1252a1b29 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -14,6 +14,7 @@ #include "trace.h" #include "block/blockjob.h" #include "block/block_int.h" +#include "sysemu/block-backend.h" #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" #include "qemu/bitmap.h" @@ -599,7 +600,9 @@ immediate_exit: g_free(s->cow_bitmap); g_free(s->in_flight_bitmap); bdrv_release_dirty_bitmap(bs, s->dirty_bitmap); - bdrv_iostatus_disable(s->target); + if (s->target->blk) { + blk_iostatus_disable(s->target->blk); + } data = g_malloc(sizeof(*data)); data->ret = ret; @@ -621,7 +624,9 @@ static void mirror_iostatus_reset(BlockJob *job) { MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); - bdrv_iostatus_reset(s->target); + if (s->target->blk) { + blk_iostatus_reset(s->target->blk); + } } static void mirror_complete(BlockJob *job, Error **errp) @@ -704,7 +709,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, if ((on_source_error == BLOCKDEV_ON_ERROR_STOP || on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) && - !bdrv_iostatus_is_enabled(bs)) { + (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) { error_setg(errp, QERR_INVALID_PARAMETER, "on-source-error"); return; } @@ -740,8 +745,10 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, return; } bdrv_set_enable_write_cache(s->target, true); - bdrv_set_on_error(s->target, on_target_error, on_target_error); - bdrv_iostatus_enable(s->target); + if (s->target->blk) { + blk_set_on_error(s->target->blk, on_target_error, on_target_error); + blk_iostatus_enable(s->target->blk); + } s->common.co = qemu_coroutine_create(mirror_run); trace_mirror_start(bs, s, s->common.co, opaque); qemu_coroutine_enter(s->common.co, s); diff --git a/block/qapi.c b/block/qapi.c index 7c8209b0cb..3b46f97b8d 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -301,9 +301,9 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, info->tray_open = blk_dev_is_tray_open(blk); } - if (bdrv_iostatus_is_enabled(bs)) { + if (blk_iostatus_is_enabled(blk)) { info->has_io_status = true; - info->io_status = bs->iostatus; + info->io_status = blk_iostatus(blk); } if (!QLIST_EMPTY(&bs->dirty_bitmaps)) { diff --git a/block/stream.c b/block/stream.c index 3f64fa2245..25af7eff62 100644 --- a/block/stream.c +++ b/block/stream.c @@ -16,6 +16,7 @@ #include "block/blockjob.h" #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" +#include "sysemu/block-backend.h" enum { /* @@ -222,7 +223,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base, if ((on_error == BLOCKDEV_ON_ERROR_STOP || on_error == BLOCKDEV_ON_ERROR_ENOSPC) && - !bdrv_iostatus_is_enabled(bs)) { + (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) { error_setg(errp, QERR_INVALID_PARAMETER, "on-error"); return; } diff --git a/blockdev.c b/blockdev.c index 0785557550..433c4e2967 100644 --- a/blockdev.c +++ b/blockdev.c @@ -549,7 +549,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, bs->detect_zeroes = detect_zeroes; - bdrv_set_on_error(bs, on_read_error, on_write_error); + blk_set_on_error(blk, on_read_error, on_write_error); /* disk I/O throttling */ if (throttle_enabled(&cfg)) { @@ -2168,8 +2168,8 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict) if (blk_get_attached_dev(blk)) { blk_hide_on_behalf_of_hmp_drive_del(blk); /* Further I/O must not pause the guest */ - bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT, - BLOCKDEV_ON_ERROR_REPORT); + blk_set_on_error(blk, BLOCKDEV_ON_ERROR_REPORT, + BLOCKDEV_ON_ERROR_REPORT); } else { blk_unref(blk); } diff --git a/blockjob.c b/blockjob.c index 1da5491228..c02fe598b8 100644 --- a/blockjob.c +++ b/blockjob.c @@ -29,6 +29,7 @@ #include "block/block.h" #include "block/blockjob.h" #include "block/block_int.h" +#include "sysemu/block-backend.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qjson.h" #include "qemu/coroutine.h" @@ -354,8 +355,8 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs, job->user_paused = true; block_job_pause(job); block_job_iostatus_set_err(job, error); - if (bs != job->bs) { - bdrv_iostatus_set_err(bs, error); + if (bs->blk && bs != job->bs) { + blk_iostatus_set_err(bs->blk, error); } } return action; diff --git a/include/block/block.h b/include/block/block.h index a39cfe30a0..77e91bdc79 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -174,11 +174,6 @@ typedef enum BlockOpType { BLOCK_OP_TYPE_MAX, } BlockOpType; -void bdrv_iostatus_enable(BlockDriverState *bs); -void bdrv_iostatus_reset(BlockDriverState *bs); -void bdrv_iostatus_disable(BlockDriverState *bs); -bool bdrv_iostatus_is_enabled(const BlockDriverState *bs); -void bdrv_iostatus_set_err(BlockDriverState *bs, int error); void bdrv_info_print(Monitor *mon, const QObject *data); void bdrv_info(Monitor *mon, QObject **ret_data); void bdrv_stats_print(Monitor *mon, const QObject *data); @@ -389,12 +384,6 @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, int64_t sector_num, int nb_sectors, int *pnum); -void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error, - BlockdevOnError on_write_error); -BlockdevOnError bdrv_get_on_error(BlockDriverState *bs, bool is_read); -BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int error); -void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action, - bool is_read, int error); int bdrv_is_read_only(BlockDriverState *bs); int bdrv_is_sg(BlockDriverState *bs); int bdrv_enable_write_cache(BlockDriverState *bs); diff --git a/include/block/block_int.h b/include/block/block_int.h index aa00aea5da..87215f8fc6 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -414,12 +414,6 @@ struct BlockDriverState { /* do we need to tell the quest if we have a volatile write cache? */ int enable_write_cache; - /* NOTE: the following infos are only hints for real hardware - drivers. They are not used by the block driver */ - BlockdevOnError on_read_error, on_write_error; - bool iostatus_enabled; - BlockDeviceIoStatus iostatus; - /* the following member gives a name to every node on the bs graph. */ char node_name[32]; /* element of the list of named nodes building the graph */ diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index 1e19d1bb79..eafcef08c9 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -76,6 +76,11 @@ BlockDriverState *blk_bs(BlockBackend *blk); void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk); void blk_iostatus_enable(BlockBackend *blk); +bool blk_iostatus_is_enabled(const BlockBackend *blk); +BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk); +void blk_iostatus_disable(BlockBackend *blk); +void blk_iostatus_reset(BlockBackend *blk); +void blk_iostatus_set_err(BlockBackend *blk, int error); int blk_attach_dev(BlockBackend *blk, void *dev); void blk_attach_dev_nofail(BlockBackend *blk, void *dev); void blk_detach_dev(BlockBackend *blk, void *dev); @@ -120,6 +125,8 @@ int blk_flush(BlockBackend *blk); int blk_flush_all(void); void blk_drain(BlockBackend *blk); void blk_drain_all(void); +void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error, + BlockdevOnError on_write_error); BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read); BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read, int error); diff --git a/qmp.c b/qmp.c index d9ecedef93..ff54e5a765 100644 --- a/qmp.c +++ b/qmp.c @@ -24,6 +24,7 @@ #include "sysemu/arch_init.h" #include "hw/qdev.h" #include "sysemu/blockdev.h" +#include "sysemu/block-backend.h" #include "qom/qom-qobject.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qobject.h" @@ -170,6 +171,7 @@ SpiceInfo *qmp_query_spice(Error **errp) void qmp_cont(Error **errp) { Error *local_err = NULL; + BlockBackend *blk; BlockDriverState *bs; if (runstate_needs_reset()) { @@ -179,8 +181,8 @@ void qmp_cont(Error **errp) return; } - for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) { - bdrv_iostatus_reset(bs); + for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { + blk_iostatus_reset(blk); } for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) { bdrv_add_key(bs, NULL, &local_err);