nbd: Update qapi to support exporting multiple bitmaps

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@redhat.com>
Message-Id: <20201027050556.269064-5-eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
This commit is contained in:
Eric Blake 2020-10-27 00:05:49 -05:00
parent 8675cbd68b
commit cbad81cef8
5 changed files with 58 additions and 29 deletions

View File

@ -209,8 +209,12 @@ void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp)
.has_writable = arg->has_writable, .has_writable = arg->has_writable,
.writable = arg->writable, .writable = arg->writable,
}; };
QAPI_CLONE_MEMBERS(BlockExportOptionsNbd, &export_opts->u.nbd, QAPI_CLONE_MEMBERS(BlockExportOptionsNbdBase, &export_opts->u.nbd,
qapi_NbdServerAddOptions_base(arg)); qapi_NbdServerAddOptions_base(arg));
if (arg->has_bitmap) {
export_opts->u.nbd.has_bitmaps = true;
QAPI_LIST_PREPEND(export_opts->u.nbd.bitmaps, g_strdup(arg->bitmap));
}
/* /*
* nbd-server-add doesn't complain when a read-only device should be * nbd-server-add doesn't complain when a read-only device should be

View File

@ -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`` 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 Human Monitor Protocol (HMP) commands
------------------------------------- -------------------------------------

View File

@ -1474,6 +1474,7 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
uint64_t perm, shared_perm; uint64_t perm, shared_perm;
bool readonly = !exp_args->writable; bool readonly = !exp_args->writable;
bool shared = !exp_args->writable; bool shared = !exp_args->writable;
strList *bitmaps;
int ret; int ret;
assert(exp_args->type == BLOCK_EXPORT_TYPE_NBD); 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); 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); BlockDriverState *bs = blk_bs(blk);
BdrvDirtyBitmap *bm = NULL; BdrvDirtyBitmap *bm = NULL;
while (bs) { while (bs) {
bm = bdrv_find_dirty_bitmap(bs, arg->bitmap); bm = bdrv_find_dirty_bitmap(bs, bitmap);
if (bm != NULL) { if (bm != NULL) {
break; break;
} }
@ -1548,7 +1555,7 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
if (bm == NULL) { if (bm == NULL) {
ret = -ENOENT; ret = -ENOENT;
error_setg(errp, "Bitmap '%s' is not found", arg->bitmap); error_setg(errp, "Bitmap '%s' is not found", bitmap);
goto fail; goto fail;
} }
@ -1562,15 +1569,15 @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
ret = -EINVAL; ret = -EINVAL;
error_setg(errp, error_setg(errp,
"Enabled bitmap '%s' incompatible with readonly export", "Enabled bitmap '%s' incompatible with readonly export",
arg->bitmap); bitmap);
goto fail; goto fail;
} }
bdrv_dirty_bitmap_set_busy(bm, true); bdrv_dirty_bitmap_set_busy(bm, true);
exp->export_bitmap = bm; 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", exp->export_bitmap_context = g_strdup_printf("qemu:dirty-bitmap:%s",
arg->bitmap); bitmap);
assert(strlen(exp->export_bitmap_context) < NBD_MAX_STRING_SIZE); assert(strlen(exp->export_bitmap_context) < NBD_MAX_STRING_SIZE);
} }

View File

@ -63,10 +63,10 @@
'*max-connections': 'uint32' } } '*max-connections': 'uint32' } }
## ##
# @BlockExportOptionsNbd: # @BlockExportOptionsNbdBase:
# #
# An NBD block export (options shared between nbd-server-add and the NBD branch # An NBD block export (common options shared between nbd-server-add and
# of block-export-add). # the NBD branch of block-export-add).
# #
# @name: Export name. If unspecified, the @device parameter is used as the # @name: Export name. If unspecified, the @device parameter is used as the
# export name. (Since 2.12) # export name. (Since 2.12)
@ -74,15 +74,27 @@
# @description: Free-form description of the export, up to 4096 bytes. # @description: Free-form description of the export, up to 4096 bytes.
# (Since 5.0) # (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 # 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', { 'struct': 'BlockExportOptionsNbd',
'data': { '*name': 'str', '*description': 'str', 'base': 'BlockExportOptionsNbdBase',
'*bitmap': 'str' } } 'data': { '*bitmaps': ['str'] } }
## ##
# @BlockExportOptionsVhostUserBlk: # @BlockExportOptionsVhostUserBlk:
@ -106,19 +118,24 @@
## ##
# @NbdServerAddOptions: # @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 # @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 # @writable: Whether clients should be able to write to the device via the
# NBD connection (default false). # 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 # Since: 5.0
## ##
{ 'struct': 'NbdServerAddOptions', { 'struct': 'NbdServerAddOptions',
'base': 'BlockExportOptionsNbd', 'base': 'BlockExportOptionsNbdBase',
'data': { 'device': 'str', 'data': { 'device': 'str',
'*writable': 'bool' } } '*writable': 'bool', '*bitmap': 'str' } }
## ##
# @nbd-server-add: # @nbd-server-add:

View File

@ -574,7 +574,7 @@ int main(int argc, char **argv)
QDict *options = NULL; QDict *options = NULL;
const char *export_name = NULL; /* defaults to "" later for server mode */ const char *export_name = NULL; /* defaults to "" later for server mode */
const char *export_description = NULL; const char *export_description = NULL;
const char *bitmap = NULL; strList *bitmaps = NULL;
const char *tlscredsid = NULL; const char *tlscredsid = NULL;
bool imageOpts = false; bool imageOpts = false;
bool writethrough = true; bool writethrough = true;
@ -690,7 +690,7 @@ int main(int argc, char **argv)
flags &= ~BDRV_O_RDWR; flags &= ~BDRV_O_RDWR;
break; break;
case 'B': case 'B':
bitmap = optarg; QAPI_LIST_PREPEND(bitmaps, g_strdup(optarg));
break; break;
case 'k': case 'k':
sockpath = optarg; sockpath = optarg;
@ -786,7 +786,7 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (export_name || export_description || dev_offset || 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) { seen_aio || seen_discard || seen_cache) {
error_report("List mode is incompatible with per-device settings"); error_report("List mode is incompatible with per-device settings");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -1067,12 +1067,12 @@ int main(int argc, char **argv)
.has_writable = true, .has_writable = true,
.writable = !readonly, .writable = !readonly,
.u.nbd = { .u.nbd = {
.has_name = true, .has_name = true,
.name = g_strdup(export_name), .name = g_strdup(export_name),
.has_description = !!export_description, .has_description = !!export_description,
.description = g_strdup(export_description), .description = g_strdup(export_description),
.has_bitmap = !!bitmap, .has_bitmaps = !!bitmaps,
.bitmap = g_strdup(bitmap), .bitmaps = bitmaps,
}, },
}; };
blk_exp_add(export_opts, &error_fatal); blk_exp_add(export_opts, &error_fatal);