diff mbox

[v2,05/16] block: Convert bs->file to BdrvChild

Message ID 1443705214-9304-6-git-send-email-kwolf@redhat.com
State New
Headers show

Commit Message

Kevin Wolf Oct. 1, 2015, 1:13 p.m. UTC
This patch removes the temporary duplication between bs->file and
bs->file_child by converting everything to BdrvChild.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c                   | 63 ++++++++++++++++++++++-------------------------
 block/blkdebug.c          | 32 +++++++++++++-----------
 block/blkverify.c         | 33 ++++++++++++++-----------
 block/bochs.c             |  8 +++---
 block/cloop.c             | 10 ++++----
 block/dmg.c               | 20 +++++++--------
 block/io.c                | 50 ++++++++++++++++++-------------------
 block/parallels.c         | 38 ++++++++++++++--------------
 block/qapi.c              |  2 +-
 block/qcow.c              | 42 ++++++++++++++++---------------
 block/qcow2-cache.c       | 11 +++++----
 block/qcow2-cluster.c     | 38 ++++++++++++++++------------
 block/qcow2-refcount.c    | 45 +++++++++++++++++----------------
 block/qcow2-snapshot.c    | 30 +++++++++++-----------
 block/qcow2.c             | 62 ++++++++++++++++++++++++----------------------
 block/qed-table.c         |  4 +--
 block/qed.c               | 32 ++++++++++++------------
 block/raw_bsd.c           | 40 +++++++++++++++---------------
 block/snapshot.c          | 12 ++++-----
 block/vdi.c               | 17 +++++++------
 block/vhdx-log.c          | 25 ++++++++++---------
 block/vhdx.c              | 36 ++++++++++++++-------------
 block/vmdk.c              | 27 ++++++++++----------
 block/vpc.c               | 34 +++++++++++++------------
 include/block/block.h     |  8 +++++-
 include/block/block_int.h |  3 +--
 26 files changed, 378 insertions(+), 344 deletions(-)

Comments

Max Reitz Oct. 2, 2015, 5:06 p.m. UTC | #1
On 01.10.2015 15:13, Kevin Wolf wrote:
> This patch removes the temporary duplication between bs->file and
> bs->file_child by converting everything to BdrvChild.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c                   | 63 ++++++++++++++++++++++-------------------------
>  block/blkdebug.c          | 32 +++++++++++++-----------
>  block/blkverify.c         | 33 ++++++++++++++-----------
>  block/bochs.c             |  8 +++---
>  block/cloop.c             | 10 ++++----
>  block/dmg.c               | 20 +++++++--------
>  block/io.c                | 50 ++++++++++++++++++-------------------
>  block/parallels.c         | 38 ++++++++++++++--------------
>  block/qapi.c              |  2 +-
>  block/qcow.c              | 42 ++++++++++++++++---------------
>  block/qcow2-cache.c       | 11 +++++----
>  block/qcow2-cluster.c     | 38 ++++++++++++++++------------
>  block/qcow2-refcount.c    | 45 +++++++++++++++++----------------
>  block/qcow2-snapshot.c    | 30 +++++++++++-----------
>  block/qcow2.c             | 62 ++++++++++++++++++++++++----------------------
>  block/qed-table.c         |  4 +--
>  block/qed.c               | 32 ++++++++++++------------
>  block/raw_bsd.c           | 40 +++++++++++++++---------------
>  block/snapshot.c          | 12 ++++-----
>  block/vdi.c               | 17 +++++++------
>  block/vhdx-log.c          | 25 ++++++++++---------
>  block/vhdx.c              | 36 ++++++++++++++-------------
>  block/vmdk.c              | 27 ++++++++++----------
>  block/vpc.c               | 34 +++++++++++++------------
>  include/block/block.h     |  8 +++++-
>  include/block/block_int.h |  3 +--
>  26 files changed, 378 insertions(+), 344 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>
Alberto Garcia Oct. 5, 2015, 12:31 p.m. UTC | #2
On Thu 01 Oct 2015 03:13:23 PM CEST, Kevin Wolf wrote:
> This patch removes the temporary duplication between bs->file and
> bs->file_child by converting everything to BdrvChild.
>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Reviewed-by: Alberto Garcia <berto@igalia.com>

Berto
Fam Zheng Oct. 8, 2015, 10:23 a.m. UTC | #3
On Thu, 10/01 15:13, Kevin Wolf wrote:
> @@ -1935,6 +1932,11 @@ void bdrv_close(BlockDriverState *bs)
>              bdrv_unref(backing_hd);
>          }
>  
> +        if (bs->file != NULL) {
> +            bdrv_unref_child(bs, bs->file);
> +            bs->file = NULL;
> +        }
> +
>          QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
>              /* TODO Remove bdrv_unref() from drivers' close function and use
>               * bdrv_unref_child() here */
> @@ -1946,7 +1948,6 @@ void bdrv_close(BlockDriverState *bs)
>  
>          g_free(bs->opaque);
>          bs->opaque = NULL;
> -        bs->drv = NULL;
>          bs->copy_on_read = 0;
>          bs->backing_file[0] = '\0';
>          bs->backing_format[0] = '\0';
> @@ -1959,11 +1960,6 @@ void bdrv_close(BlockDriverState *bs)
>          bs->options = NULL;
>          QDECREF(bs->full_open_options);
>          bs->full_open_options = NULL;
> -
> -        if (bs->file != NULL) {
> -            bdrv_unref(bs->file);
> -            bs->file = NULL;
> -        }

Why do you need to move them up? Changing bdrv_unref to bdrv_unref_child is not
enough?

>      }
>  
>      if (bs->blk) {
> @@ -2566,7 +2562,7 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
>          return drv->bdrv_get_allocated_file_size(bs);
>      }
>      if (bs->file) {
> -        return bdrv_get_allocated_file_size(bs->file);
> +        return bdrv_get_allocated_file_size(bs->file->bs);
>      }
>      return -ENOTSUP;
>  }
> @@ -3048,7 +3044,7 @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
>                            const char *tag)
>  {
>      while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) {
> -        bs = bs->file;
> +        bs = bs->file ? bs->file->bs : NULL;
>      }
>  
>      if (bs && bs->drv && bs->drv->bdrv_debug_breakpoint) {
> @@ -3061,7 +3057,7 @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
>  int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag)
>  {
>      while (bs && bs->drv && !bs->drv->bdrv_debug_remove_breakpoint) {
> -        bs = bs->file;
> +        bs = bs->file ? bs->file->bs : NULL;
>      }
>  
>      if (bs && bs->drv && bs->drv->bdrv_debug_remove_breakpoint) {
> @@ -3074,7 +3070,7 @@ int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag)
>  int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
>  {
>      while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) {
> -        bs = bs->file;
> +        bs = bs->file ? bs->file->bs : NULL;
>      }
>  
>      if (bs && bs->drv && bs->drv->bdrv_debug_resume) {
> @@ -3087,7 +3083,7 @@ int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
>  bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag)
>  {
>      while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) {
> -        bs = bs->file;
> +        bs = bs->file ? bs->file->bs : NULL;
>      }
>  
>      if (bs && bs->drv && bs->drv->bdrv_debug_is_suspended) {
> @@ -3209,7 +3205,7 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
>      if (bs->drv->bdrv_invalidate_cache) {
>          bs->drv->bdrv_invalidate_cache(bs, &local_err);
>      } else if (bs->file) {
> -        bdrv_invalidate_cache(bs->file, &local_err);
> +        bdrv_invalidate_cache(bs->file->bs, &local_err);
>      }
>      if (local_err) {
>          error_propagate(errp, local_err);
> @@ -3939,7 +3935,7 @@ void bdrv_detach_aio_context(BlockDriverState *bs)
>          bs->drv->bdrv_detach_aio_context(bs);
>      }
>      if (bs->file) {
> -        bdrv_detach_aio_context(bs->file);
> +        bdrv_detach_aio_context(bs->file->bs);
>      }
>      if (bs->backing_hd) {
>          bdrv_detach_aio_context(bs->backing_hd);
> @@ -3963,7 +3959,7 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
>          bdrv_attach_aio_context(bs->backing_hd, new_context);
>      }
>      if (bs->file) {
> -        bdrv_attach_aio_context(bs->file, new_context);
> +        bdrv_attach_aio_context(bs->file->bs, new_context);
>      }
>      if (bs->drv->bdrv_attach_aio_context) {
>          bs->drv->bdrv_attach_aio_context(bs, new_context);
> @@ -4175,7 +4171,7 @@ void bdrv_refresh_filename(BlockDriverState *bs)
>      /* This BDS's file name will most probably depend on its file's name, so
>       * refresh that first */
>      if (bs->file) {
> -        bdrv_refresh_filename(bs->file);
> +        bdrv_refresh_filename(bs->file->bs);
>      }
>  
>      if (drv->bdrv_refresh_filename) {
> @@ -4203,19 +4199,20 @@ void bdrv_refresh_filename(BlockDriverState *bs)
>  
>          /* If no specific options have been given for this BDS, the filename of
>           * the underlying file should suffice for this one as well */
> -        if (bs->file->exact_filename[0] && !has_open_options) {
> -            strcpy(bs->exact_filename, bs->file->exact_filename);
> +        if (bs->file->bs->exact_filename[0] && !has_open_options) {
> +            strcpy(bs->exact_filename, bs->file->bs->exact_filename);
>          }
>          /* Reconstructing the full options QDict is simple for most format block
>           * drivers, as long as the full options are known for the underlying
>           * file BDS. The full options QDict of that file BDS should somehow
>           * contain a representation of the filename, therefore the following
>           * suffices without querying the (exact_)filename of this BDS. */
> -        if (bs->file->full_open_options) {
> +        if (bs->file->bs->full_open_options) {
>              qdict_put_obj(opts, "driver",
>                            QOBJECT(qstring_from_str(drv->format_name)));
> -            QINCREF(bs->file->full_open_options);
> -            qdict_put_obj(opts, "file", QOBJECT(bs->file->full_open_options));
> +            QINCREF(bs->file->bs->full_open_options);
> +            qdict_put_obj(opts, "file",
> +                          QOBJECT(bs->file->bs->full_open_options));
>  
>              bs->full_open_options = opts;
>          } else {
> diff --git a/block/blkdebug.c b/block/blkdebug.c
> index bc247f4..117fce6 100644
> --- a/block/blkdebug.c
> +++ b/block/blkdebug.c
> @@ -427,10 +427,10 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
>      s->state = 1;
>  
>      /* Open the backing file */

Isn't "backing file" a confusing term for bs->file given that we have
bs->backing_hd? :)

> -    assert(bs->file == NULL);
> -    ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image",
> -                          bs, &child_file, false, &local_err);
> -    if (ret < 0) {

Should we keep the assertion?

> +    bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
> +                               bs, &child_file, false, &local_err);
> +    if (local_err) {
> +        ret = -EINVAL;
>          error_propagate(errp, local_err);
>          goto out;
>      }
> @@ -449,7 +449,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
>      goto out;
>  
>  fail_unref:
> -    bdrv_unref(bs->file);
> +    bdrv_unref(bs->file->bs);
>  out:
>      qemu_opts_del(opts);
>      return ret;
> @@ -510,7 +510,8 @@ static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
>          return inject_error(bs, cb, opaque, rule);
>      }
>  
> -    return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
> +    return bdrv_aio_readv(bs->file->bs, sector_num, qiov, nb_sectors,
> +                          cb, opaque);
>  }
>  
>  static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
> @@ -532,7 +533,8 @@ static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
>          return inject_error(bs, cb, opaque, rule);
>      }
>  
> -    return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
> +    return bdrv_aio_writev(bs->file->bs, sector_num, qiov, nb_sectors,
> +                           cb, opaque);
>  }
>  
>  static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
> @@ -551,7 +553,7 @@ static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
>          return inject_error(bs, cb, opaque, rule);
>      }
>  
> -    return bdrv_aio_flush(bs->file, cb, opaque);
> +    return bdrv_aio_flush(bs->file->bs, cb, opaque);
>  }
>  
>  
> @@ -716,12 +718,12 @@ static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
>  
>  static int64_t blkdebug_getlength(BlockDriverState *bs)
>  {
> -    return bdrv_getlength(bs->file);
> +    return bdrv_getlength(bs->file->bs);
>  }
>  
>  static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
>  {
> -    return bdrv_truncate(bs->file, offset);
> +    return bdrv_truncate(bs->file->bs, offset);
>  }
>  
>  static void blkdebug_refresh_filename(BlockDriverState *bs)
> @@ -741,24 +743,24 @@ static void blkdebug_refresh_filename(BlockDriverState *bs)
>          }
>      }
>  
> -    if (force_json && !bs->file->full_open_options) {
> +    if (force_json && !bs->file->bs->full_open_options) {
>          /* The config file cannot be recreated, so creating a plain filename
>           * is impossible */
>          return;
>      }
>  
> -    if (!force_json && bs->file->exact_filename[0]) {
> +    if (!force_json && bs->file->bs->exact_filename[0]) {
>          snprintf(bs->exact_filename, sizeof(bs->exact_filename),
>                   "blkdebug:%s:%s",
>                   qdict_get_try_str(bs->options, "config") ?: "",
> -                 bs->file->exact_filename);
> +                 bs->file->bs->exact_filename);
>      }
>  
>      opts = qdict_new();
>      qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
>  
> -    QINCREF(bs->file->full_open_options);
> -    qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
> +    QINCREF(bs->file->bs->full_open_options);
> +    qdict_put_obj(opts, "image", QOBJECT(bs->file->bs->full_open_options));
>  
>      for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
>          if (strcmp(qdict_entry_key(e), "x-image") &&
> diff --git a/block/blkverify.c b/block/blkverify.c
> index 6b71622..f8655ad 100644
> --- a/block/blkverify.c
> +++ b/block/blkverify.c
> @@ -123,10 +123,10 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
>      }
>  
>      /* Open the raw file */
> -    assert(bs->file == NULL);
> -    ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-raw"), options,
> -                          "raw", bs, &child_file, false, &local_err);
> -    if (ret < 0) {

Same as above, should we keep the assert?

> +    bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw",
> +                               bs, &child_file, false, &local_err);
> +    if (local_err) {
> +        ret = -EINVAL;
>          error_propagate(errp, local_err);
>          goto fail;
>      }
> @@ -238,13 +238,13 @@ static BlockAIOCB *blkverify_aio_readv(BlockDriverState *bs,
>                                              nb_sectors, cb, opaque);
>  
>      acb->verify = blkverify_verify_readv;
> -    acb->buf = qemu_blockalign(bs->file, qiov->size);
> +    acb->buf = qemu_blockalign(bs->file->bs, qiov->size);
>      qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
>      qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
>  
>      bdrv_aio_readv(s->test_file->bs, sector_num, qiov, nb_sectors,
>                     blkverify_aio_cb, acb);
> -    bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
> +    bdrv_aio_readv(bs->file->bs, sector_num, &acb->raw_qiov, nb_sectors,
>                     blkverify_aio_cb, acb);
>      return &acb->common;
>  }
> @@ -259,7 +259,7 @@ static BlockAIOCB *blkverify_aio_writev(BlockDriverState *bs,
>  
>      bdrv_aio_writev(s->test_file->bs, sector_num, qiov, nb_sectors,
>                      blkverify_aio_cb, acb);
> -    bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
> +    bdrv_aio_writev(bs->file->bs, sector_num, qiov, nb_sectors,
>                      blkverify_aio_cb, acb);
>      return &acb->common;
>  }
> @@ -279,7 +279,7 @@ static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
>  {
>      BDRVBlkverifyState *s = bs->opaque;
>  
> -    bool perm = bdrv_recurse_is_first_non_filter(bs->file, candidate);
> +    bool perm = bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
>  
>      if (perm) {
>          return true;
> @@ -308,15 +308,17 @@ static void blkverify_refresh_filename(BlockDriverState *bs)
>  {
>      BDRVBlkverifyState *s = bs->opaque;
>  
> -    /* bs->file has already been refreshed */
> +    /* bs->file->bs has already been refreshed */
>      bdrv_refresh_filename(s->test_file->bs);
>  
> -    if (bs->file->full_open_options && s->test_file->bs->full_open_options) {
> +    if (bs->file->bs->full_open_options
> +        && s->test_file->bs->full_open_options)
> +    {
>          QDict *opts = qdict_new();
>          qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkverify")));
>  
> -        QINCREF(bs->file->full_open_options);
> -        qdict_put_obj(opts, "raw", QOBJECT(bs->file->full_open_options));
> +        QINCREF(bs->file->bs->full_open_options);
> +        qdict_put_obj(opts, "raw", QOBJECT(bs->file->bs->full_open_options));
>          QINCREF(s->test_file->bs->full_open_options);
>          qdict_put_obj(opts, "test",
>                        QOBJECT(s->test_file->bs->full_open_options));
> @@ -324,10 +326,13 @@ static void blkverify_refresh_filename(BlockDriverState *bs)
>          bs->full_open_options = opts;
>      }
>  
> -    if (bs->file->exact_filename[0] && s->test_file->bs->exact_filename[0]) {
> +    if (bs->file->bs->exact_filename[0]
> +        && s->test_file->bs->exact_filename[0])
> +    {
>          snprintf(bs->exact_filename, sizeof(bs->exact_filename),
>                   "blkverify:%s:%s",
> -                 bs->file->exact_filename, s->test_file->bs->exact_filename);
> +                 bs->file->bs->exact_filename,
> +                 s->test_file->bs->exact_filename);
>      }
>  }
>  
> diff --git a/block/bochs.c b/block/bochs.c
> index 199ac2b..18949b9 100644
> --- a/block/bochs.c
> +++ b/block/bochs.c
> @@ -103,7 +103,7 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
>  
>      bs->read_only = 1; // no write support yet
>  
> -    ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
> +    ret = bdrv_pread(bs->file->bs, 0, &bochs, sizeof(bochs));
>      if (ret < 0) {
>          return ret;
>      }
> @@ -137,7 +137,7 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
>          return -ENOMEM;
>      }
>  
> -    ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
> +    ret = bdrv_pread(bs->file->bs, le32_to_cpu(bochs.header), s->catalog_bitmap,
>                       s->catalog_size * 4);
>      if (ret < 0) {
>          goto fail;
> @@ -206,7 +206,7 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
>          (s->extent_blocks + s->bitmap_blocks));
>  
>      /* read in bitmap for current extent */
> -    ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
> +    ret = bdrv_pread(bs->file->bs, bitmap_offset + (extent_offset / 8),
>                       &bitmap_entry, 1);
>      if (ret < 0) {
>          return ret;
> @@ -229,7 +229,7 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num,
>          if (block_offset < 0) {
>              return block_offset;
>          } else if (block_offset > 0) {
> -            ret = bdrv_pread(bs->file, block_offset, buf, 512);
> +            ret = bdrv_pread(bs->file->bs, block_offset, buf, 512);
>              if (ret < 0) {
>                  return ret;
>              }
> diff --git a/block/cloop.c b/block/cloop.c
> index f328be0..4190ae0 100644
> --- a/block/cloop.c
> +++ b/block/cloop.c
> @@ -66,7 +66,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
>      bs->read_only = 1;
>  
>      /* read header */
> -    ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
> +    ret = bdrv_pread(bs->file->bs, 128, &s->block_size, 4);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -92,7 +92,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
>          return -EINVAL;
>      }
>  
> -    ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
> +    ret = bdrv_pread(bs->file->bs, 128 + 4, &s->n_blocks, 4);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -123,7 +123,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
>          return -ENOMEM;
>      }
>  
> -    ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
> +    ret = bdrv_pread(bs->file->bs, 128 + 4 + 4, s->offsets, offsets_size);
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -203,8 +203,8 @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num)
>          int ret;
>          uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
>  
> -        ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
> -                         bytes);
> +        ret = bdrv_pread(bs->file->bs, s->offsets[block_num],
> +                         s->compressed_block, bytes);
>          if (ret != bytes) {
>              return -1;
>          }
> diff --git a/block/dmg.c b/block/dmg.c
> index 9f25281..546a6f5 100644
> --- a/block/dmg.c
> +++ b/block/dmg.c
> @@ -85,7 +85,7 @@ static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
>      uint64_t buffer;
>      int ret;
>  
> -    ret = bdrv_pread(bs->file, offset, &buffer, 8);
> +    ret = bdrv_pread(bs->file->bs, offset, &buffer, 8);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -99,7 +99,7 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
>      uint32_t buffer;
>      int ret;
>  
> -    ret = bdrv_pread(bs->file, offset, &buffer, 4);
> +    ret = bdrv_pread(bs->file->bs, offset, &buffer, 4);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -354,7 +354,7 @@ static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds,
>          offset += 4;
>  
>          buffer = g_realloc(buffer, count);
> -        ret = bdrv_pread(bs->file, offset, buffer, count);
> +        ret = bdrv_pread(bs->file->bs, offset, buffer, count);
>          if (ret < 0) {
>              goto fail;
>          }
> @@ -391,7 +391,7 @@ static int dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds,
>  
>      buffer = g_malloc(info_length + 1);
>      buffer[info_length] = '\0';
> -    ret = bdrv_pread(bs->file, info_begin, buffer, info_length);
> +    ret = bdrv_pread(bs->file->bs, info_begin, buffer, info_length);
>      if (ret != info_length) {
>          ret = -EINVAL;
>          goto fail;
> @@ -446,7 +446,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
>      ds.max_sectors_per_chunk = 1;
>  
>      /* locate the UDIF trailer */
> -    offset = dmg_find_koly_offset(bs->file, errp);
> +    offset = dmg_find_koly_offset(bs->file->bs, errp);
>      if (offset < 0) {
>          ret = offset;
>          goto fail;
> @@ -514,9 +514,9 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
>      }
>  
>      /* initialize zlib engine */
> -    s->compressed_chunk = qemu_try_blockalign(bs->file,
> +    s->compressed_chunk = qemu_try_blockalign(bs->file->bs,
>                                                ds.max_compressed_size + 1);
> -    s->uncompressed_chunk = qemu_try_blockalign(bs->file,
> +    s->uncompressed_chunk = qemu_try_blockalign(bs->file->bs,
>                                                  512 * ds.max_sectors_per_chunk);
>      if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) {
>          ret = -ENOMEM;
> @@ -592,7 +592,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
>          case 0x80000005: { /* zlib compressed */
>              /* we need to buffer, because only the chunk as whole can be
>               * inflated. */
> -            ret = bdrv_pread(bs->file, s->offsets[chunk],
> +            ret = bdrv_pread(bs->file->bs, s->offsets[chunk],
>                               s->compressed_chunk, s->lengths[chunk]);
>              if (ret != s->lengths[chunk]) {
>                  return -1;
> @@ -616,7 +616,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
>          case 0x80000006: /* bzip2 compressed */
>              /* we need to buffer, because only the chunk as whole can be
>               * inflated. */
> -            ret = bdrv_pread(bs->file, s->offsets[chunk],
> +            ret = bdrv_pread(bs->file->bs, s->offsets[chunk],
>                               s->compressed_chunk, s->lengths[chunk]);
>              if (ret != s->lengths[chunk]) {
>                  return -1;
> @@ -641,7 +641,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
>              break;
>  #endif /* CONFIG_BZIP2 */
>          case 1: /* copy */
> -            ret = bdrv_pread(bs->file, s->offsets[chunk],
> +            ret = bdrv_pread(bs->file->bs, s->offsets[chunk],
>                               s->uncompressed_chunk, s->lengths[chunk]);
>              if (ret != s->lengths[chunk]) {
>                  return -1;
> diff --git a/block/io.c b/block/io.c
> index 94e18e6..15c676a 100644
> --- a/block/io.c
> +++ b/block/io.c
> @@ -156,15 +156,15 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
>  
>      /* Take some limits from the children as a default */
>      if (bs->file) {
> -        bdrv_refresh_limits(bs->file, &local_err);
> +        bdrv_refresh_limits(bs->file->bs, &local_err);
>          if (local_err) {
>              error_propagate(errp, local_err);
>              return;
>          }
> -        bs->bl.opt_transfer_length = bs->file->bl.opt_transfer_length;
> -        bs->bl.max_transfer_length = bs->file->bl.max_transfer_length;
> -        bs->bl.min_mem_alignment = bs->file->bl.min_mem_alignment;
> -        bs->bl.opt_mem_alignment = bs->file->bl.opt_mem_alignment;
> +        bs->bl.opt_transfer_length = bs->file->bs->bl.opt_transfer_length;
> +        bs->bl.max_transfer_length = bs->file->bs->bl.max_transfer_length;
> +        bs->bl.min_mem_alignment = bs->file->bs->bl.min_mem_alignment;
> +        bs->bl.opt_mem_alignment = bs->file->bs->bl.opt_mem_alignment;
>      } else {
>          bs->bl.min_mem_alignment = 512;
>          bs->bl.opt_mem_alignment = getpagesize();
> @@ -224,7 +224,7 @@ static bool bdrv_requests_pending(BlockDriverState *bs)
>      if (!qemu_co_queue_empty(&bs->throttled_reqs[1])) {
>          return true;
>      }
> -    if (bs->file && bdrv_requests_pending(bs->file)) {
> +    if (bs->file && bdrv_requests_pending(bs->file->bs)) {
>          return true;
>      }
>      if (bs->backing_hd && bdrv_requests_pending(bs->backing_hd)) {
> @@ -1137,13 +1137,13 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
>      if (ret < 0) {
>          /* Do nothing, write notifier decided to fail this request */
>      } else if (flags & BDRV_REQ_ZERO_WRITE) {
> -        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_ZERO);
> +        bdrv_debug_event(bs, BLKDBG_PWRITEV_ZERO);
>          ret = bdrv_co_do_write_zeroes(bs, sector_num, nb_sectors, flags);
>      } else {
> -        BLKDBG_EVENT(bs, BLKDBG_PWRITEV);
> +        bdrv_debug_event(bs, BLKDBG_PWRITEV);
>          ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
>      }
> -    BLKDBG_EVENT(bs, BLKDBG_PWRITEV_DONE);
> +    bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE);
>  
>      if (ret == 0 && !bs->enable_write_cache) {
>          ret = bdrv_co_flush(bs);
> @@ -1192,13 +1192,13 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
>          /* RMW the unaligned part before head. */
>          mark_request_serialising(req, align);
>          wait_serialising_requests(req);
> -        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_HEAD);
> +        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD);
>          ret = bdrv_aligned_preadv(bs, req, offset & ~(align - 1), align,
>                                    align, &local_qiov, 0);
>          if (ret < 0) {
>              goto fail;
>          }
> -        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
> +        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
>  
>          memset(buf + head_padding_bytes, 0, zero_bytes);
>          ret = bdrv_aligned_pwritev(bs, req, offset & ~(align - 1), align,
> @@ -1230,13 +1230,13 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
>          /* RMW the unaligned part after tail. */
>          mark_request_serialising(req, align);
>          wait_serialising_requests(req);
> -        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_TAIL);
> +        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL);
>          ret = bdrv_aligned_preadv(bs, req, offset, align,
>                                    align, &local_qiov, 0);
>          if (ret < 0) {
>              goto fail;
>          }
> -        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
> +        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
>  
>          memset(buf, 0, bytes);
>          ret = bdrv_aligned_pwritev(bs, req, offset, align,
> @@ -1307,13 +1307,13 @@ static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
>          };
>          qemu_iovec_init_external(&head_qiov, &head_iov, 1);
>  
> -        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_HEAD);
> +        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD);
>          ret = bdrv_aligned_preadv(bs, &req, offset & ~(align - 1), align,
>                                    align, &head_qiov, 0);
>          if (ret < 0) {
>              goto fail;
>          }
> -        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
> +        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
>  
>          qemu_iovec_init(&local_qiov, qiov->niov + 2);
>          qemu_iovec_add(&local_qiov, head_buf, offset & (align - 1));
> @@ -1341,13 +1341,13 @@ static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
>          };
>          qemu_iovec_init_external(&tail_qiov, &tail_iov, 1);
>  
> -        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_TAIL);
> +        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL);
>          ret = bdrv_aligned_preadv(bs, &req, (offset + bytes) & ~(align - 1), align,
>                                    align, &tail_qiov, 0);
>          if (ret < 0) {
>              goto fail;
>          }
> -        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
> +        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
>  
>          if (!use_local_qiov) {
>              qemu_iovec_init(&local_qiov, qiov->niov + 1);
> @@ -1496,7 +1496,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
>  
>      if (ret & BDRV_BLOCK_RAW) {
>          assert(ret & BDRV_BLOCK_OFFSET_VALID);
> -        return bdrv_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS,
> +        return bdrv_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
>                                       *pnum, pnum);
>      }
>  
> @@ -1519,7 +1519,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
>          (ret & BDRV_BLOCK_OFFSET_VALID)) {
>          int file_pnum;
>  
> -        ret2 = bdrv_co_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS,
> +        ret2 = bdrv_co_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
>                                          *pnum, &file_pnum);
>          if (ret2 >= 0) {
>              /* Ignore errors.  This is just providing extra information, it
> @@ -1723,7 +1723,7 @@ int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
>      } else if (drv->bdrv_save_vmstate) {
>          return drv->bdrv_save_vmstate(bs, qiov, pos);
>      } else if (bs->file) {
> -        return bdrv_writev_vmstate(bs->file, qiov, pos);
> +        return bdrv_writev_vmstate(bs->file->bs, qiov, pos);
>      }
>  
>      return -ENOTSUP;
> @@ -1738,7 +1738,7 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
>      if (drv->bdrv_load_vmstate)
>          return drv->bdrv_load_vmstate(bs, buf, pos, size);
>      if (bs->file)
> -        return bdrv_load_vmstate(bs->file, buf, pos, size);
> +        return bdrv_load_vmstate(bs->file->bs, buf, pos, size);
>      return -ENOTSUP;
>  }
>  
> @@ -2366,7 +2366,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
>       * in the case of cache=unsafe, so there are no useless flushes.
>       */
>  flush_parent:
> -    return bdrv_co_flush(bs->file);
> +    return bs->file ? bdrv_co_flush(bs->file->bs) : 0;
>  }
>  
>  int bdrv_flush(BlockDriverState *bs)
> @@ -2594,7 +2594,7 @@ void bdrv_io_plug(BlockDriverState *bs)
>      if (drv && drv->bdrv_io_plug) {
>          drv->bdrv_io_plug(bs);
>      } else if (bs->file) {
> -        bdrv_io_plug(bs->file);
> +        bdrv_io_plug(bs->file->bs);
>      }
>  }
>  
> @@ -2604,7 +2604,7 @@ void bdrv_io_unplug(BlockDriverState *bs)
>      if (drv && drv->bdrv_io_unplug) {
>          drv->bdrv_io_unplug(bs);
>      } else if (bs->file) {
> -        bdrv_io_unplug(bs->file);
> +        bdrv_io_unplug(bs->file->bs);
>      }
>  }
>  
> @@ -2614,7 +2614,7 @@ void bdrv_flush_io_queue(BlockDriverState *bs)
>      if (drv && drv->bdrv_flush_io_queue) {
>          drv->bdrv_flush_io_queue(bs);
>      } else if (bs->file) {
> -        bdrv_flush_io_queue(bs->file);
> +        bdrv_flush_io_queue(bs->file->bs);
>      }
>      bdrv_start_throttled_reqs(bs);
>  }
> diff --git a/block/parallels.c b/block/parallels.c
> index 5cd6ec3..4f79293 100644
> --- a/block/parallels.c
> +++ b/block/parallels.c
> @@ -202,13 +202,13 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
>  
>      to_allocate = (sector_num + *pnum + s->tracks - 1) / s->tracks - idx;
>      space = to_allocate * s->tracks;
> -    if (s->data_end + space > bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS) {
> +    if (s->data_end + space > bdrv_getlength(bs->file->bs) >> BDRV_SECTOR_BITS) {
>          int ret;
>          space += s->prealloc_size;
>          if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) {
> -            ret = bdrv_write_zeroes(bs->file, s->data_end, space, 0);
> +            ret = bdrv_write_zeroes(bs->file->bs, s->data_end, space, 0);
>          } else {
> -            ret = bdrv_truncate(bs->file,
> +            ret = bdrv_truncate(bs->file->bs,
>                                  (s->data_end + space) << BDRV_SECTOR_BITS);
>          }
>          if (ret < 0) {
> @@ -244,7 +244,8 @@ static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs)
>          if (off + to_write > s->header_size) {
>              to_write = s->header_size - off;
>          }
> -        ret = bdrv_pwrite(bs->file, off, (uint8_t *)s->header + off, to_write);
> +        ret = bdrv_pwrite(bs->file->bs, off, (uint8_t *)s->header + off,
> +                          to_write);
>          if (ret < 0) {
>              qemu_co_mutex_unlock(&s->lock);
>              return ret;
> @@ -303,7 +304,7 @@ static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
>          qemu_iovec_reset(&hd_qiov);
>          qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
>  
> -        ret = bdrv_co_writev(bs->file, position, n, &hd_qiov);
> +        ret = bdrv_co_writev(bs->file->bs, position, n, &hd_qiov);
>          if (ret < 0) {
>              break;
>          }
> @@ -343,7 +344,7 @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
>              qemu_iovec_reset(&hd_qiov);
>              qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
>  
> -            ret = bdrv_co_readv(bs->file, position, n, &hd_qiov);
> +            ret = bdrv_co_readv(bs->file->bs, position, n, &hd_qiov);
>              if (ret < 0) {
>                  break;
>              }
> @@ -369,7 +370,7 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
>      bool flush_bat = false;
>      int cluster_size = s->tracks << BDRV_SECTOR_BITS;
>  
> -    size = bdrv_getlength(bs->file);
> +    size = bdrv_getlength(bs->file->bs);
>      if (size < 0) {
>          res->check_errors++;
>          return size;
> @@ -424,7 +425,7 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
>      }
>  
>      if (flush_bat) {
> -        ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size);
> +        ret = bdrv_pwrite_sync(bs->file->bs, 0, s->header, s->header_size);
>          if (ret < 0) {
>              res->check_errors++;
>              return ret;
> @@ -440,7 +441,7 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
>                  size - res->image_end_offset);
>          res->leaks += count;
>          if (fix & BDRV_FIX_LEAKS) {
> -            ret = bdrv_truncate(bs->file, res->image_end_offset);
> +            ret = bdrv_truncate(bs->file->bs, res->image_end_offset);
>              if (ret < 0) {
>                  res->check_errors++;
>                  return ret;
> @@ -546,12 +547,13 @@ static int parallels_probe(const uint8_t *buf, int buf_size,
>  static int parallels_update_header(BlockDriverState *bs)
>  {
>      BDRVParallelsState *s = bs->opaque;
> -    unsigned size = MAX(bdrv_opt_mem_align(bs->file), sizeof(ParallelsHeader));
> +    unsigned size = MAX(bdrv_opt_mem_align(bs->file->bs),
> +                        sizeof(ParallelsHeader));
>  
>      if (size > s->header_size) {
>          size = s->header_size;
>      }
> -    return bdrv_pwrite_sync(bs->file, 0, s->header, size);
> +    return bdrv_pwrite_sync(bs->file->bs, 0, s->header, size);
>  }
>  
>  static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
> @@ -564,7 +566,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
>      Error *local_err = NULL;
>      char *buf;
>  
> -    ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
> +    ret = bdrv_pread(bs->file->bs, 0, &ph, sizeof(ph));
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -603,8 +605,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
>      }
>  
>      size = bat_entry_off(s->bat_size);
> -    s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file));
> -    s->header = qemu_try_blockalign(bs->file, s->header_size);
> +    s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file->bs));
> +    s->header = qemu_try_blockalign(bs->file->bs, s->header_size);
>      if (s->header == NULL) {
>          ret = -ENOMEM;
>          goto fail;
> @@ -619,7 +621,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
>          s->header_size = size;
>      }
>  
> -    ret = bdrv_pread(bs->file, 0, s->header, s->header_size);
> +    ret = bdrv_pread(bs->file->bs, 0, s->header, s->header_size);
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -663,8 +665,8 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
>      if (local_err != NULL) {
>          goto fail_options;
>      }
> -    if (!bdrv_has_zero_init(bs->file) ||
> -            bdrv_truncate(bs->file, bdrv_getlength(bs->file)) != 0) {
> +    if (!bdrv_has_zero_init(bs->file->bs) ||
> +            bdrv_truncate(bs->file->bs, bdrv_getlength(bs->file->bs)) != 0) {
>          s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
>      }
>  
> @@ -707,7 +709,7 @@ static void parallels_close(BlockDriverState *bs)
>      }
>  
>      if (bs->open_flags & BDRV_O_RDWR) {
> -        bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS);
> +        bdrv_truncate(bs->file->bs, s->data_end << BDRV_SECTOR_BITS);
>      }
>  
>      g_free(s->bat_dirty_bmap);
> diff --git a/block/qapi.c b/block/qapi.c
> index 2ce5097..0c4654e 100644
> --- a/block/qapi.c
> +++ b/block/qapi.c
> @@ -359,7 +359,7 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs,
>  
>      if (bs->file) {
>          s->has_parent = true;
> -        s->parent = bdrv_query_stats(bs->file, query_backing);
> +        s->parent = bdrv_query_stats(bs->file->bs, query_backing);
>      }
>  
>      if (query_backing && bs->backing_hd) {
> diff --git a/block/qcow.c b/block/qcow.c
> index 6e35db1..4d20cd5 100644
> --- a/block/qcow.c
> +++ b/block/qcow.c
> @@ -100,7 +100,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
>      int ret;
>      QCowHeader header;
>  
> -    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
> +    ret = bdrv_pread(bs->file->bs, 0, &header, sizeof(header));
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -193,7 +193,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
>          goto fail;
>      }
>  
> -    ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
> +    ret = bdrv_pread(bs->file->bs, s->l1_table_offset, s->l1_table,
>                 s->l1_size * sizeof(uint64_t));
>      if (ret < 0) {
>          goto fail;
> @@ -205,7 +205,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
>  
>      /* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */
>      s->l2_cache =
> -        qemu_try_blockalign(bs->file,
> +        qemu_try_blockalign(bs->file->bs,
>                              s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
>      if (s->l2_cache == NULL) {
>          error_setg(errp, "Could not allocate L2 table cache");
> @@ -224,7 +224,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
>              ret = -EINVAL;
>              goto fail;
>          }
> -        ret = bdrv_pread(bs->file, header.backing_file_offset,
> +        ret = bdrv_pread(bs->file->bs, header.backing_file_offset,
>                     bs->backing_file, len);
>          if (ret < 0) {
>              goto fail;
> @@ -369,13 +369,13 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
>          if (!allocate)
>              return 0;
>          /* allocate a new l2 entry */
> -        l2_offset = bdrv_getlength(bs->file);
> +        l2_offset = bdrv_getlength(bs->file->bs);
>          /* round to cluster size */
>          l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
>          /* update the L1 entry */
>          s->l1_table[l1_index] = l2_offset;
>          tmp = cpu_to_be64(l2_offset);
> -        if (bdrv_pwrite_sync(bs->file,
> +        if (bdrv_pwrite_sync(bs->file->bs,
>                  s->l1_table_offset + l1_index * sizeof(tmp),
>                  &tmp, sizeof(tmp)) < 0)
>              return 0;
> @@ -405,11 +405,12 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
>      l2_table = s->l2_cache + (min_index << s->l2_bits);
>      if (new_l2_table) {
>          memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
> -        if (bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
> +        if (bdrv_pwrite_sync(bs->file->bs, l2_offset, l2_table,
>                  s->l2_size * sizeof(uint64_t)) < 0)
>              return 0;
>      } else {
> -        if (bdrv_pread(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
> +        if (bdrv_pread(bs->file->bs, l2_offset, l2_table,
> +                       s->l2_size * sizeof(uint64_t)) !=
>              s->l2_size * sizeof(uint64_t))
>              return 0;
>      }
> @@ -430,20 +431,21 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
>                 overwritten */
>              if (decompress_cluster(bs, cluster_offset) < 0)
>                  return 0;
> -            cluster_offset = bdrv_getlength(bs->file);
> +            cluster_offset = bdrv_getlength(bs->file->bs);
>              cluster_offset = (cluster_offset + s->cluster_size - 1) &
>                  ~(s->cluster_size - 1);
>              /* write the cluster content */
> -            if (bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache, s->cluster_size) !=
> +            if (bdrv_pwrite(bs->file->bs, cluster_offset, s->cluster_cache,
> +                            s->cluster_size) !=
>                  s->cluster_size)
>                  return -1;
>          } else {
> -            cluster_offset = bdrv_getlength(bs->file);
> +            cluster_offset = bdrv_getlength(bs->file->bs);
>              if (allocate == 1) {
>                  /* round to cluster size */
>                  cluster_offset = (cluster_offset + s->cluster_size - 1) &
>                      ~(s->cluster_size - 1);
> -                bdrv_truncate(bs->file, cluster_offset + s->cluster_size);
> +                bdrv_truncate(bs->file->bs, cluster_offset + s->cluster_size);
>                  /* if encrypted, we must initialize the cluster
>                     content which won't be written */
>                  if (bs->encrypted &&
> @@ -463,7 +465,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
>                                  errno = EIO;
>                                  return -1;
>                              }
> -                            if (bdrv_pwrite(bs->file, cluster_offset + i * 512,
> +                            if (bdrv_pwrite(bs->file->bs, cluster_offset + i * 512,
>                                              s->cluster_data, 512) != 512)
>                                  return -1;
>                          }
> @@ -477,7 +479,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
>          /* update L2 table */
>          tmp = cpu_to_be64(cluster_offset);
>          l2_table[l2_index] = tmp;
> -        if (bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
> +        if (bdrv_pwrite_sync(bs->file->bs, l2_offset + l2_index * sizeof(tmp),
>                  &tmp, sizeof(tmp)) < 0)
>              return 0;
>      }
> @@ -546,7 +548,7 @@ static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
>      if (s->cluster_cache_offset != coffset) {
>          csize = cluster_offset >> (63 - s->cluster_bits);
>          csize &= (s->cluster_size - 1);
> -        ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize);
> +        ret = bdrv_pread(bs->file->bs, coffset, s->cluster_data, csize);
>          if (ret != csize)
>              return -1;
>          if (decompress_buffer(s->cluster_cache, s->cluster_size,
> @@ -625,7 +627,7 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
>              hd_iov.iov_len = n * 512;
>              qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
>              qemu_co_mutex_unlock(&s->lock);
> -            ret = bdrv_co_readv(bs->file,
> +            ret = bdrv_co_readv(bs->file->bs,
>                                  (cluster_offset >> 9) + index_in_cluster,
>                                  n, &hd_qiov);
>              qemu_co_mutex_lock(&s->lock);
> @@ -727,7 +729,7 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
>          hd_iov.iov_len = n * 512;
>          qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
>          qemu_co_mutex_unlock(&s->lock);
> -        ret = bdrv_co_writev(bs->file,
> +        ret = bdrv_co_writev(bs->file->bs,
>                               (cluster_offset >> 9) + index_in_cluster,
>                               n, &hd_qiov);
>          qemu_co_mutex_lock(&s->lock);
> @@ -879,10 +881,10 @@ static int qcow_make_empty(BlockDriverState *bs)
>      int ret;
>  
>      memset(s->l1_table, 0, l1_length);
> -    if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
> +    if (bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset, s->l1_table,
>              l1_length) < 0)
>          return -1;
> -    ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
> +    ret = bdrv_truncate(bs->file->bs, s->l1_table_offset + l1_length);
>      if (ret < 0)
>          return ret;
>  
> @@ -962,7 +964,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
>          }
>  
>          cluster_offset &= s->cluster_offset_mask;
> -        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
> +        ret = bdrv_pwrite(bs->file->bs, cluster_offset, out_buf, out_len);
>          if (ret < 0) {
>              goto fail;
>          }
> diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
> index 7b14c5c..86dd7f2 100644
> --- a/block/qcow2-cache.c
> +++ b/block/qcow2-cache.c
> @@ -127,7 +127,7 @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
>      c = g_new0(Qcow2Cache, 1);
>      c->size = num_tables;
>      c->entries = g_try_new0(Qcow2CachedTable, num_tables);
> -    c->table_array = qemu_try_blockalign(bs->file,
> +    c->table_array = qemu_try_blockalign(bs->file->bs,
>                                           (size_t) num_tables * s->cluster_size);
>  
>      if (!c->entries || !c->table_array) {
> @@ -185,7 +185,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
>      if (c->depends) {
>          ret = qcow2_cache_flush_dependency(bs, c);
>      } else if (c->depends_on_flush) {
> -        ret = bdrv_flush(bs->file);
> +        ret = bdrv_flush(bs->file->bs);
>          if (ret >= 0) {
>              c->depends_on_flush = false;
>          }
> @@ -216,7 +216,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
>          BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
>      }
>  
> -    ret = bdrv_pwrite(bs->file, c->entries[i].offset,
> +    ret = bdrv_pwrite(bs->file->bs, c->entries[i].offset,
>                        qcow2_cache_get_table_addr(bs, c, i), s->cluster_size);
>      if (ret < 0) {
>          return ret;
> @@ -244,7 +244,7 @@ int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c)
>      }
>  
>      if (result == 0) {
> -        ret = bdrv_flush(bs->file);
> +        ret = bdrv_flush(bs->file->bs);
>          if (ret < 0) {
>              result = ret;
>          }
> @@ -356,7 +356,8 @@ static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
>              BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
>          }
>  
> -        ret = bdrv_pread(bs->file, offset, qcow2_cache_get_table_addr(bs, c, i),
> +        ret = bdrv_pread(bs->file->bs, offset,
> +                         qcow2_cache_get_table_addr(bs, c, i),
>                           s->cluster_size);
>          if (ret < 0) {
>              return ret;
> diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
> index 6ede629..7844f8e 100644
> --- a/block/qcow2-cluster.c
> +++ b/block/qcow2-cluster.c
> @@ -72,7 +72,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
>  #endif
>  
>      new_l1_size2 = sizeof(uint64_t) * new_l1_size;
> -    new_l1_table = qemu_try_blockalign(bs->file,
> +    new_l1_table = qemu_try_blockalign(bs->file->bs,
>                                         align_offset(new_l1_size2, 512));
>      if (new_l1_table == NULL) {
>          return -ENOMEM;
> @@ -105,7 +105,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
>      BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
>      for(i = 0; i < s->l1_size; i++)
>          new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
> -    ret = bdrv_pwrite_sync(bs->file, new_l1_table_offset, new_l1_table, new_l1_size2);
> +    ret = bdrv_pwrite_sync(bs->file->bs, new_l1_table_offset,
> +                           new_l1_table, new_l1_size2);
>      if (ret < 0)
>          goto fail;
>      for(i = 0; i < s->l1_size; i++)
> @@ -115,7 +116,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
>      BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE);
>      cpu_to_be32w((uint32_t*)data, new_l1_size);
>      stq_be_p(data + 4, new_l1_table_offset);
> -    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size), data,sizeof(data));
> +    ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, l1_size),
> +                           data, sizeof(data));
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -182,8 +184,9 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
>      }
>  
>      BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
> -    ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset + 8 * l1_start_index,
> -        buf, sizeof(buf));
> +    ret = bdrv_pwrite_sync(bs->file->bs,
> +                           s->l1_table_offset + 8 * l1_start_index,
> +                           buf, sizeof(buf));
>      if (ret < 0) {
>          return ret;
>      }
> @@ -440,7 +443,8 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
>      }
>  
>      BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
> -    ret = bdrv_co_writev(bs->file, (cluster_offset >> 9) + n_start, n, &qiov);
> +    ret = bdrv_co_writev(bs->file->bs, (cluster_offset >> 9) + n_start, n,
> +                         &qiov);
>      if (ret < 0) {
>          goto out;
>      }
> @@ -817,7 +821,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
>  
>      /*
>       * If this was a COW, we need to decrease the refcount of the old cluster.
> -     * Also flush bs->file to get the right order for L2 and refcount update.
> +     * Also flush bs->file->bs to get the right order for L2 and refcount update.
>       *
>       * Don't discard clusters that reach a refcount of 0 (e.g. compressed
>       * clusters), the next write will reuse them anyway.
> @@ -1412,7 +1416,8 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
>          sector_offset = coffset & 511;
>          csize = nb_csectors * 512 - sector_offset;
>          BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
> -        ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data, nb_csectors);
> +        ret = bdrv_read(bs->file->bs, coffset >> 9, s->cluster_data,
> +                        nb_csectors);
>          if (ret < 0) {
>              return ret;
>          }
> @@ -1645,7 +1650,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
>      if (!is_active_l1) {
>          /* inactive L2 tables require a buffer to be stored in when loading
>           * them from disk */
> -        l2_table = qemu_try_blockalign(bs->file, s->cluster_size);
> +        l2_table = qemu_try_blockalign(bs->file->bs, s->cluster_size);
>          if (l2_table == NULL) {
>              return -ENOMEM;
>          }
> @@ -1679,8 +1684,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
>                      (void **)&l2_table);
>          } else {
>              /* load inactive L2 tables from disk */
> -            ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
> -                    (void *)l2_table, s->cluster_sectors);
> +            ret = bdrv_read(bs->file->bs, l2_offset / BDRV_SECTOR_SIZE,
> +                            (void *)l2_table, s->cluster_sectors);
>          }
>          if (ret < 0) {
>              goto fail;
> @@ -1754,7 +1759,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
>                  goto fail;
>              }
>  
> -            ret = bdrv_write_zeroes(bs->file, offset / BDRV_SECTOR_SIZE,
> +            ret = bdrv_write_zeroes(bs->file->bs, offset / BDRV_SECTOR_SIZE,
>                                      s->cluster_sectors, 0);
>              if (ret < 0) {
>                  if (!preallocated) {
> @@ -1787,8 +1792,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
>                      goto fail;
>                  }
>  
> -                ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
> -                        (void *)l2_table, s->cluster_sectors);
> +                ret = bdrv_write(bs->file->bs, l2_offset / BDRV_SECTOR_SIZE,
> +                                 (void *)l2_table, s->cluster_sectors);
>                  if (ret < 0) {
>                      goto fail;
>                  }
> @@ -1861,8 +1866,9 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs,
>  
>          l1_table = g_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
>  
> -        ret = bdrv_read(bs->file, s->snapshots[i].l1_table_offset /
> -                BDRV_SECTOR_SIZE, (void *)l1_table, l1_sectors);
> +        ret = bdrv_read(bs->file->bs,
> +                        s->snapshots[i].l1_table_offset / BDRV_SECTOR_SIZE,
> +                        (void *)l1_table, l1_sectors);
>          if (ret < 0) {
>              goto fail;
>          }
> diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
> index 2110839..4b81c8d 100644
> --- a/block/qcow2-refcount.c
> +++ b/block/qcow2-refcount.c
> @@ -101,7 +101,7 @@ int qcow2_refcount_init(BlockDriverState *bs)
>              goto fail;
>          }
>          BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
> -        ret = bdrv_pread(bs->file, s->refcount_table_offset,
> +        ret = bdrv_pread(bs->file->bs, s->refcount_table_offset,
>                           s->refcount_table, refcount_table_size2);
>          if (ret < 0) {
>              goto fail;
> @@ -431,7 +431,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
>      if (refcount_table_index < s->refcount_table_size) {
>          uint64_t data64 = cpu_to_be64(new_block);
>          BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
> -        ret = bdrv_pwrite_sync(bs->file,
> +        ret = bdrv_pwrite_sync(bs->file->bs,
>              s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
>              &data64, sizeof(data64));
>          if (ret < 0) {
> @@ -535,7 +535,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
>  
>      /* Write refcount blocks to disk */
>      BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
> -    ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
> +    ret = bdrv_pwrite_sync(bs->file->bs, meta_offset, new_blocks,
>          blocks_clusters * s->cluster_size);
>      g_free(new_blocks);
>      new_blocks = NULL;
> @@ -549,7 +549,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
>      }
>  
>      BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
> -    ret = bdrv_pwrite_sync(bs->file, table_offset, new_table,
> +    ret = bdrv_pwrite_sync(bs->file->bs, table_offset, new_table,
>          table_size * sizeof(uint64_t));
>      if (ret < 0) {
>          goto fail_table;
> @@ -564,8 +564,9 @@ static int alloc_refcount_block(BlockDriverState *bs,
>      cpu_to_be64w((uint64_t*)data, table_offset);
>      cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
>      BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE);
> -    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, refcount_table_offset),
> -        data, sizeof(data));
> +    ret = bdrv_pwrite_sync(bs->file->bs,
> +                           offsetof(QCowHeader, refcount_table_offset),
> +                           data, sizeof(data));
>      if (ret < 0) {
>          goto fail_table;
>      }
> @@ -613,7 +614,7 @@ void qcow2_process_discards(BlockDriverState *bs, int ret)
>  
>          /* Discard is optional, ignore the return value */
>          if (ret >= 0) {
> -            bdrv_discard(bs->file,
> +            bdrv_discard(bs->file->bs,
>                           d->offset >> BDRV_SECTOR_BITS,
>                           d->bytes >> BDRV_SECTOR_BITS);
>          }
> @@ -1068,7 +1069,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
>          }
>          l1_allocated = true;
>  
> -        ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
> +        ret = bdrv_pread(bs->file->bs, l1_table_offset, l1_table, l1_size2);
>          if (ret < 0) {
>              goto fail;
>          }
> @@ -1221,7 +1222,8 @@ fail:
>              cpu_to_be64s(&l1_table[i]);
>          }
>  
> -        ret = bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table, l1_size2);
> +        ret = bdrv_pwrite_sync(bs->file->bs, l1_table_offset,
> +                               l1_table, l1_size2);
>  
>          for (i = 0; i < l1_size; i++) {
>              be64_to_cpus(&l1_table[i]);
> @@ -1376,7 +1378,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
>      l2_size = s->l2_size * sizeof(uint64_t);
>      l2_table = g_malloc(l2_size);
>  
> -    ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size);
> +    ret = bdrv_pread(bs->file->bs, l2_offset, l2_table, l2_size);
>      if (ret < 0) {
>          fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
>          res->check_errors++;
> @@ -1508,7 +1510,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
>              res->check_errors++;
>              goto fail;
>          }
> -        ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
> +        ret = bdrv_pread(bs->file->bs, l1_table_offset, l1_table, l1_size2);
>          if (ret < 0) {
>              fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
>              res->check_errors++;
> @@ -1606,7 +1608,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
>              }
>          }
>  
> -        ret = bdrv_pread(bs->file, l2_offset, l2_table,
> +        ret = bdrv_pread(bs->file->bs, l2_offset, l2_table,
>                           s->l2_size * sizeof(uint64_t));
>          if (ret < 0) {
>              fprintf(stderr, "ERROR: Could not read L2 table: %s\n",
> @@ -1658,7 +1660,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
>                  goto fail;
>              }
>  
> -            ret = bdrv_pwrite(bs->file, l2_offset, l2_table, s->cluster_size);
> +            ret = bdrv_pwrite(bs->file->bs, l2_offset, l2_table,
> +                              s->cluster_size);
>              if (ret < 0) {
>                  fprintf(stderr, "ERROR: Could not write L2 table: %s\n",
>                          strerror(-ret));
> @@ -1713,11 +1716,11 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
>                      goto resize_fail;
>                  }
>  
> -                ret = bdrv_truncate(bs->file, offset + s->cluster_size);
> +                ret = bdrv_truncate(bs->file->bs, offset + s->cluster_size);
>                  if (ret < 0) {
>                      goto resize_fail;
>                  }
> -                size = bdrv_getlength(bs->file);
> +                size = bdrv_getlength(bs->file->bs);
>                  if (size < 0) {
>                      ret = size;
>                      goto resize_fail;
> @@ -2091,7 +2094,7 @@ write_refblocks:
>          on_disk_refblock = (void *)((char *) *refcount_table +
>                                      refblock_index * s->cluster_size);
>  
> -        ret = bdrv_write(bs->file, refblock_offset / BDRV_SECTOR_SIZE,
> +        ret = bdrv_write(bs->file->bs, refblock_offset / BDRV_SECTOR_SIZE,
>                           on_disk_refblock, s->cluster_sectors);
>          if (ret < 0) {
>              fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret));
> @@ -2140,7 +2143,7 @@ write_refblocks:
>      }
>  
>      assert(reftable_size < INT_MAX / sizeof(uint64_t));
> -    ret = bdrv_pwrite(bs->file, reftable_offset, on_disk_reftable,
> +    ret = bdrv_pwrite(bs->file->bs, reftable_offset, on_disk_reftable,
>                        reftable_size * sizeof(uint64_t));
>      if (ret < 0) {
>          fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret));
> @@ -2152,8 +2155,8 @@ write_refblocks:
>                   reftable_offset);
>      cpu_to_be32w(&reftable_offset_and_clusters.reftable_clusters,
>                   size_to_clusters(s, reftable_size * sizeof(uint64_t)));
> -    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader,
> -                                              refcount_table_offset),
> +    ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader,
> +                                                  refcount_table_offset),
>                             &reftable_offset_and_clusters,
>                             sizeof(reftable_offset_and_clusters));
>      if (ret < 0) {
> @@ -2191,7 +2194,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
>      bool rebuild = false;
>      int ret;
>  
> -    size = bdrv_getlength(bs->file);
> +    size = bdrv_getlength(bs->file->bs);
>      if (size < 0) {
>          res->check_errors++;
>          return size;
> @@ -2400,7 +2403,7 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
>                  return -ENOMEM;
>              }
>  
> -            ret = bdrv_pread(bs->file, l1_ofs, l1, l1_sz2);
> +            ret = bdrv_pread(bs->file->bs, l1_ofs, l1, l1_sz2);
>              if (ret < 0) {
>                  g_free(l1);
>                  return ret;
> diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
> index 92f4dfc..def7201 100644
> --- a/block/qcow2-snapshot.c
> +++ b/block/qcow2-snapshot.c
> @@ -64,7 +64,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
>      for(i = 0; i < s->nb_snapshots; i++) {
>          /* Read statically sized part of the snapshot header */
>          offset = align_offset(offset, 8);
> -        ret = bdrv_pread(bs->file, offset, &h, sizeof(h));
> +        ret = bdrv_pread(bs->file->bs, offset, &h, sizeof(h));
>          if (ret < 0) {
>              goto fail;
>          }
> @@ -83,7 +83,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
>          name_size = be16_to_cpu(h.name_size);
>  
>          /* Read extra data */
> -        ret = bdrv_pread(bs->file, offset, &extra,
> +        ret = bdrv_pread(bs->file->bs, offset, &extra,
>                           MIN(sizeof(extra), extra_data_size));
>          if (ret < 0) {
>              goto fail;
> @@ -102,7 +102,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
>  
>          /* Read snapshot ID */
>          sn->id_str = g_malloc(id_str_size + 1);
> -        ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
> +        ret = bdrv_pread(bs->file->bs, offset, sn->id_str, id_str_size);
>          if (ret < 0) {
>              goto fail;
>          }
> @@ -111,7 +111,7 @@ int qcow2_read_snapshots(BlockDriverState *bs)
>  
>          /* Read snapshot name */
>          sn->name = g_malloc(name_size + 1);
> -        ret = bdrv_pread(bs->file, offset, sn->name, name_size);
> +        ret = bdrv_pread(bs->file->bs, offset, sn->name, name_size);
>          if (ret < 0) {
>              goto fail;
>          }
> @@ -214,25 +214,25 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
>          h.name_size = cpu_to_be16(name_size);
>          offset = align_offset(offset, 8);
>  
> -        ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h));
> +        ret = bdrv_pwrite(bs->file->bs, offset, &h, sizeof(h));
>          if (ret < 0) {
>              goto fail;
>          }
>          offset += sizeof(h);
>  
> -        ret = bdrv_pwrite(bs->file, offset, &extra, sizeof(extra));
> +        ret = bdrv_pwrite(bs->file->bs, offset, &extra, sizeof(extra));
>          if (ret < 0) {
>              goto fail;
>          }
>          offset += sizeof(extra);
>  
> -        ret = bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size);
> +        ret = bdrv_pwrite(bs->file->bs, offset, sn->id_str, id_str_size);
>          if (ret < 0) {
>              goto fail;
>          }
>          offset += id_str_size;
>  
> -        ret = bdrv_pwrite(bs->file, offset, sn->name, name_size);
> +        ret = bdrv_pwrite(bs->file->bs, offset, sn->name, name_size);
>          if (ret < 0) {
>              goto fail;
>          }
> @@ -254,7 +254,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
>      header_data.nb_snapshots        = cpu_to_be32(s->nb_snapshots);
>      header_data.snapshots_offset    = cpu_to_be64(snapshots_offset);
>  
> -    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
> +    ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, nb_snapshots),
>                             &header_data, sizeof(header_data));
>      if (ret < 0) {
>          goto fail;
> @@ -396,7 +396,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
>          goto fail;
>      }
>  
> -    ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table,
> +    ret = bdrv_pwrite(bs->file->bs, sn->l1_table_offset, l1_table,
>                        s->l1_size * sizeof(uint64_t));
>      if (ret < 0) {
>          goto fail;
> @@ -509,7 +509,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>          goto fail;
>      }
>  
> -    ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_table, sn_l1_bytes);
> +    ret = bdrv_pread(bs->file->bs, sn->l1_table_offset,
> +                     sn_l1_table, sn_l1_bytes);
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -526,7 +527,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
>          goto fail;
>      }
>  
> -    ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table,
> +    ret = bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset, sn_l1_table,
>                             cur_l1_bytes);
>      if (ret < 0) {
>          goto fail;
> @@ -706,13 +707,14 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
>          return -EFBIG;
>      }
>      new_l1_bytes = sn->l1_size * sizeof(uint64_t);
> -    new_l1_table = qemu_try_blockalign(bs->file,
> +    new_l1_table = qemu_try_blockalign(bs->file->bs,
>                                         align_offset(new_l1_bytes, 512));
>      if (new_l1_table == NULL) {
>          return -ENOMEM;
>      }
>  
> -    ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
> +    ret = bdrv_pread(bs->file->bs, sn->l1_table_offset,
> +                     new_l1_table, new_l1_bytes);
>      if (ret < 0) {
>          error_setg(errp, "Failed to read l1 table for snapshot");
>          qemu_vfree(new_l1_table);
> diff --git a/block/qcow2.c b/block/qcow2.c
> index 56ad808..38b2797 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -104,7 +104,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
>          printf("attempting to read extended header in offset %lu\n", offset);
>  #endif
>  
> -        ret = bdrv_pread(bs->file, offset, &ext, sizeof(ext));
> +        ret = bdrv_pread(bs->file->bs, offset, &ext, sizeof(ext));
>          if (ret < 0) {
>              error_setg_errno(errp, -ret, "qcow2_read_extension: ERROR: "
>                               "pread fail from offset %" PRIu64, offset);
> @@ -132,7 +132,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
>                             sizeof(bs->backing_format));
>                  return 2;
>              }
> -            ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
> +            ret = bdrv_pread(bs->file->bs, offset, bs->backing_format, ext.len);
>              if (ret < 0) {
>                  error_setg_errno(errp, -ret, "ERROR: ext_backing_format: "
>                                   "Could not read format name");
> @@ -148,7 +148,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
>          case QCOW2_EXT_MAGIC_FEATURE_TABLE:
>              if (p_feature_table != NULL) {
>                  void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
> -                ret = bdrv_pread(bs->file, offset , feature_table, ext.len);
> +                ret = bdrv_pread(bs->file->bs, offset , feature_table, ext.len);
>                  if (ret < 0) {
>                      error_setg_errno(errp, -ret, "ERROR: ext_feature_table: "
>                                       "Could not read table");
> @@ -169,7 +169,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
>                  uext->len = ext.len;
>                  QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next);
>  
> -                ret = bdrv_pread(bs->file, offset , uext->data, uext->len);
> +                ret = bdrv_pread(bs->file->bs, offset , uext->data, uext->len);
>                  if (ret < 0) {
>                      error_setg_errno(errp, -ret, "ERROR: unknown extension: "
>                                       "Could not read data");
> @@ -260,12 +260,12 @@ int qcow2_mark_dirty(BlockDriverState *bs)
>      }
>  
>      val = cpu_to_be64(s->incompatible_features | QCOW2_INCOMPAT_DIRTY);
> -    ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, incompatible_features),
> +    ret = bdrv_pwrite(bs->file->bs, offsetof(QCowHeader, incompatible_features),
>                        &val, sizeof(val));
>      if (ret < 0) {
>          return ret;
>      }
> -    ret = bdrv_flush(bs->file);
> +    ret = bdrv_flush(bs->file->bs);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -828,7 +828,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
>      uint64_t ext_end;
>      uint64_t l1_vm_state_index;
>  
> -    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
> +    ret = bdrv_pread(bs->file->bs, 0, &header, sizeof(header));
>      if (ret < 0) {
>          error_setg_errno(errp, -ret, "Could not read qcow2 header");
>          goto fail;
> @@ -903,7 +903,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
>      if (header.header_length > sizeof(header)) {
>          s->unknown_header_fields_size = header.header_length - sizeof(header);
>          s->unknown_header_fields = g_malloc(s->unknown_header_fields_size);
> -        ret = bdrv_pread(bs->file, sizeof(header), s->unknown_header_fields,
> +        ret = bdrv_pread(bs->file->bs, sizeof(header), s->unknown_header_fields,
>                           s->unknown_header_fields_size);
>          if (ret < 0) {
>              error_setg_errno(errp, -ret, "Could not read unknown qcow2 header "
> @@ -1056,14 +1056,14 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
>  
>  
>      if (s->l1_size > 0) {
> -        s->l1_table = qemu_try_blockalign(bs->file,
> +        s->l1_table = qemu_try_blockalign(bs->file->bs,
>              align_offset(s->l1_size * sizeof(uint64_t), 512));
>          if (s->l1_table == NULL) {
>              error_setg(errp, "Could not allocate L1 table");
>              ret = -ENOMEM;
>              goto fail;
>          }
> -        ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
> +        ret = bdrv_pread(bs->file->bs, s->l1_table_offset, s->l1_table,
>                           s->l1_size * sizeof(uint64_t));
>          if (ret < 0) {
>              error_setg_errno(errp, -ret, "Could not read L1 table");
> @@ -1082,7 +1082,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
>  
>      s->cluster_cache = g_malloc(s->cluster_size);
>      /* one more sector for decompressed data alignment */
> -    s->cluster_data = qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
> +    s->cluster_data = qemu_try_blockalign(bs->file->bs, QCOW_MAX_CRYPT_CLUSTERS
>                                                      * s->cluster_size + 512);
>      if (s->cluster_data == NULL) {
>          error_setg(errp, "Could not allocate temporary cluster buffer");
> @@ -1119,7 +1119,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
>              ret = -EINVAL;
>              goto fail;
>          }
> -        ret = bdrv_pread(bs->file, header.backing_file_offset,
> +        ret = bdrv_pread(bs->file->bs, header.backing_file_offset,
>                           bs->backing_file, len);
>          if (ret < 0) {
>              error_setg_errno(errp, -ret, "Could not read backing file name");
> @@ -1429,8 +1429,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
>                   */
>                  if (!cluster_data) {
>                      cluster_data =
> -                        qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
> -                                                      * s->cluster_size);
> +                        qemu_try_blockalign(bs->file->bs,
> +                                            QCOW_MAX_CRYPT_CLUSTERS
> +                                            * s->cluster_size);
>                      if (cluster_data == NULL) {
>                          ret = -ENOMEM;
>                          goto fail;
> @@ -1446,7 +1447,7 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
>  
>              BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
>              qemu_co_mutex_unlock(&s->lock);
> -            ret = bdrv_co_readv(bs->file,
> +            ret = bdrv_co_readv(bs->file->bs,
>                                  (cluster_offset >> 9) + index_in_cluster,
>                                  cur_nr_sectors, &hd_qiov);
>              qemu_co_mutex_lock(&s->lock);
> @@ -1543,7 +1544,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
>              Error *err = NULL;
>              assert(s->cipher);
>              if (!cluster_data) {
> -                cluster_data = qemu_try_blockalign(bs->file,
> +                cluster_data = qemu_try_blockalign(bs->file->bs,
>                                                     QCOW_MAX_CRYPT_CLUSTERS
>                                                     * s->cluster_size);
>                  if (cluster_data == NULL) {
> @@ -1580,7 +1581,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
>          BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
>          trace_qcow2_writev_data(qemu_coroutine_self(),
>                                  (cluster_offset >> 9) + index_in_cluster);
> -        ret = bdrv_co_writev(bs->file,
> +        ret = bdrv_co_writev(bs->file->bs,
>                               (cluster_offset >> 9) + index_in_cluster,
>                               cur_nr_sectors, &hd_qiov);
>          qemu_co_mutex_lock(&s->lock);
> @@ -1703,7 +1704,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
>  
>      qcow2_close(bs);
>  
> -    bdrv_invalidate_cache(bs->file, &local_err);
> +    bdrv_invalidate_cache(bs->file->bs, &local_err);
>      if (local_err) {
>          error_propagate(errp, local_err);
>          return;
> @@ -1911,7 +1912,7 @@ int qcow2_update_header(BlockDriverState *bs)
>      }
>  
>      /* Write the new header */
> -    ret = bdrv_pwrite(bs->file, 0, header, s->cluster_size);
> +    ret = bdrv_pwrite(bs->file->bs, 0, header, s->cluster_size);
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -1991,7 +1992,8 @@ static int preallocate(BlockDriverState *bs)
>      if (host_offset != 0) {
>          uint8_t buf[BDRV_SECTOR_SIZE];
>          memset(buf, 0, BDRV_SECTOR_SIZE);
> -        ret = bdrv_write(bs->file, (host_offset >> BDRV_SECTOR_BITS) + num - 1,
> +        ret = bdrv_write(bs->file->bs,
> +                         (host_offset >> BDRV_SECTOR_BITS) + num - 1,
>                           buf, 1);
>          if (ret < 0) {
>              return ret;
> @@ -2403,7 +2405,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
>  
>      /* write updated header.size */
>      offset = cpu_to_be64(offset);
> -    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
> +    ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, size),
>                             &offset, sizeof(uint64_t));
>      if (ret < 0) {
>          return ret;
> @@ -2427,8 +2429,8 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
>      if (nb_sectors == 0) {
>          /* align end of file to a sector boundary to ease reading with
>             sector based I/Os */
> -        cluster_offset = bdrv_getlength(bs->file);
> -        return bdrv_truncate(bs->file, cluster_offset);
> +        cluster_offset = bdrv_getlength(bs->file->bs);
> +        return bdrv_truncate(bs->file->bs, cluster_offset);
>      }
>  
>      if (nb_sectors != s->cluster_sectors) {
> @@ -2495,7 +2497,7 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
>          }
>  
>          BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
> -        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
> +        ret = bdrv_pwrite(bs->file->bs, cluster_offset, out_buf, out_len);
>          if (ret < 0) {
>              goto fail;
>          }
> @@ -2544,7 +2546,7 @@ static int make_completely_empty(BlockDriverState *bs)
>      /* After this call, neither the in-memory nor the on-disk refcount
>       * information accurately describe the actual references */
>  
> -    ret = bdrv_write_zeroes(bs->file, s->l1_table_offset / BDRV_SECTOR_SIZE,
> +    ret = bdrv_write_zeroes(bs->file->bs, s->l1_table_offset / BDRV_SECTOR_SIZE,
>                              l1_clusters * s->cluster_sectors, 0);
>      if (ret < 0) {
>          goto fail_broken_refcounts;
> @@ -2558,7 +2560,7 @@ static int make_completely_empty(BlockDriverState *bs)
>       * overwrite parts of the existing refcount and L1 table, which is not
>       * an issue because the dirty flag is set, complete data loss is in fact
>       * desired and partial data loss is consequently fine as well */
> -    ret = bdrv_write_zeroes(bs->file, s->cluster_size / BDRV_SECTOR_SIZE,
> +    ret = bdrv_write_zeroes(bs->file->bs, s->cluster_size / BDRV_SECTOR_SIZE,
>                              (2 + l1_clusters) * s->cluster_size /
>                              BDRV_SECTOR_SIZE, 0);
>      /* This call (even if it failed overall) may have overwritten on-disk
> @@ -2578,7 +2580,7 @@ static int make_completely_empty(BlockDriverState *bs)
>      cpu_to_be64w(&l1_ofs_rt_ofs_cls.l1_offset, 3 * s->cluster_size);
>      cpu_to_be64w(&l1_ofs_rt_ofs_cls.reftable_offset, s->cluster_size);
>      cpu_to_be32w(&l1_ofs_rt_ofs_cls.reftable_clusters, 1);
> -    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_table_offset),
> +    ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, l1_table_offset),
>                             &l1_ofs_rt_ofs_cls, sizeof(l1_ofs_rt_ofs_cls));
>      if (ret < 0) {
>          goto fail_broken_refcounts;
> @@ -2609,7 +2611,7 @@ static int make_completely_empty(BlockDriverState *bs)
>  
>      /* Enter the first refblock into the reftable */
>      rt_entry = cpu_to_be64(2 * s->cluster_size);
> -    ret = bdrv_pwrite_sync(bs->file, s->cluster_size,
> +    ret = bdrv_pwrite_sync(bs->file->bs, s->cluster_size,
>                             &rt_entry, sizeof(rt_entry));
>      if (ret < 0) {
>          goto fail_broken_refcounts;
> @@ -2634,7 +2636,7 @@ static int make_completely_empty(BlockDriverState *bs)
>          goto fail;
>      }
>  
> -    ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size);
> +    ret = bdrv_truncate(bs->file->bs, (3 + l1_clusters) * s->cluster_size);
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -2769,7 +2771,7 @@ static void dump_refcounts(BlockDriverState *bs)
>      int64_t nb_clusters, k, k1, size;
>      int refcount;
>  
> -    size = bdrv_getlength(bs->file);
> +    size = bdrv_getlength(bs->file->bs);
>      nb_clusters = size_to_clusters(s, size);
>      for(k = 0; k < nb_clusters;) {
>          k1 = k;
> diff --git a/block/qed-table.c b/block/qed-table.c
> index 513aa87..f4219b8 100644
> --- a/block/qed-table.c
> +++ b/block/qed-table.c
> @@ -63,7 +63,7 @@ static void qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
>      read_table_cb->iov.iov_len = s->header.cluster_size * s->header.table_size,
>  
>      qemu_iovec_init_external(qiov, &read_table_cb->iov, 1);
> -    bdrv_aio_readv(s->bs->file, offset / BDRV_SECTOR_SIZE, qiov,
> +    bdrv_aio_readv(s->bs->file->bs, offset / BDRV_SECTOR_SIZE, qiov,
>                     qiov->size / BDRV_SECTOR_SIZE,
>                     qed_read_table_cb, read_table_cb);
>  }
> @@ -152,7 +152,7 @@ static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
>      /* Adjust for offset into table */
>      offset += start * sizeof(uint64_t);
>  
> -    bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
> +    bdrv_aio_writev(s->bs->file->bs, offset / BDRV_SECTOR_SIZE,
>                      &write_table_cb->qiov,
>                      write_table_cb->qiov.size / BDRV_SECTOR_SIZE,
>                      qed_write_table_cb, write_table_cb);
> diff --git a/block/qed.c b/block/qed.c
> index a7ff1d9..d953f8c 100644
> --- a/block/qed.c
> +++ b/block/qed.c
> @@ -82,7 +82,7 @@ int qed_write_header_sync(BDRVQEDState *s)
>      int ret;
>  
>      qed_header_cpu_to_le(&s->header, &le);
> -    ret = bdrv_pwrite(s->bs->file, 0, &le, sizeof(le));
> +    ret = bdrv_pwrite(s->bs->file->bs, 0, &le, sizeof(le));
>      if (ret != sizeof(le)) {
>          return ret;
>      }
> @@ -119,7 +119,7 @@ static void qed_write_header_read_cb(void *opaque, int ret)
>      /* Update header */
>      qed_header_cpu_to_le(&s->header, (QEDHeader *)write_header_cb->buf);
>  
> -    bdrv_aio_writev(s->bs->file, 0, &write_header_cb->qiov,
> +    bdrv_aio_writev(s->bs->file->bs, 0, &write_header_cb->qiov,
>                      write_header_cb->nsectors, qed_write_header_cb,
>                      write_header_cb);
>  }
> @@ -152,7 +152,7 @@ static void qed_write_header(BDRVQEDState *s, BlockCompletionFunc cb,
>      write_header_cb->iov.iov_len = len;
>      qemu_iovec_init_external(&write_header_cb->qiov, &write_header_cb->iov, 1);
>  
> -    bdrv_aio_readv(s->bs->file, 0, &write_header_cb->qiov, nsectors,
> +    bdrv_aio_readv(s->bs->file->bs, 0, &write_header_cb->qiov, nsectors,
>                     qed_write_header_read_cb, write_header_cb);
>  }
>  
> @@ -392,7 +392,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
>      s->bs = bs;
>      QSIMPLEQ_INIT(&s->allocating_write_reqs);
>  
> -    ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header));
> +    ret = bdrv_pread(bs->file->bs, 0, &le_header, sizeof(le_header));
>      if (ret < 0) {
>          return ret;
>      }
> @@ -416,7 +416,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
>      }
>  
>      /* Round down file size to the last cluster */
> -    file_size = bdrv_getlength(bs->file);
> +    file_size = bdrv_getlength(bs->file->bs);
>      if (file_size < 0) {
>          return file_size;
>      }
> @@ -452,7 +452,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
>              return -EINVAL;
>          }
>  
> -        ret = qed_read_string(bs->file, s->header.backing_filename_offset,
> +        ret = qed_read_string(bs->file->bs, s->header.backing_filename_offset,
>                                s->header.backing_filename_size, bs->backing_file,
>                                sizeof(bs->backing_file));
>          if (ret < 0) {
> @@ -471,7 +471,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
>       * feature is no longer valid.
>       */
>      if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 &&
> -        !bdrv_is_read_only(bs->file) && !(flags & BDRV_O_INCOMING)) {
> +        !bdrv_is_read_only(bs->file->bs) && !(flags & BDRV_O_INCOMING)) {
>          s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK;
>  
>          ret = qed_write_header_sync(s);
> @@ -480,7 +480,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
>          }
>  
>          /* From here on only known autoclear feature bits are valid */
> -        bdrv_flush(bs->file);
> +        bdrv_flush(bs->file->bs);
>      }
>  
>      s->l1_table = qed_alloc_table(s);
> @@ -498,7 +498,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
>           * potentially inconsistent images to be opened read-only.  This can
>           * aid data recovery from an otherwise inconsistent image.
>           */
> -        if (!bdrv_is_read_only(bs->file) &&
> +        if (!bdrv_is_read_only(bs->file->bs) &&
>              !(flags & BDRV_O_INCOMING)) {
>              BdrvCheckResult result = {0};
>  
> @@ -541,7 +541,7 @@ static void bdrv_qed_close(BlockDriverState *bs)
>      bdrv_qed_detach_aio_context(bs);
>  
>      /* Ensure writes reach stable storage */
> -    bdrv_flush(bs->file);
> +    bdrv_flush(bs->file->bs);
>  
>      /* Clean shutdown, no check required on next open */
>      if (s->header.features & QED_F_NEED_CHECK) {
> @@ -839,7 +839,7 @@ static void qed_copy_from_backing_file_write(void *opaque, int ret)
>      }
>  
>      BLKDBG_EVENT(s->bs->file, BLKDBG_COW_WRITE);
> -    bdrv_aio_writev(s->bs->file, copy_cb->offset / BDRV_SECTOR_SIZE,
> +    bdrv_aio_writev(s->bs->file->bs, copy_cb->offset / BDRV_SECTOR_SIZE,
>                      &copy_cb->qiov, copy_cb->qiov.size / BDRV_SECTOR_SIZE,
>                      qed_copy_from_backing_file_cb, copy_cb);
>  }
> @@ -1055,7 +1055,7 @@ static void qed_aio_write_flush_before_l2_update(void *opaque, int ret)
>      QEDAIOCB *acb = opaque;
>      BDRVQEDState *s = acb_to_s(acb);
>  
> -    if (!bdrv_aio_flush(s->bs->file, qed_aio_write_l2_update_cb, opaque)) {
> +    if (!bdrv_aio_flush(s->bs->file->bs, qed_aio_write_l2_update_cb, opaque)) {
>          qed_aio_complete(acb, -EIO);
>      }
>  }
> @@ -1089,7 +1089,7 @@ static void qed_aio_write_main(void *opaque, int ret)
>      }
>  
>      BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
> -    bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
> +    bdrv_aio_writev(s->bs->file->bs, offset / BDRV_SECTOR_SIZE,
>                      &acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE,
>                      next_fn, acb);
>  }
> @@ -1321,7 +1321,7 @@ static void qed_aio_read_data(void *opaque, int ret,
>      }
>  
>      BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
> -    bdrv_aio_readv(bs->file, offset / BDRV_SECTOR_SIZE,
> +    bdrv_aio_readv(bs->file->bs, offset / BDRV_SECTOR_SIZE,
>                     &acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE,
>                     qed_aio_next_io, acb);
>      return;
> @@ -1580,7 +1580,7 @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs,
>      }
>  
>      /* Write new header */
> -    ret = bdrv_pwrite_sync(bs->file, 0, buffer, buffer_len);
> +    ret = bdrv_pwrite_sync(bs->file->bs, 0, buffer, buffer_len);
>      g_free(buffer);
>      if (ret == 0) {
>          memcpy(&s->header, &new_header, sizeof(new_header));
> @@ -1596,7 +1596,7 @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
>  
>      bdrv_qed_close(bs);
>  
> -    bdrv_invalidate_cache(bs->file, &local_err);
> +    bdrv_invalidate_cache(bs->file->bs, &local_err);
>      if (local_err) {
>          error_propagate(errp, local_err);
>          return;
> diff --git a/block/raw_bsd.c b/block/raw_bsd.c
> index e3d2d04..63ee911 100644
> --- a/block/raw_bsd.c
> +++ b/block/raw_bsd.c
> @@ -52,7 +52,7 @@ static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
>                                       int nb_sectors, QEMUIOVector *qiov)
>  {
>      BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
> -    return bdrv_co_readv(bs->file, sector_num, nb_sectors, qiov);
> +    return bdrv_co_readv(bs->file->bs, sector_num, nb_sectors, qiov);
>  }
>  
>  static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
> @@ -75,7 +75,7 @@ static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
>              return 0;
>          }
>  
> -        buf = qemu_try_blockalign(bs->file, 512);
> +        buf = qemu_try_blockalign(bs->file->bs, 512);
>          if (!buf) {
>              ret = -ENOMEM;
>              goto fail;
> @@ -102,7 +102,7 @@ static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
>      }
>  
>      BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
> -    ret = bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
> +    ret = bdrv_co_writev(bs->file->bs, sector_num, nb_sectors, qiov);
>  
>  fail:
>      if (qiov == &local_qiov) {
> @@ -125,58 +125,58 @@ static int coroutine_fn raw_co_write_zeroes(BlockDriverState *bs,
>                                              int64_t sector_num, int nb_sectors,
>                                              BdrvRequestFlags flags)
>  {
> -    return bdrv_co_write_zeroes(bs->file, sector_num, nb_sectors, flags);
> +    return bdrv_co_write_zeroes(bs->file->bs, sector_num, nb_sectors, flags);
>  }
>  
>  static int coroutine_fn raw_co_discard(BlockDriverState *bs,
>                                         int64_t sector_num, int nb_sectors)
>  {
> -    return bdrv_co_discard(bs->file, sector_num, nb_sectors);
> +    return bdrv_co_discard(bs->file->bs, sector_num, nb_sectors);
>  }
>  
>  static int64_t raw_getlength(BlockDriverState *bs)
>  {
> -    return bdrv_getlength(bs->file);
> +    return bdrv_getlength(bs->file->bs);
>  }
>  
>  static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
>  {
> -    return bdrv_get_info(bs->file, bdi);
> +    return bdrv_get_info(bs->file->bs, bdi);
>  }
>  
>  static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
>  {
> -    bs->bl = bs->file->bl;
> +    bs->bl = bs->file->bs->bl;
>  }
>  
>  static int raw_truncate(BlockDriverState *bs, int64_t offset)
>  {
> -    return bdrv_truncate(bs->file, offset);
> +    return bdrv_truncate(bs->file->bs, offset);
>  }
>  
>  static int raw_is_inserted(BlockDriverState *bs)
>  {
> -    return bdrv_is_inserted(bs->file);
> +    return bdrv_is_inserted(bs->file->bs);
>  }
>  
>  static int raw_media_changed(BlockDriverState *bs)
>  {
> -    return bdrv_media_changed(bs->file);
> +    return bdrv_media_changed(bs->file->bs);
>  }
>  
>  static void raw_eject(BlockDriverState *bs, bool eject_flag)
>  {
> -    bdrv_eject(bs->file, eject_flag);
> +    bdrv_eject(bs->file->bs, eject_flag);
>  }
>  
>  static void raw_lock_medium(BlockDriverState *bs, bool locked)
>  {
> -    bdrv_lock_medium(bs->file, locked);
> +    bdrv_lock_medium(bs->file->bs, locked);
>  }
>  
>  static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
>  {
> -    return bdrv_ioctl(bs->file, req, buf);
> +    return bdrv_ioctl(bs->file->bs, req, buf);
>  }
>  
>  static BlockAIOCB *raw_aio_ioctl(BlockDriverState *bs,
> @@ -184,12 +184,12 @@ static BlockAIOCB *raw_aio_ioctl(BlockDriverState *bs,
>                                   BlockCompletionFunc *cb,
>                                   void *opaque)
>  {
> -    return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque);
> +    return bdrv_aio_ioctl(bs->file->bs, req, buf, cb, opaque);
>  }
>  
>  static int raw_has_zero_init(BlockDriverState *bs)
>  {
> -    return bdrv_has_zero_init(bs->file);
> +    return bdrv_has_zero_init(bs->file->bs);
>  }
>  
>  static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
> @@ -207,7 +207,7 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
>  static int raw_open(BlockDriverState *bs, QDict *options, int flags,
>                      Error **errp)
>  {
> -    bs->sg = bs->file->sg;
> +    bs->sg = bs->file->bs->sg;
>  
>      if (bs->probed && !bdrv_is_read_only(bs)) {
>          fprintf(stderr,
> @@ -217,7 +217,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
>                  "raw images, write operations on block 0 will be restricted.\n"
>                  "         Specify the 'raw' format explicitly to remove the "
>                  "restrictions.\n",
> -                bs->file->filename);
> +                bs->file->bs->filename);
>      }
>  
>      return 0;
> @@ -237,12 +237,12 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
>  
>  static int raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
>  {
> -    return bdrv_probe_blocksizes(bs->file, bsz);
> +    return bdrv_probe_blocksizes(bs->file->bs, bsz);
>  }
>  
>  static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
>  {
> -    return bdrv_probe_geometry(bs->file, geo);
> +    return bdrv_probe_geometry(bs->file->bs, geo);
>  }
>  
>  BlockDriver bdrv_raw = {
> diff --git a/block/snapshot.c b/block/snapshot.c
> index 49e143e..89500f2 100644
> --- a/block/snapshot.c
> +++ b/block/snapshot.c
> @@ -149,7 +149,7 @@ int bdrv_can_snapshot(BlockDriverState *bs)
>  
>      if (!drv->bdrv_snapshot_create) {
>          if (bs->file != NULL) {
> -            return bdrv_can_snapshot(bs->file);
> +            return bdrv_can_snapshot(bs->file->bs);
>          }
>          return 0;
>      }
> @@ -168,7 +168,7 @@ int bdrv_snapshot_create(BlockDriverState *bs,
>          return drv->bdrv_snapshot_create(bs, sn_info);
>      }
>      if (bs->file) {
> -        return bdrv_snapshot_create(bs->file, sn_info);
> +        return bdrv_snapshot_create(bs->file->bs, sn_info);
>      }
>      return -ENOTSUP;
>  }
> @@ -188,10 +188,10 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
>  
>      if (bs->file) {
>          drv->bdrv_close(bs);
> -        ret = bdrv_snapshot_goto(bs->file, snapshot_id);
> +        ret = bdrv_snapshot_goto(bs->file->bs, snapshot_id);
>          open_ret = drv->bdrv_open(bs, NULL, bs->open_flags, NULL);
>          if (open_ret < 0) {
> -            bdrv_unref(bs->file);
> +            bdrv_unref(bs->file->bs);
>              bs->drv = NULL;
>              return open_ret;
>          }
> @@ -245,7 +245,7 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
>          return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
>      }
>      if (bs->file) {
> -        return bdrv_snapshot_delete(bs->file, snapshot_id, name, errp);
> +        return bdrv_snapshot_delete(bs->file->bs, snapshot_id, name, errp);
>      }
>      error_setg(errp, "Block format '%s' used by device '%s' "
>                 "does not support internal snapshot deletion",
> @@ -283,7 +283,7 @@ int bdrv_snapshot_list(BlockDriverState *bs,
>          return drv->bdrv_snapshot_list(bs, psn_info);
>      }
>      if (bs->file) {
> -        return bdrv_snapshot_list(bs->file, psn_info);
> +        return bdrv_snapshot_list(bs->file->bs, psn_info);
>      }
>      return -ENOTSUP;
>  }
> diff --git a/block/vdi.c b/block/vdi.c
> index 062a654..17626d4 100644
> --- a/block/vdi.c
> +++ b/block/vdi.c
> @@ -399,7 +399,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
>  
>      logout("\n");
>  
> -    ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1);
> +    ret = bdrv_read(bs->file->bs, 0, (uint8_t *)&header, 1);
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -490,13 +490,14 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
>  
>      bmap_size = header.blocks_in_image * sizeof(uint32_t);
>      bmap_size = DIV_ROUND_UP(bmap_size, SECTOR_SIZE);
> -    s->bmap = qemu_try_blockalign(bs->file, bmap_size * SECTOR_SIZE);
> +    s->bmap = qemu_try_blockalign(bs->file->bs, bmap_size * SECTOR_SIZE);
>      if (s->bmap == NULL) {
>          ret = -ENOMEM;
>          goto fail;
>      }
>  
> -    ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size);
> +    ret = bdrv_read(bs->file->bs, s->bmap_sector, (uint8_t *)s->bmap,
> +                    bmap_size);
>      if (ret < 0) {
>          goto fail_free_bmap;
>      }
> @@ -585,7 +586,7 @@ static int vdi_co_read(BlockDriverState *bs,
>              uint64_t offset = s->header.offset_data / SECTOR_SIZE +
>                                (uint64_t)bmap_entry * s->block_sectors +
>                                sector_in_block;
> -            ret = bdrv_read(bs->file, offset, buf, n_sectors);
> +            ret = bdrv_read(bs->file->bs, offset, buf, n_sectors);
>          }
>          logout("%u sectors read\n", n_sectors);
>  
> @@ -653,7 +654,7 @@ static int vdi_co_write(BlockDriverState *bs,
>               * acquire the lock and thus the padded cluster is written before
>               * the other coroutines can write to the affected area. */
>              qemu_co_mutex_lock(&s->write_lock);
> -            ret = bdrv_write(bs->file, offset, block, s->block_sectors);
> +            ret = bdrv_write(bs->file->bs, offset, block, s->block_sectors);
>              qemu_co_mutex_unlock(&s->write_lock);
>          } else {
>              uint64_t offset = s->header.offset_data / SECTOR_SIZE +
> @@ -669,7 +670,7 @@ static int vdi_co_write(BlockDriverState *bs,
>               * that that write operation has returned (there may be other writes
>               * in flight, but they do not concern this very operation). */
>              qemu_co_mutex_unlock(&s->write_lock);
> -            ret = bdrv_write(bs->file, offset, buf, n_sectors);
> +            ret = bdrv_write(bs->file->bs, offset, buf, n_sectors);
>          }
>  
>          nb_sectors -= n_sectors;
> @@ -694,7 +695,7 @@ static int vdi_co_write(BlockDriverState *bs,
>          assert(VDI_IS_ALLOCATED(bmap_first));
>          *header = s->header;
>          vdi_header_to_le(header);
> -        ret = bdrv_write(bs->file, 0, block, 1);
> +        ret = bdrv_write(bs->file->bs, 0, block, 1);
>          g_free(block);
>          block = NULL;
>  
> @@ -712,7 +713,7 @@ static int vdi_co_write(BlockDriverState *bs,
>          base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE;
>          logout("will write %u block map sectors starting from entry %u\n",
>                 n_sectors, bmap_first);
> -        ret = bdrv_write(bs->file, offset, base, n_sectors);
> +        ret = bdrv_write(bs->file->bs, offset, base, n_sectors);
>      }
>  
>      return ret;
> diff --git a/block/vhdx-log.c b/block/vhdx-log.c
> index 47fec63..47ae4b1 100644
> --- a/block/vhdx-log.c
> +++ b/block/vhdx-log.c
> @@ -81,7 +81,7 @@ static int vhdx_log_peek_hdr(BlockDriverState *bs, VHDXLogEntries *log,
>  
>      offset = log->offset + read;
>  
> -    ret = bdrv_pread(bs->file, offset, hdr, sizeof(VHDXLogEntryHeader));
> +    ret = bdrv_pread(bs->file->bs, offset, hdr, sizeof(VHDXLogEntryHeader));
>      if (ret < 0) {
>          goto exit;
>      }
> @@ -141,7 +141,7 @@ static int vhdx_log_read_sectors(BlockDriverState *bs, VHDXLogEntries *log,
>          }
>          offset = log->offset + read;
>  
> -        ret = bdrv_pread(bs->file, offset, buffer, VHDX_LOG_SECTOR_SIZE);
> +        ret = bdrv_pread(bs->file->bs, offset, buffer, VHDX_LOG_SECTOR_SIZE);
>          if (ret < 0) {
>              goto exit;
>          }
> @@ -191,7 +191,8 @@ static int vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log,
>              /* full */
>              break;
>          }
> -        ret = bdrv_pwrite(bs->file, offset, buffer_tmp, VHDX_LOG_SECTOR_SIZE);
> +        ret = bdrv_pwrite(bs->file->bs, offset, buffer_tmp,
> +                          VHDX_LOG_SECTOR_SIZE);
>          if (ret < 0) {
>              goto exit;
>          }
> @@ -353,7 +354,7 @@ static int vhdx_log_read_desc(BlockDriverState *bs, BDRVVHDXState *s,
>      }
>  
>      desc_sectors = vhdx_compute_desc_sectors(hdr.descriptor_count);
> -    desc_entries = qemu_try_blockalign(bs->file,
> +    desc_entries = qemu_try_blockalign(bs->file->bs,
>                                         desc_sectors * VHDX_LOG_SECTOR_SIZE);
>      if (desc_entries == NULL) {
>          ret = -ENOMEM;
> @@ -462,7 +463,7 @@ static int vhdx_log_flush_desc(BlockDriverState *bs, VHDXLogDescriptor *desc,
>  
>      /* count is only > 1 if we are writing zeroes */
>      for (i = 0; i < count; i++) {
> -        ret = bdrv_pwrite_sync(bs->file, file_offset, buffer,
> +        ret = bdrv_pwrite_sync(bs->file->bs, file_offset, buffer,
>                                 VHDX_LOG_SECTOR_SIZE);
>          if (ret < 0) {
>              goto exit;
> @@ -509,7 +510,7 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
>          /* if the log shows a FlushedFileOffset larger than our current file
>           * size, then that means the file has been truncated / corrupted, and
>           * we must refused to open it / use it */
> -        if (hdr_tmp.flushed_file_offset > bdrv_getlength(bs->file)) {
> +        if (hdr_tmp.flushed_file_offset > bdrv_getlength(bs->file->bs)) {
>              ret = -EINVAL;
>              goto exit;
>          }
> @@ -539,12 +540,12 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
>                  goto exit;
>              }
>          }
> -        if (bdrv_getlength(bs->file) < desc_entries->hdr.last_file_offset) {
> +        if (bdrv_getlength(bs->file->bs) < desc_entries->hdr.last_file_offset) {
>              new_file_size = desc_entries->hdr.last_file_offset;
>              if (new_file_size % (1024*1024)) {
>                  /* round up to nearest 1MB boundary */
>                  new_file_size = ((new_file_size >> 20) + 1) << 20;
> -                bdrv_truncate(bs->file, new_file_size);
> +                bdrv_truncate(bs->file->bs, new_file_size);
>              }
>          }
>          qemu_vfree(desc_entries);
> @@ -908,8 +909,8 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
>                  .sequence_number     = s->log.sequence,
>                  .descriptor_count    = sectors,
>                  .reserved            = 0,
> -                .flushed_file_offset = bdrv_getlength(bs->file),
> -                .last_file_offset    = bdrv_getlength(bs->file),
> +                .flushed_file_offset = bdrv_getlength(bs->file->bs),
> +                .last_file_offset    = bdrv_getlength(bs->file->bs),
>                };
>  
>      new_hdr.log_guid = header->log_guid;
> @@ -940,7 +941,7 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
>  
>          if (i == 0 && leading_length) {
>              /* partial sector at the front of the buffer */
> -            ret = bdrv_pread(bs->file, file_offset, merged_sector,
> +            ret = bdrv_pread(bs->file->bs, file_offset, merged_sector,
>                               VHDX_LOG_SECTOR_SIZE);
>              if (ret < 0) {
>                  goto exit;
> @@ -950,7 +951,7 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
>              sector_write = merged_sector;
>          } else if (i == sectors - 1 && trailing_length) {
>              /* partial sector at the end of the buffer */
> -            ret = bdrv_pread(bs->file,
> +            ret = bdrv_pread(bs->file->bs,
>                              file_offset,
>                              merged_sector + trailing_length,
>                              VHDX_LOG_SECTOR_SIZE - trailing_length);
> diff --git a/block/vhdx.c b/block/vhdx.c
> index d3bb1bd..2fe9a5e 100644
> --- a/block/vhdx.c
> +++ b/block/vhdx.c
> @@ -375,7 +375,7 @@ static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s,
>          inactive_header->log_guid = *log_guid;
>      }
>  
> -    ret = vhdx_write_header(bs->file, inactive_header, header_offset, true);
> +    ret = vhdx_write_header(bs->file->bs, inactive_header, header_offset, true);
>      if (ret < 0) {
>          goto exit;
>      }
> @@ -427,7 +427,8 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
>      /* We have to read the whole VHDX_HEADER_SIZE instead of
>       * sizeof(VHDXHeader), because the checksum is over the whole
>       * region */
> -    ret = bdrv_pread(bs->file, VHDX_HEADER1_OFFSET, buffer, VHDX_HEADER_SIZE);
> +    ret = bdrv_pread(bs->file->bs, VHDX_HEADER1_OFFSET, buffer,
> +                     VHDX_HEADER_SIZE);
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -443,7 +444,8 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
>          }
>      }
>  
> -    ret = bdrv_pread(bs->file, VHDX_HEADER2_OFFSET, buffer, VHDX_HEADER_SIZE);
> +    ret = bdrv_pread(bs->file->bs, VHDX_HEADER2_OFFSET, buffer,
> +                     VHDX_HEADER_SIZE);
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -516,7 +518,7 @@ static int vhdx_open_region_tables(BlockDriverState *bs, BDRVVHDXState *s)
>       * whole block */
>      buffer = qemu_blockalign(bs, VHDX_HEADER_BLOCK_SIZE);
>  
> -    ret = bdrv_pread(bs->file, VHDX_REGION_TABLE_OFFSET, buffer,
> +    ret = bdrv_pread(bs->file->bs, VHDX_REGION_TABLE_OFFSET, buffer,
>                       VHDX_HEADER_BLOCK_SIZE);
>      if (ret < 0) {
>          goto fail;
> @@ -629,7 +631,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
>  
>      buffer = qemu_blockalign(bs, VHDX_METADATA_TABLE_MAX_SIZE);
>  
> -    ret = bdrv_pread(bs->file, s->metadata_rt.file_offset, buffer,
> +    ret = bdrv_pread(bs->file->bs, s->metadata_rt.file_offset, buffer,
>                       VHDX_METADATA_TABLE_MAX_SIZE);
>      if (ret < 0) {
>          goto exit;
> @@ -732,7 +734,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
>          goto exit;
>      }
>  
> -    ret = bdrv_pread(bs->file,
> +    ret = bdrv_pread(bs->file->bs,
>                       s->metadata_entries.file_parameters_entry.offset
>                                           + s->metadata_rt.file_offset,
>                       &s->params,
> @@ -767,7 +769,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
>      /* determine virtual disk size, logical sector size,
>       * and phys sector size */
>  
> -    ret = bdrv_pread(bs->file,
> +    ret = bdrv_pread(bs->file->bs,
>                       s->metadata_entries.virtual_disk_size_entry.offset
>                                             + s->metadata_rt.file_offset,
>                       &s->virtual_disk_size,
> @@ -775,7 +777,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
>      if (ret < 0) {
>          goto exit;
>      }
> -    ret = bdrv_pread(bs->file,
> +    ret = bdrv_pread(bs->file->bs,
>                       s->metadata_entries.logical_sector_size_entry.offset
>                                               + s->metadata_rt.file_offset,
>                       &s->logical_sector_size,
> @@ -783,7 +785,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
>      if (ret < 0) {
>          goto exit;
>      }
> -    ret = bdrv_pread(bs->file,
> +    ret = bdrv_pread(bs->file->bs,
>                       s->metadata_entries.phys_sector_size_entry.offset
>                                            + s->metadata_rt.file_offset,
>                       &s->physical_sector_size,
> @@ -906,7 +908,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
>      QLIST_INIT(&s->regions);
>  
>      /* validate the file signature */
> -    ret = bdrv_pread(bs->file, 0, &signature, sizeof(uint64_t));
> +    ret = bdrv_pread(bs->file->bs, 0, &signature, sizeof(uint64_t));
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -959,13 +961,13 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
>      }
>  
>      /* s->bat is freed in vhdx_close() */
> -    s->bat = qemu_try_blockalign(bs->file, s->bat_rt.length);
> +    s->bat = qemu_try_blockalign(bs->file->bs, s->bat_rt.length);
>      if (s->bat == NULL) {
>          ret = -ENOMEM;
>          goto fail;
>      }
>  
> -    ret = bdrv_pread(bs->file, s->bat_offset, s->bat, s->bat_rt.length);
> +    ret = bdrv_pread(bs->file->bs, s->bat_offset, s->bat, s->bat_rt.length);
>      if (ret < 0) {
>          goto fail;
>      }
> @@ -1118,7 +1120,7 @@ static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num,
>                  break;
>              case PAYLOAD_BLOCK_FULLY_PRESENT:
>                  qemu_co_mutex_unlock(&s->lock);
> -                ret = bdrv_co_readv(bs->file,
> +                ret = bdrv_co_readv(bs->file->bs,
>                                      sinfo.file_offset >> BDRV_SECTOR_BITS,
>                                      sinfo.sectors_avail, &hd_qiov);
>                  qemu_co_mutex_lock(&s->lock);
> @@ -1156,12 +1158,12 @@ exit:
>  static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
>                                      uint64_t *new_offset)
>  {
> -    *new_offset = bdrv_getlength(bs->file);
> +    *new_offset = bdrv_getlength(bs->file->bs);
>  
>      /* per the spec, the address for a block is in units of 1MB */
>      *new_offset = ROUND_UP(*new_offset, 1024 * 1024);
>  
> -    return bdrv_truncate(bs->file, *new_offset + s->block_size);
> +    return bdrv_truncate(bs->file->bs, *new_offset + s->block_size);
>  }
>  
>  /*
> @@ -1260,7 +1262,7 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
>                  /* Queue another write of zero buffers if the underlying file
>                   * does not zero-fill on file extension */
>  
> -                if (bdrv_has_zero_init(bs->file) == 0) {
> +                if (bdrv_has_zero_init(bs->file->bs) == 0) {
>                      use_zero_buffers = true;
>  
>                      /* zero fill the front, if any */
> @@ -1327,7 +1329,7 @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
>                  }
>                  /* block exists, so we can just overwrite it */
>                  qemu_co_mutex_unlock(&s->lock);
> -                ret = bdrv_co_writev(bs->file,
> +                ret = bdrv_co_writev(bs->file->bs,
>                                      sinfo.file_offset >> BDRV_SECTOR_BITS,
>                                      sectors_to_write, &hd_qiov);
>                  qemu_co_mutex_lock(&s->lock);
> diff --git a/block/vmdk.c b/block/vmdk.c
> index 9702132..9f7e7db 100644
> --- a/block/vmdk.c
> +++ b/block/vmdk.c
> @@ -221,7 +221,7 @@ static void vmdk_free_extents(BlockDriverState *bs)
>          g_free(e->l2_cache);
>          g_free(e->l1_backup_table);
>          g_free(e->type);
> -        if (e->file != bs->file_child) {
> +        if (e->file != bs->file) {
>              bdrv_unref_child(bs, e->file);
>          }
>      }
> @@ -248,7 +248,7 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
>      BDRVVmdkState *s = bs->opaque;
>      int ret;
>  
> -    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
> +    ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
>      if (ret < 0) {
>          return 0;
>      }
> @@ -278,7 +278,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
>      BDRVVmdkState *s = bs->opaque;
>      int ret;
>  
> -    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
> +    ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -297,7 +297,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
>          pstrcat(desc, sizeof(desc), tmp_desc);
>      }
>  
> -    ret = bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE);
> +    ret = bdrv_pwrite_sync(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -340,7 +340,7 @@ static int vmdk_parent_open(BlockDriverState *bs)
>      int ret;
>  
>      desc[DESC_SIZE] = '\0';
> -    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
> +    ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -621,7 +621,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
>          } QEMU_PACKED footer;
>  
>          ret = bdrv_pread(file->bs,
> -            bs->file->total_sectors * 512 - 1536,
> +            bs->file->bs->total_sectors * 512 - 1536,
>              &footer, sizeof(footer));
>          if (ret < 0) {
>              error_setg_errno(errp, -ret, "Failed to read footer");
> @@ -819,7 +819,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
>              !desc_file_path[0])
>          {
>              error_setg(errp, "Cannot use relative extent paths with VMDK "
> -                       "descriptor file '%s'", bs->file->filename);
> +                       "descriptor file '%s'", bs->file->bs->filename);
>              return -EINVAL;
>          }
>  
> @@ -905,7 +905,8 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
>      }
>      s->create_type = g_strdup(ct);
>      s->desc_offset = 0;
> -    ret = vmdk_parse_extents(buf, bs, bs->file->exact_filename, options, errp);
> +    ret = vmdk_parse_extents(buf, bs, bs->file->bs->exact_filename, options,
> +                             errp);
>  exit:
>      return ret;
>  }
> @@ -918,7 +919,7 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
>      BDRVVmdkState *s = bs->opaque;
>      uint32_t magic;
>  
> -    buf = vmdk_read_desc(bs->file, 0, errp);
> +    buf = vmdk_read_desc(bs->file->bs, 0, errp);
>      if (!buf) {
>          return -EINVAL;
>      }
> @@ -927,7 +928,7 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
>      switch (magic) {
>          case VMDK3_MAGIC:
>          case VMDK4_MAGIC:
> -            ret = vmdk_open_sparse(bs, bs->file_child, flags, buf, options,
> +            ret = vmdk_open_sparse(bs, bs->file, flags, buf, options,
>                                     errp);
>              s->desc_offset = 0x200;
>              break;
> @@ -1275,7 +1276,7 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
>          break;
>      case VMDK_OK:
>          ret = BDRV_BLOCK_DATA;
> -        if (extent->file == bs->file_child && !extent->compressed) {
> +        if (extent->file == bs->file && !extent->compressed) {
>              ret |= BDRV_BLOCK_OFFSET_VALID | offset;
>          }
>  
> @@ -2051,12 +2052,12 @@ static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs)
>      int64_t r;
>      BDRVVmdkState *s = bs->opaque;
>  
> -    ret = bdrv_get_allocated_file_size(bs->file);
> +    ret = bdrv_get_allocated_file_size(bs->file->bs);
>      if (ret < 0) {
>          return ret;
>      }
>      for (i = 0; i < s->num_extents; i++) {
> -        if (s->extents[i].file == bs->file_child) {
> +        if (s->extents[i].file == bs->file) {
>              continue;
>          }
>          r = bdrv_get_allocated_file_size(s->extents[i].file->bs);
> diff --git a/block/vpc.c b/block/vpc.c
> index 2b3b518..299d373 100644
> --- a/block/vpc.c
> +++ b/block/vpc.c
> @@ -172,14 +172,14 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
>      int disk_type = VHD_DYNAMIC;
>      int ret;
>  
> -    ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE);
> +    ret = bdrv_pread(bs->file->bs, 0, s->footer_buf, HEADER_SIZE);
>      if (ret < 0) {
>          goto fail;
>      }
>  
>      footer = (VHDFooter *) s->footer_buf;
>      if (strncmp(footer->creator, "conectix", 8)) {
> -        int64_t offset = bdrv_getlength(bs->file);
> +        int64_t offset = bdrv_getlength(bs->file->bs);
>          if (offset < 0) {
>              ret = offset;
>              goto fail;
> @@ -189,7 +189,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
>          }
>  
>          /* If a fixed disk, the footer is found only at the end of the file */
> -        ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf,
> +        ret = bdrv_pread(bs->file->bs, offset-HEADER_SIZE, s->footer_buf,
>                           HEADER_SIZE);
>          if (ret < 0) {
>              goto fail;
> @@ -232,7 +232,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
>      }
>  
>      if (disk_type == VHD_DYNAMIC) {
> -        ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
> +        ret = bdrv_pread(bs->file->bs, be64_to_cpu(footer->data_offset), buf,
>                           HEADER_SIZE);
>          if (ret < 0) {
>              goto fail;
> @@ -280,7 +280,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
>  
>          pagetable_size = (uint64_t) s->max_table_entries * 4;
>  
> -        s->pagetable = qemu_try_blockalign(bs->file, pagetable_size);
> +        s->pagetable = qemu_try_blockalign(bs->file->bs, pagetable_size);
>          if (s->pagetable == NULL) {
>              ret = -ENOMEM;
>              goto fail;
> @@ -288,7 +288,8 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
>  
>          s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
>  
> -        ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable, pagetable_size);
> +        ret = bdrv_pread(bs->file->bs, s->bat_offset, s->pagetable,
> +                         pagetable_size);
>          if (ret < 0) {
>              goto fail;
>          }
> @@ -308,7 +309,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
>              }
>          }
>  
> -        if (s->free_data_block_offset > bdrv_getlength(bs->file)) {
> +        if (s->free_data_block_offset > bdrv_getlength(bs->file->bs)) {
>              error_setg(errp, "block-vpc: free_data_block_offset points after "
>                               "the end of file. The image has been truncated.");
>              ret = -EINVAL;
> @@ -383,7 +384,7 @@ static inline int64_t get_sector_offset(BlockDriverState *bs,
>  
>          s->last_bitmap_offset = bitmap_offset;
>          memset(bitmap, 0xff, s->bitmap_size);
> -        bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
> +        bdrv_pwrite_sync(bs->file->bs, bitmap_offset, bitmap, s->bitmap_size);
>      }
>  
>      return block_offset;
> @@ -401,7 +402,7 @@ static int rewrite_footer(BlockDriverState* bs)
>      BDRVVPCState *s = bs->opaque;
>      int64_t offset = s->free_data_block_offset;
>  
> -    ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE);
> +    ret = bdrv_pwrite_sync(bs->file->bs, offset, s->footer_buf, HEADER_SIZE);
>      if (ret < 0)
>          return ret;
>  
> @@ -436,7 +437,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
>  
>      // Initialize the block's bitmap
>      memset(bitmap, 0xff, s->bitmap_size);
> -    ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
> +    ret = bdrv_pwrite_sync(bs->file->bs, s->free_data_block_offset, bitmap,
>          s->bitmap_size);
>      if (ret < 0) {
>          return ret;
> @@ -451,7 +452,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
>      // Write BAT entry to disk
>      bat_offset = s->bat_offset + (4 * index);
>      bat_value = cpu_to_be32(s->pagetable[index]);
> -    ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
> +    ret = bdrv_pwrite_sync(bs->file->bs, bat_offset, &bat_value, 4);
>      if (ret < 0)
>          goto fail;
>  
> @@ -485,7 +486,7 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num,
>      VHDFooter *footer = (VHDFooter *) s->footer_buf;
>  
>      if (be32_to_cpu(footer->type) == VHD_FIXED) {
> -        return bdrv_read(bs->file, sector_num, buf, nb_sectors);
> +        return bdrv_read(bs->file->bs, sector_num, buf, nb_sectors);
>      }
>      while (nb_sectors > 0) {
>          offset = get_sector_offset(bs, sector_num, 0);
> @@ -499,7 +500,7 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num,
>          if (offset == -1) {
>              memset(buf, 0, sectors * BDRV_SECTOR_SIZE);
>          } else {
> -            ret = bdrv_pread(bs->file, offset, buf,
> +            ret = bdrv_pread(bs->file->bs, offset, buf,
>                  sectors * BDRV_SECTOR_SIZE);
>              if (ret != sectors * BDRV_SECTOR_SIZE) {
>                  return -1;
> @@ -534,7 +535,7 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
>      VHDFooter *footer =  (VHDFooter *) s->footer_buf;
>  
>      if (be32_to_cpu(footer->type) == VHD_FIXED) {
> -        return bdrv_write(bs->file, sector_num, buf, nb_sectors);
> +        return bdrv_write(bs->file->bs, sector_num, buf, nb_sectors);
>      }
>      while (nb_sectors > 0) {
>          offset = get_sector_offset(bs, sector_num, 1);
> @@ -551,7 +552,8 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
>                  return -1;
>          }
>  
> -        ret = bdrv_pwrite(bs->file, offset, buf, sectors * BDRV_SECTOR_SIZE);
> +        ret = bdrv_pwrite(bs->file->bs, offset, buf,
> +                          sectors * BDRV_SECTOR_SIZE);
>          if (ret != sectors * BDRV_SECTOR_SIZE) {
>              return -1;
>          }
> @@ -878,7 +880,7 @@ static int vpc_has_zero_init(BlockDriverState *bs)
>      VHDFooter *footer =  (VHDFooter *) s->footer_buf;
>  
>      if (be32_to_cpu(footer->type) == VHD_FIXED) {
> -        return bdrv_has_zero_init(bs->file);
> +        return bdrv_has_zero_init(bs->file->bs);
>      } else {
>          return 1;
>      }
> diff --git a/include/block/block.h b/include/block/block.h
> index 2dd6630..7ebb35d 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -585,7 +585,13 @@ typedef enum {
>      BLKDBG_EVENT_MAX,
>  } BlkDebugEvent;
>  
> -#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
> +#define BLKDBG_EVENT(child, evt) \
> +    do { \
> +        if (child) { \
> +            bdrv_debug_event(child->bs, evt); \
> +        } \
> +    } while(0)
> +

I'm a bit surprised you changed the argument type to BdrvChild, since adding a
BLKDBG_EVENT_CHILD is more natural to me. But that probably doesn't hurt much:

Reviewed-by: Fam Zheng <famz@redhat.com>
Kevin Wolf Oct. 9, 2015, 11:34 a.m. UTC | #4
Am 08.10.2015 um 12:23 hat Fam Zheng geschrieben:
> On Thu, 10/01 15:13, Kevin Wolf wrote:
> > @@ -1935,6 +1932,11 @@ void bdrv_close(BlockDriverState *bs)
> >              bdrv_unref(backing_hd);
> >          }
> >  
> > +        if (bs->file != NULL) {
> > +            bdrv_unref_child(bs, bs->file);
> > +            bs->file = NULL;
> > +        }
> > +
> >          QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
> >              /* TODO Remove bdrv_unref() from drivers' close function and use
> >               * bdrv_unref_child() here */
> > @@ -1946,7 +1948,6 @@ void bdrv_close(BlockDriverState *bs)
> >  
> >          g_free(bs->opaque);
> >          bs->opaque = NULL;
> > -        bs->drv = NULL;
> >          bs->copy_on_read = 0;
> >          bs->backing_file[0] = '\0';
> >          bs->backing_format[0] = '\0';
> > @@ -1959,11 +1960,6 @@ void bdrv_close(BlockDriverState *bs)
> >          bs->options = NULL;
> >          QDECREF(bs->full_open_options);
> >          bs->full_open_options = NULL;
> > -
> > -        if (bs->file != NULL) {
> > -            bdrv_unref(bs->file);
> > -            bs->file = NULL;
> > -        }
> 
> Why do you need to move them up? Changing bdrv_unref to bdrv_unref_child is not
> enough?

I think it conflicted with the foreach loop above. Technically it might
have worked if I left it as bdrv_unref() in its original place because
the loop only calls bdrv_detach_child(), but with the intention of
replacing the detach with an unref I think it makes more sense to do a
proper bdrv_unref_child() before the loop.

> > diff --git a/block/blkdebug.c b/block/blkdebug.c
> > index bc247f4..117fce6 100644
> > --- a/block/blkdebug.c
> > +++ b/block/blkdebug.c
> > @@ -427,10 +427,10 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
> >      s->state = 1;
> >  
> >      /* Open the backing file */
> 
> Isn't "backing file" a confusing term for bs->file given that we have
> bs->backing_hd? :)

I guess it is, even though blkdebug doesn't use bs->backing_hd. Feel
free to send a patch.

> > -    assert(bs->file == NULL);
> > -    ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image",
> > -                          bs, &child_file, false, &local_err);
> > -    if (ret < 0) {
> 
> Should we keep the assertion?

The assertion was there to ensure that a new BDS is created instead of
reusing an existing one. bdrv_open_child() always creates a new one.

> > +    bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
> > +                               bs, &child_file, false, &local_err);
> > +    if (local_err) {
> > +        ret = -EINVAL;
> >          error_propagate(errp, local_err);
> >          goto out;
> >      }

Kevin
diff mbox

Patch

diff --git a/block.c b/block.c
index 75afed1..8fd345b 100644
--- a/block.c
+++ b/block.c
@@ -809,7 +809,7 @@  static QemuOptsList bdrv_runtime_opts = {
  *
  * Removes all processed options from *options.
  */
-static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
+static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file,
     QDict *options, int flags, BlockDriver *drv, Error **errp)
 {
     int ret, open_flags;
@@ -823,7 +823,7 @@  static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
     assert(options != NULL && bs->options != options);
 
     if (file != NULL) {
-        filename = file->filename;
+        filename = file->bs->filename;
     } else {
         filename = qdict_get_try_str(options, "filename");
     }
@@ -1401,7 +1401,8 @@  static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
                              const BdrvChildRole *child_role, Error **errp)
 {
     int ret;
-    BlockDriverState *file = NULL, *bs;
+    BdrvChild *file = NULL;
+    BlockDriverState *bs;
     BlockDriver *drv = NULL;
     const char *drvname;
     Error *local_err = NULL;
@@ -1485,25 +1486,20 @@  static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
             flags = bdrv_backing_flags(flags);
         }
 
-        assert(file == NULL);
         bs->open_flags = flags;
 
-        bs->file_child = bdrv_open_child(filename, options, "file", bs,
-                                         &child_file, true, &local_err);
+        file = bdrv_open_child(filename, options, "file", bs,
+                               &child_file, true, &local_err);
         if (local_err) {
             ret = -EINVAL;
             goto fail;
         }
-
-        if (bs->file_child) {
-            file = bs->file_child->bs;
-        }
     }
 
     /* Image format probing */
     bs->probed = !drv;
     if (!drv && file) {
-        ret = find_image_format(file, filename, &drv, &local_err);
+        ret = find_image_format(file->bs, filename, &drv, &local_err);
         if (ret < 0) {
             goto fail;
         }
@@ -1526,7 +1522,7 @@  static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
     }
 
     if (file && (bs->file != file)) {
-        bdrv_unref(file);
+        bdrv_unref_child(bs, file);
         file = NULL;
     }
 
@@ -1587,7 +1583,7 @@  static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
 
 fail:
     if (file != NULL) {
-        bdrv_unref(file);
+        bdrv_unref_child(bs, file);
     }
     QDECREF(bs->options);
     QDECREF(options);
@@ -1928,6 +1924,7 @@  void bdrv_close(BlockDriverState *bs)
         BdrvChild *child, *next;
 
         bs->drv->bdrv_close(bs);
+        bs->drv = NULL;
 
         if (bs->backing_hd) {
             BlockDriverState *backing_hd = bs->backing_hd;
@@ -1935,6 +1932,11 @@  void bdrv_close(BlockDriverState *bs)
             bdrv_unref(backing_hd);
         }
 
+        if (bs->file != NULL) {
+            bdrv_unref_child(bs, bs->file);
+            bs->file = NULL;
+        }
+
         QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
             /* TODO Remove bdrv_unref() from drivers' close function and use
              * bdrv_unref_child() here */
@@ -1946,7 +1948,6 @@  void bdrv_close(BlockDriverState *bs)
 
         g_free(bs->opaque);
         bs->opaque = NULL;
-        bs->drv = NULL;
         bs->copy_on_read = 0;
         bs->backing_file[0] = '\0';
         bs->backing_format[0] = '\0';
@@ -1959,11 +1960,6 @@  void bdrv_close(BlockDriverState *bs)
         bs->options = NULL;
         QDECREF(bs->full_open_options);
         bs->full_open_options = NULL;
-
-        if (bs->file != NULL) {
-            bdrv_unref(bs->file);
-            bs->file = NULL;
-        }
     }
 
     if (bs->blk) {
@@ -2566,7 +2562,7 @@  int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
         return drv->bdrv_get_allocated_file_size(bs);
     }
     if (bs->file) {
-        return bdrv_get_allocated_file_size(bs->file);
+        return bdrv_get_allocated_file_size(bs->file->bs);
     }
     return -ENOTSUP;
 }
@@ -3048,7 +3044,7 @@  int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
                           const char *tag)
 {
     while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) {
-        bs = bs->file;
+        bs = bs->file ? bs->file->bs : NULL;
     }
 
     if (bs && bs->drv && bs->drv->bdrv_debug_breakpoint) {
@@ -3061,7 +3057,7 @@  int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
 int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag)
 {
     while (bs && bs->drv && !bs->drv->bdrv_debug_remove_breakpoint) {
-        bs = bs->file;
+        bs = bs->file ? bs->file->bs : NULL;
     }
 
     if (bs && bs->drv && bs->drv->bdrv_debug_remove_breakpoint) {
@@ -3074,7 +3070,7 @@  int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag)
 int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
 {
     while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) {
-        bs = bs->file;
+        bs = bs->file ? bs->file->bs : NULL;
     }
 
     if (bs && bs->drv && bs->drv->bdrv_debug_resume) {
@@ -3087,7 +3083,7 @@  int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
 bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag)
 {
     while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) {
-        bs = bs->file;
+        bs = bs->file ? bs->file->bs : NULL;
     }
 
     if (bs && bs->drv && bs->drv->bdrv_debug_is_suspended) {
@@ -3209,7 +3205,7 @@  void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
     if (bs->drv->bdrv_invalidate_cache) {
         bs->drv->bdrv_invalidate_cache(bs, &local_err);
     } else if (bs->file) {
-        bdrv_invalidate_cache(bs->file, &local_err);
+        bdrv_invalidate_cache(bs->file->bs, &local_err);
     }
     if (local_err) {
         error_propagate(errp, local_err);
@@ -3939,7 +3935,7 @@  void bdrv_detach_aio_context(BlockDriverState *bs)
         bs->drv->bdrv_detach_aio_context(bs);
     }
     if (bs->file) {
-        bdrv_detach_aio_context(bs->file);
+        bdrv_detach_aio_context(bs->file->bs);
     }
     if (bs->backing_hd) {
         bdrv_detach_aio_context(bs->backing_hd);
@@ -3963,7 +3959,7 @@  void bdrv_attach_aio_context(BlockDriverState *bs,
         bdrv_attach_aio_context(bs->backing_hd, new_context);
     }
     if (bs->file) {
-        bdrv_attach_aio_context(bs->file, new_context);
+        bdrv_attach_aio_context(bs->file->bs, new_context);
     }
     if (bs->drv->bdrv_attach_aio_context) {
         bs->drv->bdrv_attach_aio_context(bs, new_context);
@@ -4175,7 +4171,7 @@  void bdrv_refresh_filename(BlockDriverState *bs)
     /* This BDS's file name will most probably depend on its file's name, so
      * refresh that first */
     if (bs->file) {
-        bdrv_refresh_filename(bs->file);
+        bdrv_refresh_filename(bs->file->bs);
     }
 
     if (drv->bdrv_refresh_filename) {
@@ -4203,19 +4199,20 @@  void bdrv_refresh_filename(BlockDriverState *bs)
 
         /* If no specific options have been given for this BDS, the filename of
          * the underlying file should suffice for this one as well */
-        if (bs->file->exact_filename[0] && !has_open_options) {
-            strcpy(bs->exact_filename, bs->file->exact_filename);
+        if (bs->file->bs->exact_filename[0] && !has_open_options) {
+            strcpy(bs->exact_filename, bs->file->bs->exact_filename);
         }
         /* Reconstructing the full options QDict is simple for most format block
          * drivers, as long as the full options are known for the underlying
          * file BDS. The full options QDict of that file BDS should somehow
          * contain a representation of the filename, therefore the following
          * suffices without querying the (exact_)filename of this BDS. */
-        if (bs->file->full_open_options) {
+        if (bs->file->bs->full_open_options) {
             qdict_put_obj(opts, "driver",
                           QOBJECT(qstring_from_str(drv->format_name)));
-            QINCREF(bs->file->full_open_options);
-            qdict_put_obj(opts, "file", QOBJECT(bs->file->full_open_options));
+            QINCREF(bs->file->bs->full_open_options);
+            qdict_put_obj(opts, "file",
+                          QOBJECT(bs->file->bs->full_open_options));
 
             bs->full_open_options = opts;
         } else {
diff --git a/block/blkdebug.c b/block/blkdebug.c
index bc247f4..117fce6 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -427,10 +427,10 @@  static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
     s->state = 1;
 
     /* Open the backing file */
-    assert(bs->file == NULL);
-    ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-image"), options, "image",
-                          bs, &child_file, false, &local_err);
-    if (ret < 0) {
+    bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
+                               bs, &child_file, false, &local_err);
+    if (local_err) {
+        ret = -EINVAL;
         error_propagate(errp, local_err);
         goto out;
     }
@@ -449,7 +449,7 @@  static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
     goto out;
 
 fail_unref:
-    bdrv_unref(bs->file);
+    bdrv_unref(bs->file->bs);
 out:
     qemu_opts_del(opts);
     return ret;
@@ -510,7 +510,8 @@  static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
         return inject_error(bs, cb, opaque, rule);
     }
 
-    return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
+    return bdrv_aio_readv(bs->file->bs, sector_num, qiov, nb_sectors,
+                          cb, opaque);
 }
 
 static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
@@ -532,7 +533,8 @@  static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
         return inject_error(bs, cb, opaque, rule);
     }
 
-    return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
+    return bdrv_aio_writev(bs->file->bs, sector_num, qiov, nb_sectors,
+                           cb, opaque);
 }
 
 static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
@@ -551,7 +553,7 @@  static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
         return inject_error(bs, cb, opaque, rule);
     }
 
-    return bdrv_aio_flush(bs->file, cb, opaque);
+    return bdrv_aio_flush(bs->file->bs, cb, opaque);
 }
 
 
@@ -716,12 +718,12 @@  static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag)
 
 static int64_t blkdebug_getlength(BlockDriverState *bs)
 {
-    return bdrv_getlength(bs->file);
+    return bdrv_getlength(bs->file->bs);
 }
 
 static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
 {
-    return bdrv_truncate(bs->file, offset);
+    return bdrv_truncate(bs->file->bs, offset);
 }
 
 static void blkdebug_refresh_filename(BlockDriverState *bs)
@@ -741,24 +743,24 @@  static void blkdebug_refresh_filename(BlockDriverState *bs)
         }
     }
 
-    if (force_json && !bs->file->full_open_options) {
+    if (force_json && !bs->file->bs->full_open_options) {
         /* The config file cannot be recreated, so creating a plain filename
          * is impossible */
         return;
     }
 
-    if (!force_json && bs->file->exact_filename[0]) {
+    if (!force_json && bs->file->bs->exact_filename[0]) {
         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
                  "blkdebug:%s:%s",
                  qdict_get_try_str(bs->options, "config") ?: "",
-                 bs->file->exact_filename);
+                 bs->file->bs->exact_filename);
     }
 
     opts = qdict_new();
     qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
 
-    QINCREF(bs->file->full_open_options);
-    qdict_put_obj(opts, "image", QOBJECT(bs->file->full_open_options));
+    QINCREF(bs->file->bs->full_open_options);
+    qdict_put_obj(opts, "image", QOBJECT(bs->file->bs->full_open_options));
 
     for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
         if (strcmp(qdict_entry_key(e), "x-image") &&
diff --git a/block/blkverify.c b/block/blkverify.c
index 6b71622..f8655ad 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -123,10 +123,10 @@  static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     /* Open the raw file */
-    assert(bs->file == NULL);
-    ret = bdrv_open_image(&bs->file, qemu_opt_get(opts, "x-raw"), options,
-                          "raw", bs, &child_file, false, &local_err);
-    if (ret < 0) {
+    bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw",
+                               bs, &child_file, false, &local_err);
+    if (local_err) {
+        ret = -EINVAL;
         error_propagate(errp, local_err);
         goto fail;
     }
@@ -238,13 +238,13 @@  static BlockAIOCB *blkverify_aio_readv(BlockDriverState *bs,
                                             nb_sectors, cb, opaque);
 
     acb->verify = blkverify_verify_readv;
-    acb->buf = qemu_blockalign(bs->file, qiov->size);
+    acb->buf = qemu_blockalign(bs->file->bs, qiov->size);
     qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
     qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
 
     bdrv_aio_readv(s->test_file->bs, sector_num, qiov, nb_sectors,
                    blkverify_aio_cb, acb);
-    bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
+    bdrv_aio_readv(bs->file->bs, sector_num, &acb->raw_qiov, nb_sectors,
                    blkverify_aio_cb, acb);
     return &acb->common;
 }
@@ -259,7 +259,7 @@  static BlockAIOCB *blkverify_aio_writev(BlockDriverState *bs,
 
     bdrv_aio_writev(s->test_file->bs, sector_num, qiov, nb_sectors,
                     blkverify_aio_cb, acb);
-    bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
+    bdrv_aio_writev(bs->file->bs, sector_num, qiov, nb_sectors,
                     blkverify_aio_cb, acb);
     return &acb->common;
 }
@@ -279,7 +279,7 @@  static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
 {
     BDRVBlkverifyState *s = bs->opaque;
 
-    bool perm = bdrv_recurse_is_first_non_filter(bs->file, candidate);
+    bool perm = bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
 
     if (perm) {
         return true;
@@ -308,15 +308,17 @@  static void blkverify_refresh_filename(BlockDriverState *bs)
 {
     BDRVBlkverifyState *s = bs->opaque;
 
-    /* bs->file has already been refreshed */
+    /* bs->file->bs has already been refreshed */
     bdrv_refresh_filename(s->test_file->bs);
 
-    if (bs->file->full_open_options && s->test_file->bs->full_open_options) {
+    if (bs->file->bs->full_open_options
+        && s->test_file->bs->full_open_options)
+    {
         QDict *opts = qdict_new();
         qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkverify")));
 
-        QINCREF(bs->file->full_open_options);
-        qdict_put_obj(opts, "raw", QOBJECT(bs->file->full_open_options));
+        QINCREF(bs->file->bs->full_open_options);
+        qdict_put_obj(opts, "raw", QOBJECT(bs->file->bs->full_open_options));
         QINCREF(s->test_file->bs->full_open_options);
         qdict_put_obj(opts, "test",
                       QOBJECT(s->test_file->bs->full_open_options));
@@ -324,10 +326,13 @@  static void blkverify_refresh_filename(BlockDriverState *bs)
         bs->full_open_options = opts;
     }
 
-    if (bs->file->exact_filename[0] && s->test_file->bs->exact_filename[0]) {
+    if (bs->file->bs->exact_filename[0]
+        && s->test_file->bs->exact_filename[0])
+    {
         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
                  "blkverify:%s:%s",
-                 bs->file->exact_filename, s->test_file->bs->exact_filename);
+                 bs->file->bs->exact_filename,
+                 s->test_file->bs->exact_filename);
     }
 }
 
diff --git a/block/bochs.c b/block/bochs.c
index 199ac2b..18949b9 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -103,7 +103,7 @@  static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
 
     bs->read_only = 1; // no write support yet
 
-    ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
+    ret = bdrv_pread(bs->file->bs, 0, &bochs, sizeof(bochs));
     if (ret < 0) {
         return ret;
     }
@@ -137,7 +137,7 @@  static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
         return -ENOMEM;
     }
 
-    ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
+    ret = bdrv_pread(bs->file->bs, le32_to_cpu(bochs.header), s->catalog_bitmap,
                      s->catalog_size * 4);
     if (ret < 0) {
         goto fail;
@@ -206,7 +206,7 @@  static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
         (s->extent_blocks + s->bitmap_blocks));
 
     /* read in bitmap for current extent */
-    ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
+    ret = bdrv_pread(bs->file->bs, bitmap_offset + (extent_offset / 8),
                      &bitmap_entry, 1);
     if (ret < 0) {
         return ret;
@@ -229,7 +229,7 @@  static int bochs_read(BlockDriverState *bs, int64_t sector_num,
         if (block_offset < 0) {
             return block_offset;
         } else if (block_offset > 0) {
-            ret = bdrv_pread(bs->file, block_offset, buf, 512);
+            ret = bdrv_pread(bs->file->bs, block_offset, buf, 512);
             if (ret < 0) {
                 return ret;
             }
diff --git a/block/cloop.c b/block/cloop.c
index f328be0..4190ae0 100644
--- a/block/cloop.c
+++ b/block/cloop.c
@@ -66,7 +66,7 @@  static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
     bs->read_only = 1;
 
     /* read header */
-    ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
+    ret = bdrv_pread(bs->file->bs, 128, &s->block_size, 4);
     if (ret < 0) {
         return ret;
     }
@@ -92,7 +92,7 @@  static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
         return -EINVAL;
     }
 
-    ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4);
+    ret = bdrv_pread(bs->file->bs, 128 + 4, &s->n_blocks, 4);
     if (ret < 0) {
         return ret;
     }
@@ -123,7 +123,7 @@  static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
         return -ENOMEM;
     }
 
-    ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
+    ret = bdrv_pread(bs->file->bs, 128 + 4 + 4, s->offsets, offsets_size);
     if (ret < 0) {
         goto fail;
     }
@@ -203,8 +203,8 @@  static inline int cloop_read_block(BlockDriverState *bs, int block_num)
         int ret;
         uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
 
-        ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block,
-                         bytes);
+        ret = bdrv_pread(bs->file->bs, s->offsets[block_num],
+                         s->compressed_block, bytes);
         if (ret != bytes) {
             return -1;
         }
diff --git a/block/dmg.c b/block/dmg.c
index 9f25281..546a6f5 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -85,7 +85,7 @@  static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
     uint64_t buffer;
     int ret;
 
-    ret = bdrv_pread(bs->file, offset, &buffer, 8);
+    ret = bdrv_pread(bs->file->bs, offset, &buffer, 8);
     if (ret < 0) {
         return ret;
     }
@@ -99,7 +99,7 @@  static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
     uint32_t buffer;
     int ret;
 
-    ret = bdrv_pread(bs->file, offset, &buffer, 4);
+    ret = bdrv_pread(bs->file->bs, offset, &buffer, 4);
     if (ret < 0) {
         return ret;
     }
@@ -354,7 +354,7 @@  static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds,
         offset += 4;
 
         buffer = g_realloc(buffer, count);
-        ret = bdrv_pread(bs->file, offset, buffer, count);
+        ret = bdrv_pread(bs->file->bs, offset, buffer, count);
         if (ret < 0) {
             goto fail;
         }
@@ -391,7 +391,7 @@  static int dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds,
 
     buffer = g_malloc(info_length + 1);
     buffer[info_length] = '\0';
-    ret = bdrv_pread(bs->file, info_begin, buffer, info_length);
+    ret = bdrv_pread(bs->file->bs, info_begin, buffer, info_length);
     if (ret != info_length) {
         ret = -EINVAL;
         goto fail;
@@ -446,7 +446,7 @@  static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
     ds.max_sectors_per_chunk = 1;
 
     /* locate the UDIF trailer */
-    offset = dmg_find_koly_offset(bs->file, errp);
+    offset = dmg_find_koly_offset(bs->file->bs, errp);
     if (offset < 0) {
         ret = offset;
         goto fail;
@@ -514,9 +514,9 @@  static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     /* initialize zlib engine */
-    s->compressed_chunk = qemu_try_blockalign(bs->file,
+    s->compressed_chunk = qemu_try_blockalign(bs->file->bs,
                                               ds.max_compressed_size + 1);
-    s->uncompressed_chunk = qemu_try_blockalign(bs->file,
+    s->uncompressed_chunk = qemu_try_blockalign(bs->file->bs,
                                                 512 * ds.max_sectors_per_chunk);
     if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) {
         ret = -ENOMEM;
@@ -592,7 +592,7 @@  static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
         case 0x80000005: { /* zlib compressed */
             /* we need to buffer, because only the chunk as whole can be
              * inflated. */
-            ret = bdrv_pread(bs->file, s->offsets[chunk],
+            ret = bdrv_pread(bs->file->bs, s->offsets[chunk],
                              s->compressed_chunk, s->lengths[chunk]);
             if (ret != s->lengths[chunk]) {
                 return -1;
@@ -616,7 +616,7 @@  static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
         case 0x80000006: /* bzip2 compressed */
             /* we need to buffer, because only the chunk as whole can be
              * inflated. */
-            ret = bdrv_pread(bs->file, s->offsets[chunk],
+            ret = bdrv_pread(bs->file->bs, s->offsets[chunk],
                              s->compressed_chunk, s->lengths[chunk]);
             if (ret != s->lengths[chunk]) {
                 return -1;
@@ -641,7 +641,7 @@  static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
             break;
 #endif /* CONFIG_BZIP2 */
         case 1: /* copy */
-            ret = bdrv_pread(bs->file, s->offsets[chunk],
+            ret = bdrv_pread(bs->file->bs, s->offsets[chunk],
                              s->uncompressed_chunk, s->lengths[chunk]);
             if (ret != s->lengths[chunk]) {
                 return -1;
diff --git a/block/io.c b/block/io.c
index 94e18e6..15c676a 100644
--- a/block/io.c
+++ b/block/io.c
@@ -156,15 +156,15 @@  void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
 
     /* Take some limits from the children as a default */
     if (bs->file) {
-        bdrv_refresh_limits(bs->file, &local_err);
+        bdrv_refresh_limits(bs->file->bs, &local_err);
         if (local_err) {
             error_propagate(errp, local_err);
             return;
         }
-        bs->bl.opt_transfer_length = bs->file->bl.opt_transfer_length;
-        bs->bl.max_transfer_length = bs->file->bl.max_transfer_length;
-        bs->bl.min_mem_alignment = bs->file->bl.min_mem_alignment;
-        bs->bl.opt_mem_alignment = bs->file->bl.opt_mem_alignment;
+        bs->bl.opt_transfer_length = bs->file->bs->bl.opt_transfer_length;
+        bs->bl.max_transfer_length = bs->file->bs->bl.max_transfer_length;
+        bs->bl.min_mem_alignment = bs->file->bs->bl.min_mem_alignment;
+        bs->bl.opt_mem_alignment = bs->file->bs->bl.opt_mem_alignment;
     } else {
         bs->bl.min_mem_alignment = 512;
         bs->bl.opt_mem_alignment = getpagesize();
@@ -224,7 +224,7 @@  static bool bdrv_requests_pending(BlockDriverState *bs)
     if (!qemu_co_queue_empty(&bs->throttled_reqs[1])) {
         return true;
     }
-    if (bs->file && bdrv_requests_pending(bs->file)) {
+    if (bs->file && bdrv_requests_pending(bs->file->bs)) {
         return true;
     }
     if (bs->backing_hd && bdrv_requests_pending(bs->backing_hd)) {
@@ -1137,13 +1137,13 @@  static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
     if (ret < 0) {
         /* Do nothing, write notifier decided to fail this request */
     } else if (flags & BDRV_REQ_ZERO_WRITE) {
-        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_ZERO);
+        bdrv_debug_event(bs, BLKDBG_PWRITEV_ZERO);
         ret = bdrv_co_do_write_zeroes(bs, sector_num, nb_sectors, flags);
     } else {
-        BLKDBG_EVENT(bs, BLKDBG_PWRITEV);
+        bdrv_debug_event(bs, BLKDBG_PWRITEV);
         ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov);
     }
-    BLKDBG_EVENT(bs, BLKDBG_PWRITEV_DONE);
+    bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE);
 
     if (ret == 0 && !bs->enable_write_cache) {
         ret = bdrv_co_flush(bs);
@@ -1192,13 +1192,13 @@  static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
         /* RMW the unaligned part before head. */
         mark_request_serialising(req, align);
         wait_serialising_requests(req);
-        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_HEAD);
+        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD);
         ret = bdrv_aligned_preadv(bs, req, offset & ~(align - 1), align,
                                   align, &local_qiov, 0);
         if (ret < 0) {
             goto fail;
         }
-        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
+        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
 
         memset(buf + head_padding_bytes, 0, zero_bytes);
         ret = bdrv_aligned_pwritev(bs, req, offset & ~(align - 1), align,
@@ -1230,13 +1230,13 @@  static int coroutine_fn bdrv_co_do_zero_pwritev(BlockDriverState *bs,
         /* RMW the unaligned part after tail. */
         mark_request_serialising(req, align);
         wait_serialising_requests(req);
-        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_TAIL);
+        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL);
         ret = bdrv_aligned_preadv(bs, req, offset, align,
                                   align, &local_qiov, 0);
         if (ret < 0) {
             goto fail;
         }
-        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
+        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
 
         memset(buf, 0, bytes);
         ret = bdrv_aligned_pwritev(bs, req, offset, align,
@@ -1307,13 +1307,13 @@  static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
         };
         qemu_iovec_init_external(&head_qiov, &head_iov, 1);
 
-        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_HEAD);
+        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_HEAD);
         ret = bdrv_aligned_preadv(bs, &req, offset & ~(align - 1), align,
                                   align, &head_qiov, 0);
         if (ret < 0) {
             goto fail;
         }
-        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
+        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_HEAD);
 
         qemu_iovec_init(&local_qiov, qiov->niov + 2);
         qemu_iovec_add(&local_qiov, head_buf, offset & (align - 1));
@@ -1341,13 +1341,13 @@  static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
         };
         qemu_iovec_init_external(&tail_qiov, &tail_iov, 1);
 
-        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_TAIL);
+        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_TAIL);
         ret = bdrv_aligned_preadv(bs, &req, (offset + bytes) & ~(align - 1), align,
                                   align, &tail_qiov, 0);
         if (ret < 0) {
             goto fail;
         }
-        BLKDBG_EVENT(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
+        bdrv_debug_event(bs, BLKDBG_PWRITEV_RMW_AFTER_TAIL);
 
         if (!use_local_qiov) {
             qemu_iovec_init(&local_qiov, qiov->niov + 1);
@@ -1496,7 +1496,7 @@  static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
 
     if (ret & BDRV_BLOCK_RAW) {
         assert(ret & BDRV_BLOCK_OFFSET_VALID);
-        return bdrv_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS,
+        return bdrv_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
                                      *pnum, pnum);
     }
 
@@ -1519,7 +1519,7 @@  static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
         (ret & BDRV_BLOCK_OFFSET_VALID)) {
         int file_pnum;
 
-        ret2 = bdrv_co_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS,
+        ret2 = bdrv_co_get_block_status(bs->file->bs, ret >> BDRV_SECTOR_BITS,
                                         *pnum, &file_pnum);
         if (ret2 >= 0) {
             /* Ignore errors.  This is just providing extra information, it
@@ -1723,7 +1723,7 @@  int bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
     } else if (drv->bdrv_save_vmstate) {
         return drv->bdrv_save_vmstate(bs, qiov, pos);
     } else if (bs->file) {
-        return bdrv_writev_vmstate(bs->file, qiov, pos);
+        return bdrv_writev_vmstate(bs->file->bs, qiov, pos);
     }
 
     return -ENOTSUP;
@@ -1738,7 +1738,7 @@  int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
     if (drv->bdrv_load_vmstate)
         return drv->bdrv_load_vmstate(bs, buf, pos, size);
     if (bs->file)
-        return bdrv_load_vmstate(bs->file, buf, pos, size);
+        return bdrv_load_vmstate(bs->file->bs, buf, pos, size);
     return -ENOTSUP;
 }
 
@@ -2366,7 +2366,7 @@  int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
      * in the case of cache=unsafe, so there are no useless flushes.
      */
 flush_parent:
-    return bdrv_co_flush(bs->file);
+    return bs->file ? bdrv_co_flush(bs->file->bs) : 0;
 }
 
 int bdrv_flush(BlockDriverState *bs)
@@ -2594,7 +2594,7 @@  void bdrv_io_plug(BlockDriverState *bs)
     if (drv && drv->bdrv_io_plug) {
         drv->bdrv_io_plug(bs);
     } else if (bs->file) {
-        bdrv_io_plug(bs->file);
+        bdrv_io_plug(bs->file->bs);
     }
 }
 
@@ -2604,7 +2604,7 @@  void bdrv_io_unplug(BlockDriverState *bs)
     if (drv && drv->bdrv_io_unplug) {
         drv->bdrv_io_unplug(bs);
     } else if (bs->file) {
-        bdrv_io_unplug(bs->file);
+        bdrv_io_unplug(bs->file->bs);
     }
 }
 
@@ -2614,7 +2614,7 @@  void bdrv_flush_io_queue(BlockDriverState *bs)
     if (drv && drv->bdrv_flush_io_queue) {
         drv->bdrv_flush_io_queue(bs);
     } else if (bs->file) {
-        bdrv_flush_io_queue(bs->file);
+        bdrv_flush_io_queue(bs->file->bs);
     }
     bdrv_start_throttled_reqs(bs);
 }
diff --git a/block/parallels.c b/block/parallels.c
index 5cd6ec3..4f79293 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -202,13 +202,13 @@  static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
 
     to_allocate = (sector_num + *pnum + s->tracks - 1) / s->tracks - idx;
     space = to_allocate * s->tracks;
-    if (s->data_end + space > bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS) {
+    if (s->data_end + space > bdrv_getlength(bs->file->bs) >> BDRV_SECTOR_BITS) {
         int ret;
         space += s->prealloc_size;
         if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) {
-            ret = bdrv_write_zeroes(bs->file, s->data_end, space, 0);
+            ret = bdrv_write_zeroes(bs->file->bs, s->data_end, space, 0);
         } else {
-            ret = bdrv_truncate(bs->file,
+            ret = bdrv_truncate(bs->file->bs,
                                 (s->data_end + space) << BDRV_SECTOR_BITS);
         }
         if (ret < 0) {
@@ -244,7 +244,8 @@  static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs)
         if (off + to_write > s->header_size) {
             to_write = s->header_size - off;
         }
-        ret = bdrv_pwrite(bs->file, off, (uint8_t *)s->header + off, to_write);
+        ret = bdrv_pwrite(bs->file->bs, off, (uint8_t *)s->header + off,
+                          to_write);
         if (ret < 0) {
             qemu_co_mutex_unlock(&s->lock);
             return ret;
@@ -303,7 +304,7 @@  static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
         qemu_iovec_reset(&hd_qiov);
         qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
 
-        ret = bdrv_co_writev(bs->file, position, n, &hd_qiov);
+        ret = bdrv_co_writev(bs->file->bs, position, n, &hd_qiov);
         if (ret < 0) {
             break;
         }
@@ -343,7 +344,7 @@  static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
             qemu_iovec_reset(&hd_qiov);
             qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
 
-            ret = bdrv_co_readv(bs->file, position, n, &hd_qiov);
+            ret = bdrv_co_readv(bs->file->bs, position, n, &hd_qiov);
             if (ret < 0) {
                 break;
             }
@@ -369,7 +370,7 @@  static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
     bool flush_bat = false;
     int cluster_size = s->tracks << BDRV_SECTOR_BITS;
 
-    size = bdrv_getlength(bs->file);
+    size = bdrv_getlength(bs->file->bs);
     if (size < 0) {
         res->check_errors++;
         return size;
@@ -424,7 +425,7 @@  static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
     }
 
     if (flush_bat) {
-        ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size);
+        ret = bdrv_pwrite_sync(bs->file->bs, 0, s->header, s->header_size);
         if (ret < 0) {
             res->check_errors++;
             return ret;
@@ -440,7 +441,7 @@  static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
                 size - res->image_end_offset);
         res->leaks += count;
         if (fix & BDRV_FIX_LEAKS) {
-            ret = bdrv_truncate(bs->file, res->image_end_offset);
+            ret = bdrv_truncate(bs->file->bs, res->image_end_offset);
             if (ret < 0) {
                 res->check_errors++;
                 return ret;
@@ -546,12 +547,13 @@  static int parallels_probe(const uint8_t *buf, int buf_size,
 static int parallels_update_header(BlockDriverState *bs)
 {
     BDRVParallelsState *s = bs->opaque;
-    unsigned size = MAX(bdrv_opt_mem_align(bs->file), sizeof(ParallelsHeader));
+    unsigned size = MAX(bdrv_opt_mem_align(bs->file->bs),
+                        sizeof(ParallelsHeader));
 
     if (size > s->header_size) {
         size = s->header_size;
     }
-    return bdrv_pwrite_sync(bs->file, 0, s->header, size);
+    return bdrv_pwrite_sync(bs->file->bs, 0, s->header, size);
 }
 
 static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
@@ -564,7 +566,7 @@  static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
     Error *local_err = NULL;
     char *buf;
 
-    ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
+    ret = bdrv_pread(bs->file->bs, 0, &ph, sizeof(ph));
     if (ret < 0) {
         goto fail;
     }
@@ -603,8 +605,8 @@  static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     size = bat_entry_off(s->bat_size);
-    s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file));
-    s->header = qemu_try_blockalign(bs->file, s->header_size);
+    s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file->bs));
+    s->header = qemu_try_blockalign(bs->file->bs, s->header_size);
     if (s->header == NULL) {
         ret = -ENOMEM;
         goto fail;
@@ -619,7 +621,7 @@  static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
         s->header_size = size;
     }
 
-    ret = bdrv_pread(bs->file, 0, s->header, s->header_size);
+    ret = bdrv_pread(bs->file->bs, 0, s->header, s->header_size);
     if (ret < 0) {
         goto fail;
     }
@@ -663,8 +665,8 @@  static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
     if (local_err != NULL) {
         goto fail_options;
     }
-    if (!bdrv_has_zero_init(bs->file) ||
-            bdrv_truncate(bs->file, bdrv_getlength(bs->file)) != 0) {
+    if (!bdrv_has_zero_init(bs->file->bs) ||
+            bdrv_truncate(bs->file->bs, bdrv_getlength(bs->file->bs)) != 0) {
         s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
     }
 
@@ -707,7 +709,7 @@  static void parallels_close(BlockDriverState *bs)
     }
 
     if (bs->open_flags & BDRV_O_RDWR) {
-        bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS);
+        bdrv_truncate(bs->file->bs, s->data_end << BDRV_SECTOR_BITS);
     }
 
     g_free(s->bat_dirty_bmap);
diff --git a/block/qapi.c b/block/qapi.c
index 2ce5097..0c4654e 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -359,7 +359,7 @@  static BlockStats *bdrv_query_stats(const BlockDriverState *bs,
 
     if (bs->file) {
         s->has_parent = true;
-        s->parent = bdrv_query_stats(bs->file, query_backing);
+        s->parent = bdrv_query_stats(bs->file->bs, query_backing);
     }
 
     if (query_backing && bs->backing_hd) {
diff --git a/block/qcow.c b/block/qcow.c
index 6e35db1..4d20cd5 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -100,7 +100,7 @@  static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
     int ret;
     QCowHeader header;
 
-    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
+    ret = bdrv_pread(bs->file->bs, 0, &header, sizeof(header));
     if (ret < 0) {
         goto fail;
     }
@@ -193,7 +193,7 @@  static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
         goto fail;
     }
 
-    ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
+    ret = bdrv_pread(bs->file->bs, s->l1_table_offset, s->l1_table,
                s->l1_size * sizeof(uint64_t));
     if (ret < 0) {
         goto fail;
@@ -205,7 +205,7 @@  static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
 
     /* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */
     s->l2_cache =
-        qemu_try_blockalign(bs->file,
+        qemu_try_blockalign(bs->file->bs,
                             s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
     if (s->l2_cache == NULL) {
         error_setg(errp, "Could not allocate L2 table cache");
@@ -224,7 +224,7 @@  static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
             ret = -EINVAL;
             goto fail;
         }
-        ret = bdrv_pread(bs->file, header.backing_file_offset,
+        ret = bdrv_pread(bs->file->bs, header.backing_file_offset,
                    bs->backing_file, len);
         if (ret < 0) {
             goto fail;
@@ -369,13 +369,13 @@  static uint64_t get_cluster_offset(BlockDriverState *bs,
         if (!allocate)
             return 0;
         /* allocate a new l2 entry */
-        l2_offset = bdrv_getlength(bs->file);
+        l2_offset = bdrv_getlength(bs->file->bs);
         /* round to cluster size */
         l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
         /* update the L1 entry */
         s->l1_table[l1_index] = l2_offset;
         tmp = cpu_to_be64(l2_offset);
-        if (bdrv_pwrite_sync(bs->file,
+        if (bdrv_pwrite_sync(bs->file->bs,
                 s->l1_table_offset + l1_index * sizeof(tmp),
                 &tmp, sizeof(tmp)) < 0)
             return 0;
@@ -405,11 +405,12 @@  static uint64_t get_cluster_offset(BlockDriverState *bs,
     l2_table = s->l2_cache + (min_index << s->l2_bits);
     if (new_l2_table) {
         memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
-        if (bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
+        if (bdrv_pwrite_sync(bs->file->bs, l2_offset, l2_table,
                 s->l2_size * sizeof(uint64_t)) < 0)
             return 0;
     } else {
-        if (bdrv_pread(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
+        if (bdrv_pread(bs->file->bs, l2_offset, l2_table,
+                       s->l2_size * sizeof(uint64_t)) !=
             s->l2_size * sizeof(uint64_t))
             return 0;
     }
@@ -430,20 +431,21 @@  static uint64_t get_cluster_offset(BlockDriverState *bs,
                overwritten */
             if (decompress_cluster(bs, cluster_offset) < 0)
                 return 0;
-            cluster_offset = bdrv_getlength(bs->file);
+            cluster_offset = bdrv_getlength(bs->file->bs);
             cluster_offset = (cluster_offset + s->cluster_size - 1) &
                 ~(s->cluster_size - 1);
             /* write the cluster content */
-            if (bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache, s->cluster_size) !=
+            if (bdrv_pwrite(bs->file->bs, cluster_offset, s->cluster_cache,
+                            s->cluster_size) !=
                 s->cluster_size)
                 return -1;
         } else {
-            cluster_offset = bdrv_getlength(bs->file);
+            cluster_offset = bdrv_getlength(bs->file->bs);
             if (allocate == 1) {
                 /* round to cluster size */
                 cluster_offset = (cluster_offset + s->cluster_size - 1) &
                     ~(s->cluster_size - 1);
-                bdrv_truncate(bs->file, cluster_offset + s->cluster_size);
+                bdrv_truncate(bs->file->bs, cluster_offset + s->cluster_size);
                 /* if encrypted, we must initialize the cluster
                    content which won't be written */
                 if (bs->encrypted &&
@@ -463,7 +465,7 @@  static uint64_t get_cluster_offset(BlockDriverState *bs,
                                 errno = EIO;
                                 return -1;
                             }
-                            if (bdrv_pwrite(bs->file, cluster_offset + i * 512,
+                            if (bdrv_pwrite(bs->file->bs, cluster_offset + i * 512,
                                             s->cluster_data, 512) != 512)
                                 return -1;
                         }
@@ -477,7 +479,7 @@  static uint64_t get_cluster_offset(BlockDriverState *bs,
         /* update L2 table */
         tmp = cpu_to_be64(cluster_offset);
         l2_table[l2_index] = tmp;
-        if (bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
+        if (bdrv_pwrite_sync(bs->file->bs, l2_offset + l2_index * sizeof(tmp),
                 &tmp, sizeof(tmp)) < 0)
             return 0;
     }
@@ -546,7 +548,7 @@  static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
     if (s->cluster_cache_offset != coffset) {
         csize = cluster_offset >> (63 - s->cluster_bits);
         csize &= (s->cluster_size - 1);
-        ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize);
+        ret = bdrv_pread(bs->file->bs, coffset, s->cluster_data, csize);
         if (ret != csize)
             return -1;
         if (decompress_buffer(s->cluster_cache, s->cluster_size,
@@ -625,7 +627,7 @@  static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
             hd_iov.iov_len = n * 512;
             qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
             qemu_co_mutex_unlock(&s->lock);
-            ret = bdrv_co_readv(bs->file,
+            ret = bdrv_co_readv(bs->file->bs,
                                 (cluster_offset >> 9) + index_in_cluster,
                                 n, &hd_qiov);
             qemu_co_mutex_lock(&s->lock);
@@ -727,7 +729,7 @@  static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
         hd_iov.iov_len = n * 512;
         qemu_iovec_init_external(&hd_qiov, &hd_iov, 1);
         qemu_co_mutex_unlock(&s->lock);
-        ret = bdrv_co_writev(bs->file,
+        ret = bdrv_co_writev(bs->file->bs,
                              (cluster_offset >> 9) + index_in_cluster,
                              n, &hd_qiov);
         qemu_co_mutex_lock(&s->lock);
@@ -879,10 +881,10 @@  static int qcow_make_empty(BlockDriverState *bs)
     int ret;
 
     memset(s->l1_table, 0, l1_length);
-    if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
+    if (bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset, s->l1_table,
             l1_length) < 0)
         return -1;
-    ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
+    ret = bdrv_truncate(bs->file->bs, s->l1_table_offset + l1_length);
     if (ret < 0)
         return ret;
 
@@ -962,7 +964,7 @@  static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
         }
 
         cluster_offset &= s->cluster_offset_mask;
-        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
+        ret = bdrv_pwrite(bs->file->bs, cluster_offset, out_buf, out_len);
         if (ret < 0) {
             goto fail;
         }
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index 7b14c5c..86dd7f2 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -127,7 +127,7 @@  Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
     c = g_new0(Qcow2Cache, 1);
     c->size = num_tables;
     c->entries = g_try_new0(Qcow2CachedTable, num_tables);
-    c->table_array = qemu_try_blockalign(bs->file,
+    c->table_array = qemu_try_blockalign(bs->file->bs,
                                          (size_t) num_tables * s->cluster_size);
 
     if (!c->entries || !c->table_array) {
@@ -185,7 +185,7 @@  static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
     if (c->depends) {
         ret = qcow2_cache_flush_dependency(bs, c);
     } else if (c->depends_on_flush) {
-        ret = bdrv_flush(bs->file);
+        ret = bdrv_flush(bs->file->bs);
         if (ret >= 0) {
             c->depends_on_flush = false;
         }
@@ -216,7 +216,7 @@  static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
         BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE);
     }
 
-    ret = bdrv_pwrite(bs->file, c->entries[i].offset,
+    ret = bdrv_pwrite(bs->file->bs, c->entries[i].offset,
                       qcow2_cache_get_table_addr(bs, c, i), s->cluster_size);
     if (ret < 0) {
         return ret;
@@ -244,7 +244,7 @@  int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c)
     }
 
     if (result == 0) {
-        ret = bdrv_flush(bs->file);
+        ret = bdrv_flush(bs->file->bs);
         if (ret < 0) {
             result = ret;
         }
@@ -356,7 +356,8 @@  static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
             BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD);
         }
 
-        ret = bdrv_pread(bs->file, offset, qcow2_cache_get_table_addr(bs, c, i),
+        ret = bdrv_pread(bs->file->bs, offset,
+                         qcow2_cache_get_table_addr(bs, c, i),
                          s->cluster_size);
         if (ret < 0) {
             return ret;
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 6ede629..7844f8e 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -72,7 +72,7 @@  int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
 #endif
 
     new_l1_size2 = sizeof(uint64_t) * new_l1_size;
-    new_l1_table = qemu_try_blockalign(bs->file,
+    new_l1_table = qemu_try_blockalign(bs->file->bs,
                                        align_offset(new_l1_size2, 512));
     if (new_l1_table == NULL) {
         return -ENOMEM;
@@ -105,7 +105,8 @@  int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
     BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
     for(i = 0; i < s->l1_size; i++)
         new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
-    ret = bdrv_pwrite_sync(bs->file, new_l1_table_offset, new_l1_table, new_l1_size2);
+    ret = bdrv_pwrite_sync(bs->file->bs, new_l1_table_offset,
+                           new_l1_table, new_l1_size2);
     if (ret < 0)
         goto fail;
     for(i = 0; i < s->l1_size; i++)
@@ -115,7 +116,8 @@  int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
     BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE);
     cpu_to_be32w((uint32_t*)data, new_l1_size);
     stq_be_p(data + 4, new_l1_table_offset);
-    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size), data,sizeof(data));
+    ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, l1_size),
+                           data, sizeof(data));
     if (ret < 0) {
         goto fail;
     }
@@ -182,8 +184,9 @@  int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
     }
 
     BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
-    ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset + 8 * l1_start_index,
-        buf, sizeof(buf));
+    ret = bdrv_pwrite_sync(bs->file->bs,
+                           s->l1_table_offset + 8 * l1_start_index,
+                           buf, sizeof(buf));
     if (ret < 0) {
         return ret;
     }
@@ -440,7 +443,8 @@  static int coroutine_fn copy_sectors(BlockDriverState *bs,
     }
 
     BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
-    ret = bdrv_co_writev(bs->file, (cluster_offset >> 9) + n_start, n, &qiov);
+    ret = bdrv_co_writev(bs->file->bs, (cluster_offset >> 9) + n_start, n,
+                         &qiov);
     if (ret < 0) {
         goto out;
     }
@@ -817,7 +821,7 @@  int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
 
     /*
      * If this was a COW, we need to decrease the refcount of the old cluster.
-     * Also flush bs->file to get the right order for L2 and refcount update.
+     * Also flush bs->file->bs to get the right order for L2 and refcount update.
      *
      * Don't discard clusters that reach a refcount of 0 (e.g. compressed
      * clusters), the next write will reuse them anyway.
@@ -1412,7 +1416,8 @@  int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
         sector_offset = coffset & 511;
         csize = nb_csectors * 512 - sector_offset;
         BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
-        ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data, nb_csectors);
+        ret = bdrv_read(bs->file->bs, coffset >> 9, s->cluster_data,
+                        nb_csectors);
         if (ret < 0) {
             return ret;
         }
@@ -1645,7 +1650,7 @@  static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
     if (!is_active_l1) {
         /* inactive L2 tables require a buffer to be stored in when loading
          * them from disk */
-        l2_table = qemu_try_blockalign(bs->file, s->cluster_size);
+        l2_table = qemu_try_blockalign(bs->file->bs, s->cluster_size);
         if (l2_table == NULL) {
             return -ENOMEM;
         }
@@ -1679,8 +1684,8 @@  static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
                     (void **)&l2_table);
         } else {
             /* load inactive L2 tables from disk */
-            ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,
-                    (void *)l2_table, s->cluster_sectors);
+            ret = bdrv_read(bs->file->bs, l2_offset / BDRV_SECTOR_SIZE,
+                            (void *)l2_table, s->cluster_sectors);
         }
         if (ret < 0) {
             goto fail;
@@ -1754,7 +1759,7 @@  static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
                 goto fail;
             }
 
-            ret = bdrv_write_zeroes(bs->file, offset / BDRV_SECTOR_SIZE,
+            ret = bdrv_write_zeroes(bs->file->bs, offset / BDRV_SECTOR_SIZE,
                                     s->cluster_sectors, 0);
             if (ret < 0) {
                 if (!preallocated) {
@@ -1787,8 +1792,8 @@  static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
                     goto fail;
                 }
 
-                ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,
-                        (void *)l2_table, s->cluster_sectors);
+                ret = bdrv_write(bs->file->bs, l2_offset / BDRV_SECTOR_SIZE,
+                                 (void *)l2_table, s->cluster_sectors);
                 if (ret < 0) {
                     goto fail;
                 }
@@ -1861,8 +1866,9 @@  int qcow2_expand_zero_clusters(BlockDriverState *bs,
 
         l1_table = g_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
 
-        ret = bdrv_read(bs->file, s->snapshots[i].l1_table_offset /
-                BDRV_SECTOR_SIZE, (void *)l1_table, l1_sectors);
+        ret = bdrv_read(bs->file->bs,
+                        s->snapshots[i].l1_table_offset / BDRV_SECTOR_SIZE,
+                        (void *)l1_table, l1_sectors);
         if (ret < 0) {
             goto fail;
         }
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 2110839..4b81c8d 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -101,7 +101,7 @@  int qcow2_refcount_init(BlockDriverState *bs)
             goto fail;
         }
         BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
-        ret = bdrv_pread(bs->file, s->refcount_table_offset,
+        ret = bdrv_pread(bs->file->bs, s->refcount_table_offset,
                          s->refcount_table, refcount_table_size2);
         if (ret < 0) {
             goto fail;
@@ -431,7 +431,7 @@  static int alloc_refcount_block(BlockDriverState *bs,
     if (refcount_table_index < s->refcount_table_size) {
         uint64_t data64 = cpu_to_be64(new_block);
         BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
-        ret = bdrv_pwrite_sync(bs->file,
+        ret = bdrv_pwrite_sync(bs->file->bs,
             s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
             &data64, sizeof(data64));
         if (ret < 0) {
@@ -535,7 +535,7 @@  static int alloc_refcount_block(BlockDriverState *bs,
 
     /* Write refcount blocks to disk */
     BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
-    ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
+    ret = bdrv_pwrite_sync(bs->file->bs, meta_offset, new_blocks,
         blocks_clusters * s->cluster_size);
     g_free(new_blocks);
     new_blocks = NULL;
@@ -549,7 +549,7 @@  static int alloc_refcount_block(BlockDriverState *bs,
     }
 
     BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
-    ret = bdrv_pwrite_sync(bs->file, table_offset, new_table,
+    ret = bdrv_pwrite_sync(bs->file->bs, table_offset, new_table,
         table_size * sizeof(uint64_t));
     if (ret < 0) {
         goto fail_table;
@@ -564,8 +564,9 @@  static int alloc_refcount_block(BlockDriverState *bs,
     cpu_to_be64w((uint64_t*)data, table_offset);
     cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
     BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE);
-    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, refcount_table_offset),
-        data, sizeof(data));
+    ret = bdrv_pwrite_sync(bs->file->bs,
+                           offsetof(QCowHeader, refcount_table_offset),
+                           data, sizeof(data));
     if (ret < 0) {
         goto fail_table;
     }
@@ -613,7 +614,7 @@  void qcow2_process_discards(BlockDriverState *bs, int ret)
 
         /* Discard is optional, ignore the return value */
         if (ret >= 0) {
-            bdrv_discard(bs->file,
+            bdrv_discard(bs->file->bs,
                          d->offset >> BDRV_SECTOR_BITS,
                          d->bytes >> BDRV_SECTOR_BITS);
         }
@@ -1068,7 +1069,7 @@  int qcow2_update_snapshot_refcount(BlockDriverState *bs,
         }
         l1_allocated = true;
 
-        ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
+        ret = bdrv_pread(bs->file->bs, l1_table_offset, l1_table, l1_size2);
         if (ret < 0) {
             goto fail;
         }
@@ -1221,7 +1222,8 @@  fail:
             cpu_to_be64s(&l1_table[i]);
         }
 
-        ret = bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table, l1_size2);
+        ret = bdrv_pwrite_sync(bs->file->bs, l1_table_offset,
+                               l1_table, l1_size2);
 
         for (i = 0; i < l1_size; i++) {
             be64_to_cpus(&l1_table[i]);
@@ -1376,7 +1378,7 @@  static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
     l2_size = s->l2_size * sizeof(uint64_t);
     l2_table = g_malloc(l2_size);
 
-    ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size);
+    ret = bdrv_pread(bs->file->bs, l2_offset, l2_table, l2_size);
     if (ret < 0) {
         fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
         res->check_errors++;
@@ -1508,7 +1510,7 @@  static int check_refcounts_l1(BlockDriverState *bs,
             res->check_errors++;
             goto fail;
         }
-        ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
+        ret = bdrv_pread(bs->file->bs, l1_table_offset, l1_table, l1_size2);
         if (ret < 0) {
             fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
             res->check_errors++;
@@ -1606,7 +1608,7 @@  static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
             }
         }
 
-        ret = bdrv_pread(bs->file, l2_offset, l2_table,
+        ret = bdrv_pread(bs->file->bs, l2_offset, l2_table,
                          s->l2_size * sizeof(uint64_t));
         if (ret < 0) {
             fprintf(stderr, "ERROR: Could not read L2 table: %s\n",
@@ -1658,7 +1660,8 @@  static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
                 goto fail;
             }
 
-            ret = bdrv_pwrite(bs->file, l2_offset, l2_table, s->cluster_size);
+            ret = bdrv_pwrite(bs->file->bs, l2_offset, l2_table,
+                              s->cluster_size);
             if (ret < 0) {
                 fprintf(stderr, "ERROR: Could not write L2 table: %s\n",
                         strerror(-ret));
@@ -1713,11 +1716,11 @@  static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
                     goto resize_fail;
                 }
 
-                ret = bdrv_truncate(bs->file, offset + s->cluster_size);
+                ret = bdrv_truncate(bs->file->bs, offset + s->cluster_size);
                 if (ret < 0) {
                     goto resize_fail;
                 }
-                size = bdrv_getlength(bs->file);
+                size = bdrv_getlength(bs->file->bs);
                 if (size < 0) {
                     ret = size;
                     goto resize_fail;
@@ -2091,7 +2094,7 @@  write_refblocks:
         on_disk_refblock = (void *)((char *) *refcount_table +
                                     refblock_index * s->cluster_size);
 
-        ret = bdrv_write(bs->file, refblock_offset / BDRV_SECTOR_SIZE,
+        ret = bdrv_write(bs->file->bs, refblock_offset / BDRV_SECTOR_SIZE,
                          on_disk_refblock, s->cluster_sectors);
         if (ret < 0) {
             fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret));
@@ -2140,7 +2143,7 @@  write_refblocks:
     }
 
     assert(reftable_size < INT_MAX / sizeof(uint64_t));
-    ret = bdrv_pwrite(bs->file, reftable_offset, on_disk_reftable,
+    ret = bdrv_pwrite(bs->file->bs, reftable_offset, on_disk_reftable,
                       reftable_size * sizeof(uint64_t));
     if (ret < 0) {
         fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret));
@@ -2152,8 +2155,8 @@  write_refblocks:
                  reftable_offset);
     cpu_to_be32w(&reftable_offset_and_clusters.reftable_clusters,
                  size_to_clusters(s, reftable_size * sizeof(uint64_t)));
-    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader,
-                                              refcount_table_offset),
+    ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader,
+                                                  refcount_table_offset),
                            &reftable_offset_and_clusters,
                            sizeof(reftable_offset_and_clusters));
     if (ret < 0) {
@@ -2191,7 +2194,7 @@  int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
     bool rebuild = false;
     int ret;
 
-    size = bdrv_getlength(bs->file);
+    size = bdrv_getlength(bs->file->bs);
     if (size < 0) {
         res->check_errors++;
         return size;
@@ -2400,7 +2403,7 @@  int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
                 return -ENOMEM;
             }
 
-            ret = bdrv_pread(bs->file, l1_ofs, l1, l1_sz2);
+            ret = bdrv_pread(bs->file->bs, l1_ofs, l1, l1_sz2);
             if (ret < 0) {
                 g_free(l1);
                 return ret;
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 92f4dfc..def7201 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -64,7 +64,7 @@  int qcow2_read_snapshots(BlockDriverState *bs)
     for(i = 0; i < s->nb_snapshots; i++) {
         /* Read statically sized part of the snapshot header */
         offset = align_offset(offset, 8);
-        ret = bdrv_pread(bs->file, offset, &h, sizeof(h));
+        ret = bdrv_pread(bs->file->bs, offset, &h, sizeof(h));
         if (ret < 0) {
             goto fail;
         }
@@ -83,7 +83,7 @@  int qcow2_read_snapshots(BlockDriverState *bs)
         name_size = be16_to_cpu(h.name_size);
 
         /* Read extra data */
-        ret = bdrv_pread(bs->file, offset, &extra,
+        ret = bdrv_pread(bs->file->bs, offset, &extra,
                          MIN(sizeof(extra), extra_data_size));
         if (ret < 0) {
             goto fail;
@@ -102,7 +102,7 @@  int qcow2_read_snapshots(BlockDriverState *bs)
 
         /* Read snapshot ID */
         sn->id_str = g_malloc(id_str_size + 1);
-        ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
+        ret = bdrv_pread(bs->file->bs, offset, sn->id_str, id_str_size);
         if (ret < 0) {
             goto fail;
         }
@@ -111,7 +111,7 @@  int qcow2_read_snapshots(BlockDriverState *bs)
 
         /* Read snapshot name */
         sn->name = g_malloc(name_size + 1);
-        ret = bdrv_pread(bs->file, offset, sn->name, name_size);
+        ret = bdrv_pread(bs->file->bs, offset, sn->name, name_size);
         if (ret < 0) {
             goto fail;
         }
@@ -214,25 +214,25 @@  static int qcow2_write_snapshots(BlockDriverState *bs)
         h.name_size = cpu_to_be16(name_size);
         offset = align_offset(offset, 8);
 
-        ret = bdrv_pwrite(bs->file, offset, &h, sizeof(h));
+        ret = bdrv_pwrite(bs->file->bs, offset, &h, sizeof(h));
         if (ret < 0) {
             goto fail;
         }
         offset += sizeof(h);
 
-        ret = bdrv_pwrite(bs->file, offset, &extra, sizeof(extra));
+        ret = bdrv_pwrite(bs->file->bs, offset, &extra, sizeof(extra));
         if (ret < 0) {
             goto fail;
         }
         offset += sizeof(extra);
 
-        ret = bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size);
+        ret = bdrv_pwrite(bs->file->bs, offset, sn->id_str, id_str_size);
         if (ret < 0) {
             goto fail;
         }
         offset += id_str_size;
 
-        ret = bdrv_pwrite(bs->file, offset, sn->name, name_size);
+        ret = bdrv_pwrite(bs->file->bs, offset, sn->name, name_size);
         if (ret < 0) {
             goto fail;
         }
@@ -254,7 +254,7 @@  static int qcow2_write_snapshots(BlockDriverState *bs)
     header_data.nb_snapshots        = cpu_to_be32(s->nb_snapshots);
     header_data.snapshots_offset    = cpu_to_be64(snapshots_offset);
 
-    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
+    ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, nb_snapshots),
                            &header_data, sizeof(header_data));
     if (ret < 0) {
         goto fail;
@@ -396,7 +396,7 @@  int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
         goto fail;
     }
 
-    ret = bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table,
+    ret = bdrv_pwrite(bs->file->bs, sn->l1_table_offset, l1_table,
                       s->l1_size * sizeof(uint64_t));
     if (ret < 0) {
         goto fail;
@@ -509,7 +509,8 @@  int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
         goto fail;
     }
 
-    ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_table, sn_l1_bytes);
+    ret = bdrv_pread(bs->file->bs, sn->l1_table_offset,
+                     sn_l1_table, sn_l1_bytes);
     if (ret < 0) {
         goto fail;
     }
@@ -526,7 +527,7 @@  int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
         goto fail;
     }
 
-    ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset, sn_l1_table,
+    ret = bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset, sn_l1_table,
                            cur_l1_bytes);
     if (ret < 0) {
         goto fail;
@@ -706,13 +707,14 @@  int qcow2_snapshot_load_tmp(BlockDriverState *bs,
         return -EFBIG;
     }
     new_l1_bytes = sn->l1_size * sizeof(uint64_t);
-    new_l1_table = qemu_try_blockalign(bs->file,
+    new_l1_table = qemu_try_blockalign(bs->file->bs,
                                        align_offset(new_l1_bytes, 512));
     if (new_l1_table == NULL) {
         return -ENOMEM;
     }
 
-    ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
+    ret = bdrv_pread(bs->file->bs, sn->l1_table_offset,
+                     new_l1_table, new_l1_bytes);
     if (ret < 0) {
         error_setg(errp, "Failed to read l1 table for snapshot");
         qemu_vfree(new_l1_table);
diff --git a/block/qcow2.c b/block/qcow2.c
index 56ad808..38b2797 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -104,7 +104,7 @@  static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
         printf("attempting to read extended header in offset %lu\n", offset);
 #endif
 
-        ret = bdrv_pread(bs->file, offset, &ext, sizeof(ext));
+        ret = bdrv_pread(bs->file->bs, offset, &ext, sizeof(ext));
         if (ret < 0) {
             error_setg_errno(errp, -ret, "qcow2_read_extension: ERROR: "
                              "pread fail from offset %" PRIu64, offset);
@@ -132,7 +132,7 @@  static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
                            sizeof(bs->backing_format));
                 return 2;
             }
-            ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
+            ret = bdrv_pread(bs->file->bs, offset, bs->backing_format, ext.len);
             if (ret < 0) {
                 error_setg_errno(errp, -ret, "ERROR: ext_backing_format: "
                                  "Could not read format name");
@@ -148,7 +148,7 @@  static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
         case QCOW2_EXT_MAGIC_FEATURE_TABLE:
             if (p_feature_table != NULL) {
                 void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
-                ret = bdrv_pread(bs->file, offset , feature_table, ext.len);
+                ret = bdrv_pread(bs->file->bs, offset , feature_table, ext.len);
                 if (ret < 0) {
                     error_setg_errno(errp, -ret, "ERROR: ext_feature_table: "
                                      "Could not read table");
@@ -169,7 +169,7 @@  static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
                 uext->len = ext.len;
                 QLIST_INSERT_HEAD(&s->unknown_header_ext, uext, next);
 
-                ret = bdrv_pread(bs->file, offset , uext->data, uext->len);
+                ret = bdrv_pread(bs->file->bs, offset , uext->data, uext->len);
                 if (ret < 0) {
                     error_setg_errno(errp, -ret, "ERROR: unknown extension: "
                                      "Could not read data");
@@ -260,12 +260,12 @@  int qcow2_mark_dirty(BlockDriverState *bs)
     }
 
     val = cpu_to_be64(s->incompatible_features | QCOW2_INCOMPAT_DIRTY);
-    ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, incompatible_features),
+    ret = bdrv_pwrite(bs->file->bs, offsetof(QCowHeader, incompatible_features),
                       &val, sizeof(val));
     if (ret < 0) {
         return ret;
     }
-    ret = bdrv_flush(bs->file);
+    ret = bdrv_flush(bs->file->bs);
     if (ret < 0) {
         return ret;
     }
@@ -828,7 +828,7 @@  static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
     uint64_t ext_end;
     uint64_t l1_vm_state_index;
 
-    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
+    ret = bdrv_pread(bs->file->bs, 0, &header, sizeof(header));
     if (ret < 0) {
         error_setg_errno(errp, -ret, "Could not read qcow2 header");
         goto fail;
@@ -903,7 +903,7 @@  static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
     if (header.header_length > sizeof(header)) {
         s->unknown_header_fields_size = header.header_length - sizeof(header);
         s->unknown_header_fields = g_malloc(s->unknown_header_fields_size);
-        ret = bdrv_pread(bs->file, sizeof(header), s->unknown_header_fields,
+        ret = bdrv_pread(bs->file->bs, sizeof(header), s->unknown_header_fields,
                          s->unknown_header_fields_size);
         if (ret < 0) {
             error_setg_errno(errp, -ret, "Could not read unknown qcow2 header "
@@ -1056,14 +1056,14 @@  static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
 
 
     if (s->l1_size > 0) {
-        s->l1_table = qemu_try_blockalign(bs->file,
+        s->l1_table = qemu_try_blockalign(bs->file->bs,
             align_offset(s->l1_size * sizeof(uint64_t), 512));
         if (s->l1_table == NULL) {
             error_setg(errp, "Could not allocate L1 table");
             ret = -ENOMEM;
             goto fail;
         }
-        ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
+        ret = bdrv_pread(bs->file->bs, s->l1_table_offset, s->l1_table,
                          s->l1_size * sizeof(uint64_t));
         if (ret < 0) {
             error_setg_errno(errp, -ret, "Could not read L1 table");
@@ -1082,7 +1082,7 @@  static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
 
     s->cluster_cache = g_malloc(s->cluster_size);
     /* one more sector for decompressed data alignment */
-    s->cluster_data = qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
+    s->cluster_data = qemu_try_blockalign(bs->file->bs, QCOW_MAX_CRYPT_CLUSTERS
                                                     * s->cluster_size + 512);
     if (s->cluster_data == NULL) {
         error_setg(errp, "Could not allocate temporary cluster buffer");
@@ -1119,7 +1119,7 @@  static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
             ret = -EINVAL;
             goto fail;
         }
-        ret = bdrv_pread(bs->file, header.backing_file_offset,
+        ret = bdrv_pread(bs->file->bs, header.backing_file_offset,
                          bs->backing_file, len);
         if (ret < 0) {
             error_setg_errno(errp, -ret, "Could not read backing file name");
@@ -1429,8 +1429,9 @@  static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
                  */
                 if (!cluster_data) {
                     cluster_data =
-                        qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
-                                                      * s->cluster_size);
+                        qemu_try_blockalign(bs->file->bs,
+                                            QCOW_MAX_CRYPT_CLUSTERS
+                                            * s->cluster_size);
                     if (cluster_data == NULL) {
                         ret = -ENOMEM;
                         goto fail;
@@ -1446,7 +1447,7 @@  static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
 
             BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
             qemu_co_mutex_unlock(&s->lock);
-            ret = bdrv_co_readv(bs->file,
+            ret = bdrv_co_readv(bs->file->bs,
                                 (cluster_offset >> 9) + index_in_cluster,
                                 cur_nr_sectors, &hd_qiov);
             qemu_co_mutex_lock(&s->lock);
@@ -1543,7 +1544,7 @@  static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
             Error *err = NULL;
             assert(s->cipher);
             if (!cluster_data) {
-                cluster_data = qemu_try_blockalign(bs->file,
+                cluster_data = qemu_try_blockalign(bs->file->bs,
                                                    QCOW_MAX_CRYPT_CLUSTERS
                                                    * s->cluster_size);
                 if (cluster_data == NULL) {
@@ -1580,7 +1581,7 @@  static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
         BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
         trace_qcow2_writev_data(qemu_coroutine_self(),
                                 (cluster_offset >> 9) + index_in_cluster);
-        ret = bdrv_co_writev(bs->file,
+        ret = bdrv_co_writev(bs->file->bs,
                              (cluster_offset >> 9) + index_in_cluster,
                              cur_nr_sectors, &hd_qiov);
         qemu_co_mutex_lock(&s->lock);
@@ -1703,7 +1704,7 @@  static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
 
     qcow2_close(bs);
 
-    bdrv_invalidate_cache(bs->file, &local_err);
+    bdrv_invalidate_cache(bs->file->bs, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         return;
@@ -1911,7 +1912,7 @@  int qcow2_update_header(BlockDriverState *bs)
     }
 
     /* Write the new header */
-    ret = bdrv_pwrite(bs->file, 0, header, s->cluster_size);
+    ret = bdrv_pwrite(bs->file->bs, 0, header, s->cluster_size);
     if (ret < 0) {
         goto fail;
     }
@@ -1991,7 +1992,8 @@  static int preallocate(BlockDriverState *bs)
     if (host_offset != 0) {
         uint8_t buf[BDRV_SECTOR_SIZE];
         memset(buf, 0, BDRV_SECTOR_SIZE);
-        ret = bdrv_write(bs->file, (host_offset >> BDRV_SECTOR_BITS) + num - 1,
+        ret = bdrv_write(bs->file->bs,
+                         (host_offset >> BDRV_SECTOR_BITS) + num - 1,
                          buf, 1);
         if (ret < 0) {
             return ret;
@@ -2403,7 +2405,7 @@  static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
 
     /* write updated header.size */
     offset = cpu_to_be64(offset);
-    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
+    ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, size),
                            &offset, sizeof(uint64_t));
     if (ret < 0) {
         return ret;
@@ -2427,8 +2429,8 @@  static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
     if (nb_sectors == 0) {
         /* align end of file to a sector boundary to ease reading with
            sector based I/Os */
-        cluster_offset = bdrv_getlength(bs->file);
-        return bdrv_truncate(bs->file, cluster_offset);
+        cluster_offset = bdrv_getlength(bs->file->bs);
+        return bdrv_truncate(bs->file->bs, cluster_offset);
     }
 
     if (nb_sectors != s->cluster_sectors) {
@@ -2495,7 +2497,7 @@  static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
         }
 
         BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED);
-        ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
+        ret = bdrv_pwrite(bs->file->bs, cluster_offset, out_buf, out_len);
         if (ret < 0) {
             goto fail;
         }
@@ -2544,7 +2546,7 @@  static int make_completely_empty(BlockDriverState *bs)
     /* After this call, neither the in-memory nor the on-disk refcount
      * information accurately describe the actual references */
 
-    ret = bdrv_write_zeroes(bs->file, s->l1_table_offset / BDRV_SECTOR_SIZE,
+    ret = bdrv_write_zeroes(bs->file->bs, s->l1_table_offset / BDRV_SECTOR_SIZE,
                             l1_clusters * s->cluster_sectors, 0);
     if (ret < 0) {
         goto fail_broken_refcounts;
@@ -2558,7 +2560,7 @@  static int make_completely_empty(BlockDriverState *bs)
      * overwrite parts of the existing refcount and L1 table, which is not
      * an issue because the dirty flag is set, complete data loss is in fact
      * desired and partial data loss is consequently fine as well */
-    ret = bdrv_write_zeroes(bs->file, s->cluster_size / BDRV_SECTOR_SIZE,
+    ret = bdrv_write_zeroes(bs->file->bs, s->cluster_size / BDRV_SECTOR_SIZE,
                             (2 + l1_clusters) * s->cluster_size /
                             BDRV_SECTOR_SIZE, 0);
     /* This call (even if it failed overall) may have overwritten on-disk
@@ -2578,7 +2580,7 @@  static int make_completely_empty(BlockDriverState *bs)
     cpu_to_be64w(&l1_ofs_rt_ofs_cls.l1_offset, 3 * s->cluster_size);
     cpu_to_be64w(&l1_ofs_rt_ofs_cls.reftable_offset, s->cluster_size);
     cpu_to_be32w(&l1_ofs_rt_ofs_cls.reftable_clusters, 1);
-    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_table_offset),
+    ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, l1_table_offset),
                            &l1_ofs_rt_ofs_cls, sizeof(l1_ofs_rt_ofs_cls));
     if (ret < 0) {
         goto fail_broken_refcounts;
@@ -2609,7 +2611,7 @@  static int make_completely_empty(BlockDriverState *bs)
 
     /* Enter the first refblock into the reftable */
     rt_entry = cpu_to_be64(2 * s->cluster_size);
-    ret = bdrv_pwrite_sync(bs->file, s->cluster_size,
+    ret = bdrv_pwrite_sync(bs->file->bs, s->cluster_size,
                            &rt_entry, sizeof(rt_entry));
     if (ret < 0) {
         goto fail_broken_refcounts;
@@ -2634,7 +2636,7 @@  static int make_completely_empty(BlockDriverState *bs)
         goto fail;
     }
 
-    ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size);
+    ret = bdrv_truncate(bs->file->bs, (3 + l1_clusters) * s->cluster_size);
     if (ret < 0) {
         goto fail;
     }
@@ -2769,7 +2771,7 @@  static void dump_refcounts(BlockDriverState *bs)
     int64_t nb_clusters, k, k1, size;
     int refcount;
 
-    size = bdrv_getlength(bs->file);
+    size = bdrv_getlength(bs->file->bs);
     nb_clusters = size_to_clusters(s, size);
     for(k = 0; k < nb_clusters;) {
         k1 = k;
diff --git a/block/qed-table.c b/block/qed-table.c
index 513aa87..f4219b8 100644
--- a/block/qed-table.c
+++ b/block/qed-table.c
@@ -63,7 +63,7 @@  static void qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
     read_table_cb->iov.iov_len = s->header.cluster_size * s->header.table_size,
 
     qemu_iovec_init_external(qiov, &read_table_cb->iov, 1);
-    bdrv_aio_readv(s->bs->file, offset / BDRV_SECTOR_SIZE, qiov,
+    bdrv_aio_readv(s->bs->file->bs, offset / BDRV_SECTOR_SIZE, qiov,
                    qiov->size / BDRV_SECTOR_SIZE,
                    qed_read_table_cb, read_table_cb);
 }
@@ -152,7 +152,7 @@  static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
     /* Adjust for offset into table */
     offset += start * sizeof(uint64_t);
 
-    bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
+    bdrv_aio_writev(s->bs->file->bs, offset / BDRV_SECTOR_SIZE,
                     &write_table_cb->qiov,
                     write_table_cb->qiov.size / BDRV_SECTOR_SIZE,
                     qed_write_table_cb, write_table_cb);
diff --git a/block/qed.c b/block/qed.c
index a7ff1d9..d953f8c 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -82,7 +82,7 @@  int qed_write_header_sync(BDRVQEDState *s)
     int ret;
 
     qed_header_cpu_to_le(&s->header, &le);
-    ret = bdrv_pwrite(s->bs->file, 0, &le, sizeof(le));
+    ret = bdrv_pwrite(s->bs->file->bs, 0, &le, sizeof(le));
     if (ret != sizeof(le)) {
         return ret;
     }
@@ -119,7 +119,7 @@  static void qed_write_header_read_cb(void *opaque, int ret)
     /* Update header */
     qed_header_cpu_to_le(&s->header, (QEDHeader *)write_header_cb->buf);
 
-    bdrv_aio_writev(s->bs->file, 0, &write_header_cb->qiov,
+    bdrv_aio_writev(s->bs->file->bs, 0, &write_header_cb->qiov,
                     write_header_cb->nsectors, qed_write_header_cb,
                     write_header_cb);
 }
@@ -152,7 +152,7 @@  static void qed_write_header(BDRVQEDState *s, BlockCompletionFunc cb,
     write_header_cb->iov.iov_len = len;
     qemu_iovec_init_external(&write_header_cb->qiov, &write_header_cb->iov, 1);
 
-    bdrv_aio_readv(s->bs->file, 0, &write_header_cb->qiov, nsectors,
+    bdrv_aio_readv(s->bs->file->bs, 0, &write_header_cb->qiov, nsectors,
                    qed_write_header_read_cb, write_header_cb);
 }
 
@@ -392,7 +392,7 @@  static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
     s->bs = bs;
     QSIMPLEQ_INIT(&s->allocating_write_reqs);
 
-    ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header));
+    ret = bdrv_pread(bs->file->bs, 0, &le_header, sizeof(le_header));
     if (ret < 0) {
         return ret;
     }
@@ -416,7 +416,7 @@  static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     /* Round down file size to the last cluster */
-    file_size = bdrv_getlength(bs->file);
+    file_size = bdrv_getlength(bs->file->bs);
     if (file_size < 0) {
         return file_size;
     }
@@ -452,7 +452,7 @@  static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
             return -EINVAL;
         }
 
-        ret = qed_read_string(bs->file, s->header.backing_filename_offset,
+        ret = qed_read_string(bs->file->bs, s->header.backing_filename_offset,
                               s->header.backing_filename_size, bs->backing_file,
                               sizeof(bs->backing_file));
         if (ret < 0) {
@@ -471,7 +471,7 @@  static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
      * feature is no longer valid.
      */
     if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 &&
-        !bdrv_is_read_only(bs->file) && !(flags & BDRV_O_INCOMING)) {
+        !bdrv_is_read_only(bs->file->bs) && !(flags & BDRV_O_INCOMING)) {
         s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK;
 
         ret = qed_write_header_sync(s);
@@ -480,7 +480,7 @@  static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
         }
 
         /* From here on only known autoclear feature bits are valid */
-        bdrv_flush(bs->file);
+        bdrv_flush(bs->file->bs);
     }
 
     s->l1_table = qed_alloc_table(s);
@@ -498,7 +498,7 @@  static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
          * potentially inconsistent images to be opened read-only.  This can
          * aid data recovery from an otherwise inconsistent image.
          */
-        if (!bdrv_is_read_only(bs->file) &&
+        if (!bdrv_is_read_only(bs->file->bs) &&
             !(flags & BDRV_O_INCOMING)) {
             BdrvCheckResult result = {0};
 
@@ -541,7 +541,7 @@  static void bdrv_qed_close(BlockDriverState *bs)
     bdrv_qed_detach_aio_context(bs);
 
     /* Ensure writes reach stable storage */
-    bdrv_flush(bs->file);
+    bdrv_flush(bs->file->bs);
 
     /* Clean shutdown, no check required on next open */
     if (s->header.features & QED_F_NEED_CHECK) {
@@ -839,7 +839,7 @@  static void qed_copy_from_backing_file_write(void *opaque, int ret)
     }
 
     BLKDBG_EVENT(s->bs->file, BLKDBG_COW_WRITE);
-    bdrv_aio_writev(s->bs->file, copy_cb->offset / BDRV_SECTOR_SIZE,
+    bdrv_aio_writev(s->bs->file->bs, copy_cb->offset / BDRV_SECTOR_SIZE,
                     &copy_cb->qiov, copy_cb->qiov.size / BDRV_SECTOR_SIZE,
                     qed_copy_from_backing_file_cb, copy_cb);
 }
@@ -1055,7 +1055,7 @@  static void qed_aio_write_flush_before_l2_update(void *opaque, int ret)
     QEDAIOCB *acb = opaque;
     BDRVQEDState *s = acb_to_s(acb);
 
-    if (!bdrv_aio_flush(s->bs->file, qed_aio_write_l2_update_cb, opaque)) {
+    if (!bdrv_aio_flush(s->bs->file->bs, qed_aio_write_l2_update_cb, opaque)) {
         qed_aio_complete(acb, -EIO);
     }
 }
@@ -1089,7 +1089,7 @@  static void qed_aio_write_main(void *opaque, int ret)
     }
 
     BLKDBG_EVENT(s->bs->file, BLKDBG_WRITE_AIO);
-    bdrv_aio_writev(s->bs->file, offset / BDRV_SECTOR_SIZE,
+    bdrv_aio_writev(s->bs->file->bs, offset / BDRV_SECTOR_SIZE,
                     &acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE,
                     next_fn, acb);
 }
@@ -1321,7 +1321,7 @@  static void qed_aio_read_data(void *opaque, int ret,
     }
 
     BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
-    bdrv_aio_readv(bs->file, offset / BDRV_SECTOR_SIZE,
+    bdrv_aio_readv(bs->file->bs, offset / BDRV_SECTOR_SIZE,
                    &acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE,
                    qed_aio_next_io, acb);
     return;
@@ -1580,7 +1580,7 @@  static int bdrv_qed_change_backing_file(BlockDriverState *bs,
     }
 
     /* Write new header */
-    ret = bdrv_pwrite_sync(bs->file, 0, buffer, buffer_len);
+    ret = bdrv_pwrite_sync(bs->file->bs, 0, buffer, buffer_len);
     g_free(buffer);
     if (ret == 0) {
         memcpy(&s->header, &new_header, sizeof(new_header));
@@ -1596,7 +1596,7 @@  static void bdrv_qed_invalidate_cache(BlockDriverState *bs, Error **errp)
 
     bdrv_qed_close(bs);
 
-    bdrv_invalidate_cache(bs->file, &local_err);
+    bdrv_invalidate_cache(bs->file->bs, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         return;
diff --git a/block/raw_bsd.c b/block/raw_bsd.c
index e3d2d04..63ee911 100644
--- a/block/raw_bsd.c
+++ b/block/raw_bsd.c
@@ -52,7 +52,7 @@  static int coroutine_fn raw_co_readv(BlockDriverState *bs, int64_t sector_num,
                                      int nb_sectors, QEMUIOVector *qiov)
 {
     BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
-    return bdrv_co_readv(bs->file, sector_num, nb_sectors, qiov);
+    return bdrv_co_readv(bs->file->bs, sector_num, nb_sectors, qiov);
 }
 
 static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
@@ -75,7 +75,7 @@  static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
             return 0;
         }
 
-        buf = qemu_try_blockalign(bs->file, 512);
+        buf = qemu_try_blockalign(bs->file->bs, 512);
         if (!buf) {
             ret = -ENOMEM;
             goto fail;
@@ -102,7 +102,7 @@  static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num,
     }
 
     BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
-    ret = bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
+    ret = bdrv_co_writev(bs->file->bs, sector_num, nb_sectors, qiov);
 
 fail:
     if (qiov == &local_qiov) {
@@ -125,58 +125,58 @@  static int coroutine_fn raw_co_write_zeroes(BlockDriverState *bs,
                                             int64_t sector_num, int nb_sectors,
                                             BdrvRequestFlags flags)
 {
-    return bdrv_co_write_zeroes(bs->file, sector_num, nb_sectors, flags);
+    return bdrv_co_write_zeroes(bs->file->bs, sector_num, nb_sectors, flags);
 }
 
 static int coroutine_fn raw_co_discard(BlockDriverState *bs,
                                        int64_t sector_num, int nb_sectors)
 {
-    return bdrv_co_discard(bs->file, sector_num, nb_sectors);
+    return bdrv_co_discard(bs->file->bs, sector_num, nb_sectors);
 }
 
 static int64_t raw_getlength(BlockDriverState *bs)
 {
-    return bdrv_getlength(bs->file);
+    return bdrv_getlength(bs->file->bs);
 }
 
 static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 {
-    return bdrv_get_info(bs->file, bdi);
+    return bdrv_get_info(bs->file->bs, bdi);
 }
 
 static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
 {
-    bs->bl = bs->file->bl;
+    bs->bl = bs->file->bs->bl;
 }
 
 static int raw_truncate(BlockDriverState *bs, int64_t offset)
 {
-    return bdrv_truncate(bs->file, offset);
+    return bdrv_truncate(bs->file->bs, offset);
 }
 
 static int raw_is_inserted(BlockDriverState *bs)
 {
-    return bdrv_is_inserted(bs->file);
+    return bdrv_is_inserted(bs->file->bs);
 }
 
 static int raw_media_changed(BlockDriverState *bs)
 {
-    return bdrv_media_changed(bs->file);
+    return bdrv_media_changed(bs->file->bs);
 }
 
 static void raw_eject(BlockDriverState *bs, bool eject_flag)
 {
-    bdrv_eject(bs->file, eject_flag);
+    bdrv_eject(bs->file->bs, eject_flag);
 }
 
 static void raw_lock_medium(BlockDriverState *bs, bool locked)
 {
-    bdrv_lock_medium(bs->file, locked);
+    bdrv_lock_medium(bs->file->bs, locked);
 }
 
 static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
 {
-    return bdrv_ioctl(bs->file, req, buf);
+    return bdrv_ioctl(bs->file->bs, req, buf);
 }
 
 static BlockAIOCB *raw_aio_ioctl(BlockDriverState *bs,
@@ -184,12 +184,12 @@  static BlockAIOCB *raw_aio_ioctl(BlockDriverState *bs,
                                  BlockCompletionFunc *cb,
                                  void *opaque)
 {
-    return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque);
+    return bdrv_aio_ioctl(bs->file->bs, req, buf, cb, opaque);
 }
 
 static int raw_has_zero_init(BlockDriverState *bs)
 {
-    return bdrv_has_zero_init(bs->file);
+    return bdrv_has_zero_init(bs->file->bs);
 }
 
 static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
@@ -207,7 +207,7 @@  static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
 static int raw_open(BlockDriverState *bs, QDict *options, int flags,
                     Error **errp)
 {
-    bs->sg = bs->file->sg;
+    bs->sg = bs->file->bs->sg;
 
     if (bs->probed && !bdrv_is_read_only(bs)) {
         fprintf(stderr,
@@ -217,7 +217,7 @@  static int raw_open(BlockDriverState *bs, QDict *options, int flags,
                 "raw images, write operations on block 0 will be restricted.\n"
                 "         Specify the 'raw' format explicitly to remove the "
                 "restrictions.\n",
-                bs->file->filename);
+                bs->file->bs->filename);
     }
 
     return 0;
@@ -237,12 +237,12 @@  static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
 
 static int raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
 {
-    return bdrv_probe_blocksizes(bs->file, bsz);
+    return bdrv_probe_blocksizes(bs->file->bs, bsz);
 }
 
 static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
 {
-    return bdrv_probe_geometry(bs->file, geo);
+    return bdrv_probe_geometry(bs->file->bs, geo);
 }
 
 BlockDriver bdrv_raw = {
diff --git a/block/snapshot.c b/block/snapshot.c
index 49e143e..89500f2 100644
--- a/block/snapshot.c
+++ b/block/snapshot.c
@@ -149,7 +149,7 @@  int bdrv_can_snapshot(BlockDriverState *bs)
 
     if (!drv->bdrv_snapshot_create) {
         if (bs->file != NULL) {
-            return bdrv_can_snapshot(bs->file);
+            return bdrv_can_snapshot(bs->file->bs);
         }
         return 0;
     }
@@ -168,7 +168,7 @@  int bdrv_snapshot_create(BlockDriverState *bs,
         return drv->bdrv_snapshot_create(bs, sn_info);
     }
     if (bs->file) {
-        return bdrv_snapshot_create(bs->file, sn_info);
+        return bdrv_snapshot_create(bs->file->bs, sn_info);
     }
     return -ENOTSUP;
 }
@@ -188,10 +188,10 @@  int bdrv_snapshot_goto(BlockDriverState *bs,
 
     if (bs->file) {
         drv->bdrv_close(bs);
-        ret = bdrv_snapshot_goto(bs->file, snapshot_id);
+        ret = bdrv_snapshot_goto(bs->file->bs, snapshot_id);
         open_ret = drv->bdrv_open(bs, NULL, bs->open_flags, NULL);
         if (open_ret < 0) {
-            bdrv_unref(bs->file);
+            bdrv_unref(bs->file->bs);
             bs->drv = NULL;
             return open_ret;
         }
@@ -245,7 +245,7 @@  int bdrv_snapshot_delete(BlockDriverState *bs,
         return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
     }
     if (bs->file) {
-        return bdrv_snapshot_delete(bs->file, snapshot_id, name, errp);
+        return bdrv_snapshot_delete(bs->file->bs, snapshot_id, name, errp);
     }
     error_setg(errp, "Block format '%s' used by device '%s' "
                "does not support internal snapshot deletion",
@@ -283,7 +283,7 @@  int bdrv_snapshot_list(BlockDriverState *bs,
         return drv->bdrv_snapshot_list(bs, psn_info);
     }
     if (bs->file) {
-        return bdrv_snapshot_list(bs->file, psn_info);
+        return bdrv_snapshot_list(bs->file->bs, psn_info);
     }
     return -ENOTSUP;
 }
diff --git a/block/vdi.c b/block/vdi.c
index 062a654..17626d4 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -399,7 +399,7 @@  static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
 
     logout("\n");
 
-    ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1);
+    ret = bdrv_read(bs->file->bs, 0, (uint8_t *)&header, 1);
     if (ret < 0) {
         goto fail;
     }
@@ -490,13 +490,14 @@  static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
 
     bmap_size = header.blocks_in_image * sizeof(uint32_t);
     bmap_size = DIV_ROUND_UP(bmap_size, SECTOR_SIZE);
-    s->bmap = qemu_try_blockalign(bs->file, bmap_size * SECTOR_SIZE);
+    s->bmap = qemu_try_blockalign(bs->file->bs, bmap_size * SECTOR_SIZE);
     if (s->bmap == NULL) {
         ret = -ENOMEM;
         goto fail;
     }
 
-    ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size);
+    ret = bdrv_read(bs->file->bs, s->bmap_sector, (uint8_t *)s->bmap,
+                    bmap_size);
     if (ret < 0) {
         goto fail_free_bmap;
     }
@@ -585,7 +586,7 @@  static int vdi_co_read(BlockDriverState *bs,
             uint64_t offset = s->header.offset_data / SECTOR_SIZE +
                               (uint64_t)bmap_entry * s->block_sectors +
                               sector_in_block;
-            ret = bdrv_read(bs->file, offset, buf, n_sectors);
+            ret = bdrv_read(bs->file->bs, offset, buf, n_sectors);
         }
         logout("%u sectors read\n", n_sectors);
 
@@ -653,7 +654,7 @@  static int vdi_co_write(BlockDriverState *bs,
              * acquire the lock and thus the padded cluster is written before
              * the other coroutines can write to the affected area. */
             qemu_co_mutex_lock(&s->write_lock);
-            ret = bdrv_write(bs->file, offset, block, s->block_sectors);
+            ret = bdrv_write(bs->file->bs, offset, block, s->block_sectors);
             qemu_co_mutex_unlock(&s->write_lock);
         } else {
             uint64_t offset = s->header.offset_data / SECTOR_SIZE +
@@ -669,7 +670,7 @@  static int vdi_co_write(BlockDriverState *bs,
              * that that write operation has returned (there may be other writes
              * in flight, but they do not concern this very operation). */
             qemu_co_mutex_unlock(&s->write_lock);
-            ret = bdrv_write(bs->file, offset, buf, n_sectors);
+            ret = bdrv_write(bs->file->bs, offset, buf, n_sectors);
         }
 
         nb_sectors -= n_sectors;
@@ -694,7 +695,7 @@  static int vdi_co_write(BlockDriverState *bs,
         assert(VDI_IS_ALLOCATED(bmap_first));
         *header = s->header;
         vdi_header_to_le(header);
-        ret = bdrv_write(bs->file, 0, block, 1);
+        ret = bdrv_write(bs->file->bs, 0, block, 1);
         g_free(block);
         block = NULL;
 
@@ -712,7 +713,7 @@  static int vdi_co_write(BlockDriverState *bs,
         base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE;
         logout("will write %u block map sectors starting from entry %u\n",
                n_sectors, bmap_first);
-        ret = bdrv_write(bs->file, offset, base, n_sectors);
+        ret = bdrv_write(bs->file->bs, offset, base, n_sectors);
     }
 
     return ret;
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
index 47fec63..47ae4b1 100644
--- a/block/vhdx-log.c
+++ b/block/vhdx-log.c
@@ -81,7 +81,7 @@  static int vhdx_log_peek_hdr(BlockDriverState *bs, VHDXLogEntries *log,
 
     offset = log->offset + read;
 
-    ret = bdrv_pread(bs->file, offset, hdr, sizeof(VHDXLogEntryHeader));
+    ret = bdrv_pread(bs->file->bs, offset, hdr, sizeof(VHDXLogEntryHeader));
     if (ret < 0) {
         goto exit;
     }
@@ -141,7 +141,7 @@  static int vhdx_log_read_sectors(BlockDriverState *bs, VHDXLogEntries *log,
         }
         offset = log->offset + read;
 
-        ret = bdrv_pread(bs->file, offset, buffer, VHDX_LOG_SECTOR_SIZE);
+        ret = bdrv_pread(bs->file->bs, offset, buffer, VHDX_LOG_SECTOR_SIZE);
         if (ret < 0) {
             goto exit;
         }
@@ -191,7 +191,8 @@  static int vhdx_log_write_sectors(BlockDriverState *bs, VHDXLogEntries *log,
             /* full */
             break;
         }
-        ret = bdrv_pwrite(bs->file, offset, buffer_tmp, VHDX_LOG_SECTOR_SIZE);
+        ret = bdrv_pwrite(bs->file->bs, offset, buffer_tmp,
+                          VHDX_LOG_SECTOR_SIZE);
         if (ret < 0) {
             goto exit;
         }
@@ -353,7 +354,7 @@  static int vhdx_log_read_desc(BlockDriverState *bs, BDRVVHDXState *s,
     }
 
     desc_sectors = vhdx_compute_desc_sectors(hdr.descriptor_count);
-    desc_entries = qemu_try_blockalign(bs->file,
+    desc_entries = qemu_try_blockalign(bs->file->bs,
                                        desc_sectors * VHDX_LOG_SECTOR_SIZE);
     if (desc_entries == NULL) {
         ret = -ENOMEM;
@@ -462,7 +463,7 @@  static int vhdx_log_flush_desc(BlockDriverState *bs, VHDXLogDescriptor *desc,
 
     /* count is only > 1 if we are writing zeroes */
     for (i = 0; i < count; i++) {
-        ret = bdrv_pwrite_sync(bs->file, file_offset, buffer,
+        ret = bdrv_pwrite_sync(bs->file->bs, file_offset, buffer,
                                VHDX_LOG_SECTOR_SIZE);
         if (ret < 0) {
             goto exit;
@@ -509,7 +510,7 @@  static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
         /* if the log shows a FlushedFileOffset larger than our current file
          * size, then that means the file has been truncated / corrupted, and
          * we must refused to open it / use it */
-        if (hdr_tmp.flushed_file_offset > bdrv_getlength(bs->file)) {
+        if (hdr_tmp.flushed_file_offset > bdrv_getlength(bs->file->bs)) {
             ret = -EINVAL;
             goto exit;
         }
@@ -539,12 +540,12 @@  static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
                 goto exit;
             }
         }
-        if (bdrv_getlength(bs->file) < desc_entries->hdr.last_file_offset) {
+        if (bdrv_getlength(bs->file->bs) < desc_entries->hdr.last_file_offset) {
             new_file_size = desc_entries->hdr.last_file_offset;
             if (new_file_size % (1024*1024)) {
                 /* round up to nearest 1MB boundary */
                 new_file_size = ((new_file_size >> 20) + 1) << 20;
-                bdrv_truncate(bs->file, new_file_size);
+                bdrv_truncate(bs->file->bs, new_file_size);
             }
         }
         qemu_vfree(desc_entries);
@@ -908,8 +909,8 @@  static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
                 .sequence_number     = s->log.sequence,
                 .descriptor_count    = sectors,
                 .reserved            = 0,
-                .flushed_file_offset = bdrv_getlength(bs->file),
-                .last_file_offset    = bdrv_getlength(bs->file),
+                .flushed_file_offset = bdrv_getlength(bs->file->bs),
+                .last_file_offset    = bdrv_getlength(bs->file->bs),
               };
 
     new_hdr.log_guid = header->log_guid;
@@ -940,7 +941,7 @@  static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
 
         if (i == 0 && leading_length) {
             /* partial sector at the front of the buffer */
-            ret = bdrv_pread(bs->file, file_offset, merged_sector,
+            ret = bdrv_pread(bs->file->bs, file_offset, merged_sector,
                              VHDX_LOG_SECTOR_SIZE);
             if (ret < 0) {
                 goto exit;
@@ -950,7 +951,7 @@  static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
             sector_write = merged_sector;
         } else if (i == sectors - 1 && trailing_length) {
             /* partial sector at the end of the buffer */
-            ret = bdrv_pread(bs->file,
+            ret = bdrv_pread(bs->file->bs,
                             file_offset,
                             merged_sector + trailing_length,
                             VHDX_LOG_SECTOR_SIZE - trailing_length);
diff --git a/block/vhdx.c b/block/vhdx.c
index d3bb1bd..2fe9a5e 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -375,7 +375,7 @@  static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s,
         inactive_header->log_guid = *log_guid;
     }
 
-    ret = vhdx_write_header(bs->file, inactive_header, header_offset, true);
+    ret = vhdx_write_header(bs->file->bs, inactive_header, header_offset, true);
     if (ret < 0) {
         goto exit;
     }
@@ -427,7 +427,8 @@  static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
     /* We have to read the whole VHDX_HEADER_SIZE instead of
      * sizeof(VHDXHeader), because the checksum is over the whole
      * region */
-    ret = bdrv_pread(bs->file, VHDX_HEADER1_OFFSET, buffer, VHDX_HEADER_SIZE);
+    ret = bdrv_pread(bs->file->bs, VHDX_HEADER1_OFFSET, buffer,
+                     VHDX_HEADER_SIZE);
     if (ret < 0) {
         goto fail;
     }
@@ -443,7 +444,8 @@  static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
         }
     }
 
-    ret = bdrv_pread(bs->file, VHDX_HEADER2_OFFSET, buffer, VHDX_HEADER_SIZE);
+    ret = bdrv_pread(bs->file->bs, VHDX_HEADER2_OFFSET, buffer,
+                     VHDX_HEADER_SIZE);
     if (ret < 0) {
         goto fail;
     }
@@ -516,7 +518,7 @@  static int vhdx_open_region_tables(BlockDriverState *bs, BDRVVHDXState *s)
      * whole block */
     buffer = qemu_blockalign(bs, VHDX_HEADER_BLOCK_SIZE);
 
-    ret = bdrv_pread(bs->file, VHDX_REGION_TABLE_OFFSET, buffer,
+    ret = bdrv_pread(bs->file->bs, VHDX_REGION_TABLE_OFFSET, buffer,
                      VHDX_HEADER_BLOCK_SIZE);
     if (ret < 0) {
         goto fail;
@@ -629,7 +631,7 @@  static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
 
     buffer = qemu_blockalign(bs, VHDX_METADATA_TABLE_MAX_SIZE);
 
-    ret = bdrv_pread(bs->file, s->metadata_rt.file_offset, buffer,
+    ret = bdrv_pread(bs->file->bs, s->metadata_rt.file_offset, buffer,
                      VHDX_METADATA_TABLE_MAX_SIZE);
     if (ret < 0) {
         goto exit;
@@ -732,7 +734,7 @@  static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
         goto exit;
     }
 
-    ret = bdrv_pread(bs->file,
+    ret = bdrv_pread(bs->file->bs,
                      s->metadata_entries.file_parameters_entry.offset
                                          + s->metadata_rt.file_offset,
                      &s->params,
@@ -767,7 +769,7 @@  static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
     /* determine virtual disk size, logical sector size,
      * and phys sector size */
 
-    ret = bdrv_pread(bs->file,
+    ret = bdrv_pread(bs->file->bs,
                      s->metadata_entries.virtual_disk_size_entry.offset
                                            + s->metadata_rt.file_offset,
                      &s->virtual_disk_size,
@@ -775,7 +777,7 @@  static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
     if (ret < 0) {
         goto exit;
     }
-    ret = bdrv_pread(bs->file,
+    ret = bdrv_pread(bs->file->bs,
                      s->metadata_entries.logical_sector_size_entry.offset
                                              + s->metadata_rt.file_offset,
                      &s->logical_sector_size,
@@ -783,7 +785,7 @@  static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
     if (ret < 0) {
         goto exit;
     }
-    ret = bdrv_pread(bs->file,
+    ret = bdrv_pread(bs->file->bs,
                      s->metadata_entries.phys_sector_size_entry.offset
                                           + s->metadata_rt.file_offset,
                      &s->physical_sector_size,
@@ -906,7 +908,7 @@  static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
     QLIST_INIT(&s->regions);
 
     /* validate the file signature */
-    ret = bdrv_pread(bs->file, 0, &signature, sizeof(uint64_t));
+    ret = bdrv_pread(bs->file->bs, 0, &signature, sizeof(uint64_t));
     if (ret < 0) {
         goto fail;
     }
@@ -959,13 +961,13 @@  static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     /* s->bat is freed in vhdx_close() */
-    s->bat = qemu_try_blockalign(bs->file, s->bat_rt.length);
+    s->bat = qemu_try_blockalign(bs->file->bs, s->bat_rt.length);
     if (s->bat == NULL) {
         ret = -ENOMEM;
         goto fail;
     }
 
-    ret = bdrv_pread(bs->file, s->bat_offset, s->bat, s->bat_rt.length);
+    ret = bdrv_pread(bs->file->bs, s->bat_offset, s->bat, s->bat_rt.length);
     if (ret < 0) {
         goto fail;
     }
@@ -1118,7 +1120,7 @@  static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num,
                 break;
             case PAYLOAD_BLOCK_FULLY_PRESENT:
                 qemu_co_mutex_unlock(&s->lock);
-                ret = bdrv_co_readv(bs->file,
+                ret = bdrv_co_readv(bs->file->bs,
                                     sinfo.file_offset >> BDRV_SECTOR_BITS,
                                     sinfo.sectors_avail, &hd_qiov);
                 qemu_co_mutex_lock(&s->lock);
@@ -1156,12 +1158,12 @@  exit:
 static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
                                     uint64_t *new_offset)
 {
-    *new_offset = bdrv_getlength(bs->file);
+    *new_offset = bdrv_getlength(bs->file->bs);
 
     /* per the spec, the address for a block is in units of 1MB */
     *new_offset = ROUND_UP(*new_offset, 1024 * 1024);
 
-    return bdrv_truncate(bs->file, *new_offset + s->block_size);
+    return bdrv_truncate(bs->file->bs, *new_offset + s->block_size);
 }
 
 /*
@@ -1260,7 +1262,7 @@  static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
                 /* Queue another write of zero buffers if the underlying file
                  * does not zero-fill on file extension */
 
-                if (bdrv_has_zero_init(bs->file) == 0) {
+                if (bdrv_has_zero_init(bs->file->bs) == 0) {
                     use_zero_buffers = true;
 
                     /* zero fill the front, if any */
@@ -1327,7 +1329,7 @@  static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
                 }
                 /* block exists, so we can just overwrite it */
                 qemu_co_mutex_unlock(&s->lock);
-                ret = bdrv_co_writev(bs->file,
+                ret = bdrv_co_writev(bs->file->bs,
                                     sinfo.file_offset >> BDRV_SECTOR_BITS,
                                     sectors_to_write, &hd_qiov);
                 qemu_co_mutex_lock(&s->lock);
diff --git a/block/vmdk.c b/block/vmdk.c
index 9702132..9f7e7db 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -221,7 +221,7 @@  static void vmdk_free_extents(BlockDriverState *bs)
         g_free(e->l2_cache);
         g_free(e->l1_backup_table);
         g_free(e->type);
-        if (e->file != bs->file_child) {
+        if (e->file != bs->file) {
             bdrv_unref_child(bs, e->file);
         }
     }
@@ -248,7 +248,7 @@  static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
     BDRVVmdkState *s = bs->opaque;
     int ret;
 
-    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
+    ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
     if (ret < 0) {
         return 0;
     }
@@ -278,7 +278,7 @@  static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
     BDRVVmdkState *s = bs->opaque;
     int ret;
 
-    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
+    ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
     if (ret < 0) {
         return ret;
     }
@@ -297,7 +297,7 @@  static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
         pstrcat(desc, sizeof(desc), tmp_desc);
     }
 
-    ret = bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE);
+    ret = bdrv_pwrite_sync(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
     if (ret < 0) {
         return ret;
     }
@@ -340,7 +340,7 @@  static int vmdk_parent_open(BlockDriverState *bs)
     int ret;
 
     desc[DESC_SIZE] = '\0';
-    ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
+    ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE);
     if (ret < 0) {
         return ret;
     }
@@ -621,7 +621,7 @@  static int vmdk_open_vmdk4(BlockDriverState *bs,
         } QEMU_PACKED footer;
 
         ret = bdrv_pread(file->bs,
-            bs->file->total_sectors * 512 - 1536,
+            bs->file->bs->total_sectors * 512 - 1536,
             &footer, sizeof(footer));
         if (ret < 0) {
             error_setg_errno(errp, -ret, "Failed to read footer");
@@ -819,7 +819,7 @@  static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
             !desc_file_path[0])
         {
             error_setg(errp, "Cannot use relative extent paths with VMDK "
-                       "descriptor file '%s'", bs->file->filename);
+                       "descriptor file '%s'", bs->file->bs->filename);
             return -EINVAL;
         }
 
@@ -905,7 +905,8 @@  static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
     }
     s->create_type = g_strdup(ct);
     s->desc_offset = 0;
-    ret = vmdk_parse_extents(buf, bs, bs->file->exact_filename, options, errp);
+    ret = vmdk_parse_extents(buf, bs, bs->file->bs->exact_filename, options,
+                             errp);
 exit:
     return ret;
 }
@@ -918,7 +919,7 @@  static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
     BDRVVmdkState *s = bs->opaque;
     uint32_t magic;
 
-    buf = vmdk_read_desc(bs->file, 0, errp);
+    buf = vmdk_read_desc(bs->file->bs, 0, errp);
     if (!buf) {
         return -EINVAL;
     }
@@ -927,7 +928,7 @@  static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
     switch (magic) {
         case VMDK3_MAGIC:
         case VMDK4_MAGIC:
-            ret = vmdk_open_sparse(bs, bs->file_child, flags, buf, options,
+            ret = vmdk_open_sparse(bs, bs->file, flags, buf, options,
                                    errp);
             s->desc_offset = 0x200;
             break;
@@ -1275,7 +1276,7 @@  static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
         break;
     case VMDK_OK:
         ret = BDRV_BLOCK_DATA;
-        if (extent->file == bs->file_child && !extent->compressed) {
+        if (extent->file == bs->file && !extent->compressed) {
             ret |= BDRV_BLOCK_OFFSET_VALID | offset;
         }
 
@@ -2051,12 +2052,12 @@  static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs)
     int64_t r;
     BDRVVmdkState *s = bs->opaque;
 
-    ret = bdrv_get_allocated_file_size(bs->file);
+    ret = bdrv_get_allocated_file_size(bs->file->bs);
     if (ret < 0) {
         return ret;
     }
     for (i = 0; i < s->num_extents; i++) {
-        if (s->extents[i].file == bs->file_child) {
+        if (s->extents[i].file == bs->file) {
             continue;
         }
         r = bdrv_get_allocated_file_size(s->extents[i].file->bs);
diff --git a/block/vpc.c b/block/vpc.c
index 2b3b518..299d373 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -172,14 +172,14 @@  static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
     int disk_type = VHD_DYNAMIC;
     int ret;
 
-    ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE);
+    ret = bdrv_pread(bs->file->bs, 0, s->footer_buf, HEADER_SIZE);
     if (ret < 0) {
         goto fail;
     }
 
     footer = (VHDFooter *) s->footer_buf;
     if (strncmp(footer->creator, "conectix", 8)) {
-        int64_t offset = bdrv_getlength(bs->file);
+        int64_t offset = bdrv_getlength(bs->file->bs);
         if (offset < 0) {
             ret = offset;
             goto fail;
@@ -189,7 +189,7 @@  static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
         }
 
         /* If a fixed disk, the footer is found only at the end of the file */
-        ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf,
+        ret = bdrv_pread(bs->file->bs, offset-HEADER_SIZE, s->footer_buf,
                          HEADER_SIZE);
         if (ret < 0) {
             goto fail;
@@ -232,7 +232,7 @@  static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     if (disk_type == VHD_DYNAMIC) {
-        ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
+        ret = bdrv_pread(bs->file->bs, be64_to_cpu(footer->data_offset), buf,
                          HEADER_SIZE);
         if (ret < 0) {
             goto fail;
@@ -280,7 +280,7 @@  static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
 
         pagetable_size = (uint64_t) s->max_table_entries * 4;
 
-        s->pagetable = qemu_try_blockalign(bs->file, pagetable_size);
+        s->pagetable = qemu_try_blockalign(bs->file->bs, pagetable_size);
         if (s->pagetable == NULL) {
             ret = -ENOMEM;
             goto fail;
@@ -288,7 +288,8 @@  static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
 
         s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
 
-        ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable, pagetable_size);
+        ret = bdrv_pread(bs->file->bs, s->bat_offset, s->pagetable,
+                         pagetable_size);
         if (ret < 0) {
             goto fail;
         }
@@ -308,7 +309,7 @@  static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
             }
         }
 
-        if (s->free_data_block_offset > bdrv_getlength(bs->file)) {
+        if (s->free_data_block_offset > bdrv_getlength(bs->file->bs)) {
             error_setg(errp, "block-vpc: free_data_block_offset points after "
                              "the end of file. The image has been truncated.");
             ret = -EINVAL;
@@ -383,7 +384,7 @@  static inline int64_t get_sector_offset(BlockDriverState *bs,
 
         s->last_bitmap_offset = bitmap_offset;
         memset(bitmap, 0xff, s->bitmap_size);
-        bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
+        bdrv_pwrite_sync(bs->file->bs, bitmap_offset, bitmap, s->bitmap_size);
     }
 
     return block_offset;
@@ -401,7 +402,7 @@  static int rewrite_footer(BlockDriverState* bs)
     BDRVVPCState *s = bs->opaque;
     int64_t offset = s->free_data_block_offset;
 
-    ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE);
+    ret = bdrv_pwrite_sync(bs->file->bs, offset, s->footer_buf, HEADER_SIZE);
     if (ret < 0)
         return ret;
 
@@ -436,7 +437,7 @@  static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
 
     // Initialize the block's bitmap
     memset(bitmap, 0xff, s->bitmap_size);
-    ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
+    ret = bdrv_pwrite_sync(bs->file->bs, s->free_data_block_offset, bitmap,
         s->bitmap_size);
     if (ret < 0) {
         return ret;
@@ -451,7 +452,7 @@  static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num)
     // Write BAT entry to disk
     bat_offset = s->bat_offset + (4 * index);
     bat_value = cpu_to_be32(s->pagetable[index]);
-    ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
+    ret = bdrv_pwrite_sync(bs->file->bs, bat_offset, &bat_value, 4);
     if (ret < 0)
         goto fail;
 
@@ -485,7 +486,7 @@  static int vpc_read(BlockDriverState *bs, int64_t sector_num,
     VHDFooter *footer = (VHDFooter *) s->footer_buf;
 
     if (be32_to_cpu(footer->type) == VHD_FIXED) {
-        return bdrv_read(bs->file, sector_num, buf, nb_sectors);
+        return bdrv_read(bs->file->bs, sector_num, buf, nb_sectors);
     }
     while (nb_sectors > 0) {
         offset = get_sector_offset(bs, sector_num, 0);
@@ -499,7 +500,7 @@  static int vpc_read(BlockDriverState *bs, int64_t sector_num,
         if (offset == -1) {
             memset(buf, 0, sectors * BDRV_SECTOR_SIZE);
         } else {
-            ret = bdrv_pread(bs->file, offset, buf,
+            ret = bdrv_pread(bs->file->bs, offset, buf,
                 sectors * BDRV_SECTOR_SIZE);
             if (ret != sectors * BDRV_SECTOR_SIZE) {
                 return -1;
@@ -534,7 +535,7 @@  static int vpc_write(BlockDriverState *bs, int64_t sector_num,
     VHDFooter *footer =  (VHDFooter *) s->footer_buf;
 
     if (be32_to_cpu(footer->type) == VHD_FIXED) {
-        return bdrv_write(bs->file, sector_num, buf, nb_sectors);
+        return bdrv_write(bs->file->bs, sector_num, buf, nb_sectors);
     }
     while (nb_sectors > 0) {
         offset = get_sector_offset(bs, sector_num, 1);
@@ -551,7 +552,8 @@  static int vpc_write(BlockDriverState *bs, int64_t sector_num,
                 return -1;
         }
 
-        ret = bdrv_pwrite(bs->file, offset, buf, sectors * BDRV_SECTOR_SIZE);
+        ret = bdrv_pwrite(bs->file->bs, offset, buf,
+                          sectors * BDRV_SECTOR_SIZE);
         if (ret != sectors * BDRV_SECTOR_SIZE) {
             return -1;
         }
@@ -878,7 +880,7 @@  static int vpc_has_zero_init(BlockDriverState *bs)
     VHDFooter *footer =  (VHDFooter *) s->footer_buf;
 
     if (be32_to_cpu(footer->type) == VHD_FIXED) {
-        return bdrv_has_zero_init(bs->file);
+        return bdrv_has_zero_init(bs->file->bs);
     } else {
         return 1;
     }
diff --git a/include/block/block.h b/include/block/block.h
index 2dd6630..7ebb35d 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -585,7 +585,13 @@  typedef enum {
     BLKDBG_EVENT_MAX,
 } BlkDebugEvent;
 
-#define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
+#define BLKDBG_EVENT(child, evt) \
+    do { \
+        if (child) { \
+            bdrv_debug_event(child->bs, evt); \
+        } \
+    } while(0)
+
 void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
 
 int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
diff --git a/include/block/block_int.h b/include/block/block_int.h
index d0dd93e..98936c9 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -380,8 +380,7 @@  struct BlockDriverState {
 
     BlockDriverState *backing_hd;
     BdrvChild *backing_child;
-    BlockDriverState *file;
-    BdrvChild *file_child;
+    BdrvChild *file;
 
     NotifierList close_notifiers;