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 <ebl...@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(-) diff --git a/qapi/block-export.json b/qapi/block-export.json index 524cd3a94400..2dc45a54e364 100644 --- a/qapi/block-export.json +++ b/qapi/block-export.json @@ -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: diff --git a/blockdev-nbd.c b/blockdev-nbd.c index f9012f93e2bb..f0a03c830c5f 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -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, }, diff --git a/nbd/server.c b/nbd/server.c index e24495d93e2e..ea5de0b503cd 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -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); } diff --git a/qemu-nbd.c b/qemu-nbd.c index e3cff17d6760..8648a39d0ab9 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -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, }, -- 2.28.0