@@ -1143,6 +1143,7 @@ out:
}
#define ALLOW_WRITE_BACKING_FILE "allow-write-backing-file"
+#define BACKING_REFERENCE "backing_reference"
static QemuOptsList backing_file_opts = {
.name = "backing_file",
.head = QTAILQ_HEAD_INITIALIZER(backing_file_opts.head),
@@ -1152,6 +1153,11 @@ static QemuOptsList backing_file_opts = {
.type = QEMU_OPT_BOOL,
.help = "allow write to backing file",
},
+ {
+ .name = BACKING_REFERENCE,
+ .type = QEMU_OPT_STRING,
+ .help = "reference to the exsiting BDS",
+ },
{ /* end of list */ }
},
};
@@ -1168,11 +1174,12 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
{
char *backing_filename = g_malloc0(PATH_MAX);
int ret = 0;
- BlockDriverState *backing_hd;
+ BlockDriverState *backing_hd = NULL;
Error *local_err = NULL;
QemuOpts *opts = NULL;
bool child_rw = false;
const BdrvChildRole *child_role = NULL;
+ const char *reference = NULL;
if (bs->backing_hd != NULL) {
QDECREF(options);
@@ -1195,9 +1202,10 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
goto free_exit;
}
child_rw = qemu_opt_get_bool(opts, ALLOW_WRITE_BACKING_FILE, false);
+ reference = qemu_opt_get(opts, BACKING_REFERENCE);
child_role = child_rw ? &child_backing_rw : &child_backing;
- if (qdict_haskey(options, "file.filename")) {
+ if (qdict_haskey(options, "file.filename") || reference) {
backing_filename[0] = '\0';
} else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
QDECREF(options);
@@ -1220,7 +1228,9 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
goto free_exit;
}
- backing_hd = bdrv_new();
+ if (!reference) {
+ backing_hd = bdrv_new();
+ }
if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
qdict_put(options, "driver", qstring_from_str(bs->backing_format));
@@ -1229,7 +1239,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
assert(bs->backing_hd == NULL);
ret = bdrv_open_inherit(&backing_hd,
*backing_filename ? backing_filename : NULL,
- NULL, options, 0, bs, child_role,
+ reference, options, 0, bs, child_role,
NULL, &local_err);
if (ret < 0) {
bdrv_unref(backing_hd);
@@ -1240,12 +1250,30 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
error_free(local_err);
goto free_exit;
}
+ if (reference) {
+ if (bdrv_op_is_blocked(backing_hd, BLOCK_OP_TYPE_BACKING_REFERENCE,
+ errp)) {
+ ret = -EBUSY;
+ goto free_reference_exit;
+ }
+ if (backing_hd->blk && blk_disable_attach_dev(backing_hd->blk)) {
+ error_setg(errp, "backing_hd %s is used by the other device model",
+ reference);
+ ret = -EBUSY;
+ goto free_reference_exit;
+ }
+ }
bdrv_set_backing_hd(bs, backing_hd);
free_exit:
qemu_opts_del(opts);
g_free(backing_filename);
return ret;
+
+free_reference_exit:
+ bdrv_unref(backing_hd);
+ bs->open_flags |= BDRV_O_NO_BACKING;
+ goto free_exit;
}
/*
@@ -1899,6 +1927,9 @@ void bdrv_close(BlockDriverState *bs)
if (bs->backing_hd) {
BlockDriverState *backing_hd = bs->backing_hd;
bdrv_set_backing_hd(bs, NULL);
+ if (backing_hd->blk) {
+ blk_enable_attach_dev(backing_hd->blk);
+ }
bdrv_unref(backing_hd);
}
bs->drv->bdrv_close(bs);
@@ -168,6 +168,7 @@ typedef enum BlockOpType {
BLOCK_OP_TYPE_RESIZE,
BLOCK_OP_TYPE_STREAM,
BLOCK_OP_TYPE_REPLACE,
+ BLOCK_OP_TYPE_BACKING_REFERENCE,
BLOCK_OP_TYPE_MAX,
} BlockOpType;