diff options
author | Markus Armbruster <armbru@redhat.com> | 2014-10-07 13:59:05 +0200 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2014-10-20 13:41:26 +0200 |
commit | 7e7d56d9e05b340290669442cfa05f5869204572 (patch) | |
tree | 5ac3934eadc67544a188e1f368357bfe16c6b81c /block | |
parent | 26f54e9a3cfe62fca61baf83a06b269935d6b9a4 (diff) |
block: Connect BlockBackend to BlockDriverState
Convenience function blk_new_with_bs() creates a BlockBackend with its
BlockDriverState. Callers have to unref both. The commit after next
will relieve them of the need to unref the BlockDriverState.
Complication: due to the silly way drive_del works, we need a way to
hide a BlockBackend, just like bdrv_make_anon(). To emphasize its
"special" status, give the function a suitably off-putting name:
blk_hide_on_behalf_of_do_drive_del(). Unfortunately, hiding turns the
BlockBackend's name into the empty string. Can't avoid that without
breaking the blk->bs->device_name equals blk->name invariant.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/block-backend.c | 71 |
1 files changed, 68 insertions, 3 deletions
diff --git a/block/block-backend.c b/block/block-backend.c index e89caa9611..a12215a546 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -16,10 +16,11 @@ struct BlockBackend { char *name; int refcnt; + BlockDriverState *bs; QTAILQ_ENTRY(BlockBackend) link; /* for blk_backends */ }; -/* All the BlockBackends */ +/* All the BlockBackends (except for hidden ones) */ static QTAILQ_HEAD(, BlockBackend) blk_backends = QTAILQ_HEAD_INITIALIZER(blk_backends); @@ -47,10 +48,44 @@ BlockBackend *blk_new(const char *name, Error **errp) return blk; } +/* + * Create a new BlockBackend with a new BlockDriverState attached. + * Both have a reference count of one. Caller owns *both* references. + * TODO Let caller own only the BlockBackend reference + * Otherwise just like blk_new(), which see. + */ +BlockBackend *blk_new_with_bs(const char *name, Error **errp) +{ + BlockBackend *blk; + BlockDriverState *bs; + + blk = blk_new(name, errp); + if (!blk) { + return NULL; + } + + bs = bdrv_new_root(name, errp); + if (!bs) { + blk_unref(blk); + return NULL; + } + + blk->bs = bs; + bs->blk = blk; + return blk; +} + static void blk_delete(BlockBackend *blk) { assert(!blk->refcnt); - QTAILQ_REMOVE(&blk_backends, blk, link); + if (blk->bs) { + blk->bs->blk = NULL; + blk->bs = NULL; + } + /* Avoid double-remove after blk_hide_on_behalf_of_do_drive_del() */ + if (blk->name[0]) { + QTAILQ_REMOVE(&blk_backends, blk, link); + } g_free(blk->name); g_free(blk); } @@ -68,6 +103,8 @@ void blk_ref(BlockBackend *blk) * Decrement @blk's reference count. * If this drops it to zero, destroy @blk. * For convenience, do nothing if @blk is null. + * Does *not* touch the attached BlockDriverState's reference count. + * TODO Decrement it! */ void blk_unref(BlockBackend *blk) { @@ -95,7 +132,9 @@ BlockBackend *blk_next(BlockBackend *blk) } /* - * Return @blk's name, a non-null, non-empty string. + * Return @blk's name, a non-null string. + * Wart: the name is empty iff @blk has been hidden with + * blk_hide_on_behalf_of_do_drive_del(). */ const char *blk_name(BlockBackend *blk) { @@ -118,3 +157,29 @@ BlockBackend *blk_by_name(const char *name) } return NULL; } + +/* + * Return the BlockDriverState attached to @blk if any, else null. + */ +BlockDriverState *blk_bs(BlockBackend *blk) +{ + return blk->bs; +} + +/* + * Hide @blk. + * @blk must not have been hidden already. + * Make attached BlockDriverState, if any, anonymous. + * Once hidden, @blk is invisible to all functions that don't receive + * it as argument. For example, blk_by_name() won't return it. + * Strictly for use by do_drive_del(). + * TODO get rid of it! + */ +void blk_hide_on_behalf_of_do_drive_del(BlockBackend *blk) +{ + QTAILQ_REMOVE(&blk_backends, blk, link); + blk->name[0] = 0; + if (blk->bs) { + bdrv_make_anon(blk->bs); + } +} |