958e1b
From 2513477895b7fd9434a66be645dfeae5dc2eccb8 Mon Sep 17 00:00:00 2001
2382db
From: Eric Blake <eblake@redhat.com>
2382db
Date: Wed, 20 Aug 2014 16:40:12 +0200
958e1b
Subject: [PATCH 09/11] block: make 'top' argument to block-commit optional
2382db
2382db
Message-id: <1408552814-23031-6-git-send-email-eblake@redhat.com>
2382db
Patchwork-id: 60647
2382db
O-Subject: [qemu-kvm-rhev 7.0.z PATCH 5/7] block: make 'top' argument to block-commit optional
958e1b
Bugzilla: 1130603
2382db
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
2382db
RH-Acked-by: Fam Zheng <famz@redhat.com>
2382db
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
2382db
2382db
From: Jeff Cody <jcody@redhat.com>
2382db
2382db
Now that active layer block-commit is supported, the 'top' argument
2382db
no longer needs to be mandatory.
2382db
2382db
Change it to optional, with the default being the active layer in the
2382db
device chain.
2382db
2382db
[kwolf: Rebased and resolved conflict in tests/qemu-iotests/040]
2382db
2382db
Reviewed-by: Eric Blake <eblake@redhat.com>
2382db
Reviewed-by: Benoit Canet <benoit@irqsave.net>
2382db
Signed-off-by: Jeff Cody <jcody@redhat.com>
2382db
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2382db
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2382db
(cherry picked from commit 7676e2c597000eff3a7233b40cca768b358f9bc9)
2382db
2382db
Conflicts:
2382db
	qapi/block-core.json - downstream in qapi-schema.json still
2382db
	tests/qemu-iotests/040 - context due to no common event handling
2382db
2382db
Signed-off-by: Eric Blake <eblake@redhat.com>
2382db
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
2382db
---
2382db
 blockdev.c             |   16 ++++++++++++++--
2382db
 qapi-schema.json       |    7 ++++---
2382db
 qmp-commands.hx        |    5 +++--
2382db
 tests/qemu-iotests/040 |   28 ++++++++++++++++++----------
2382db
 4 files changed, 39 insertions(+), 17 deletions(-)
2382db
2382db
diff --git a/blockdev.c b/blockdev.c
958e1b
index aa5d0a6..107e27e 100644
2382db
--- a/blockdev.c
2382db
+++ b/blockdev.c
2382db
@@ -1463,7 +1463,8 @@ void qmp_block_stream(const char *device, bool has_base,
2382db
 }
2382db
 
2382db
 void qmp_block_commit(const char *device,
2382db
-                      bool has_base, const char *base, const char *top,
2382db
+                      bool has_base, const char *base,
2382db
+                      bool has_top, const char *top,
2382db
                       bool has_speed, int64_t speed,
2382db
                       Error **errp)
2382db
 {
2382db
@@ -1478,6 +1479,11 @@ void qmp_block_commit(const char *device,
2382db
     /* drain all i/o before commits */
2382db
     bdrv_drain_all();
2382db
 
2382db
+    /* Important Note:
2382db
+     *  libvirt relies on the DeviceNotFound error class in order to probe for
2382db
+     *  live commit feature versions; for this to work, we must make sure to
2382db
+     *  perform the device lookup before any generic errors that may occur in a
2382db
+     *  scenario in which all optional arguments are omitted. */
2382db
     bs = bdrv_find(device);
2382db
     if (!bs) {
2382db
         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
2382db
@@ -1487,7 +1493,7 @@ void qmp_block_commit(const char *device,
2382db
     /* default top_bs is the active layer */
2382db
     top_bs = bs;
2382db
 
2382db
-    if (top) {
2382db
+    if (has_top && top) {
2382db
         if (strcmp(bs->filename, top) != 0) {
2382db
             top_bs = bdrv_find_backing_image(bs, top);
2382db
         }
2382db
@@ -1509,6 +1515,12 @@ void qmp_block_commit(const char *device,
2382db
         return;
2382db
     }
2382db
 
2382db
+    /* Do not allow attempts to commit an image into itself */
2382db
+    if (top_bs == base_bs) {
2382db
+        error_setg(errp, "cannot commit an image into itself");
2382db
+        return;
2382db
+    }
2382db
+
2382db
     if (top_bs == bs) {
2382db
         commit_active_start(bs, base_bs, speed, on_error, block_job_cb,
2382db
                             bs, &local_err);
2382db
diff --git a/qapi-schema.json b/qapi-schema.json
958e1b
index 604ec69..18ab949 100644
2382db
--- a/qapi-schema.json
2382db
+++ b/qapi-schema.json
958e1b
@@ -1844,8 +1844,9 @@
2382db
 # @base:   #optional The file name of the backing image to write data into.
2382db
 #                    If not specified, this is the deepest backing image
2382db
 #
2382db
-# @top:              The file name of the backing image within the image chain,
2382db
-#                    which contains the topmost data to be committed down.
2382db
+# @top:    #optional The file name of the backing image within the image chain,
2382db
+#                    which contains the topmost data to be committed down. If
2382db
+#                    not specified, this is the active layer.
2382db
 #
2382db
 #                    If top == base, that is an error.
2382db
 #                    If top == active, the job will not be completed by itself,
958e1b
@@ -1873,7 +1874,7 @@
2382db
 #
2382db
 ##
2382db
 { 'command': 'block-commit',
2382db
-  'data': { 'device': 'str', '*base': 'str', 'top': 'str',
2382db
+  'data': { 'device': 'str', '*base': 'str', '*top': 'str',
2382db
             '*speed': 'int' } }
2382db
 
2382db
 ##
2382db
diff --git a/qmp-commands.hx b/qmp-commands.hx
958e1b
index 405275c..f67121a 100644
2382db
--- a/qmp-commands.hx
2382db
+++ b/qmp-commands.hx
2382db
@@ -1005,7 +1005,7 @@ EQMP
2382db
 
2382db
     {
2382db
         .name       = "block-commit",
2382db
-        .args_type  = "device:B,base:s?,top:s,speed:o?",
2382db
+        .args_type  = "device:B,base:s?,top:s?,speed:o?",
2382db
         .mhandler.cmd_new = qmp_marshal_input_block_commit,
2382db
     },
2382db
 
2382db
@@ -1023,7 +1023,8 @@ Arguments:
2382db
           If not specified, this is the deepest backing image
2382db
           (json-string, optional)
2382db
 - "top":  The file name of the backing image within the image chain,
2382db
-          which contains the topmost data to be committed down.
2382db
+          which contains the topmost data to be committed down. If
2382db
+          not specified, this is the active layer. (json-string, optional)
2382db
 
2382db
           If top == base, that is an error.
2382db
           If top == active, the job will not be completed by itself,
2382db
diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040
2382db
index cf80e0c..c5ab930 100755
2382db
--- a/tests/qemu-iotests/040
2382db
+++ b/tests/qemu-iotests/040
2382db
@@ -63,11 +63,7 @@ class ImageCommitTestCase(iotests.QMPTestCase):
2382db
             i = i + 512
2382db
         file.close()
2382db
 
2382db
-    def run_commit_test(self, top, base, need_ready=False):
2382db
-        self.assert_no_active_commit()
2382db
-        result = self.vm.qmp('block-commit', device='drive0', top=top, base=base)
2382db
-        self.assert_qmp(result, 'return', {})
2382db
-
2382db
+    def wait_for_complete(self, need_ready=False):
2382db
         completed = False
2382db
         ready = False
2382db
         while not completed:
2382db
@@ -90,6 +86,18 @@ class ImageCommitTestCase(iotests.QMPTestCase):
2382db
         self.assert_no_active_commit()
2382db
         self.vm.shutdown()
2382db
 
2382db
+    def run_commit_test(self, top, base, need_ready=False):
2382db
+        self.assert_no_active_commit()
2382db
+        result = self.vm.qmp('block-commit', device='drive0', top=top, base=base)
2382db
+        self.assert_qmp(result, 'return', {})
2382db
+        self.wait_for_complete(need_ready)
2382db
+
2382db
+    def run_default_commit_test(self):
2382db
+        self.assert_no_active_commit()
2382db
+        result = self.vm.qmp('block-commit', device='drive0')
2382db
+        self.assert_qmp(result, 'return', {})
2382db
+        self.wait_for_complete()
2382db
+
2382db
 class TestSingleDrive(ImageCommitTestCase):
2382db
     image_len = 1 * 1024 * 1024
2382db
     test_len = 1 * 1024 * 256
2382db
@@ -141,17 +149,17 @@ class TestSingleDrive(ImageCommitTestCase):
2382db
         self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed"))
2382db
         self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed"))
2382db
 
2382db
+    def test_top_is_default_active(self):
2382db
+        self.run_default_commit_test()
2382db
+        self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed"))
2382db
+        self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed"))
2382db
+
2382db
     def test_top_and_base_reversed(self):
2382db
         self.assert_no_active_commit()
2382db
         result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % mid_img)
2382db
         self.assert_qmp(result, 'error/class', 'GenericError')
2382db
         self.assert_qmp(result, 'error/desc', 'Base \'%s\' not found' % mid_img)
2382db
 
2382db
-    def test_top_omitted(self):
2382db
-        self.assert_no_active_commit()
2382db
-        result = self.vm.qmp('block-commit', device='drive0')
2382db
-        self.assert_qmp(result, 'error/class', 'GenericError')
2382db
-        self.assert_qmp(result, 'error/desc', "Parameter 'top' is missing")
2382db
 
2382db
 class TestRelativePaths(ImageCommitTestCase):
2382db
     image_len = 1 * 1024 * 1024
2382db
-- 
2382db
1.7.1
2382db