@@ -6,6 +6,7 @@
##
{ 'include': 'sockets.json' }
+{ 'include': 'block-core.json' }
##
# @NbdServerOptions:
@@ -89,6 +90,7 @@
# @device, so the NBD client can use NBD_OPT_SET_META_CONTEXT with
# the metadata context name "qemu:dirty-bitmap:BITMAP" to inspect
# each bitmap.
+# Since 7.1 bitmap may be specified by node/name pair.
#
# @allocation-depth: Also export the allocation depth map for @device, so
# the NBD client can use NBD_OPT_SET_META_CONTEXT with
@@ -99,7 +101,8 @@
##
{ 'struct': 'BlockExportOptionsNbd',
'base': 'BlockExportOptionsNbdBase',
- 'data': { '*bitmaps': ['str'], '*allocation-depth': 'bool' } }
+ 'data': { '*bitmaps': ['BlockDirtyBitmapOrStr'],
+ '*allocation-depth': 'bool' } }
##
# @BlockExportOptionsVhostUserBlk:
@@ -211,8 +211,14 @@ void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp)
QAPI_CLONE_MEMBERS(BlockExportOptionsNbdBase, &export_opts->u.nbd,
qapi_NbdServerAddOptions_base(arg));
if (arg->has_bitmap) {
+ BlockDirtyBitmapOrStr *el = g_new(BlockDirtyBitmapOrStr, 1);
+
+ *el = (BlockDirtyBitmapOrStr) {
+ .type = QTYPE_QSTRING,
+ .u.local = g_strdup(arg->bitmap),
+ };
export_opts->u.nbd.has_bitmaps = true;
- QAPI_LIST_PREPEND(export_opts->u.nbd.bitmaps, g_strdup(arg->bitmap));
+ QAPI_LIST_PREPEND(export_opts->u.nbd.bitmaps, el);
}
/*
@@ -1643,7 +1643,7 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
uint64_t perm, shared_perm;
bool readonly = !exp_args->writable;
bool shared = !exp_args->writable;
- strList *bitmaps;
+ BlockDirtyBitmapOrStrList *bitmaps;
size_t i;
int ret;
@@ -1709,40 +1709,59 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
}
exp->export_bitmaps = g_new0(BdrvDirtyBitmap *, exp->nr_export_bitmaps);
for (i = 0, bitmaps = arg->bitmaps; bitmaps;
- i++, bitmaps = bitmaps->next) {
- const char *bitmap = bitmaps->value;
+ i++, bitmaps = bitmaps->next)
+ {
+ const char *bitmap;
BlockDriverState *bs = blk_bs(blk);
BdrvDirtyBitmap *bm = NULL;
- while (bs) {
- bm = bdrv_find_dirty_bitmap(bs, bitmap);
- if (bm != NULL) {
- break;
+ switch (bitmaps->value->type) {
+ case QTYPE_QSTRING:
+ bitmap = bitmaps->value->u.local;
+ while (bs) {
+ bm = bdrv_find_dirty_bitmap(bs, bitmap);
+ if (bm != NULL) {
+ break;
+ }
+
+ bs = bdrv_filter_or_cow_bs(bs);
}
- bs = bdrv_filter_or_cow_bs(bs);
- }
+ if (bm == NULL) {
+ ret = -ENOENT;
+ error_setg(errp, "Bitmap '%s' is not found",
+ bitmaps->value->u.local);
+ goto fail;
+ }
- if (bm == NULL) {
- ret = -ENOENT;
- error_setg(errp, "Bitmap '%s' is not found", bitmap);
- goto fail;
+ if (readonly && bdrv_is_writable(bs) &&
+ bdrv_dirty_bitmap_enabled(bm)) {
+ ret = -EINVAL;
+ error_setg(errp, "Enabled bitmap '%s' incompatible with "
+ "readonly export", bitmap);
+ goto fail;
+ }
+ break;
+ case QTYPE_QDICT:
+ bitmap = bitmaps->value->u.external.name;
+ bm = block_dirty_bitmap_lookup(bitmaps->value->u.external.node,
+ bitmap, NULL, errp);
+ if (!bm) {
+ ret = -ENOENT;
+ goto fail;
+ }
+ break;
+ default:
+ abort();
}
+ assert(bm);
+
if (bdrv_dirty_bitmap_check(bm, BDRV_BITMAP_ALLOW_RO, errp)) {
ret = -EINVAL;
goto fail;
}
- if (readonly && bdrv_is_writable(bs) &&
- bdrv_dirty_bitmap_enabled(bm)) {
- ret = -EINVAL;
- error_setg(errp,
- "Enabled bitmap '%s' incompatible with readonly export",
- bitmap);
- goto fail;
- }
-
exp->export_bitmaps[i] = bm;
assert(strlen(bitmap) <= BDRV_BITMAP_MAX_NAME_SIZE);
}
@@ -567,7 +567,7 @@ int main(int argc, char **argv)
QDict *options = NULL;
const char *export_name = NULL; /* defaults to "" later for server mode */
const char *export_description = NULL;
- strList *bitmaps = NULL;
+ BlockDirtyBitmapOrStrList *bitmaps = NULL;
bool alloc_depth = false;
const char *tlscredsid = NULL;
const char *tlshostname = NULL;
@@ -687,7 +687,14 @@ int main(int argc, char **argv)
alloc_depth = true;
break;
case 'B':
- QAPI_LIST_PREPEND(bitmaps, g_strdup(optarg));
+ {
+ BlockDirtyBitmapOrStr *el = g_new(BlockDirtyBitmapOrStr, 1);
+ *el = (BlockDirtyBitmapOrStr) {
+ .type = QTYPE_QSTRING,
+ .u.local = g_strdup(optarg),
+ };
+ QAPI_LIST_PREPEND(bitmaps, el);
+ }
break;
case 'k':
sockpath = optarg;