diff mbox

[v2,1/3] block: pass bdrv_* methods to bs->file by default

Message ID 20170629184320.7151-2-el13635@mail.ntua.gr (mailing list archive)
State New, archived
Headers show

Commit Message

Manos Pitsidianakis June 29, 2017, 6:43 p.m. UTC
The following functions fail if bs->drv does not implement them:

bdrv_probe_blocksizes
bdrv_probe_geometry
bdrv_truncate
bdrv_has_zero_init
bdrv_get_info
bdrv_media_changed
bdrv_eject
bdrv_lock_medium
bdrv_co_ioctl

Instead, the call should be passed to bs->file if it exists, to allow
filter drivers to support those methods without implementing them.

Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
---
 block.c    | 27 +++++++++++++++++++++++++--
 block/io.c |  5 +++++
 2 files changed, 30 insertions(+), 2 deletions(-)

Comments

Eric Blake July 3, 2017, 3:56 p.m. UTC | #1
On 06/29/2017 01:43 PM, Manos Pitsidianakis wrote:
> The following functions fail if bs->drv does not implement them:
> 
> bdrv_probe_blocksizes
> bdrv_probe_geometry
> bdrv_truncate
> bdrv_has_zero_init
> bdrv_get_info
> bdrv_media_changed
> bdrv_eject
> bdrv_lock_medium
> bdrv_co_ioctl
> 
> Instead, the call should be passed to bs->file if it exists, to allow
> filter drivers to support those methods without implementing them.
> 
> Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
> ---
>  block.c    | 27 +++++++++++++++++++++++++--
>  block/io.c |  5 +++++
>  2 files changed, 30 insertions(+), 2 deletions(-)

Did you check whether any other existing drivers can be cleaned up to
rely on the defaults?  Or is it just the raw driver that you cleaned in 2/3?

At any rate, this makes sense to me.  However,

> @@ -4205,6 +4222,8 @@ int bdrv_media_changed(BlockDriverState *bs)
>  
>      if (drv && drv->bdrv_media_changed) {
>          return drv->bdrv_media_changed(bs);
> +    } else if (drv && bs->file && bs->file->bs) {
> +        bdrv_media_changed(bs->file->bs);
>      }
>      return -ENOTSUP;

This one returns -ENOTSUP unconditionally after recursing; looks like
you omitted 'return'.

If that's the only fix you make for v3, you can add:
Reviewed-by: Eric Blake <eblake@redhat.com>
Eric Blake July 3, 2017, 6:40 p.m. UTC | #2
On 07/03/2017 10:56 AM, Eric Blake wrote:
> On 06/29/2017 01:43 PM, Manos Pitsidianakis wrote:
>> The following functions fail if bs->drv does not implement them:

One other suggestion: most patches in the tree use 'topic: Capital',
while yours used 'topic: lowercase'.  It's probably worth posting a v3
that addresses all of the nits I've pointed out, including tweaking the
commit messages.
Stefan Hajnoczi July 6, 2017, 8:40 a.m. UTC | #3
On Mon, Jul 03, 2017 at 01:40:57PM -0500, Eric Blake wrote:
> On 07/03/2017 10:56 AM, Eric Blake wrote:
> > On 06/29/2017 01:43 PM, Manos Pitsidianakis wrote:
> >> The following functions fail if bs->drv does not implement them:
> 
> One other suggestion: most patches in the tree use 'topic: Capital',
> while yours used 'topic: lowercase'.  It's probably worth posting a v3
> that addresses all of the nits I've pointed out, including tweaking the
> commit messages.

Plenty of regular contributors use "topic: lowercase" including Michael
Tsirkin, Mark Cave-Ayland, Peter Xu, and myself (just from looking at
the first page of git log --oneline on qemu.git/master).

If we want to enforce a consistent style in the future then it should be
discussed separately.
Stefan Hajnoczi July 6, 2017, 9:09 a.m. UTC | #4
On Thu, Jun 29, 2017 at 09:43:18PM +0300, Manos Pitsidianakis wrote:
> diff --git a/block.c b/block.c
> index 69439628..9e8d34ad 100644
> --- a/block.c
> +++ b/block.c
> @@ -494,6 +494,8 @@ int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
>  
>      if (drv && drv->bdrv_probe_blocksizes) {
>          return drv->bdrv_probe_blocksizes(bs, bsz);
> +    } else if (drv && bs->file && bs->file->bs) {
> +        return bdrv_probe_blocksizes(bs->file->bs, bsz);
>      }
>  
>      return -ENOTSUP;

Currently only raw-format.c and file-posix.c implement
bdrv_probe_blocksizes().  qcow2 will start reporting bs->file's
blocksizes after this patch.

This can lead to a change in blocksizes when live migrating from an old
QEMU to a new QEMU.  Guest operating systems and applications can be
confused if the device suddenly changes beneath them.

On the other hand, it's already possible to hit that today by migrating
from a raw image to a qcow2 image.

I think this change makes sense - we should propagate blocksizes through
the graph - but it may introduce an incompatibility.

Kevin: Do you think this is safe?

> @@ -3406,11 +3410,15 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp)
>  
>      assert(child->perm & BLK_PERM_RESIZE);
>  
> +    /* if bs->drv == NULL, bs is closed, so there's nothing to do here */
>      if (!drv) {
>          error_setg(errp, "No medium inserted");
>          return -ENOMEDIUM;
>      }
>      if (!drv->bdrv_truncate) {
> +        if (bs->file && bs->file->bs) {
> +            return bdrv_truncate(bs->file, offset, errp);
> +        }
>          error_setg(errp, "Image format driver does not support resize");
>          return -ENOTSUP;
>      }

This is not safe because existing image formats (e.g. vmdk, dmg) do not
implement .bdrv_truncate().  If we begin truncating the underlying host
file ("foo.vmdk") the disk image will be corrupted.

It is only safe to forward .bdrv_truncate() in filter drivers.  I
suggest providing a default implementation instead:

int bdrv_truncate_file(...);

Then filters can do:

  .bdrv_truncate = bdrv_truncate_file,

> diff --git a/block/io.c b/block/io.c
> index c72d7015..a1aee01d 100644
> --- a/block/io.c
> +++ b/block/io.c
> @@ -2401,6 +2401,11 @@ int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf)
>      };
>      BlockAIOCB *acb;
>  
> +    if (drv && !drv->bdrv_aio_ioctl && !drv->bdrv_co_ioctl &&
> +        bs->file && bs->file->bs) {
> +        return bdrv_co_ioctl(bs->file->bs, req, buf);
> +    }
> +
>      bdrv_inc_in_flight(bs);
>      if (!drv || (!drv->bdrv_aio_ioctl && !drv->bdrv_co_ioctl)) {
>          co.ret = -ENOTSUP;

This operation cannot be allowed by default for the same reason as
.bdrv_truncate().  It could change the host file in ways that the format
driver can't handle.  A separate function is needed here:
bdrv_co_ioctl_file().
diff mbox

Patch

diff --git a/block.c b/block.c
index 69439628..9e8d34ad 100644
--- a/block.c
+++ b/block.c
@@ -494,6 +494,8 @@  int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
 
     if (drv && drv->bdrv_probe_blocksizes) {
         return drv->bdrv_probe_blocksizes(bs, bsz);
+    } else if (drv && bs->file && bs->file->bs) {
+        return bdrv_probe_blocksizes(bs->file->bs, bsz);
     }
 
     return -ENOTSUP;
@@ -511,6 +513,8 @@  int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
 
     if (drv && drv->bdrv_probe_geometry) {
         return drv->bdrv_probe_geometry(bs, geo);
+    } else if (drv && bs->file && bs->file->bs) {
+        return bdrv_probe_geometry(bs->file->bs, geo);
     }
 
     return -ENOTSUP;
@@ -3406,11 +3410,15 @@  int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp)
 
     assert(child->perm & BLK_PERM_RESIZE);
 
+    /* if bs->drv == NULL, bs is closed, so there's nothing to do here */
     if (!drv) {
         error_setg(errp, "No medium inserted");
         return -ENOMEDIUM;
     }
     if (!drv->bdrv_truncate) {
+        if (bs->file && bs->file->bs) {
+            return bdrv_truncate(bs->file, offset, errp);
+        }
         error_setg(errp, "Image format driver does not support resize");
         return -ENOTSUP;
     }
@@ -3778,6 +3786,9 @@  int bdrv_has_zero_init(BlockDriverState *bs)
     if (bs->drv->bdrv_has_zero_init) {
         return bs->drv->bdrv_has_zero_init(bs);
     }
+    if (bs->file && bs->file->bs) {
+        return bdrv_has_zero_init(bs->file->bs);
+    }
 
     /* safe default */
     return 0;
@@ -3832,10 +3843,16 @@  void bdrv_get_backing_filename(BlockDriverState *bs,
 int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 {
     BlockDriver *drv = bs->drv;
-    if (!drv)
+    /* if bs->drv == NULL, bs is closed, so there's nothing to do here */
+    if (!drv) {
         return -ENOMEDIUM;
-    if (!drv->bdrv_get_info)
+    }
+    if (!drv->bdrv_get_info) {
+        if (bs->file && bs->file->bs) {
+            return bdrv_get_info(bs->file->bs, bdi);
+        }
         return -ENOTSUP;
+    }
     memset(bdi, 0, sizeof(*bdi));
     return drv->bdrv_get_info(bs, bdi);
 }
@@ -4205,6 +4222,8 @@  int bdrv_media_changed(BlockDriverState *bs)
 
     if (drv && drv->bdrv_media_changed) {
         return drv->bdrv_media_changed(bs);
+    } else if (drv && bs->file && bs->file->bs) {
+        bdrv_media_changed(bs->file->bs);
     }
     return -ENOTSUP;
 }
@@ -4218,6 +4237,8 @@  void bdrv_eject(BlockDriverState *bs, bool eject_flag)
 
     if (drv && drv->bdrv_eject) {
         drv->bdrv_eject(bs, eject_flag);
+    } else if (drv && bs->file && bs->file->bs) {
+        bdrv_eject(bs->file->bs, eject_flag);
     }
 }
 
@@ -4233,6 +4254,8 @@  void bdrv_lock_medium(BlockDriverState *bs, bool locked)
 
     if (drv && drv->bdrv_lock_medium) {
         drv->bdrv_lock_medium(bs, locked);
+    } else if (drv && bs->file && bs->file->bs) {
+        bdrv_lock_medium(bs->file->bs, locked);
     }
 }
 
diff --git a/block/io.c b/block/io.c
index c72d7015..a1aee01d 100644
--- a/block/io.c
+++ b/block/io.c
@@ -2401,6 +2401,11 @@  int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf)
     };
     BlockAIOCB *acb;
 
+    if (drv && !drv->bdrv_aio_ioctl && !drv->bdrv_co_ioctl &&
+        bs->file && bs->file->bs) {
+        return bdrv_co_ioctl(bs->file->bs, req, buf);
+    }
+
     bdrv_inc_in_flight(bs);
     if (!drv || (!drv->bdrv_aio_ioctl && !drv->bdrv_co_ioctl)) {
         co.ret = -ENOTSUP;