@@ -45,6 +45,7 @@ typedef struct CowRequest {
typedef struct BackupBlockJob {
BlockJob common;
BlockDriverState *target;
+ bool release_target;
RateLimit limit;
CoRwlock flush_rwlock;
uint64_t sectors_read;
@@ -255,14 +256,17 @@ static void coroutine_fn backup_run(void *opaque)
hbitmap_free(job->bitmap);
- bdrv_delete(job->target);
+ if (job->release_target) {
+ bdrv_close(job->target);
+ bdrv_delete(job->target);
+ }
DPRINTF("backup_run complete %d\n", ret);
block_job_completed(&job->common, ret);
}
void backup_start(BlockDriverState *bs, BlockDriverState *target,
- int64_t speed,
+ int64_t speed, bool release_target,
BlockDriverCompletionFunc *cb, void *opaque,
Error **errp)
{
@@ -279,6 +283,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
}
job->target = target;
+ job->release_target = release_target;
job->common.len = bdrv_getlength(bs);
job->common.co = qemu_coroutine_create(backup_run);
qemu_coroutine_enter(job->common.co, job);
@@ -908,6 +908,11 @@ static void external_snapshot_prepare(BlkTransactionState *common,
flags = state->old_bs->open_flags;
+ if (mode == NEW_IMAGE_MODE_DRIVE) {
+ error_set(errp, QERR_INVALID_PARAMETER, "mode");
+ return;
+ }
+
/* create new image w/backing file */
if (mode != NEW_IMAGE_MODE_EXISTING) {
bdrv_img_create(new_image_file, format,
@@ -1505,28 +1510,39 @@ void qmp_drive_backup(const char *device, const char *target,
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;
- }
+ if (mode == NEW_IMAGE_MODE_DRIVE) {
+ target_bs = bdrv_find(target);
+ if (!target_bs) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, target);
+ return;
+ }
+ } else {
+ 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_set(errp, QERR_OPEN_FILE_FAILED, target);
- return;
+ target_bs = bdrv_new("");
+ ret = bdrv_open(target_bs, target, NULL, flags, drv);
+ if (ret < 0) {
+ bdrv_delete(target_bs);
+ error_set(errp, QERR_OPEN_FILE_FAILED, target);
+ return;
+ }
}
- backup_start(bs, target_bs, speed, block_job_cb, bs, &local_err);
+ backup_start(bs, target_bs, speed,
+ mode != NEW_IMAGE_MODE_DRIVE,
+ block_job_cb, bs, &local_err);
if (local_err != NULL) {
- bdrv_delete(target_bs);
+ if (mode != NEW_IMAGE_MODE_DRIVE) {
+ bdrv_delete(target_bs);
+ }
error_propagate(errp, local_err);
return;
}
@@ -1577,6 +1593,11 @@ void qmp_drive_mirror(const char *device, const char *target,
buf_size = DEFAULT_MIRROR_BUF_SIZE;
}
+ if (mode == NEW_IMAGE_MODE_DRIVE) {
+ error_set(errp, QERR_INVALID_PARAMETER, "mode");
+ return;
+ }
+
if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {
error_set(errp, QERR_INVALID_PARAMETER, device);
return;
@@ -403,6 +403,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
* @bs: Block device to operate on.
* @target: Block device to write to.
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
+ * @release_target: If block job should release target bs before completion
* @cb: Completion function for the job.
* @opaque: Opaque pointer value passed to @cb.
*
@@ -410,7 +411,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
* until the job is cancelled or manually completed.
*/
void backup_start(BlockDriverState *bs, BlockDriverState *target,
- int64_t speed,
+ int64_t speed, bool release_target,
BlockDriverCompletionFunc *cb, void *opaque,
Error **errp);
@@ -1593,10 +1593,12 @@
# @absolute-paths: QEMU should create a new image with absolute paths
# for the backing file.
#
+# @drive: QEMU should look for an existing drive
+#
# Since: 1.1
##
{ 'enum': 'NewImageMode'
- 'data': [ 'existing', 'absolute-paths' ] }
+ 'data': [ 'existing', 'absolute-paths', 'drive' ] }
##
# @BlockdevSnapshot
Introduce a "drive" option to new image mode. With this mode, QMP command should (this patch only modified drive-backup to support it, and report invalid parameter error for drive-mirror) skip creating the image file or trying to open it, it should just reuse the existing BDS by looking for the named drive with bdrv_find(). It will be useful to utilize "none" sync mode of drive-backup for point-in-time snapshot. The example with drive-backup is: -> { "execute": "drive-backup", "arguments": { "device": "ide0-hd0", "mode": "drive", "target": "drive_id_here" } } <- { "return": {} } Target bs is not released when block job completes in this case since it's still used as a device drive or exported by nbd server. Signed-off-by: Fam Zheng <famz@redhat.com> --- block/backup.c | 9 ++++++-- blockdev.c | 57 ++++++++++++++++++++++++++++++++--------------- include/block/block_int.h | 3 ++- qapi-schema.json | 4 +++- 4 files changed, 51 insertions(+), 22 deletions(-)