mirror of https://github.com/xqemu/xqemu.git
block: add drive-backup QMP command
@drive-backup Start a point-in-time copy of a block device to a new destination. The status of ongoing drive-backup operations can be checked with query-block-jobs where the BlockJobInfo.type field has the value 'backup'. The operation can be stopped before it has completed using the block-job-cancel command. @device: the name of the device which should be copied. @target: the target of the new image. If the file exists, or if it is a device, the existing file/device will be used as the new destination. If it does not exist, a new file will be created. @format: #optional the format of the new destination, default is to probe if @mode is 'existing', else the format of the source @mode: #optional whether and how QEMU should create a new image, default is 'absolute-paths'. @speed: #optional the maximum speed, in bytes per second @on-source-error: #optional the action to take on an error on the source, default 'report'. 'stop' and 'enospc' can only be used if the block device supports io-status (see BlockInfo). @on-target-error: #optional the action to take on an error on the target, default 'report' (no limitations, since this applies to a different block device than @device). Note that @on-source-error and @on-target-error only affect background I/O. If an error occurs during a guest write request, the device's rerror/werror actions will be used. Returns: nothing on success If @device is not a valid block device, DeviceNotFound Since 1.6 Reviewed-by: Eric Blake <eblake@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
ac3c5d831a
commit
99a9addf56
97
blockdev.c
97
blockdev.c
|
@ -1353,6 +1353,103 @@ void qmp_block_commit(const char *device,
|
||||||
drive_get_ref(drive_get_by_blockdev(bs));
|
drive_get_ref(drive_get_by_blockdev(bs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qmp_drive_backup(const char *device, const char *target,
|
||||||
|
bool has_format, const char *format,
|
||||||
|
bool has_mode, enum NewImageMode mode,
|
||||||
|
bool has_speed, int64_t speed,
|
||||||
|
bool has_on_source_error, BlockdevOnError on_source_error,
|
||||||
|
bool has_on_target_error, BlockdevOnError on_target_error,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
BlockDriverState *bs;
|
||||||
|
BlockDriverState *target_bs;
|
||||||
|
BlockDriver *drv = NULL;
|
||||||
|
Error *local_err = NULL;
|
||||||
|
int flags;
|
||||||
|
int64_t size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!has_speed) {
|
||||||
|
speed = 0;
|
||||||
|
}
|
||||||
|
if (!has_on_source_error) {
|
||||||
|
on_source_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||||
|
}
|
||||||
|
if (!has_on_target_error) {
|
||||||
|
on_target_error = BLOCKDEV_ON_ERROR_REPORT;
|
||||||
|
}
|
||||||
|
if (!has_mode) {
|
||||||
|
mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs = bdrv_find(device);
|
||||||
|
if (!bs) {
|
||||||
|
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bdrv_is_inserted(bs)) {
|
||||||
|
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_format) {
|
||||||
|
format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
|
||||||
|
}
|
||||||
|
if (format) {
|
||||||
|
drv = bdrv_find_format(format);
|
||||||
|
if (!drv) {
|
||||||
|
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bdrv_in_use(bs)) {
|
||||||
|
error_set(errp, QERR_DEVICE_IN_USE, device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = bs->open_flags | BDRV_O_RDWR;
|
||||||
|
|
||||||
|
size = bdrv_getlength(bs);
|
||||||
|
if (size < 0) {
|
||||||
|
error_setg_errno(errp, -size, "bdrv_getlength failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode != NEW_IMAGE_MODE_EXISTING) {
|
||||||
|
assert(format && drv);
|
||||||
|
bdrv_img_create(target, format,
|
||||||
|
NULL, NULL, NULL, size, flags, &local_err, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error_is_set(&local_err)) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_bs = bdrv_new("");
|
||||||
|
ret = bdrv_open(target_bs, target, NULL, flags, drv);
|
||||||
|
if (ret < 0) {
|
||||||
|
bdrv_delete(target_bs);
|
||||||
|
error_setg_file_open(errp, -ret, target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
backup_start(bs, target_bs, speed, on_source_error, on_target_error,
|
||||||
|
block_job_cb, bs, &local_err);
|
||||||
|
if (local_err != NULL) {
|
||||||
|
bdrv_delete(target_bs);
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grab a reference so hotplug does not delete the BlockDriverState from
|
||||||
|
* underneath us.
|
||||||
|
*/
|
||||||
|
drive_get_ref(drive_get_by_blockdev(bs));
|
||||||
|
}
|
||||||
|
|
||||||
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
|
#define DEFAULT_MIRROR_BUF_SIZE (10 << 20)
|
||||||
|
|
||||||
void qmp_drive_mirror(const char *device, const char *target,
|
void qmp_drive_mirror(const char *device, const char *target,
|
||||||
|
|
|
@ -1743,6 +1743,52 @@
|
||||||
'data': { 'device': 'str', '*base': 'str', 'top': 'str',
|
'data': { 'device': 'str', '*base': 'str', 'top': 'str',
|
||||||
'*speed': 'int' } }
|
'*speed': 'int' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @drive-backup
|
||||||
|
#
|
||||||
|
# Start a point-in-time copy of a block device to a new destination. The
|
||||||
|
# status of ongoing drive-backup operations can be checked with
|
||||||
|
# query-block-jobs where the BlockJobInfo.type field has the value 'backup'.
|
||||||
|
# The operation can be stopped before it has completed using the
|
||||||
|
# block-job-cancel command.
|
||||||
|
#
|
||||||
|
# @device: the name of the device which should be copied.
|
||||||
|
#
|
||||||
|
# @target: the target of the new image. If the file exists, or if it
|
||||||
|
# is a device, the existing file/device will be used as the new
|
||||||
|
# destination. If it does not exist, a new file will be created.
|
||||||
|
#
|
||||||
|
# @format: #optional the format of the new destination, default is to
|
||||||
|
# probe if @mode is 'existing', else the format of the source
|
||||||
|
#
|
||||||
|
# @mode: #optional whether and how QEMU should create a new image, default is
|
||||||
|
# 'absolute-paths'.
|
||||||
|
#
|
||||||
|
# @speed: #optional the maximum speed, in bytes per second
|
||||||
|
#
|
||||||
|
# @on-source-error: #optional the action to take on an error on the source,
|
||||||
|
# default 'report'. 'stop' and 'enospc' can only be used
|
||||||
|
# if the block device supports io-status (see BlockInfo).
|
||||||
|
#
|
||||||
|
# @on-target-error: #optional the action to take on an error on the target,
|
||||||
|
# default 'report' (no limitations, since this applies to
|
||||||
|
# a different block device than @device).
|
||||||
|
#
|
||||||
|
# Note that @on-source-error and @on-target-error only affect background I/O.
|
||||||
|
# If an error occurs during a guest write request, the device's rerror/werror
|
||||||
|
# actions will be used.
|
||||||
|
#
|
||||||
|
# Returns: nothing on success
|
||||||
|
# If @device is not a valid block device, DeviceNotFound
|
||||||
|
#
|
||||||
|
# Since 1.6
|
||||||
|
##
|
||||||
|
{ 'command': 'drive-backup',
|
||||||
|
'data': { 'device': 'str', 'target': 'str', '*format': 'str',
|
||||||
|
'*mode': 'NewImageMode', '*speed': 'int',
|
||||||
|
'*on-source-error': 'BlockdevOnError',
|
||||||
|
'*on-target-error': 'BlockdevOnError' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @drive-mirror
|
# @drive-mirror
|
||||||
#
|
#
|
||||||
|
|
|
@ -911,6 +911,52 @@ EQMP
|
||||||
.mhandler.cmd_new = qmp_marshal_input_block_commit,
|
.mhandler.cmd_new = qmp_marshal_input_block_commit,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.name = "drive-backup",
|
||||||
|
.args_type = "device:B,target:s,speed:i?,mode:s?,format:s?,"
|
||||||
|
"on-source-error:s?,on-target-error:s?",
|
||||||
|
.mhandler.cmd_new = qmp_marshal_input_drive_backup,
|
||||||
|
},
|
||||||
|
|
||||||
|
SQMP
|
||||||
|
drive-backup
|
||||||
|
------------
|
||||||
|
|
||||||
|
Start a point-in-time copy of a block device to a new destination. The
|
||||||
|
status of ongoing drive-backup operations can be checked with
|
||||||
|
query-block-jobs where the BlockJobInfo.type field has the value 'backup'.
|
||||||
|
The operation can be stopped before it has completed using the
|
||||||
|
block-job-cancel command.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
- "device": the name of the device which should be copied.
|
||||||
|
(json-string)
|
||||||
|
- "target": the target of the new image. If the file exists, or if it is a
|
||||||
|
device, the existing file/device will be used as the new
|
||||||
|
destination. If it does not exist, a new file will be created.
|
||||||
|
(json-string)
|
||||||
|
- "format": the format of the new destination, default is to probe if 'mode' is
|
||||||
|
'existing', else the format of the source
|
||||||
|
(json-string, optional)
|
||||||
|
- "mode": whether and how QEMU should create a new image
|
||||||
|
(NewImageMode, optional, default 'absolute-paths')
|
||||||
|
- "speed": the maximum speed, in bytes per second (json-int, optional)
|
||||||
|
- "on-source-error": the action to take on an error on the source, default
|
||||||
|
'report'. 'stop' and 'enospc' can only be used
|
||||||
|
if the block device supports io-status.
|
||||||
|
(BlockdevOnError, optional)
|
||||||
|
- "on-target-error": the action to take on an error on the target, default
|
||||||
|
'report' (no limitations, since this applies to
|
||||||
|
a different block device than device).
|
||||||
|
(BlockdevOnError, optional)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
-> { "execute": "drive-backup", "arguments": { "device": "drive0",
|
||||||
|
"target": "backup.img" } }
|
||||||
|
<- { "return": {} }
|
||||||
|
EQMP
|
||||||
|
|
||||||
{
|
{
|
||||||
.name = "block-job-set-speed",
|
.name = "block-job-set-speed",
|
||||||
.args_type = "device:B,speed:o",
|
.args_type = "device:B,speed:o",
|
||||||
|
|
Loading…
Reference in New Issue