qapi: nbd-export: allow select bitmaps by node/name pair

Hi all! Current logic of relying on search through backing chain is not
safe neither convenient.

Sometimes it leads to necessity of extra bitmap copying. Also, we are
going to add "snapshot-access" driver, to access some snapshot state
through NBD. And this driver is not formally a filter, and of course
it's not a COW format driver. So, searching through backing chain will
not work. Instead of widening the workaround of bitmap searching, let's
extend the interface so that user can select bitmap precisely.

Note, that checking for bitmap active status is not copied to the new
API, I don't see a reason for it, user should understand the risks. And
anyway, bitmap from other node is unrelated to this export being
read-only or read-write.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org>
Message-Id: <20220314213226.362217-3-v.sementsov-og@mail.ru>
[eblake: Adjust S-o-b to Vladimir's new email, with permission]
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Vladimir Sementsov-Ogievskiy 2022-03-15 00:32:25 +03:00 committed by Eric Blake
parent 1466ef6cbe
commit e5fb29d5d0
4 changed files with 61 additions and 26 deletions

View file

@ -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 (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();
}
if (bm == NULL) {
ret = -ENOENT;
error_setg(errp, "Bitmap '%s' is not found", bitmap);
goto fail;
}
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);
}