mirror: Deal with filters

This includes some permission limiting (for example, we only need to
take the RESIZE permission for active commits where the base is smaller
than the top).

base_overlay is introduced so we can query bdrv_is_allocated_above() on
it - we cannot do that with base itself, because a filter's block_status
is the same as its child node, so if there are filters on base,
bdrv_is_allocated_above() on base would return information including
base.

Use this opportunity to rename qmp_drive_mirror()'s "source" BDS to
"target_backing_bs", because that is what it really refers to.

Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
Max Reitz
2019-06-12 16:27:32 +02:00
committed by Kevin Wolf
parent c6f6d8462c
commit 3f072a7fb7
3 changed files with 118 additions and 38 deletions

View File

@@ -2899,6 +2899,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
bool has_auto_dismiss, bool auto_dismiss,
Error **errp)
{
BlockDriverState *unfiltered_bs;
int job_flags = JOB_DEFAULT;
if (!has_speed) {
@@ -2950,10 +2951,19 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
return;
}
if (!bs->backing && sync == MIRROR_SYNC_MODE_TOP) {
if (!bdrv_backing_chain_next(bs) && sync == MIRROR_SYNC_MODE_TOP) {
sync = MIRROR_SYNC_MODE_FULL;
}
if (!has_replaces) {
/* We want to mirror from @bs, but keep implicit filters on top */
unfiltered_bs = bdrv_skip_implicit_filters(bs);
if (unfiltered_bs != bs) {
replaces = unfiltered_bs->node_name;
has_replaces = true;
}
}
if (has_replaces) {
BlockDriverState *to_replace_bs;
AioContext *replace_aio_context;
@@ -3000,7 +3010,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
void qmp_drive_mirror(DriveMirror *arg, Error **errp)
{
BlockDriverState *bs;
BlockDriverState *source, *target_bs;
BlockDriverState *target_backing_bs, *target_bs;
AioContext *aio_context;
AioContext *old_context;
BlockMirrorBackingMode backing_mode;
@@ -3035,12 +3045,12 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
}
flags = bs->open_flags | BDRV_O_RDWR;
source = backing_bs(bs);
if (!source && arg->sync == MIRROR_SYNC_MODE_TOP) {
target_backing_bs = bdrv_cow_bs(bdrv_skip_filters(bs));
if (!target_backing_bs && arg->sync == MIRROR_SYNC_MODE_TOP) {
arg->sync = MIRROR_SYNC_MODE_FULL;
}
if (arg->sync == MIRROR_SYNC_MODE_NONE) {
source = bs;
target_backing_bs = bs;
}
size = bdrv_getlength(bs);
@@ -3066,7 +3076,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
/* Don't open backing image in create() */
flags |= BDRV_O_NO_BACKING;
if ((arg->sync == MIRROR_SYNC_MODE_FULL || !source)
if ((arg->sync == MIRROR_SYNC_MODE_FULL || !target_backing_bs)
&& arg->mode != NEW_IMAGE_MODE_EXISTING)
{
/* create new image w/o backing file */
@@ -3074,15 +3084,19 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
bdrv_img_create(arg->target, format,
NULL, NULL, NULL, size, flags, false, &local_err);
} else {
/* Implicit filters should not appear in the filename */
BlockDriverState *explicit_backing =
bdrv_skip_implicit_filters(target_backing_bs);
switch (arg->mode) {
case NEW_IMAGE_MODE_EXISTING:
break;
case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
/* create new image with backing file */
bdrv_refresh_filename(source);
bdrv_refresh_filename(explicit_backing);
bdrv_img_create(arg->target, format,
source->filename,
source->drv->format_name,
explicit_backing->filename,
explicit_backing->drv->format_name,
NULL, size, flags, false, &local_err);
break;
default: