qemu-io: Use BlockBackend

qemu-io should behave like a guest, therefore it should use BlockBackend
to access the block layer.

There are a couple of places where that is infeasible: First, the
bdrv_debug_* functions could theoretically be mirrored in the
BlockBackend, but since these are functions internal to the block layer,
they should not be visible externally (qemu-io as a test tool is exempt
from this).

Second, bdrv_get_info() and bdrv_get_specific_info() work on a single
BDS alone, therefore they should stay BDS-specific.

Third, bdrv_is_allocated() mainly works on a single BDS as well. Some
data may be passed through from the BDS's file (if sectors which are
apparently allocated in the file are not really allocated there but just
zero).

[Fixed conflicts around block_acct_start() usage from Fam Zheng's
"qemu-io: Account IO by aio_read and aio_write" commit.  Use
BlockBackend and blk_get_stats() instead of BlockDriverState.
--Stefan]

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1423162705-32065-14-git-send-email-mreitz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
diff --git a/hmp.c b/hmp.c
index b47f331..3825b29 100644
--- a/hmp.c
+++ b/hmp.c
@@ -16,6 +16,7 @@
 #include "hmp.h"
 #include "net/net.h"
 #include "sysemu/char.h"
+#include "sysemu/block-backend.h"
 #include "qemu/option.h"
 #include "qemu/timer.h"
 #include "qmp-commands.h"
@@ -1720,14 +1721,14 @@
 
 void hmp_qemu_io(Monitor *mon, const QDict *qdict)
 {
-    BlockDriverState *bs;
+    BlockBackend *blk;
     const char* device = qdict_get_str(qdict, "device");
     const char* command = qdict_get_str(qdict, "command");
     Error *err = NULL;
 
-    bs = bdrv_find(device);
-    if (bs) {
-        qemuio_command(bs, command);
+    blk = blk_by_name(device);
+    if (blk) {
+        qemuio_command(blk, command);
     } else {
         error_set(&err, QERR_DEVICE_NOT_FOUND, device);
     }
diff --git a/include/qemu-io.h b/include/qemu-io.h
index 5d6006f..4d402b9 100644
--- a/include/qemu-io.h
+++ b/include/qemu-io.h
@@ -22,7 +22,7 @@
 
 #define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */
 
-typedef int (*cfunc_t)(BlockDriverState *bs, int argc, char **argv);
+typedef int (*cfunc_t)(BlockBackend *blk, int argc, char **argv);
 typedef void (*helpfunc_t)(void);
 
 typedef struct cmdinfo {
@@ -40,7 +40,7 @@
 
 extern bool qemuio_misalign;
 
-bool qemuio_command(BlockDriverState *bs, const char *cmd);
+bool qemuio_command(BlockBackend *blk, const char *cmd);
 
 void qemuio_add_command(const cmdinfo_t *ci);
 int qemuio_command_usage(const cmdinfo_t *ci);
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 29377cd..1afcfc0 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -9,7 +9,9 @@
  */
 
 #include "qemu-io.h"
-#include "block/block_int.h"
+#include "sysemu/block-backend.h"
+#include "block/block.h"
+#include "block/block_int.h" /* for info_f() */
 #include "block/qapi.h"
 #include "qemu/main-loop.h"
 #include "qemu/timer.h"
@@ -41,24 +43,24 @@
     return 0;
 }
 
-static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct)
+static int init_check_command(BlockBackend *blk, const cmdinfo_t *ct)
 {
     if (ct->flags & CMD_FLAG_GLOBAL) {
         return 1;
     }
-    if (!(ct->flags & CMD_NOFILE_OK) && !bs) {
+    if (!(ct->flags & CMD_NOFILE_OK) && !blk) {
         fprintf(stderr, "no file open, try 'help open'\n");
         return 0;
     }
     return 1;
 }
 
-static int command(BlockDriverState *bs, const cmdinfo_t *ct, int argc,
+static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc,
                    char **argv)
 {
     char *cmd = argv[0];
 
-    if (!init_check_command(bs, ct)) {
+    if (!init_check_command(blk, ct)) {
         return 0;
     }
 
@@ -79,7 +81,7 @@
         return 0;
     }
     optind = 0;
-    return ct->cfunc(bs, argc, argv);
+    return ct->cfunc(blk, argc, argv);
 }
 
 static const cmdinfo_t *find_command(const char *cmd)
@@ -268,14 +270,14 @@
  */
 
 #define MISALIGN_OFFSET     16
-static void *qemu_io_alloc(BlockDriverState *bs, size_t len, int pattern)
+static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern)
 {
     void *buf;
 
     if (qemuio_misalign) {
         len += MISALIGN_OFFSET;
     }
-    buf = qemu_blockalign(bs, len);
+    buf = blk_blockalign(blk, len);
     memset(buf, pattern, len);
     if (qemuio_misalign) {
         buf += MISALIGN_OFFSET;
@@ -341,7 +343,7 @@
  * vector matching it.
  */
 static void *
-create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov,
+create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov,
              int pattern)
 {
     size_t *sizes = g_new0(size_t, nr_iov);
@@ -378,7 +380,7 @@
 
     qemu_iovec_init(qiov, nr_iov);
 
-    buf = p = qemu_io_alloc(bs, count, pattern);
+    buf = p = qemu_io_alloc(blk, count, pattern);
 
     for (i = 0; i < nr_iov; i++) {
         qemu_iovec_add(qiov, p, sizes[i]);
@@ -390,12 +392,12 @@
     return buf;
 }
 
-static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count,
+static int do_read(BlockBackend *blk, char *buf, int64_t offset, int count,
                    int *total)
 {
     int ret;
 
-    ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    ret = blk_read(blk, offset >> 9, (uint8_t *)buf, count >> 9);
     if (ret < 0) {
         return ret;
     }
@@ -403,12 +405,12 @@
     return 1;
 }
 
-static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count,
+static int do_write(BlockBackend *blk, char *buf, int64_t offset, int count,
                     int *total)
 {
     int ret;
 
-    ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    ret = blk_write(blk, offset >> 9, (uint8_t *)buf, count >> 9);
     if (ret < 0) {
         return ret;
     }
@@ -416,20 +418,20 @@
     return 1;
 }
 
-static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count,
+static int do_pread(BlockBackend *blk, char *buf, int64_t offset, int count,
                     int *total)
 {
-    *total = bdrv_pread(bs, offset, (uint8_t *)buf, count);
+    *total = blk_pread(blk, offset, (uint8_t *)buf, count);
     if (*total < 0) {
         return *total;
     }
     return 1;
 }
 
-static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count,
+static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset, int count,
                      int *total)
 {
-    *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count);
+    *total = blk_pwrite(blk, offset, (uint8_t *)buf, count);
     if (*total < 0) {
         return *total;
     }
@@ -437,7 +439,7 @@
 }
 
 typedef struct {
-    BlockDriverState *bs;
+    BlockBackend *blk;
     int64_t offset;
     int count;
     int *total;
@@ -449,8 +451,8 @@
 {
     CoWriteZeroes *data = opaque;
 
-    data->ret = bdrv_co_write_zeroes(data->bs, data->offset / BDRV_SECTOR_SIZE,
-                                     data->count / BDRV_SECTOR_SIZE, 0);
+    data->ret = blk_co_write_zeroes(data->blk, data->offset / BDRV_SECTOR_SIZE,
+                                    data->count / BDRV_SECTOR_SIZE, 0);
     data->done = true;
     if (data->ret < 0) {
         *data->total = data->ret;
@@ -460,12 +462,12 @@
     *data->total = data->count;
 }
 
-static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count,
+static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int count,
                               int *total)
 {
     Coroutine *co;
     CoWriteZeroes data = {
-        .bs     = bs,
+        .blk    = blk,
         .offset = offset,
         .count  = count,
         .total  = total,
@@ -475,7 +477,7 @@
     co = qemu_coroutine_create(co_write_zeroes_entry);
     qemu_coroutine_enter(co, &data);
     while (!data.done) {
-        aio_poll(bdrv_get_aio_context(bs), true);
+        aio_poll(blk_get_aio_context(blk), true);
     }
     if (data.ret < 0) {
         return data.ret;
@@ -484,12 +486,12 @@
     }
 }
 
-static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset,
+static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset,
                                int count, int *total)
 {
     int ret;
 
-    ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9);
+    ret = blk_write_compressed(blk, offset >> 9, (uint8_t *)buf, count >> 9);
     if (ret < 0) {
         return ret;
     }
@@ -497,20 +499,20 @@
     return 1;
 }
 
-static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset,
+static int do_load_vmstate(BlockBackend *blk, char *buf, int64_t offset,
                            int count, int *total)
 {
-    *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count);
+    *total = blk_load_vmstate(blk, (uint8_t *)buf, offset, count);
     if (*total < 0) {
         return *total;
     }
     return 1;
 }
 
-static int do_save_vmstate(BlockDriverState *bs, char *buf, int64_t offset,
+static int do_save_vmstate(BlockBackend *blk, char *buf, int64_t offset,
                            int count, int *total)
 {
-    *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count);
+    *total = blk_save_vmstate(blk, (uint8_t *)buf, offset, count);
     if (*total < 0) {
         return *total;
     }
@@ -523,13 +525,13 @@
     *(int *)opaque = ret;
 }
 
-static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov,
+static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
                         int64_t offset, int *total)
 {
     int async_ret = NOT_DONE;
 
-    bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
-                   aio_rw_done, &async_ret);
+    blk_aio_readv(blk, offset >> 9, qiov, qiov->size >> 9,
+                  aio_rw_done, &async_ret);
     while (async_ret == NOT_DONE) {
         main_loop_wait(false);
     }
@@ -538,13 +540,13 @@
     return async_ret < 0 ? async_ret : 1;
 }
 
-static int do_aio_writev(BlockDriverState *bs, QEMUIOVector *qiov,
+static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov,
                          int64_t offset, int *total)
 {
     int async_ret = NOT_DONE;
 
-    bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
-                    aio_rw_done, &async_ret);
+    blk_aio_writev(blk, offset >> 9, qiov, qiov->size >> 9,
+                   aio_rw_done, &async_ret);
     while (async_ret == NOT_DONE) {
         main_loop_wait(false);
     }
@@ -568,7 +570,7 @@
     }
 }
 
-static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs,
+static int do_aio_multiwrite(BlockBackend *blk, BlockRequest* reqs,
                              int num_reqs, int *total)
 {
     int i, ret;
@@ -584,7 +586,7 @@
         *total += reqs[i].qiov->size;
     }
 
-    ret = bdrv_aio_multiwrite(bs, reqs, num_reqs);
+    ret = blk_aio_multiwrite(blk, reqs, num_reqs);
     if (ret < 0) {
         return ret;
     }
@@ -610,7 +612,7 @@
 " -b, -- read from the VM state rather than the virtual disk\n"
 " -C, -- report statistics in a machine parsable format\n"
 " -l, -- length for pattern verification (only with -P)\n"
-" -p, -- use bdrv_pread to read the file\n"
+" -p, -- use blk_pread to read the file\n"
 " -P, -- use a pattern to verify read data\n"
 " -q, -- quiet mode, do not show I/O statistics\n"
 " -s, -- start offset for pattern verification (only with -P)\n"
@@ -618,7 +620,7 @@
 "\n");
 }
 
-static int read_f(BlockDriverState *bs, int argc, char **argv);
+static int read_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t read_cmd = {
     .name       = "read",
@@ -631,7 +633,7 @@
     .help       = read_help,
 };
 
-static int read_f(BlockDriverState *bs, int argc, char **argv)
+static int read_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, pflag = 0, qflag = 0, vflag = 0;
@@ -737,15 +739,15 @@
         }
     }
 
-    buf = qemu_io_alloc(bs, count, 0xab);
+    buf = qemu_io_alloc(blk, count, 0xab);
 
     gettimeofday(&t1, NULL);
     if (pflag) {
-        cnt = do_pread(bs, buf, offset, count, &total);
+        cnt = do_pread(blk, buf, offset, count, &total);
     } else if (bflag) {
-        cnt = do_load_vmstate(bs, buf, offset, count, &total);
+        cnt = do_load_vmstate(blk, buf, offset, count, &total);
     } else {
-        cnt = do_read(bs, buf, offset, count, &total);
+        cnt = do_read(blk, buf, offset, count, &total);
     }
     gettimeofday(&t2, NULL);
 
@@ -802,7 +804,7 @@
 "\n");
 }
 
-static int readv_f(BlockDriverState *bs, int argc, char **argv);
+static int readv_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t readv_cmd = {
     .name       = "readv",
@@ -814,7 +816,7 @@
     .help       = readv_help,
 };
 
-static int readv_f(BlockDriverState *bs, int argc, char **argv)
+static int readv_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, qflag = 0, vflag = 0;
@@ -870,13 +872,13 @@
     }
 
     nr_iov = argc - optind;
-    buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, 0xab);
+    buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab);
     if (buf == NULL) {
         return 0;
     }
 
     gettimeofday(&t1, NULL);
-    cnt = do_aio_readv(bs, &qiov, offset, &total);
+    cnt = do_aio_readv(blk, &qiov, offset, &total);
     gettimeofday(&t2, NULL);
 
     if (cnt < 0) {
@@ -924,16 +926,16 @@
 " Writes into a segment of the currently open file, using a buffer\n"
 " filled with a set pattern (0xcdcdcdcd).\n"
 " -b, -- write to the VM state rather than the virtual disk\n"
-" -c, -- write compressed data with bdrv_write_compressed\n"
-" -p, -- use bdrv_pwrite to write the file\n"
+" -c, -- write compressed data with blk_write_compressed\n"
+" -p, -- use blk_pwrite to write the file\n"
 " -P, -- use different pattern to fill file\n"
 " -C, -- report statistics in a machine parsable format\n"
 " -q, -- quiet mode, do not show I/O statistics\n"
-" -z, -- write zeroes using bdrv_co_write_zeroes\n"
+" -z, -- write zeroes using blk_co_write_zeroes\n"
 "\n");
 }
 
-static int write_f(BlockDriverState *bs, int argc, char **argv);
+static int write_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t write_cmd = {
     .name       = "write",
@@ -946,7 +948,7 @@
     .help       = write_help,
 };
 
-static int write_f(BlockDriverState *bs, int argc, char **argv)
+static int write_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0;
@@ -1033,20 +1035,20 @@
     }
 
     if (!zflag) {
-        buf = qemu_io_alloc(bs, count, pattern);
+        buf = qemu_io_alloc(blk, count, pattern);
     }
 
     gettimeofday(&t1, NULL);
     if (pflag) {
-        cnt = do_pwrite(bs, buf, offset, count, &total);
+        cnt = do_pwrite(blk, buf, offset, count, &total);
     } else if (bflag) {
-        cnt = do_save_vmstate(bs, buf, offset, count, &total);
+        cnt = do_save_vmstate(blk, buf, offset, count, &total);
     } else if (zflag) {
-        cnt = do_co_write_zeroes(bs, offset, count, &total);
+        cnt = do_co_write_zeroes(blk, offset, count, &total);
     } else if (cflag) {
-        cnt = do_write_compressed(bs, buf, offset, count, &total);
+        cnt = do_write_compressed(blk, buf, offset, count, &total);
     } else {
-        cnt = do_write(bs, buf, offset, count, &total);
+        cnt = do_write(blk, buf, offset, count, &total);
     }
     gettimeofday(&t2, NULL);
 
@@ -1089,7 +1091,7 @@
 "\n");
 }
 
-static int writev_f(BlockDriverState *bs, int argc, char **argv);
+static int writev_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t writev_cmd = {
     .name       = "writev",
@@ -1101,7 +1103,7 @@
     .help       = writev_help,
 };
 
-static int writev_f(BlockDriverState *bs, int argc, char **argv)
+static int writev_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, qflag = 0;
@@ -1151,13 +1153,13 @@
     }
 
     nr_iov = argc - optind;
-    buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, pattern);
+    buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern);
     if (buf == NULL) {
         return 0;
     }
 
     gettimeofday(&t1, NULL);
-    cnt = do_aio_writev(bs, &qiov, offset, &total);
+    cnt = do_aio_writev(blk, &qiov, offset, &total);
     gettimeofday(&t2, NULL);
 
     if (cnt < 0) {
@@ -1198,7 +1200,7 @@
 "\n");
 }
 
-static int multiwrite_f(BlockDriverState *bs, int argc, char **argv);
+static int multiwrite_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t multiwrite_cmd = {
     .name       = "multiwrite",
@@ -1210,7 +1212,7 @@
     .help       = multiwrite_help,
 };
 
-static int multiwrite_f(BlockDriverState *bs, int argc, char **argv)
+static int multiwrite_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, qflag = 0;
@@ -1291,7 +1293,7 @@
         nr_iov = j - optind;
 
         /* Build request */
-        buf[i] = create_iovec(bs, &qiovs[i], &argv[optind], nr_iov, pattern);
+        buf[i] = create_iovec(blk, &qiovs[i], &argv[optind], nr_iov, pattern);
         if (buf[i] == NULL) {
             goto out;
         }
@@ -1309,7 +1311,7 @@
     nr_reqs = i;
 
     gettimeofday(&t1, NULL);
-    cnt = do_aio_multiwrite(bs, reqs, nr_reqs, &total);
+    cnt = do_aio_multiwrite(blk, reqs, nr_reqs, &total);
     gettimeofday(&t2, NULL);
 
     if (cnt < 0) {
@@ -1338,7 +1340,7 @@
 }
 
 struct aio_ctx {
-    BlockDriverState *bs;
+    BlockBackend *blk;
     QEMUIOVector qiov;
     int64_t offset;
     char *buf;
@@ -1364,7 +1366,7 @@
         goto out;
     }
 
-    block_acct_done(&ctx->bs->stats, &ctx->acct);
+    block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
 
     if (ctx->qflag) {
         goto out;
@@ -1403,7 +1405,7 @@
         g_free(cmp_buf);
     }
 
-    block_acct_done(&ctx->bs->stats, &ctx->acct);
+    block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
 
     if (ctx->qflag) {
         goto out;
@@ -1443,7 +1445,7 @@
 "\n");
 }
 
-static int aio_read_f(BlockDriverState *bs, int argc, char **argv);
+static int aio_read_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t aio_read_cmd = {
     .name       = "aio_read",
@@ -1455,12 +1457,12 @@
     .help       = aio_read_help,
 };
 
-static int aio_read_f(BlockDriverState *bs, int argc, char **argv)
+static int aio_read_f(BlockBackend *blk, int argc, char **argv)
 {
     int nr_iov, c;
     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
 
-    ctx->bs = bs;
+    ctx->blk = blk;
     while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
         switch (c) {
         case 'C':
@@ -1507,16 +1509,17 @@
     }
 
     nr_iov = argc - optind;
-    ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, 0xab);
+    ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab);
     if (ctx->buf == NULL) {
         g_free(ctx);
         return 0;
     }
 
     gettimeofday(&ctx->t1, NULL);
-    block_acct_start(&bs->stats, &ctx->acct, ctx->qiov.size, BLOCK_ACCT_READ);
-    bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
-                   ctx->qiov.size >> 9, aio_read_done, ctx);
+    block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
+                     BLOCK_ACCT_READ);
+    blk_aio_readv(blk, ctx->offset >> 9, &ctx->qiov,
+                  ctx->qiov.size >> 9, aio_read_done, ctx);
     return 0;
 }
 
@@ -1540,7 +1543,7 @@
 "\n");
 }
 
-static int aio_write_f(BlockDriverState *bs, int argc, char **argv);
+static int aio_write_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t aio_write_cmd = {
     .name       = "aio_write",
@@ -1552,13 +1555,13 @@
     .help       = aio_write_help,
 };
 
-static int aio_write_f(BlockDriverState *bs, int argc, char **argv)
+static int aio_write_f(BlockBackend *blk, int argc, char **argv)
 {
     int nr_iov, c;
     int pattern = 0xcd;
     struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
 
-    ctx->bs = bs;
+    ctx->blk = blk;
     while ((c = getopt(argc, argv, "CqP:")) != EOF) {
         switch (c) {
         case 'C':
@@ -1601,22 +1604,23 @@
     }
 
     nr_iov = argc - optind;
-    ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, pattern);
+    ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, pattern);
     if (ctx->buf == NULL) {
         g_free(ctx);
         return 0;
     }
 
     gettimeofday(&ctx->t1, NULL);
-    block_acct_start(&bs->stats, &ctx->acct, ctx->qiov.size, BLOCK_ACCT_WRITE);
-    bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
-                    ctx->qiov.size >> 9, aio_write_done, ctx);
+    block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
+                     BLOCK_ACCT_WRITE);
+    blk_aio_writev(blk, ctx->offset >> 9, &ctx->qiov,
+                   ctx->qiov.size >> 9, aio_write_done, ctx);
     return 0;
 }
 
-static int aio_flush_f(BlockDriverState *bs, int argc, char **argv)
+static int aio_flush_f(BlockBackend *blk, int argc, char **argv)
 {
-    bdrv_drain_all();
+    blk_drain_all();
     return 0;
 }
 
@@ -1626,9 +1630,9 @@
     .oneline    = "completes all outstanding aio requests"
 };
 
-static int flush_f(BlockDriverState *bs, int argc, char **argv)
+static int flush_f(BlockBackend *blk, int argc, char **argv)
 {
-    bdrv_flush(bs);
+    blk_flush(blk);
     return 0;
 }
 
@@ -1639,7 +1643,7 @@
     .oneline    = "flush all in-core file state to disk",
 };
 
-static int truncate_f(BlockDriverState *bs, int argc, char **argv)
+static int truncate_f(BlockBackend *blk, int argc, char **argv)
 {
     int64_t offset;
     int ret;
@@ -1650,7 +1654,7 @@
         return 0;
     }
 
-    ret = bdrv_truncate(bs, offset);
+    ret = blk_truncate(blk, offset);
     if (ret < 0) {
         printf("truncate: %s\n", strerror(-ret));
         return 0;
@@ -1669,12 +1673,12 @@
     .oneline    = "truncates the current file at the given offset",
 };
 
-static int length_f(BlockDriverState *bs, int argc, char **argv)
+static int length_f(BlockBackend *blk, int argc, char **argv)
 {
     int64_t size;
     char s1[64];
 
-    size = bdrv_getlength(bs);
+    size = blk_getlength(blk);
     if (size < 0) {
         printf("getlength: %s\n", strerror(-size));
         return 0;
@@ -1694,8 +1698,9 @@
 };
 
 
-static int info_f(BlockDriverState *bs, int argc, char **argv)
+static int info_f(BlockBackend *blk, int argc, char **argv)
 {
+    BlockDriverState *bs = blk_bs(blk);
     BlockDriverInfo bdi;
     ImageInfoSpecific *spec_info;
     char s1[64], s2[64];
@@ -1753,7 +1758,7 @@
 "\n");
 }
 
-static int discard_f(BlockDriverState *bs, int argc, char **argv);
+static int discard_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t discard_cmd = {
     .name       = "discard",
@@ -1766,7 +1771,7 @@
     .help       = discard_help,
 };
 
-static int discard_f(BlockDriverState *bs, int argc, char **argv)
+static int discard_f(BlockBackend *blk, int argc, char **argv)
 {
     struct timeval t1, t2;
     int Cflag = 0, qflag = 0;
@@ -1805,8 +1810,8 @@
     }
 
     gettimeofday(&t1, NULL);
-    ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS,
-                       count >> BDRV_SECTOR_BITS);
+    ret = blk_discard(blk, offset >> BDRV_SECTOR_BITS,
+                      count >> BDRV_SECTOR_BITS);
     gettimeofday(&t2, NULL);
 
     if (ret < 0) {
@@ -1824,8 +1829,9 @@
     return 0;
 }
 
-static int alloc_f(BlockDriverState *bs, int argc, char **argv)
+static int alloc_f(BlockBackend *blk, int argc, char **argv)
 {
+    BlockDriverState *bs = blk_bs(blk);
     int64_t offset, sector_num;
     int nb_sectors, remaining;
     char s1[64];
@@ -1921,20 +1927,27 @@
     return firstret;
 }
 
-static int map_f(BlockDriverState *bs, int argc, char **argv)
+static int map_f(BlockBackend *blk, int argc, char **argv)
 {
     int64_t offset;
-    int64_t nb_sectors;
+    int64_t nb_sectors, total_sectors;
     char s1[64];
     int64_t num;
     int ret;
     const char *retstr;
 
     offset = 0;
-    nb_sectors = bs->total_sectors;
+    total_sectors = blk_nb_sectors(blk);
+    if (total_sectors < 0) {
+        error_report("Failed to query image length: %s",
+                     strerror(-total_sectors));
+        return 0;
+    }
+
+    nb_sectors = total_sectors;
 
     do {
-        ret = map_is_allocated(bs, offset, nb_sectors, &num);
+        ret = map_is_allocated(blk_bs(blk), offset, nb_sectors, &num);
         if (ret < 0) {
             error_report("Failed to get allocation status: %s", strerror(-ret));
             return 0;
@@ -1951,7 +1964,7 @@
 
         offset += num;
         nb_sectors -= num;
-    } while (offset < bs->total_sectors);
+    } while (offset < total_sectors);
 
     return 0;
 }
@@ -1965,11 +1978,11 @@
        .oneline        = "prints the allocated areas of a file",
 };
 
-static int break_f(BlockDriverState *bs, int argc, char **argv)
+static int break_f(BlockBackend *blk, int argc, char **argv)
 {
     int ret;
 
-    ret = bdrv_debug_breakpoint(bs, argv[1], argv[2]);
+    ret = bdrv_debug_breakpoint(blk_bs(blk), argv[1], argv[2]);
     if (ret < 0) {
         printf("Could not set breakpoint: %s\n", strerror(-ret));
     }
@@ -1977,11 +1990,11 @@
     return 0;
 }
 
-static int remove_break_f(BlockDriverState *bs, int argc, char **argv)
+static int remove_break_f(BlockBackend *blk, int argc, char **argv)
 {
     int ret;
 
-    ret = bdrv_debug_remove_breakpoint(bs, argv[1]);
+    ret = bdrv_debug_remove_breakpoint(blk_bs(blk), argv[1]);
     if (ret < 0) {
         printf("Could not remove breakpoint %s: %s\n", argv[1], strerror(-ret));
     }
@@ -2008,11 +2021,11 @@
        .oneline        = "remove a breakpoint by tag",
 };
 
-static int resume_f(BlockDriverState *bs, int argc, char **argv)
+static int resume_f(BlockBackend *blk, int argc, char **argv)
 {
     int ret;
 
-    ret = bdrv_debug_resume(bs, argv[1]);
+    ret = bdrv_debug_resume(blk_bs(blk), argv[1]);
     if (ret < 0) {
         printf("Could not resume request: %s\n", strerror(-ret));
     }
@@ -2029,10 +2042,10 @@
        .oneline        = "resumes the request tagged as tag",
 };
 
-static int wait_break_f(BlockDriverState *bs, int argc, char **argv)
+static int wait_break_f(BlockBackend *blk, int argc, char **argv)
 {
-    while (!bdrv_debug_is_suspended(bs, argv[1])) {
-        aio_poll(bdrv_get_aio_context(bs), true);
+    while (!bdrv_debug_is_suspended(blk_bs(blk), argv[1])) {
+        aio_poll(blk_get_aio_context(blk), true);
     }
 
     return 0;
@@ -2047,7 +2060,7 @@
        .oneline        = "waits for the suspension of a request",
 };
 
-static int abort_f(BlockDriverState *bs, int argc, char **argv)
+static int abort_f(BlockBackend *blk, int argc, char **argv)
 {
     abort();
 }
@@ -2073,7 +2086,7 @@
 "\n", SIGTERM);
 }
 
-static int sigraise_f(BlockDriverState *bs, int argc, char **argv);
+static int sigraise_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t sigraise_cmd = {
     .name       = "sigraise",
@@ -2086,7 +2099,7 @@
     .help       = sigraise_help,
 };
 
-static int sigraise_f(BlockDriverState *bs, int argc, char **argv)
+static int sigraise_f(BlockBackend *blk, int argc, char **argv)
 {
     int sig = cvtnum(argv[1]);
     if (sig < 0) {
@@ -2110,7 +2123,7 @@
     *expired = true;
 }
 
-static int sleep_f(BlockDriverState *bs, int argc, char **argv)
+static int sleep_f(BlockBackend *blk, int argc, char **argv)
 {
     char *endptr;
     long ms;
@@ -2179,7 +2192,7 @@
     printf("\nUse 'help commandname' for extended help.\n");
 }
 
-static int help_f(BlockDriverState *bs, int argc, char **argv)
+static int help_f(BlockBackend *blk, int argc, char **argv)
 {
     const cmdinfo_t *ct;
 
@@ -2209,7 +2222,7 @@
     .oneline    = "help for one or all commands",
 };
 
-bool qemuio_command(BlockDriverState *bs, const char *cmd)
+bool qemuio_command(BlockBackend *blk, const char *cmd)
 {
     char *input;
     const cmdinfo_t *ct;
@@ -2222,7 +2235,7 @@
     if (c) {
         ct = find_command(v[0]);
         if (ct) {
-            done = command(bs, ct, c, v);
+            done = command(blk, ct, c, v);
         } else {
             fprintf(stderr, "command \"%s\" not found\n", v[0]);
         }
diff --git a/qemu-io.c b/qemu-io.c
index a85522a..4a3e719 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -28,7 +28,6 @@
 static char *progname;
 
 static BlockBackend *qemuio_blk;
-static BlockDriverState *qemuio_bs;
 
 /* qemu-io commands passed using -c */
 static int ncmdline;
@@ -36,10 +35,9 @@
 
 static ReadLineState *readline_state;
 
-static int close_f(BlockDriverState *bs, int argc, char **argv)
+static int close_f(BlockBackend *blk, int argc, char **argv)
 {
     blk_unref(qemuio_blk);
-    qemuio_bs = NULL;
     qemuio_blk = NULL;
     return 0;
 }
@@ -69,7 +67,6 @@
         error_free(local_err);
         return 1;
     }
-    qemuio_bs = blk_bs(qemuio_blk);
 
     return 0;
 }
@@ -91,7 +88,7 @@
 "\n");
 }
 
-static int open_f(BlockDriverState *bs, int argc, char **argv);
+static int open_f(BlockBackend *blk, int argc, char **argv);
 
 static const cmdinfo_t open_cmd = {
     .name       = "open",
@@ -115,7 +112,7 @@
     },
 };
 
-static int open_f(BlockDriverState *bs, int argc, char **argv)
+static int open_f(BlockBackend *blk, int argc, char **argv)
 {
     int flags = 0;
     int readonly = 0;
@@ -165,7 +162,7 @@
     }
 }
 
-static int quit_f(BlockDriverState *bs, int argc, char **argv)
+static int quit_f(BlockBackend *blk, int argc, char **argv)
 {
     return 1;
 }
@@ -302,7 +299,7 @@
     char *input;
 
     for (i = 0; !done && i < ncmdline; i++) {
-        done = qemuio_command(qemuio_bs, cmdline[i]);
+        done = qemuio_command(qemuio_blk, cmdline[i]);
     }
     if (cmdline) {
         g_free(cmdline);
@@ -327,7 +324,7 @@
         if (input == NULL) {
             break;
         }
-        done = qemuio_command(qemuio_bs, input);
+        done = qemuio_command(qemuio_blk, input);
         g_free(input);
 
         prompted = 0;