@@ -74,9 +74,9 @@
# @description: Free-form description of the export, up to 4096 bytes.
# (Since 5.0)
#
-# @bitmap: Also export the dirty bitmap reachable from @device, so the
-# NBD client can use NBD_OPT_SET_META_CONTEXT with
-# "qemu:dirty-bitmap:NAME" to inspect the bitmap. (since 4.0)
+# @bitmaps: Also export each of the named dirty bitmaps reachable from
+# @device, so the NBD client can use NBD_OPT_SET_META_CONTEXT with
+# "qemu:dirty-bitmap:BITMAP" to inspect each bitmap. (since 5.2)
#
# @alloc: Also export the allocation map for @device, so the NBD client
# can use NBD_OPT_SET_META_CONTEXT with "qemu:allocation-depth"
@@ -86,7 +86,7 @@
##
{ 'struct': 'BlockExportOptionsNbd',
'data': { '*name': 'str', '*description': 'str',
- '*bitmap': 'str', '*alloc': 'bool' } }
+ '*bitmaps': ['str'], '*alloc': 'bool' } }
##
# @NbdServerAddOptions:
@@ -98,12 +98,18 @@
# @writable: Whether clients should be able to write to the device via the
# NBD connection (default false).
#
+# @bitmap: Also export a single dirty bitmap reachable from @device, so the
+# NBD client can use NBD_OPT_SET_META_CONTEXT with
+# "qemu:dirty-bitmap:BITMAP" to inspect the bitmap (since 4.0);
+# mutually exclusive with @bitmaps, and newer clients should use
+# that instead.
+#
# Since: 5.0
##
{ 'struct': 'NbdServerAddOptions',
'base': 'BlockExportOptionsNbd',
'data': { 'device': 'str',
- '*writable': 'bool' } }
+ '*writable': 'bool', '*bitmap': 'str' } }
##
# @nbd-server-add:
@@ -190,6 +190,20 @@ void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp)
return;
}
+ /*
+ * New code should use the list 'bitmaps'; but until this code is
+ * gone, we must support the older single 'bitmap'. Use only one.
+ */
+ if (arg->has_bitmap) {
+ if (arg->has_bitmaps) {
+ error_setg(errp, "Can't mix 'bitmap' and 'bitmaps'");
+ return;
+ }
+ arg->has_bitmaps = true;
+ arg->bitmaps = g_new0(strList, 1);
+ arg->bitmaps->value = g_strdup(arg->bitmap);
+ }
+
/*
* block-export-add would default to the node-name, but we may have to use
* the device name as a default here for compatibility.
@@ -210,8 +224,8 @@ void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp)
.name = g_strdup(arg->name),
.has_description = arg->has_description,
.description = g_strdup(arg->description),
- .has_bitmap = arg->has_bitmap,
- .bitmap = g_strdup(arg->bitmap),
+ .has_bitmaps = arg->has_bitmaps,
+ .bitmaps = g_steal_pointer(&arg->bitmaps),
.has_alloc = arg->alloc,
.alloc = arg->alloc,
},
@@ -1495,6 +1495,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;
int ret;
assert(exp_args->type == BLOCK_EXPORT_TYPE_NBD);
@@ -1556,12 +1557,18 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
}
exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE);
- if (arg->bitmap) {
+ /* XXX Allow more than one bitmap */
+ if (arg->bitmaps && arg->bitmaps->next) {
+ error_setg(errp, "multiple bitmaps per export not supported yet");
+ return -EOPNOTSUPP;
+ }
+ for (bitmaps = arg->bitmaps; bitmaps; bitmaps = bitmaps->next) {
+ const char *bitmap = bitmaps->value;
BlockDriverState *bs = blk_bs(blk);
BdrvDirtyBitmap *bm = NULL;
while (bs) {
- bm = bdrv_find_dirty_bitmap(bs, arg->bitmap);
+ bm = bdrv_find_dirty_bitmap(bs, bitmap);
if (bm != NULL) {
break;
}
@@ -1571,7 +1578,7 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
if (bm == NULL) {
ret = -ENOENT;
- error_setg(errp, "Bitmap '%s' is not found", arg->bitmap);
+ error_setg(errp, "Bitmap '%s' is not found", bitmap);
goto fail;
}
@@ -1585,15 +1592,15 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
ret = -EINVAL;
error_setg(errp,
"Enabled bitmap '%s' incompatible with readonly export",
- arg->bitmap);
+ bitmap);
goto fail;
}
bdrv_dirty_bitmap_set_busy(bm, true);
exp->export_bitmap = bm;
- assert(strlen(arg->bitmap) <= BDRV_BITMAP_MAX_NAME_SIZE);
+ assert(strlen(bitmap) <= BDRV_BITMAP_MAX_NAME_SIZE);
exp->export_bitmap_context = g_strdup_printf("qemu:dirty-bitmap:%s",
- arg->bitmap);
+ bitmap);
assert(strlen(exp->export_bitmap_context) < NBD_MAX_STRING_SIZE);
}
@@ -572,7 +572,7 @@ int main(int argc, char **argv)
const char *export_name = NULL; /* defaults to "" later for server mode */
const char *export_description = NULL;
bool alloc_depth = false;
- const char *bitmap = NULL;
+ strList *bitmaps = NULL, *tmp;
const char *tlscredsid = NULL;
bool imageOpts = false;
bool writethrough = true;
@@ -701,7 +701,10 @@ int main(int argc, char **argv)
alloc_depth = true;
break;
case 'B':
- bitmap = optarg;
+ tmp = g_new(strList, 1);
+ tmp->value = g_strdup(optarg);
+ tmp->next = bitmaps;
+ bitmaps = tmp;
break;
case 'k':
sockpath = optarg;
@@ -798,7 +801,7 @@ int main(int argc, char **argv)
}
if (export_name || export_description || dev_offset ||
device || disconnect || fmt || sn_id_or_name || alloc_depth ||
- bitmap || seen_aio || seen_discard || seen_cache) {
+ bitmaps || seen_aio || seen_discard || seen_cache) {
error_report("List mode is incompatible with per-device settings");
exit(EXIT_FAILURE);
}
@@ -1082,8 +1085,8 @@ int main(int argc, char **argv)
.name = g_strdup(export_name),
.has_description = !!export_description,
.description = g_strdup(export_description),
- .has_bitmap = !!bitmap,
- .bitmap = g_strdup(bitmap),
+ .has_bitmaps = !!bitmaps,
+ .bitmaps = bitmaps,
.has_alloc = alloc_depth,
.alloc = alloc_depth,
},
Since 'nbd-server-add' is deprecated, and 'block-export-add' is new to 5.2, we can still tweak the interface. Allowing 'bitmaps':['str'] is nicer than 'bitmap':'str'. This wires up the qapi and qemu-nbd changes to permit passing multiple bitmaps, but the actual support will require a further patch to the server. Signed-off-by: Eric Blake <eblake@redhat.com> --- qapi/block-export.json | 16 +++++++++++----- blockdev-nbd.c | 18 ++++++++++++++++-- nbd/server.c | 19 +++++++++++++------ qemu-nbd.c | 13 ++++++++----- 4 files changed, 48 insertions(+), 18 deletions(-)