diff options
-rw-r--r-- | block.c | 3 | ||||
-rw-r--r-- | block/block-backend.c | 48 | ||||
-rw-r--r-- | block/snapshot.c | 6 | ||||
-rw-r--r-- | include/block/block.h | 1 | ||||
-rw-r--r-- | migration/block.c | 1 |
5 files changed, 57 insertions, 2 deletions
@@ -4255,6 +4255,7 @@ void bdrv_invalidate_cache_all(Error **errp) aio_context_release(aio_context); if (local_err) { error_propagate(errp, local_err); + bdrv_next_cleanup(&it); return; } } @@ -4330,6 +4331,7 @@ int bdrv_inactivate_all(void) for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { ret = bdrv_inactivate_recurse(bs, pass); if (ret < 0) { + bdrv_next_cleanup(&it); goto out; } } @@ -4864,6 +4866,7 @@ bool bdrv_is_first_non_filter(BlockDriverState *candidate) /* candidate is the first non filter */ if (perm) { + bdrv_next_cleanup(&it); return true; } } diff --git a/block/block-backend.c b/block/block-backend.c index f10b1db612..5836cb3087 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -442,21 +442,37 @@ BlockBackend *blk_next(BlockBackend *blk) * the monitor or attached to a BlockBackend */ BlockDriverState *bdrv_next(BdrvNextIterator *it) { - BlockDriverState *bs; + BlockDriverState *bs, *old_bs; + + /* Must be called from the main loop */ + assert(qemu_get_current_aio_context() == qemu_get_aio_context()); /* First, return all root nodes of BlockBackends. In order to avoid * returning a BDS twice when multiple BBs refer to it, we only return it * if the BB is the first one in the parent list of the BDS. */ if (it->phase == BDRV_NEXT_BACKEND_ROOTS) { + BlockBackend *old_blk = it->blk; + + old_bs = old_blk ? blk_bs(old_blk) : NULL; + do { it->blk = blk_all_next(it->blk); bs = it->blk ? blk_bs(it->blk) : NULL; } while (it->blk && (bs == NULL || bdrv_first_blk(bs) != it->blk)); + if (it->blk) { + blk_ref(it->blk); + } + blk_unref(old_blk); + if (bs) { + bdrv_ref(bs); + bdrv_unref(old_bs); return bs; } it->phase = BDRV_NEXT_MONITOR_OWNED; + } else { + old_bs = it->bs; } /* Then return the monitor-owned BDSes without a BB attached. Ignore all @@ -467,18 +483,46 @@ BlockDriverState *bdrv_next(BdrvNextIterator *it) bs = it->bs; } while (bs && bdrv_has_blk(bs)); + if (bs) { + bdrv_ref(bs); + } + bdrv_unref(old_bs); + return bs; } -BlockDriverState *bdrv_first(BdrvNextIterator *it) +static void bdrv_next_reset(BdrvNextIterator *it) { *it = (BdrvNextIterator) { .phase = BDRV_NEXT_BACKEND_ROOTS, }; +} +BlockDriverState *bdrv_first(BdrvNextIterator *it) +{ + bdrv_next_reset(it); return bdrv_next(it); } +/* Must be called when aborting a bdrv_next() iteration before + * bdrv_next() returns NULL */ +void bdrv_next_cleanup(BdrvNextIterator *it) +{ + /* Must be called from the main loop */ + assert(qemu_get_current_aio_context() == qemu_get_aio_context()); + + if (it->phase == BDRV_NEXT_BACKEND_ROOTS) { + if (it->blk) { + bdrv_unref(blk_bs(it->blk)); + blk_unref(it->blk); + } + } else { + bdrv_unref(it->bs); + } + + bdrv_next_reset(it); +} + /* * Add a BlockBackend into the list of backends referenced by the monitor, with * the given @name acting as the handle for the monitor. diff --git a/block/snapshot.c b/block/snapshot.c index 1d5ab5f90f..be0743abac 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -417,6 +417,7 @@ bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs) } aio_context_release(ctx); if (!ok) { + bdrv_next_cleanup(&it); goto fail; } } @@ -444,6 +445,7 @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs, } aio_context_release(ctx); if (ret < 0) { + bdrv_next_cleanup(&it); goto fail; } } @@ -469,6 +471,7 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs) } aio_context_release(ctx); if (err < 0) { + bdrv_next_cleanup(&it); goto fail; } } @@ -494,6 +497,7 @@ int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs) } aio_context_release(ctx); if (err < 0) { + bdrv_next_cleanup(&it); goto fail; } } @@ -525,6 +529,7 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn, } aio_context_release(ctx); if (err < 0) { + bdrv_next_cleanup(&it); goto fail; } } @@ -548,6 +553,7 @@ BlockDriverState *bdrv_all_find_vmstate_bs(void) aio_context_release(ctx); if (found) { + bdrv_next_cleanup(&it); break; } } diff --git a/include/block/block.h b/include/block/block.h index fbc21daf62..c05cac57e5 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -461,6 +461,7 @@ typedef struct BdrvNextIterator { BlockDriverState *bdrv_first(BdrvNextIterator *it); BlockDriverState *bdrv_next(BdrvNextIterator *it); +void bdrv_next_cleanup(BdrvNextIterator *it); BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); bool bdrv_is_encrypted(BlockDriverState *bs); diff --git a/migration/block.c b/migration/block.c index 3282809583..7147171bb7 100644 --- a/migration/block.c +++ b/migration/block.c @@ -415,6 +415,7 @@ static int init_blk_migration(QEMUFile *f) sectors = bdrv_nb_sectors(bs); if (sectors <= 0) { ret = sectors; + bdrv_next_cleanup(&it); goto out; } |