mirror of https://github.com/xqemu/xqemu.git
block: Simplify drive-mirror
Now that we can support boxed commands, use it to greatly reduce the number of parameters (and likelihood of getting out of sync) when adjusting drive-mirror parameters. Signed-off-by: Eric Blake <eblake@redhat.com> Reviewed-by: John Snow <jsnow@redhat.com> Message-Id: <1468535878-3760-1-git-send-email-eblake@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
parent
4dc9397b62
commit
faecd40a59
78
blockdev.c
78
blockdev.c
|
@ -3466,19 +3466,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
|
||||||
block_job_cb, bs, errp);
|
block_job_cb, bs, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qmp_drive_mirror(bool has_job_id, const char *job_id, const char *device,
|
void qmp_drive_mirror(DriveMirror *arg, Error **errp)
|
||||||
const char *target, bool has_format, const char *format,
|
|
||||||
bool has_node_name, const char *node_name,
|
|
||||||
bool has_replaces, const char *replaces,
|
|
||||||
enum MirrorSyncMode sync,
|
|
||||||
bool has_mode, enum NewImageMode mode,
|
|
||||||
bool has_speed, int64_t speed,
|
|
||||||
bool has_granularity, uint32_t granularity,
|
|
||||||
bool has_buf_size, int64_t buf_size,
|
|
||||||
bool has_on_source_error, BlockdevOnError on_source_error,
|
|
||||||
bool has_on_target_error, BlockdevOnError on_target_error,
|
|
||||||
bool has_unmap, bool unmap,
|
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
|
@ -3489,11 +3477,12 @@ void qmp_drive_mirror(bool has_job_id, const char *job_id, const char *device,
|
||||||
QDict *options = NULL;
|
QDict *options = NULL;
|
||||||
int flags;
|
int flags;
|
||||||
int64_t size;
|
int64_t size;
|
||||||
|
const char *format = arg->format;
|
||||||
|
|
||||||
blk = blk_by_name(device);
|
blk = blk_by_name(arg->device);
|
||||||
if (!blk) {
|
if (!blk) {
|
||||||
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
||||||
"Device '%s' not found", device);
|
"Device '%s' not found", arg->device);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3501,24 +3490,25 @@ void qmp_drive_mirror(bool has_job_id, const char *job_id, const char *device,
|
||||||
aio_context_acquire(aio_context);
|
aio_context_acquire(aio_context);
|
||||||
|
|
||||||
if (!blk_is_available(blk)) {
|
if (!blk_is_available(blk)) {
|
||||||
error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, arg->device);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
bs = blk_bs(blk);
|
bs = blk_bs(blk);
|
||||||
if (!has_mode) {
|
if (!arg->has_mode) {
|
||||||
mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
arg->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_format) {
|
if (!arg->has_format) {
|
||||||
format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
|
format = (arg->mode == NEW_IMAGE_MODE_EXISTING
|
||||||
|
? NULL : bs->drv->format_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = bs->open_flags | BDRV_O_RDWR;
|
flags = bs->open_flags | BDRV_O_RDWR;
|
||||||
source = backing_bs(bs);
|
source = backing_bs(bs);
|
||||||
if (!source && sync == MIRROR_SYNC_MODE_TOP) {
|
if (!source && arg->sync == MIRROR_SYNC_MODE_TOP) {
|
||||||
sync = MIRROR_SYNC_MODE_FULL;
|
arg->sync = MIRROR_SYNC_MODE_FULL;
|
||||||
}
|
}
|
||||||
if (sync == MIRROR_SYNC_MODE_NONE) {
|
if (arg->sync == MIRROR_SYNC_MODE_NONE) {
|
||||||
source = bs;
|
source = bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3528,18 +3518,18 @@ void qmp_drive_mirror(bool has_job_id, const char *job_id, const char *device,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_replaces) {
|
if (arg->has_replaces) {
|
||||||
BlockDriverState *to_replace_bs;
|
BlockDriverState *to_replace_bs;
|
||||||
AioContext *replace_aio_context;
|
AioContext *replace_aio_context;
|
||||||
int64_t replace_size;
|
int64_t replace_size;
|
||||||
|
|
||||||
if (!has_node_name) {
|
if (!arg->has_node_name) {
|
||||||
error_setg(errp, "a node-name must be provided when replacing a"
|
error_setg(errp, "a node-name must be provided when replacing a"
|
||||||
" named node of the graph");
|
" named node of the graph");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
to_replace_bs = check_to_replace_node(bs, replaces, &local_err);
|
to_replace_bs = check_to_replace_node(bs, arg->replaces, &local_err);
|
||||||
|
|
||||||
if (!to_replace_bs) {
|
if (!to_replace_bs) {
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
|
@ -3558,26 +3548,26 @@ void qmp_drive_mirror(bool has_job_id, const char *job_id, const char *device,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == NEW_IMAGE_MODE_ABSOLUTE_PATHS) {
|
if (arg->mode == NEW_IMAGE_MODE_ABSOLUTE_PATHS) {
|
||||||
backing_mode = MIRROR_SOURCE_BACKING_CHAIN;
|
backing_mode = MIRROR_SOURCE_BACKING_CHAIN;
|
||||||
} else {
|
} else {
|
||||||
backing_mode = MIRROR_OPEN_BACKING_CHAIN;
|
backing_mode = MIRROR_OPEN_BACKING_CHAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sync == MIRROR_SYNC_MODE_FULL || !source)
|
if ((arg->sync == MIRROR_SYNC_MODE_FULL || !source)
|
||||||
&& mode != NEW_IMAGE_MODE_EXISTING)
|
&& arg->mode != NEW_IMAGE_MODE_EXISTING)
|
||||||
{
|
{
|
||||||
/* create new image w/o backing file */
|
/* create new image w/o backing file */
|
||||||
assert(format);
|
assert(format);
|
||||||
bdrv_img_create(target, format,
|
bdrv_img_create(arg->target, format,
|
||||||
NULL, NULL, NULL, size, flags, &local_err, false);
|
NULL, NULL, NULL, size, flags, &local_err, false);
|
||||||
} else {
|
} else {
|
||||||
switch (mode) {
|
switch (arg->mode) {
|
||||||
case NEW_IMAGE_MODE_EXISTING:
|
case NEW_IMAGE_MODE_EXISTING:
|
||||||
break;
|
break;
|
||||||
case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
|
case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
|
||||||
/* create new image with backing file */
|
/* create new image with backing file */
|
||||||
bdrv_img_create(target, format,
|
bdrv_img_create(arg->target, format,
|
||||||
source->filename,
|
source->filename,
|
||||||
source->drv->format_name,
|
source->drv->format_name,
|
||||||
NULL, size, flags, &local_err, false);
|
NULL, size, flags, &local_err, false);
|
||||||
|
@ -3593,8 +3583,8 @@ void qmp_drive_mirror(bool has_job_id, const char *job_id, const char *device,
|
||||||
}
|
}
|
||||||
|
|
||||||
options = qdict_new();
|
options = qdict_new();
|
||||||
if (has_node_name) {
|
if (arg->has_node_name) {
|
||||||
qdict_put(options, "node-name", qstring_from_str(node_name));
|
qdict_put(options, "node-name", qstring_from_str(arg->node_name));
|
||||||
}
|
}
|
||||||
if (format) {
|
if (format) {
|
||||||
qdict_put(options, "driver", qstring_from_str(format));
|
qdict_put(options, "driver", qstring_from_str(format));
|
||||||
|
@ -3603,22 +3593,22 @@ void qmp_drive_mirror(bool has_job_id, const char *job_id, const char *device,
|
||||||
/* Mirroring takes care of copy-on-write using the source's backing
|
/* Mirroring takes care of copy-on-write using the source's backing
|
||||||
* file.
|
* file.
|
||||||
*/
|
*/
|
||||||
target_bs = bdrv_open(target, NULL, options, flags | BDRV_O_NO_BACKING,
|
target_bs = bdrv_open(arg->target, NULL, options,
|
||||||
errp);
|
flags | BDRV_O_NO_BACKING, errp);
|
||||||
if (!target_bs) {
|
if (!target_bs) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_set_aio_context(target_bs, aio_context);
|
bdrv_set_aio_context(target_bs, aio_context);
|
||||||
|
|
||||||
blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs,
|
blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs,
|
||||||
has_replaces, replaces, sync, backing_mode,
|
arg->has_replaces, arg->replaces, arg->sync,
|
||||||
has_speed, speed,
|
backing_mode, arg->has_speed, arg->speed,
|
||||||
has_granularity, granularity,
|
arg->has_granularity, arg->granularity,
|
||||||
has_buf_size, buf_size,
|
arg->has_buf_size, arg->buf_size,
|
||||||
has_on_source_error, on_source_error,
|
arg->has_on_source_error, arg->on_source_error,
|
||||||
has_on_target_error, on_target_error,
|
arg->has_on_target_error, arg->on_target_error,
|
||||||
has_unmap, unmap,
|
arg->has_unmap, arg->unmap,
|
||||||
&local_err);
|
&local_err);
|
||||||
bdrv_unref(target_bs);
|
bdrv_unref(target_bs);
|
||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
|
|
25
hmp.c
25
hmp.c
|
@ -1077,31 +1077,28 @@ void hmp_block_resize(Monitor *mon, const QDict *qdict)
|
||||||
|
|
||||||
void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
const char *device = qdict_get_str(qdict, "device");
|
|
||||||
const char *filename = qdict_get_str(qdict, "target");
|
const char *filename = qdict_get_str(qdict, "target");
|
||||||
const char *format = qdict_get_try_str(qdict, "format");
|
const char *format = qdict_get_try_str(qdict, "format");
|
||||||
bool reuse = qdict_get_try_bool(qdict, "reuse", false);
|
bool reuse = qdict_get_try_bool(qdict, "reuse", false);
|
||||||
bool full = qdict_get_try_bool(qdict, "full", false);
|
bool full = qdict_get_try_bool(qdict, "full", false);
|
||||||
enum NewImageMode mode;
|
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
DriveMirror mirror = {
|
||||||
|
.device = (char *)qdict_get_str(qdict, "device"),
|
||||||
|
.target = (char *)filename,
|
||||||
|
.has_format = !!format,
|
||||||
|
.format = (char *)format,
|
||||||
|
.sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
||||||
|
.has_mode = true,
|
||||||
|
.mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
|
||||||
|
.unmap = true,
|
||||||
|
};
|
||||||
|
|
||||||
if (!filename) {
|
if (!filename) {
|
||||||
error_setg(&err, QERR_MISSING_PARAMETER, "target");
|
error_setg(&err, QERR_MISSING_PARAMETER, "target");
|
||||||
hmp_handle_error(mon, &err);
|
hmp_handle_error(mon, &err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
qmp_drive_mirror(&mirror, &err);
|
||||||
if (reuse) {
|
|
||||||
mode = NEW_IMAGE_MODE_EXISTING;
|
|
||||||
} else {
|
|
||||||
mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
|
||||||
}
|
|
||||||
|
|
||||||
qmp_drive_mirror(false, NULL, device, filename, !!format, format,
|
|
||||||
false, NULL, false, NULL,
|
|
||||||
full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
|
|
||||||
true, mode, false, 0, false, 0, false, 0,
|
|
||||||
false, 0, false, 0, false, true, &err);
|
|
||||||
hmp_handle_error(mon, &err);
|
hmp_handle_error(mon, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1120,6 +1120,21 @@
|
||||||
#
|
#
|
||||||
# Start mirroring a block device's writes to a new destination.
|
# Start mirroring a block device's writes to a new destination.
|
||||||
#
|
#
|
||||||
|
# See DriveMirror for parameter descriptions
|
||||||
|
#
|
||||||
|
# Returns: nothing on success
|
||||||
|
# If @device is not a valid block device, DeviceNotFound
|
||||||
|
#
|
||||||
|
# Since 1.3
|
||||||
|
##
|
||||||
|
{ 'command': 'drive-mirror', 'boxed': true,
|
||||||
|
'data': 'DriveMirror' }
|
||||||
|
|
||||||
|
##
|
||||||
|
# DriveMirror
|
||||||
|
#
|
||||||
|
# A set of parameters describing drive mirror setup.
|
||||||
|
#
|
||||||
# @job-id: #optional identifier for the newly-created block job. If
|
# @job-id: #optional identifier for the newly-created block job. If
|
||||||
# omitted, the device name will be used. (Since 2.7)
|
# omitted, the device name will be used. (Since 2.7)
|
||||||
#
|
#
|
||||||
|
@ -1169,12 +1184,9 @@
|
||||||
# written. Both will result in identical contents.
|
# written. Both will result in identical contents.
|
||||||
# Default is true. (Since 2.4)
|
# Default is true. (Since 2.4)
|
||||||
#
|
#
|
||||||
# Returns: nothing on success
|
|
||||||
# If @device is not a valid block device, DeviceNotFound
|
|
||||||
#
|
|
||||||
# Since 1.3
|
# Since 1.3
|
||||||
##
|
##
|
||||||
{ 'command': 'drive-mirror',
|
{ 'struct': 'DriveMirror',
|
||||||
'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
|
'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
|
||||||
'*format': 'str', '*node-name': 'str', '*replaces': 'str',
|
'*format': 'str', '*node-name': 'str', '*replaces': 'str',
|
||||||
'sync': 'MirrorSyncMode', '*mode': 'NewImageMode',
|
'sync': 'MirrorSyncMode', '*mode': 'NewImageMode',
|
||||||
|
|
Loading…
Reference in New Issue