The monitor does hold references to some BlockBackends so it should have a list of those BBs; blk_backends is a different list, as it contains references to all BBs (after a follow-up patch, that is), and that should not be changed because we do need such a list.
monitor_remove_blk() is idempotent so that we can call it in blockdev_auto_del() without having to care whether it had been called in do_drive_del() before. monitor_add_blk() is idempotent for symmetry reasons (monitor_remove_blk() is, so it would be strange for monitor_add_blk() not to be). Signed-off-by: Max Reitz <mre...@redhat.com> --- block/block-backend.c | 34 +++++++++++++++++++++++++++++++++- blockdev.c | 8 ++++++++ include/sysemu/block-backend.h | 2 ++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/block/block-backend.c b/block/block-backend.c index c89340e..e35d84f 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -29,6 +29,8 @@ struct BlockBackend { BlockDriverState *bs; DriveInfo *legacy_dinfo; /* null unless created by drive_new() */ QTAILQ_ENTRY(BlockBackend) link; /* for blk_backends */ + QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */ + bool in_monitor_list; void *dev; /* attached device model, if any */ /* TODO change to DeviceState when all users are qdevified */ @@ -70,6 +72,11 @@ static void drive_info_del(DriveInfo *dinfo); static QTAILQ_HEAD(, BlockBackend) blk_backends = QTAILQ_HEAD_INITIALIZER(blk_backends); +/* All BlockBackends referenced by the monitor and which are iterated through by + * blk_next() */ +static QTAILQ_HEAD(, BlockBackend) monitor_block_backends = + QTAILQ_HEAD_INITIALIZER(monitor_block_backends); + /* * Create a new BlockBackend with @name, with a reference count of one. * @name must not be null or empty. @@ -248,7 +255,8 @@ void blk_remove_all_bs(void) */ BlockBackend *blk_next(BlockBackend *blk) { - return blk ? QTAILQ_NEXT(blk, link) : QTAILQ_FIRST(&blk_backends); + return blk ? QTAILQ_NEXT(blk, monitor_link) + : QTAILQ_FIRST(&monitor_block_backends); } /* @@ -267,6 +275,30 @@ BlockBackend *blk_next_inserted(BlockBackend *blk) } /* + * Add a BlockBackend into the list of backends referenced by the monitor. + * Strictly for use by blockdev.c. + */ +void monitor_add_blk(BlockBackend *blk) +{ + if (!blk->in_monitor_list) { + QTAILQ_INSERT_TAIL(&monitor_block_backends, blk, monitor_link); + blk->in_monitor_list = true; + } +} + +/* + * Remove a BlockBackend from the list of backends referenced by the monitor. + * Strictly for use by blockdev.c. + */ +void monitor_remove_blk(BlockBackend *blk) +{ + if (blk->in_monitor_list) { + QTAILQ_REMOVE(&monitor_block_backends, blk, monitor_link); + blk->in_monitor_list = false; + } +} + +/* * Return @blk's name, a non-null string. * Wart: the name is empty iff @blk has been hidden with * blk_hide_on_behalf_of_hmp_drive_del(). diff --git a/blockdev.c b/blockdev.c index 97e6897..f5dde19 100644 --- a/blockdev.c +++ b/blockdev.c @@ -146,6 +146,7 @@ void blockdev_auto_del(BlockBackend *blk) DriveInfo *dinfo = blk_legacy_dinfo(blk); if (dinfo && dinfo->auto_del) { + monitor_remove_blk(blk); blk_unref(blk); } } @@ -606,6 +607,8 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, blk_set_on_error(blk, on_read_error, on_write_error); + monitor_add_blk(blk); + err_no_bs_opts: qemu_opts_del(opts); return blk; @@ -2528,6 +2531,8 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict) blk_remove_bs(blk); } + monitor_remove_blk(blk); + /* if we have a device attached to this BlockDriverState * then we need to make the drive anonymous until the device * can be removed. If this is a drive with no device backing @@ -3486,6 +3491,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) if (bs && bdrv_key_required(bs)) { if (blk) { + monitor_remove_blk(blk); blk_unref(blk); } else { QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list); @@ -3515,6 +3521,7 @@ void qmp_x_blockdev_del(bool has_id, const char *id, } if (has_id) { + /* blk_by_name() never returns a BB that is not owned by the monitor */ blk = blk_by_name(id); if (!blk) { error_setg(errp, "Cannot find block backend %s", id); @@ -3562,6 +3569,7 @@ void qmp_x_blockdev_del(bool has_id, const char *id, } if (blk) { + monitor_remove_blk(blk); blk_unref(blk); } else { QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list); diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index ee36f93..9a3d8db 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -74,6 +74,8 @@ BlockBackend *blk_by_name(const char *name); bool blk_name_taken(const char *name); BlockBackend *blk_next(BlockBackend *blk); BlockBackend *blk_next_inserted(BlockBackend *blk); +void monitor_add_blk(BlockBackend *blk); +void monitor_remove_blk(BlockBackend *blk); BlockDriverState *blk_bs(BlockBackend *blk); void blk_remove_bs(BlockBackend *blk); -- 2.6.2