Since 'block-export-add' is new to 5.2, we can still tweak the interface; there, allowing 'bitmaps':['str'] is nicer than 'bitmap':'str'. This wires up the qapi and qemu-nbd changes to permit passing multiple bitmaps as distinct metadata contexts that the NBD client may request, but the actual support for more than one will require a further patch to the server. Note that there are no changes made to the existing deprecated 'nbd-server-add' command; this required splitting the QAPI type BlockExportOptionsNbd, which fortunately does not affect QMP introspection. Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> --- docs/system/deprecated.rst | 3 ++- qapi/block-export.json | 41 +++++++++++++++++++++++++++----------- blockdev-nbd.c | 6 +++++- nbd/server.c | 19 ++++++++++++------ qemu-nbd.c | 18 ++++++++--------- 5 files changed, 58 insertions(+), 29 deletions(-) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 0ebce37a1919..32a0e620dbb9 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -257,7 +257,8 @@ the 'wait' field, which is only applicable to sockets in server mode '''''''''''''''''''''''''''''''''''''''''''''''''''''''' Use the more generic commands ``block-export-add`` and ``block-export-del`` -instead. +instead. As part of this deprecation, where ``nbd-server-add`` used a +single ``bitmap``, the new ``block-export-add`` uses a list of ``bitmaps``. Human Monitor Protocol (HMP) commands ------------------------------------- diff --git a/qapi/block-export.json b/qapi/block-export.json index 480c497690b0..c4125f4d2104 100644 --- a/qapi/block-export.json +++ b/qapi/block-export.json @@ -63,10 +63,10 @@ '*max-connections': 'uint32' } } ## -# @BlockExportOptionsNbd: +# @BlockExportOptionsNbdBase: # -# An NBD block export (options shared between nbd-server-add and the NBD branch -# of block-export-add). +# An NBD block export (common options shared between nbd-server-add and +# the NBD branch of block-export-add). # # @name: Export name. If unspecified, the @device parameter is used as the # export name. (Since 2.12) @@ -74,15 +74,27 @@ # @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) -# # Since: 5.0 ## +{ 'struct': 'BlockExportOptionsNbdBase', + 'data': { '*name': 'str', '*description': 'str' } } + +## +# @BlockExportOptionsNbd: +# +# An NBD block export (distinct options used in the NBD branch of +# block-export-add). +# +# @bitmaps: Also export each of the named dirty bitmaps reachable from +# @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: 5.2 +## { 'struct': 'BlockExportOptionsNbd', - 'data': { '*name': 'str', '*description': 'str', - '*bitmap': 'str' } } + 'base': 'BlockExportOptionsNbdBase', + 'data': { '*bitmaps': ['str'] } } ## # @BlockExportOptionsVhostUserBlk: @@ -106,19 +118,24 @@ ## # @NbdServerAddOptions: # -# An NBD block export. +# An NBD block export, per legacy nbd-server-add command. # # @device: The device name or node name of the node to be exported # # @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 the metadata +# context name "qemu:dirty-bitmap:BITMAP" to inspect the bitmap +# (since 4.0). +# # Since: 5.0 ## { 'struct': 'NbdServerAddOptions', - 'base': 'BlockExportOptionsNbd', + 'base': 'BlockExportOptionsNbdBase', 'data': { 'device': 'str', - '*writable': 'bool' } } + '*writable': 'bool', '*bitmap': 'str' } } ## # @nbd-server-add: diff --git a/blockdev-nbd.c b/blockdev-nbd.c index cee9134b12eb..d1d41f635564 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -209,8 +209,12 @@ void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp) .has_writable = arg->has_writable, .writable = arg->writable, }; - QAPI_CLONE_MEMBERS(BlockExportOptionsNbd, &export_opts->u.nbd, + QAPI_CLONE_MEMBERS(BlockExportOptionsNbdBase, &export_opts->u.nbd, qapi_NbdServerAddOptions_base(arg)); + if (arg->has_bitmap) { + export_opts->u.nbd.has_bitmaps = true; + QAPI_LIST_ADD(export_opts->u.nbd.bitmaps, g_strdup(arg->bitmap)); + } /* * nbd-server-add doesn't complain when a read-only device should be diff --git a/nbd/server.c b/nbd/server.c index 08b621f70a3a..8d01662b4511 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1474,6 +1474,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); @@ -1533,12 +1534,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; } @@ -1548,7 +1555,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; } @@ -1562,15 +1569,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 a0701cdf369d..4b7825c44093 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -574,7 +574,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; - const char *bitmap = NULL; + strList *bitmaps = NULL; const char *tlscredsid = NULL; bool imageOpts = false; bool writethrough = true; @@ -690,7 +690,7 @@ int main(int argc, char **argv) flags &= ~BDRV_O_RDWR; break; case 'B': - bitmap = optarg; + QAPI_LIST_ADD(bitmaps, g_strdup(optarg)); break; case 'k': sockpath = optarg; @@ -786,7 +786,7 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } if (export_name || export_description || dev_offset || - device || disconnect || fmt || sn_id_or_name || bitmap || + device || disconnect || fmt || sn_id_or_name || bitmaps || seen_aio || seen_discard || seen_cache) { error_report("List mode is incompatible with per-device settings"); exit(EXIT_FAILURE); @@ -1067,12 +1067,12 @@ int main(int argc, char **argv) .has_writable = true, .writable = !readonly, .u.nbd = { - .has_name = true, - .name = g_strdup(export_name), - .has_description = !!export_description, - .description = g_strdup(export_description), - .has_bitmap = !!bitmap, - .bitmap = g_strdup(bitmap), + .has_name = true, + .name = g_strdup(export_name), + .has_description = !!export_description, + .description = g_strdup(export_description), + .has_bitmaps = !!bitmaps, + .bitmaps = bitmaps, }, }; blk_exp_add(export_opts, &error_fatal); -- 2.29.0