block: Introduce bdrv_open_child()

It is the same as bdrv_open_image(), except that it doesn't only return
success or failure, but the newly created BdrvChild object for the new
child node.

As the BdrvChild object already contains a BlockDriverState pointer (and
this is supposed to become the only pointer so that bdrv_append() and
friends can just change a single pointer in BdrvChild), the pbs
parameter is removed for bdrv_open_child().

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
Kevin Wolf 2015-06-15 13:24:19 +02:00
parent df58179267
commit b4b059f628
3 changed files with 60 additions and 21 deletions

71
block.c
View File

@ -1102,9 +1102,9 @@ static int bdrv_fill_options(QDict **options, const char **pfilename,
return 0; return 0;
} }
static void bdrv_attach_child(BlockDriverState *parent_bs, static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
BlockDriverState *child_bs, BlockDriverState *child_bs,
const BdrvChildRole *child_role) const BdrvChildRole *child_role)
{ {
BdrvChild *child = g_new(BdrvChild, 1); BdrvChild *child = g_new(BdrvChild, 1);
*child = (BdrvChild) { *child = (BdrvChild) {
@ -1113,6 +1113,8 @@ static void bdrv_attach_child(BlockDriverState *parent_bs,
}; };
QLIST_INSERT_HEAD(&parent_bs->children, child, next); QLIST_INSERT_HEAD(&parent_bs->children, child, next);
return child;
} }
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd) void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
@ -1229,7 +1231,7 @@ free_exit:
* device's options. * device's options.
* *
* If allow_none is true, no image will be opened if filename is false and no * If allow_none is true, no image will be opened if filename is false and no
* BlockdevRef is given. *pbs will remain unchanged and 0 will be returned. * BlockdevRef is given. NULL will be returned, but errp remains unset.
* *
* bdrev_key specifies the key for the image's BlockdevRef in the options QDict. * bdrev_key specifies the key for the image's BlockdevRef in the options QDict.
* That QDict has to be flattened; therefore, if the BlockdevRef is a QDict * That QDict has to be flattened; therefore, if the BlockdevRef is a QDict
@ -1237,21 +1239,20 @@ free_exit:
* BlockdevRef. * BlockdevRef.
* *
* The BlockdevRef will be removed from the options QDict. * The BlockdevRef will be removed from the options QDict.
*
* To conform with the behavior of bdrv_open(), *pbs has to be NULL.
*/ */
int bdrv_open_image(BlockDriverState **pbs, const char *filename, BdrvChild *bdrv_open_child(const char *filename,
QDict *options, const char *bdref_key, QDict *options, const char *bdref_key,
BlockDriverState* parent, const BdrvChildRole *child_role, BlockDriverState* parent,
bool allow_none, Error **errp) const BdrvChildRole *child_role,
bool allow_none, Error **errp)
{ {
BdrvChild *c = NULL;
BlockDriverState *bs;
QDict *image_options; QDict *image_options;
int ret; int ret;
char *bdref_key_dot; char *bdref_key_dot;
const char *reference; const char *reference;
assert(pbs);
assert(*pbs == NULL);
assert(child_role != NULL); assert(child_role != NULL);
bdref_key_dot = g_strdup_printf("%s.", bdref_key); bdref_key_dot = g_strdup_printf("%s.", bdref_key);
@ -1260,28 +1261,60 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
reference = qdict_get_try_str(options, bdref_key); reference = qdict_get_try_str(options, bdref_key);
if (!filename && !reference && !qdict_size(image_options)) { if (!filename && !reference && !qdict_size(image_options)) {
if (allow_none) { if (!allow_none) {
ret = 0;
} else {
error_setg(errp, "A block device must be specified for \"%s\"", error_setg(errp, "A block device must be specified for \"%s\"",
bdref_key); bdref_key);
ret = -EINVAL;
} }
QDECREF(image_options); QDECREF(image_options);
goto done; goto done;
} }
ret = bdrv_open_inherit(pbs, filename, reference, image_options, 0, bs = NULL;
ret = bdrv_open_inherit(&bs, filename, reference, image_options, 0,
parent, child_role, NULL, errp); parent, child_role, NULL, errp);
if (ret < 0) { if (ret < 0) {
goto done; goto done;
} }
bdrv_attach_child(parent, *pbs, child_role); c = bdrv_attach_child(parent, bs, child_role);
done: done:
qdict_del(options, bdref_key); qdict_del(options, bdref_key);
return ret; return c;
}
/*
* This is a version of bdrv_open_child() that returns 0/-EINVAL instead of
* a BdrvChild object.
*
* If allow_none is true, no image will be opened if filename is false and no
* BlockdevRef is given. *pbs will remain unchanged and 0 will be returned.
*
* To conform with the behavior of bdrv_open(), *pbs has to be NULL.
*/
int bdrv_open_image(BlockDriverState **pbs, const char *filename,
QDict *options, const char *bdref_key,
BlockDriverState* parent, const BdrvChildRole *child_role,
bool allow_none, Error **errp)
{
Error *local_err = NULL;
BdrvChild *c;
assert(pbs);
assert(*pbs == NULL);
c = bdrv_open_child(filename, options, bdref_key, parent, child_role,
allow_none, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return -EINVAL;
}
if (c != NULL) {
*pbs = c->bs;
}
return 0;
} }
int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)

View File

@ -12,6 +12,7 @@
/* block.c */ /* block.c */
typedef struct BlockDriver BlockDriver; typedef struct BlockDriver BlockDriver;
typedef struct BlockJob BlockJob; typedef struct BlockJob BlockJob;
typedef struct BdrvChild BdrvChild;
typedef struct BdrvChildRole BdrvChildRole; typedef struct BdrvChildRole BdrvChildRole;
typedef struct BlockDriverInfo { typedef struct BlockDriverInfo {
@ -208,6 +209,11 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
QDict *options, const char *bdref_key, QDict *options, const char *bdref_key,
BlockDriverState* parent, const BdrvChildRole *child_role, BlockDriverState* parent, const BdrvChildRole *child_role,
bool allow_none, Error **errp); bool allow_none, Error **errp);
BdrvChild *bdrv_open_child(const char *filename,
QDict *options, const char *bdref_key,
BlockDriverState* parent,
const BdrvChildRole *child_role,
bool allow_none, Error **errp);
void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd); void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp); int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp); int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp);

View File

@ -335,11 +335,11 @@ struct BdrvChildRole {
extern const BdrvChildRole child_file; extern const BdrvChildRole child_file;
extern const BdrvChildRole child_format; extern const BdrvChildRole child_format;
typedef struct BdrvChild { struct BdrvChild {
BlockDriverState *bs; BlockDriverState *bs;
const BdrvChildRole *role; const BdrvChildRole *role;
QLIST_ENTRY(BdrvChild) next; QLIST_ENTRY(BdrvChild) next;
} BdrvChild; };
/* /*
* Note: the function bdrv_append() copies and swaps contents of * Note: the function bdrv_append() copies and swaps contents of