diff mbox

[v4,09/11] block: Accept node-name for drive-mirror

Message ID 1468502894-18098-10-git-send-email-kwolf@redhat.com
State New
Headers show

Commit Message

Kevin Wolf July 14, 2016, 1:28 p.m. UTC
In order to remove the necessity to use BlockBackend names in the
external API, we want to allow node-names everywhere. This converts
drive-mirror to accept a node-name without lifting the restriction that
we're operating at a root node.

In case of an invalid device name, the command returns the GenericError
error class now instead of DeviceNotFound, because this is what
qmp_get_root_bs() returns.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 blockdev.c             | 14 +++-----------
 qapi/block-core.json   |  5 +++--
 qmp-commands.hx        |  3 ++-
 tests/qemu-iotests/041 |  8 +++-----
 4 files changed, 11 insertions(+), 19 deletions(-)

Comments

Eric Blake July 14, 2016, 8:54 p.m. UTC | #1
On 07/14/2016 07:28 AM, Kevin Wolf wrote:
> In order to remove the necessity to use BlockBackend names in the
> external API, we want to allow node-names everywhere. This converts
> drive-mirror to accept a node-name without lifting the restriction that
> we're operating at a root node.
> 
> In case of an invalid device name, the command returns the GenericError
> error class now instead of DeviceNotFound, because this is what
> qmp_get_root_bs() returns.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  blockdev.c             | 14 +++-----------
>  qapi/block-core.json   |  5 +++--
>  qmp-commands.hx        |  3 ++-
>  tests/qemu-iotests/041 |  8 +++-----
>  4 files changed, 11 insertions(+), 19 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>
Max Reitz July 18, 2016, 2:30 p.m. UTC | #2
On 14.07.2016 15:28, Kevin Wolf wrote:
> In order to remove the necessity to use BlockBackend names in the
> external API, we want to allow node-names everywhere. This converts
> drive-mirror to accept a node-name without lifting the restriction that
> we're operating at a root node.
> 
> In case of an invalid device name, the command returns the GenericError
> error class now instead of DeviceNotFound, because this is what
> qmp_get_root_bs() returns.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  blockdev.c             | 14 +++-----------
>  qapi/block-core.json   |  5 +++--
>  qmp-commands.hx        |  3 ++-
>  tests/qemu-iotests/041 |  8 +++-----
>  4 files changed, 11 insertions(+), 19 deletions(-)
> 
> diff --git a/blockdev.c b/blockdev.c
> index b89b5f8..2d38537 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -3467,7 +3467,6 @@ void qmp_drive_mirror(bool has_job_id, const char *job_id, const char *device,
>                        Error **errp)
>  {
>      BlockDriverState *bs;
> -    BlockBackend *blk;
>      BlockDriverState *source, *target_bs;
>      AioContext *aio_context;
>      BlockMirrorBackingMode backing_mode;
> @@ -3476,21 +3475,14 @@ void qmp_drive_mirror(bool has_job_id, const char *job_id, const char *device,
>      int flags;
>      int64_t size;
>  
> -    blk = blk_by_name(device);
> -    if (!blk) {
> -        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
> -                  "Device '%s' not found", device);
> +    bs = qmp_get_root_bs(device, errp);
> +    if (!bs) {
>          return;
>      }
>  
> -    aio_context = blk_get_aio_context(blk);
> +    aio_context = bdrv_get_aio_context(bs);
>      aio_context_acquire(aio_context);
>  
> -    if (!blk_is_available(blk)) {
> -        error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
> -        goto out;
> -    }
> -    bs = blk_bs(blk);
>      if (!has_mode) {
>          mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
>      }

After this, bs->drv may be used. So I think we should keep a
bdrv_is_inserted() or bs->drv check here.

Max
Kevin Wolf Aug. 2, 2016, 4:19 p.m. UTC | #3
Am 18.07.2016 um 16:30 hat Max Reitz geschrieben:
> On 14.07.2016 15:28, Kevin Wolf wrote:
> > In order to remove the necessity to use BlockBackend names in the
> > external API, we want to allow node-names everywhere. This converts
> > drive-mirror to accept a node-name without lifting the restriction that
> > we're operating at a root node.
> > 
> > In case of an invalid device name, the command returns the GenericError
> > error class now instead of DeviceNotFound, because this is what
> > qmp_get_root_bs() returns.
> > 
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>

> > -    aio_context = blk_get_aio_context(blk);
> > +    aio_context = bdrv_get_aio_context(bs);
> >      aio_context_acquire(aio_context);
> >  
> > -    if (!blk_is_available(blk)) {
> > -        error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
> > -        goto out;
> > -    }
> > -    bs = blk_bs(blk);
> >      if (!has_mode) {
> >          mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
> >      }
> 
> After this, bs->drv may be used. So I think we should keep a
> bdrv_is_inserted() or bs->drv check here.

Do BDSes with bs->drv == NULL still happen normally, i.e. other than in
cases where a driver gives up on a broken image? If not, maybe doing
that check in qmp_get_root_bs() would be best.

Kevin
Max Reitz Aug. 3, 2016, 11:16 a.m. UTC | #4
On 02.08.2016 18:19, Kevin Wolf wrote:
> Am 18.07.2016 um 16:30 hat Max Reitz geschrieben:
>> On 14.07.2016 15:28, Kevin Wolf wrote:
>>> In order to remove the necessity to use BlockBackend names in the
>>> external API, we want to allow node-names everywhere. This converts
>>> drive-mirror to accept a node-name without lifting the restriction that
>>> we're operating at a root node.
>>>
>>> In case of an invalid device name, the command returns the GenericError
>>> error class now instead of DeviceNotFound, because this is what
>>> qmp_get_root_bs() returns.
>>>
>>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> 
>>> -    aio_context = blk_get_aio_context(blk);
>>> +    aio_context = bdrv_get_aio_context(bs);
>>>      aio_context_acquire(aio_context);
>>>  
>>> -    if (!blk_is_available(blk)) {
>>> -        error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
>>> -        goto out;
>>> -    }
>>> -    bs = blk_bs(blk);
>>>      if (!has_mode) {
>>>          mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
>>>      }
>>
>> After this, bs->drv may be used. So I think we should keep a
>> bdrv_is_inserted() or bs->drv check here.
> 
> Do BDSes with bs->drv == NULL still happen normally, i.e. other than in
> cases where a driver gives up on a broken image? If not, maybe doing
> that check in qmp_get_root_bs() would be best.

Well, while corrupt qcow2 images aren't strictly normal, it can happen
and I don't think qemu should crash if one is encountered.

Max
diff mbox

Patch

diff --git a/blockdev.c b/blockdev.c
index b89b5f8..2d38537 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3467,7 +3467,6 @@  void qmp_drive_mirror(bool has_job_id, const char *job_id, const char *device,
                       Error **errp)
 {
     BlockDriverState *bs;
-    BlockBackend *blk;
     BlockDriverState *source, *target_bs;
     AioContext *aio_context;
     BlockMirrorBackingMode backing_mode;
@@ -3476,21 +3475,14 @@  void qmp_drive_mirror(bool has_job_id, const char *job_id, const char *device,
     int flags;
     int64_t size;
 
-    blk = blk_by_name(device);
-    if (!blk) {
-        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
-                  "Device '%s' not found", device);
+    bs = qmp_get_root_bs(device, errp);
+    if (!bs) {
         return;
     }
 
-    aio_context = blk_get_aio_context(blk);
+    aio_context = bdrv_get_aio_context(bs);
     aio_context_acquire(aio_context);
 
-    if (!blk_is_available(blk)) {
-        error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
-        goto out;
-    }
-    bs = blk_bs(blk);
     if (!has_mode) {
         mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
     }
diff --git a/qapi/block-core.json b/qapi/block-core.json
index ab885e8..8c92918 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1124,7 +1124,8 @@ 
 # @job-id: #optional identifier for the newly-created block job. If
 #          omitted, the device name will be used. (Since 2.7)
 #
-# @device:  the name of the device whose writes should be mirrored.
+# @device:  the device name or node-name of a root node whose writes should be
+#           mirrored.
 #
 # @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
@@ -1171,7 +1172,7 @@ 
 #         Default is true. (Since 2.4)
 #
 # Returns: nothing on success
-#          If @device is not a valid block device, DeviceNotFound
+#          If @device is not a valid block device, GenericError
 #
 # Since 1.3
 ##
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 5586546..2c90d23 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1689,7 +1689,8 @@  Arguments:
 
 - "job-id": Identifier for the newly-created block job. If omitted,
             the device name will be used. (json-string, optional)
-- "device": device name to operate on (json-string)
+- "device": the device name or node-name of a root node whose writes should be
+            mirrored.(json-string)
 - "target": name of new image file (json-string)
 - "format": format of new image (json-string, optional)
 - "node-name": the name of the new block driver state in the node graph
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index cbf5e0b..80939c0 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -38,7 +38,6 @@  class TestSingleDrive(iotests.QMPTestCase):
     image_len = 1 * 1024 * 1024 # MB
     qmp_cmd = 'drive-mirror'
     qmp_target = target_img
-    not_found_error = 'DeviceNotFound'
 
     def setUp(self):
         iotests.create_image(backing_img, self.image_len)
@@ -176,7 +175,7 @@  class TestSingleDrive(iotests.QMPTestCase):
 
         result = self.vm.qmp(self.qmp_cmd, device='ide1-cd0', sync='full',
                              target=self.qmp_target)
-        self.assert_qmp(result, 'error/class', self.not_found_error)
+        self.assert_qmp(result, 'error/class', 'GenericError')
 
     def test_image_not_found(self):
         result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full',
@@ -186,12 +185,11 @@  class TestSingleDrive(iotests.QMPTestCase):
     def test_device_not_found(self):
         result = self.vm.qmp(self.qmp_cmd, device='nonexistent', sync='full',
                              target=self.qmp_target)
-        self.assert_qmp(result, 'error/class', self.not_found_error)
+        self.assert_qmp(result, 'error/class', 'GenericError')
 
 class TestSingleBlockdev(TestSingleDrive):
     qmp_cmd = 'blockdev-mirror'
     qmp_target = 'node1'
-    not_found_error = 'GenericError'
 
     def setUp(self):
         TestSingleDrive.setUp(self)
@@ -922,7 +920,7 @@  class TestRepairQuorum(iotests.QMPTestCase):
                              node_name='repair0',
                              replaces='img1',
                              target=quorum_repair_img, format=iotests.imgfmt)
-        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
+        self.assert_qmp(result, 'error/class', 'GenericError')
 
     def test_wrong_sync_mode(self):
         if not self.has_quorum():