aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blockdev.c6
-rw-r--r--qapi-schema.json7
-rw-r--r--qmp-commands.hx6
-rwxr-xr-xtests/qemu-iotests/05536
4 files changed, 38 insertions, 17 deletions
diff --git a/blockdev.c b/blockdev.c
index b3a57e0c1d..c5abd65182 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -936,6 +936,7 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
qmp_drive_backup(backup->device, backup->target,
backup->has_format, backup->format,
+ backup->sync,
backup->has_mode, backup->mode,
backup->has_speed, backup->speed,
backup->has_on_source_error, backup->on_source_error,
@@ -1421,6 +1422,7 @@ void qmp_block_commit(const char *device,
void qmp_drive_backup(const char *device, const char *target,
bool has_format, const char *format,
+ enum MirrorSyncMode sync,
bool has_mode, enum NewImageMode mode,
bool has_speed, int64_t speed,
bool has_on_source_error, BlockdevOnError on_source_error,
@@ -1435,6 +1437,10 @@ void qmp_drive_backup(const char *device, const char *target,
int64_t size;
int ret;
+ if (sync != MIRROR_SYNC_MODE_FULL) {
+ error_setg(errp, "only sync mode 'full' is currently supported");
+ return;
+ }
if (!has_speed) {
speed = 0;
}
diff --git a/qapi-schema.json b/qapi-schema.json
index b251d282cc..cf57783caf 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1634,6 +1634,10 @@
# @format: #optional the format of the new destination, default is to
# probe if @mode is 'existing', else the format of the source
#
+# @sync: what parts of the disk image should be copied to the destination
+# (all the disk, only the sectors allocated in the topmost image, or
+# only new I/O).
+#
# @mode: #optional whether and how QEMU should create a new image, default is
# 'absolute-paths'.
#
@@ -1655,7 +1659,8 @@
##
{ 'type': 'DriveBackup',
'data': { 'device': 'str', 'target': 'str', '*format': 'str',
- '*mode': 'NewImageMode', '*speed': 'int',
+ 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode',
+ '*speed': 'int',
'*on-source-error': 'BlockdevOnError',
'*on-target-error': 'BlockdevOnError' } }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 362f0e1ef8..e075df423a 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -913,7 +913,7 @@ EQMP
{
.name = "drive-backup",
- .args_type = "device:B,target:s,speed:i?,mode:s?,format:s?,"
+ .args_type = "sync:s,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,
},
@@ -939,6 +939,10 @@ Arguments:
- "format": the format of the new destination, default is to probe if 'mode' is
'existing', else the format of the source
(json-string, optional)
+- "sync": what parts of the disk image should be copied to the destination;
+ possibilities include "full" for all the disk, "top" for only the sectors
+ allocated in the topmost image, or "none" to only replicate new I/O
+ (MirrorSyncMode).
- "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)
diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055
index 887c959a3d..c66f8dbd7d 100755
--- a/tests/qemu-iotests/055
+++ b/tests/qemu-iotests/055
@@ -54,7 +54,7 @@ class TestSingleDrive(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-backup', device='drive0',
- target=target_img)
+ target=target_img, sync='full')
self.assert_qmp(result, 'return', {})
event = self.cancel_and_wait()
@@ -64,7 +64,7 @@ class TestSingleDrive(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-backup', device='drive0',
- target=target_img)
+ target=target_img, sync='full')
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('block-job-pause', device='drive0')
@@ -89,17 +89,17 @@ class TestSingleDrive(iotests.QMPTestCase):
def test_medium_not_found(self):
result = self.vm.qmp('drive-backup', device='ide1-cd0',
- target=target_img)
+ target=target_img, sync='full')
self.assert_qmp(result, 'error/class', 'GenericError')
def test_image_not_found(self):
result = self.vm.qmp('drive-backup', device='drive0',
- mode='existing', target=target_img)
+ target=target_img, sync='full', mode='existing')
self.assert_qmp(result, 'error/class', 'GenericError')
def test_device_not_found(self):
result = self.vm.qmp('drive-backup', device='nonexistent',
- target=target_img)
+ target=target_img, sync='full')
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
class TestSetSpeed(iotests.QMPTestCase):
@@ -119,7 +119,7 @@ class TestSetSpeed(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-backup', device='drive0',
- target=target_img)
+ target=target_img, sync='full')
self.assert_qmp(result, 'return', {})
# Default speed is 0
@@ -140,7 +140,7 @@ class TestSetSpeed(iotests.QMPTestCase):
# Check setting speed in drive-backup works
result = self.vm.qmp('drive-backup', device='drive0',
- target=target_img, speed=4*1024*1024)
+ target=target_img, sync='full', speed=4*1024*1024)
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('query-block-jobs')
@@ -154,13 +154,13 @@ class TestSetSpeed(iotests.QMPTestCase):
self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-backup', device='drive0',
- target=target_img, speed=-1)
+ target=target_img, sync='full', speed=-1)
self.assert_qmp(result, 'error/class', 'GenericError')
self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-backup', device='drive0',
- target=target_img)
+ target=target_img, sync='full')
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
@@ -196,7 +196,8 @@ class TestSingleTransaction(iotests.QMPTestCase):
result = self.vm.qmp('transaction', actions=[{
'type': 'drive-backup',
'data': { 'device': 'drive0',
- 'target': target_img },
+ 'target': target_img,
+ 'sync': 'full' },
}
])
self.assert_qmp(result, 'return', {})
@@ -210,7 +211,8 @@ class TestSingleTransaction(iotests.QMPTestCase):
result = self.vm.qmp('transaction', actions=[{
'type': 'drive-backup',
'data': { 'device': 'drive0',
- 'target': target_img },
+ 'target': target_img,
+ 'sync': 'full' },
}
])
self.assert_qmp(result, 'return', {})
@@ -239,7 +241,8 @@ class TestSingleTransaction(iotests.QMPTestCase):
result = self.vm.qmp('transaction', actions=[{
'type': 'drive-backup',
'data': { 'device': 'ide1-cd0',
- 'target': target_img },
+ 'target': target_img,
+ 'sync': 'full' },
}
])
self.assert_qmp(result, 'error/class', 'GenericError')
@@ -249,7 +252,8 @@ class TestSingleTransaction(iotests.QMPTestCase):
'type': 'drive-backup',
'data': { 'device': 'drive0',
'mode': 'existing',
- 'target': target_img },
+ 'target': target_img,
+ 'sync': 'full' },
}
])
self.assert_qmp(result, 'error/class', 'GenericError')
@@ -259,7 +263,8 @@ class TestSingleTransaction(iotests.QMPTestCase):
'type': 'drive-backup',
'data': { 'device': 'nonexistent',
'mode': 'existing',
- 'target': target_img },
+ 'target': target_img,
+ 'sync': 'full' },
}
])
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
@@ -269,7 +274,8 @@ class TestSingleTransaction(iotests.QMPTestCase):
'type': 'drive-backup',
'data': { 'device': 'nonexistent',
'mode': 'existing',
- 'target': target_img },
+ 'target': target_img,
+ 'sync': 'full' },
}, {
'type': 'Abort',
'data': {},