diff mbox

[v8,01/15] block: Add "file" output parameter to block status query functions

Message ID 1453689887-2567-2-git-send-email-famz@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Fam Zheng Jan. 25, 2016, 2:44 a.m. UTC
The added parameter can be used to return the BDS pointer which the
valid offset is referring to. Its value should be ignored unless
BDRV_BLOCK_OFFSET_VALID in ret is set.

Until block drivers fill in the right value, let's clear it explicitly
right before calling .bdrv_get_block_status.

The "bs->file" condition in bdrv_co_get_block_status is kept now to keep iotest
case 102 passing, and will be fixed once all drivers return the right file
pointer.

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/io.c                | 38 ++++++++++++++++++++++++++------------
 block/iscsi.c             |  6 ++++--
 block/mirror.c            |  3 ++-
 block/parallels.c         |  2 +-
 block/qcow.c              |  2 +-
 block/qcow2.c             |  2 +-
 block/qed.c               |  3 ++-
 block/raw-posix.c         |  3 ++-
 block/raw_bsd.c           |  3 ++-
 block/sheepdog.c          |  2 +-
 block/vdi.c               |  2 +-
 block/vmdk.c              |  2 +-
 block/vpc.c               |  2 +-
 block/vvfat.c             |  2 +-
 include/block/block.h     | 11 +++++++----
 include/block/block_int.h |  3 ++-
 qemu-img.c                | 13 +++++++++----
 17 files changed, 64 insertions(+), 35 deletions(-)

Comments

Kevin Wolf Jan. 25, 2016, 1:04 p.m. UTC | #1
Am 25.01.2016 um 03:44 hat Fam Zheng geschrieben:
> The added parameter can be used to return the BDS pointer which the
> valid offset is referring to. Its value should be ignored unless
> BDRV_BLOCK_OFFSET_VALID in ret is set.
> 
> Until block drivers fill in the right value, let's clear it explicitly
> right before calling .bdrv_get_block_status.
> 
> The "bs->file" condition in bdrv_co_get_block_status is kept now to keep iotest
> case 102 passing, and will be fixed once all drivers return the right file
> pointer.
> 
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> ---
>  block/io.c                | 38 ++++++++++++++++++++++++++------------
>  block/iscsi.c             |  6 ++++--
>  block/mirror.c            |  3 ++-
>  block/parallels.c         |  2 +-
>  block/qcow.c              |  2 +-
>  block/qcow2.c             |  2 +-
>  block/qed.c               |  3 ++-
>  block/raw-posix.c         |  3 ++-
>  block/raw_bsd.c           |  3 ++-
>  block/sheepdog.c          |  2 +-
>  block/vdi.c               |  2 +-
>  block/vmdk.c              |  2 +-
>  block/vpc.c               |  2 +-
>  block/vvfat.c             |  2 +-
>  include/block/block.h     | 11 +++++++----
>  include/block/block_int.h |  3 ++-
>  qemu-img.c                | 13 +++++++++----
>  17 files changed, 64 insertions(+), 35 deletions(-)
> 
> diff --git a/block/io.c b/block/io.c
> index 5bb353a..0836991 100644
> --- a/block/io.c
> +++ b/block/io.c
> @@ -664,6 +664,7 @@ int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
>  int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
>  {
>      int64_t target_sectors, ret, nb_sectors, sector_num = 0;
> +    BlockDriverState *file;
>      int n;
>  
>      target_sectors = bdrv_nb_sectors(bs);
> @@ -676,7 +677,7 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
>          if (nb_sectors <= 0) {
>              return 0;
>          }
> -        ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n);
> +        ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, &file);
>          if (ret < 0) {
>              error_report("error getting block status at sector %" PRId64 ": %s",
>                           sector_num, strerror(-ret));
> @@ -1466,6 +1467,7 @@ int bdrv_flush_all(void)
>  typedef struct BdrvCoGetBlockStatusData {
>      BlockDriverState *bs;
>      BlockDriverState *base;
> +    BlockDriverState **file;
>      int64_t sector_num;
>      int nb_sectors;
>      int *pnum;
> @@ -1490,7 +1492,8 @@ typedef struct BdrvCoGetBlockStatusData {
>   */
>  static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
>                                                       int64_t sector_num,
> -                                                     int nb_sectors, int *pnum)
> +                                                     int nb_sectors, int *pnum,
> +                                                     BlockDriverState **file)

This function has a comment explaining all parameters. Except **file
now.

My impression at the moment is that it generally returns bs->file for
format drivers and bs itself for protocol drivers if the sector is
allocated in this layer.

>  {
>      int64_t total_sectors;
>      int64_t n;
> @@ -1520,16 +1523,19 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
>          return ret;
>      }
>  
> -    ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum);
> +    *file = NULL;
> +    ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum,
> +                                            file);
>      if (ret < 0) {
>          *pnum = 0;
> +        *file = NULL;

You specified that file is to be ignored unless BDRV_BLOCK_OFFSET_VALID
is set. Why reset it here then? It's not reset in other error cases.

>          return ret;
>      }
>  
>      if (ret & BDRV_BLOCK_RAW) {
>          assert(ret & BDRV_BLOCK_OFFSET_VALID);
>          return bdrv_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
> -                                     *pnum, pnum);
> +                                     *pnum, pnum, file);
>      }
>  
>      if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {

> diff --git a/block/vvfat.c b/block/vvfat.c
> index 2ea5a4a..b8d29e1 100644
> --- a/block/vvfat.c
> +++ b/block/vvfat.c
> @@ -2884,7 +2884,7 @@ static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
>  }
>  
>  static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs,
> -	int64_t sector_num, int nb_sectors, int* n)
> +	int64_t sector_num, int nb_sectors, int *n, BlockDriverState **file)
>  {
>      BDRVVVFATState* s = bs->opaque;
>      *n = s->sector_count - sector_num;

This still returns NULL at the end of the series. Shouldn't it return bs
like other protocol drivers do?

Kevin
Fam Zheng Jan. 26, 2016, 3:27 a.m. UTC | #2
On Mon, 01/25 14:04, Kevin Wolf wrote:
> Am 25.01.2016 um 03:44 hat Fam Zheng geschrieben:
> > The added parameter can be used to return the BDS pointer which the
> > valid offset is referring to. Its value should be ignored unless
> > BDRV_BLOCK_OFFSET_VALID in ret is set.
> > 
> > Until block drivers fill in the right value, let's clear it explicitly
> > right before calling .bdrv_get_block_status.
> > 
> > The "bs->file" condition in bdrv_co_get_block_status is kept now to keep iotest
> > case 102 passing, and will be fixed once all drivers return the right file
> > pointer.
> > 
> > Signed-off-by: Fam Zheng <famz@redhat.com>
> > Reviewed-by: Max Reitz <mreitz@redhat.com>
> > ---
> >  block/io.c                | 38 ++++++++++++++++++++++++++------------
> >  block/iscsi.c             |  6 ++++--
> >  block/mirror.c            |  3 ++-
> >  block/parallels.c         |  2 +-
> >  block/qcow.c              |  2 +-
> >  block/qcow2.c             |  2 +-
> >  block/qed.c               |  3 ++-
> >  block/raw-posix.c         |  3 ++-
> >  block/raw_bsd.c           |  3 ++-
> >  block/sheepdog.c          |  2 +-
> >  block/vdi.c               |  2 +-
> >  block/vmdk.c              |  2 +-
> >  block/vpc.c               |  2 +-
> >  block/vvfat.c             |  2 +-
> >  include/block/block.h     | 11 +++++++----
> >  include/block/block_int.h |  3 ++-
> >  qemu-img.c                | 13 +++++++++----
> >  17 files changed, 64 insertions(+), 35 deletions(-)
> > 
> > diff --git a/block/io.c b/block/io.c
> > index 5bb353a..0836991 100644
> > --- a/block/io.c
> > +++ b/block/io.c
> > @@ -664,6 +664,7 @@ int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
> >  int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
> >  {
> >      int64_t target_sectors, ret, nb_sectors, sector_num = 0;
> > +    BlockDriverState *file;
> >      int n;
> >  
> >      target_sectors = bdrv_nb_sectors(bs);
> > @@ -676,7 +677,7 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
> >          if (nb_sectors <= 0) {
> >              return 0;
> >          }
> > -        ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n);
> > +        ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, &file);
> >          if (ret < 0) {
> >              error_report("error getting block status at sector %" PRId64 ": %s",
> >                           sector_num, strerror(-ret));
> > @@ -1466,6 +1467,7 @@ int bdrv_flush_all(void)
> >  typedef struct BdrvCoGetBlockStatusData {
> >      BlockDriverState *bs;
> >      BlockDriverState *base;
> > +    BlockDriverState **file;
> >      int64_t sector_num;
> >      int nb_sectors;
> >      int *pnum;
> > @@ -1490,7 +1492,8 @@ typedef struct BdrvCoGetBlockStatusData {
> >   */
> >  static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
> >                                                       int64_t sector_num,
> > -                                                     int nb_sectors, int *pnum)
> > +                                                     int nb_sectors, int *pnum,
> > +                                                     BlockDriverState **file)
> 
> This function has a comment explaining all parameters. Except **file
> now.

Will add comment for @file too.

> 
> My impression at the moment is that it generally returns bs->file for
> format drivers and bs itself for protocol drivers if the sector is
> allocated in this layer.

Yes.

> 
> >  {
> >      int64_t total_sectors;
> >      int64_t n;
> > @@ -1520,16 +1523,19 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
> >          return ret;
> >      }
> >  
> > -    ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum);
> > +    *file = NULL;
> > +    ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum,
> > +                                            file);
> >      if (ret < 0) {
> >          *pnum = 0;
> > +        *file = NULL;
> 
> You specified that file is to be ignored unless BDRV_BLOCK_OFFSET_VALID
> is set. Why reset it here then? It's not reset in other error cases.

No particular reason, and it can be safely removed.

> 
> >          return ret;
> >      }
> >  
> >      if (ret & BDRV_BLOCK_RAW) {
> >          assert(ret & BDRV_BLOCK_OFFSET_VALID);
> >          return bdrv_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
> > -                                     *pnum, pnum);
> > +                                     *pnum, pnum, file);
> >      }
> >  
> >      if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
> 
> > diff --git a/block/vvfat.c b/block/vvfat.c
> > index 2ea5a4a..b8d29e1 100644
> > --- a/block/vvfat.c
> > +++ b/block/vvfat.c
> > @@ -2884,7 +2884,7 @@ static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
> >  }
> >  
> >  static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs,
> > -	int64_t sector_num, int nb_sectors, int* n)
> > +	int64_t sector_num, int nb_sectors, int *n, BlockDriverState **file)
> >  {
> >      BDRVVVFATState* s = bs->opaque;
> >      *n = s->sector_count - sector_num;
> 
> This still returns NULL at the end of the series. Shouldn't it return bs
> like other protocol drivers do?

Yes, we need another patch for vvfat.

Thanks!

Fam
Fam Zheng Jan. 26, 2016, 3:36 a.m. UTC | #3
On Tue, 01/26 11:27, Fam Zheng wrote:
> On Mon, 01/25 14:04, Kevin Wolf wrote:
> > Am 25.01.2016 um 03:44 hat Fam Zheng geschrieben:
> > > diff --git a/block/vvfat.c b/block/vvfat.c
> > > index 2ea5a4a..b8d29e1 100644
> > > --- a/block/vvfat.c
> > > +++ b/block/vvfat.c
> > > @@ -2884,7 +2884,7 @@ static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
> > >  }
> > >  
> > >  static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs,
> > > -	int64_t sector_num, int nb_sectors, int* n)
> > > +	int64_t sector_num, int nb_sectors, int *n, BlockDriverState **file)
> > >  {
> > >      BDRVVVFATState* s = bs->opaque;
> > >      *n = s->sector_count - sector_num;
> > 
> > This still returns NULL at the end of the series. Shouldn't it return bs
> > like other protocol drivers do?
> 
> Yes, we need another patch for vvfat.

No, I now remember why vvfat didn't need a patch: it never sets the
BDRV_BLOCK_OFFSET_VALID bit.

Fam
diff mbox

Patch

diff --git a/block/io.c b/block/io.c
index 5bb353a..0836991 100644
--- a/block/io.c
+++ b/block/io.c
@@ -664,6 +664,7 @@  int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
 int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
 {
     int64_t target_sectors, ret, nb_sectors, sector_num = 0;
+    BlockDriverState *file;
     int n;
 
     target_sectors = bdrv_nb_sectors(bs);
@@ -676,7 +677,7 @@  int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
         if (nb_sectors <= 0) {
             return 0;
         }
-        ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n);
+        ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n, &file);
         if (ret < 0) {
             error_report("error getting block status at sector %" PRId64 ": %s",
                          sector_num, strerror(-ret));
@@ -1466,6 +1467,7 @@  int bdrv_flush_all(void)
 typedef struct BdrvCoGetBlockStatusData {
     BlockDriverState *bs;
     BlockDriverState *base;
+    BlockDriverState **file;
     int64_t sector_num;
     int nb_sectors;
     int *pnum;
@@ -1490,7 +1492,8 @@  typedef struct BdrvCoGetBlockStatusData {
  */
 static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
                                                      int64_t sector_num,
-                                                     int nb_sectors, int *pnum)
+                                                     int nb_sectors, int *pnum,
+                                                     BlockDriverState **file)
 {
     int64_t total_sectors;
     int64_t n;
@@ -1520,16 +1523,19 @@  static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
         return ret;
     }
 
-    ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum);
+    *file = NULL;
+    ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum,
+                                            file);
     if (ret < 0) {
         *pnum = 0;
+        *file = NULL;
         return ret;
     }
 
     if (ret & BDRV_BLOCK_RAW) {
         assert(ret & BDRV_BLOCK_OFFSET_VALID);
         return bdrv_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
-                                     *pnum, pnum);
+                                     *pnum, pnum, file);
     }
 
     if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
@@ -1549,10 +1555,11 @@  static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
     if (bs->file &&
         (ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
         (ret & BDRV_BLOCK_OFFSET_VALID)) {
+        BlockDriverState *file2;
         int file_pnum;
 
         ret2 = bdrv_co_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
-                                        *pnum, &file_pnum);
+                                        *pnum, &file_pnum, &file2);
         if (ret2 >= 0) {
             /* Ignore errors.  This is just providing extra information, it
              * is useful but not necessary.
@@ -1577,14 +1584,15 @@  static int64_t coroutine_fn bdrv_co_get_block_status_above(BlockDriverState *bs,
         BlockDriverState *base,
         int64_t sector_num,
         int nb_sectors,
-        int *pnum)
+        int *pnum,
+        BlockDriverState **file)
 {
     BlockDriverState *p;
     int64_t ret = 0;
 
     assert(bs != base);
     for (p = bs; p != base; p = backing_bs(p)) {
-        ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum);
+        ret = bdrv_co_get_block_status(p, sector_num, nb_sectors, pnum, file);
         if (ret < 0 || ret & BDRV_BLOCK_ALLOCATED) {
             break;
         }
@@ -1603,7 +1611,8 @@  static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
     data->ret = bdrv_co_get_block_status_above(data->bs, data->base,
                                                data->sector_num,
                                                data->nb_sectors,
-                                               data->pnum);
+                                               data->pnum,
+                                               data->file);
     data->done = true;
 }
 
@@ -1615,12 +1624,14 @@  static void coroutine_fn bdrv_get_block_status_above_co_entry(void *opaque)
 int64_t bdrv_get_block_status_above(BlockDriverState *bs,
                                     BlockDriverState *base,
                                     int64_t sector_num,
-                                    int nb_sectors, int *pnum)
+                                    int nb_sectors, int *pnum,
+                                    BlockDriverState **file)
 {
     Coroutine *co;
     BdrvCoGetBlockStatusData data = {
         .bs = bs,
         .base = base,
+        .file = file,
         .sector_num = sector_num,
         .nb_sectors = nb_sectors,
         .pnum = pnum,
@@ -1644,16 +1655,19 @@  int64_t bdrv_get_block_status_above(BlockDriverState *bs,
 
 int64_t bdrv_get_block_status(BlockDriverState *bs,
                               int64_t sector_num,
-                              int nb_sectors, int *pnum)
+                              int nb_sectors, int *pnum,
+                              BlockDriverState **file)
 {
     return bdrv_get_block_status_above(bs, backing_bs(bs),
-                                       sector_num, nb_sectors, pnum);
+                                       sector_num, nb_sectors, pnum, file);
 }
 
 int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
                                    int nb_sectors, int *pnum)
 {
-    int64_t ret = bdrv_get_block_status(bs, sector_num, nb_sectors, pnum);
+    BlockDriverState *file;
+    int64_t ret = bdrv_get_block_status(bs, sector_num, nb_sectors, pnum,
+                                        &file);
     if (ret < 0) {
         return ret;
     }
diff --git a/block/iscsi.c b/block/iscsi.c
index bffd707..e182557 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -532,7 +532,8 @@  static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
 
 static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
                                                   int64_t sector_num,
-                                                  int nb_sectors, int *pnum)
+                                                  int nb_sectors, int *pnum,
+                                                  BlockDriverState **file)
 {
     IscsiLun *iscsilun = bs->opaque;
     struct scsi_get_lba_status *lbas = NULL;
@@ -650,7 +651,8 @@  static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
         !iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
         int64_t ret;
         int pnum;
-        ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum);
+        BlockDriverState *file;
+        ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum, &file);
         if (ret < 0) {
             return ret;
         }
diff --git a/block/mirror.c b/block/mirror.c
index e9e151c..2c0edfa 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -168,6 +168,7 @@  static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
     MirrorOp *op;
     int pnum;
     int64_t ret;
+    BlockDriverState *file;
 
     max_iov = MIN(source->bl.max_iov, s->target->bl.max_iov);
 
@@ -306,7 +307,7 @@  static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
     trace_mirror_one_iteration(s, sector_num, nb_sectors);
 
     ret = bdrv_get_block_status_above(source, NULL, sector_num,
-                                      nb_sectors, &pnum);
+                                      nb_sectors, &pnum, &file);
     if (ret < 0 || pnum < nb_sectors ||
             (ret & BDRV_BLOCK_DATA && !(ret & BDRV_BLOCK_ZERO))) {
         bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
diff --git a/block/parallels.c b/block/parallels.c
index ee39081..e2de308 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -261,7 +261,7 @@  static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs)
 
 
 static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
-        int64_t sector_num, int nb_sectors, int *pnum)
+        int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
 {
     BDRVParallelsState *s = bs->opaque;
     int64_t offset;
diff --git a/block/qcow.c b/block/qcow.c
index afed18f..4202797 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -489,7 +489,7 @@  static uint64_t get_cluster_offset(BlockDriverState *bs,
 }
 
 static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
-        int64_t sector_num, int nb_sectors, int *pnum)
+        int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
 {
     BDRVQcowState *s = bs->opaque;
     int index_in_cluster, n;
diff --git a/block/qcow2.c b/block/qcow2.c
index fd8436c..d4ea6b4 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1330,7 +1330,7 @@  static void qcow2_join_options(QDict *options, QDict *old_options)
 }
 
 static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs,
-        int64_t sector_num, int nb_sectors, int *pnum)
+        int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
 {
     BDRVQcow2State *s = bs->opaque;
     uint64_t cluster_offset;
diff --git a/block/qed.c b/block/qed.c
index 0c870cd..8f6f841 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -725,7 +725,8 @@  static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t l
 
 static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs,
                                                  int64_t sector_num,
-                                                 int nb_sectors, int *pnum)
+                                                 int nb_sectors, int *pnum,
+                                                 BlockDriverState **file)
 {
     BDRVQEDState *s = bs->opaque;
     size_t len = (size_t)nb_sectors * BDRV_SECTOR_SIZE;
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 6df3067..3ef9b25 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1818,7 +1818,8 @@  static int find_allocation(BlockDriverState *bs, off_t start,
  */
 static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
                                                     int64_t sector_num,
-                                                    int nb_sectors, int *pnum)
+                                                    int nb_sectors, int *pnum,
+                                                    BlockDriverState **file)
 {
     off_t start, data = 0, hole = 0;
     int64_t total_size;
diff --git a/block/raw_bsd.c b/block/raw_bsd.c
index bcaee11..9a8933b 100644
--- a/block/raw_bsd.c
+++ b/block/raw_bsd.c
@@ -115,7 +115,8 @@  fail:
 
 static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
                                             int64_t sector_num,
-                                            int nb_sectors, int *pnum)
+                                            int nb_sectors, int *pnum,
+                                            BlockDriverState **file)
 {
     *pnum = nb_sectors;
     return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_DATA |
diff --git a/block/sheepdog.c b/block/sheepdog.c
index ff89298..2ea05a6 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -2708,7 +2708,7 @@  retry:
 
 static coroutine_fn int64_t
 sd_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
-                       int *pnum)
+                       int *pnum, BlockDriverState **file)
 {
     BDRVSheepdogState *s = bs->opaque;
     SheepdogInode *inode = &s->inode;
diff --git a/block/vdi.c b/block/vdi.c
index 61bcd54..294c438 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -527,7 +527,7 @@  static int vdi_reopen_prepare(BDRVReopenState *state,
 }
 
 static int64_t coroutine_fn vdi_co_get_block_status(BlockDriverState *bs,
-        int64_t sector_num, int nb_sectors, int *pnum)
+        int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
 {
     /* TODO: Check for too large sector_num (in bdrv_is_allocated or here). */
     BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
diff --git a/block/vmdk.c b/block/vmdk.c
index 698679d..e1d3e27 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1257,7 +1257,7 @@  static inline uint64_t vmdk_find_index_in_cluster(VmdkExtent *extent,
 }
 
 static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
-        int64_t sector_num, int nb_sectors, int *pnum)
+        int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
 {
     BDRVVmdkState *s = bs->opaque;
     int64_t index_in_cluster, n, ret;
diff --git a/block/vpc.c b/block/vpc.c
index d852f96..a070307 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -579,7 +579,7 @@  static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num,
 }
 
 static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
-        int64_t sector_num, int nb_sectors, int *pnum)
+        int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
 {
     BDRVVPCState *s = bs->opaque;
     VHDFooter *footer = (VHDFooter*) s->footer_buf;
diff --git a/block/vvfat.c b/block/vvfat.c
index 2ea5a4a..b8d29e1 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -2884,7 +2884,7 @@  static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num,
 }
 
 static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs,
-	int64_t sector_num, int nb_sectors, int* n)
+	int64_t sector_num, int nb_sectors, int *n, BlockDriverState **file)
 {
     BDRVVVFATState* s = bs->opaque;
     *n = s->sector_count - sector_num;
diff --git a/include/block/block.h b/include/block/block.h
index 25f36dc..ee845a9 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -111,9 +111,10 @@  typedef struct HDGeometry {
 
 /*
  * Allocation status flags
- * BDRV_BLOCK_DATA: data is read from bs->file or another file
+ * BDRV_BLOCK_DATA: data is read from a file returned by bdrv_get_block_status.
  * BDRV_BLOCK_ZERO: sectors read as zero
- * BDRV_BLOCK_OFFSET_VALID: sector stored in bs->file as raw data
+ * BDRV_BLOCK_OFFSET_VALID: sector stored as raw data in a file returned by
+ *                          bdrv_get_block_status.
  * BDRV_BLOCK_ALLOCATED: the content of the block is determined by this
  *                       layer (as opposed to the backing file)
  * BDRV_BLOCK_RAW: used internally to indicate that the request
@@ -386,11 +387,13 @@  int bdrv_has_zero_init(BlockDriverState *bs);
 bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs);
 bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
 int64_t bdrv_get_block_status(BlockDriverState *bs, int64_t sector_num,
-                              int nb_sectors, int *pnum);
+                              int nb_sectors, int *pnum,
+                              BlockDriverState **file);
 int64_t bdrv_get_block_status_above(BlockDriverState *bs,
                                     BlockDriverState *base,
                                     int64_t sector_num,
-                                    int nb_sectors, int *pnum);
+                                    int nb_sectors, int *pnum,
+                                    BlockDriverState **file);
 int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
                       int *pnum);
 int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 428fa33..5fa58e8 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -166,7 +166,8 @@  struct BlockDriver {
     int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs,
         int64_t sector_num, int nb_sectors);
     int64_t coroutine_fn (*bdrv_co_get_block_status)(BlockDriverState *bs,
-        int64_t sector_num, int nb_sectors, int *pnum);
+        int64_t sector_num, int nb_sectors, int *pnum,
+        BlockDriverState **file);
 
     /*
      * Invalidate any cached meta-data.
diff --git a/qemu-img.c b/qemu-img.c
index 33e451c..e653b2f 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1072,13 +1072,15 @@  static int img_compare(int argc, char **argv)
 
     for (;;) {
         int64_t status1, status2;
+        BlockDriverState *file;
+
         nb_sectors = sectors_to_process(total_sectors, sector_num);
         if (nb_sectors <= 0) {
             break;
         }
         status1 = bdrv_get_block_status_above(bs1, NULL, sector_num,
                                               total_sectors1 - sector_num,
-                                              &pnum1);
+                                              &pnum1, &file);
         if (status1 < 0) {
             ret = 3;
             error_report("Sector allocation test failed for %s", filename1);
@@ -1088,7 +1090,7 @@  static int img_compare(int argc, char **argv)
 
         status2 = bdrv_get_block_status_above(bs2, NULL, sector_num,
                                               total_sectors2 - sector_num,
-                                              &pnum2);
+                                              &pnum2, &file);
         if (status2 < 0) {
             ret = 3;
             error_report("Sector allocation test failed for %s", filename2);
@@ -1271,9 +1273,10 @@  static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
     n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
 
     if (s->sector_next_status <= sector_num) {
+        BlockDriverState *file;
         ret = bdrv_get_block_status(blk_bs(s->src[s->src_cur]),
                                     sector_num - s->src_cur_offset,
-                                    n, &n);
+                                    n, &n, &file);
         if (ret < 0) {
             return ret;
         }
@@ -2201,6 +2204,7 @@  static int get_block_status(BlockDriverState *bs, int64_t sector_num,
 {
     int64_t ret;
     int depth;
+    BlockDriverState *file;
 
     /* As an optimization, we could cache the current range of unallocated
      * clusters in each file of the chain, and avoid querying the same
@@ -2209,7 +2213,8 @@  static int get_block_status(BlockDriverState *bs, int64_t sector_num,
 
     depth = 0;
     for (;;) {
-        ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &nb_sectors);
+        ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &nb_sectors,
+                                    &file);
         if (ret < 0) {
             return ret;
         }