diff mbox

[v2,07/22] block: Add bdrv_close_all() handlers

Message ID 1423507124-29809-8-git-send-email-mreitz@redhat.com
State New
Headers show

Commit Message

Max Reitz Feb. 9, 2015, 6:38 p.m. UTC
Every time a reference to a BlockBackend is taken, a notifier for
bdrv_close_all() has to be deposited so the reference holder can
relinquish its reference when bdrv_close_all() is called. That notifier
should be revoked on a bdrv_unref() call.

Add a Notifier * parameter to all the functions changing the reference
count of a BlockBackend: blk_new(), blk_new_with_bs(), blk_new_open(),
blk_ref() and blk_unref().

By dropping the manual reference handling in hw/block/xen_disk.c, the
blk_unref() in hw/ide/piix.c can be dropped as well.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block/block-backend.c          | 69 ++++++++++++++++++++++++++++++++++++------
 blockdev.c                     | 62 ++++++++++++++++++++++++++++++++++---
 device-hotplug.c               |  2 +-
 hw/block/xen_disk.c            | 16 +++++++---
 hw/ide/piix.c                  |  1 -
 include/sysemu/block-backend.h | 13 +++++---
 include/sysemu/blockdev.h      |  3 ++
 nbd.c                          | 26 ++++++++++++++--
 qemu-img.c                     | 39 ++++++++++++------------
 qemu-io.c                      |  6 ++--
 qemu-nbd.c                     |  6 ++--
 11 files changed, 189 insertions(+), 54 deletions(-)

Comments

Max Reitz Feb. 13, 2015, 11:02 p.m. UTC | #1
On 2015-02-09 at 13:38, Max Reitz wrote:
> Every time a reference to a BlockBackend is taken, a notifier for
> bdrv_close_all() has to be deposited so the reference holder can
> relinquish its reference when bdrv_close_all() is called. That notifier
> should be revoked on a bdrv_unref() call.
>
> Add a Notifier * parameter to all the functions changing the reference
> count of a BlockBackend: blk_new(), blk_new_with_bs(), blk_new_open(),
> blk_ref() and blk_unref().
>
> By dropping the manual reference handling in hw/block/xen_disk.c, the
> blk_unref() in hw/ide/piix.c can be dropped as well.
>
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>   block/block-backend.c          | 69 ++++++++++++++++++++++++++++++++++++------
>   blockdev.c                     | 62 ++++++++++++++++++++++++++++++++++---
>   device-hotplug.c               |  2 +-
>   hw/block/xen_disk.c            | 16 +++++++---
>   hw/ide/piix.c                  |  1 -
>   include/sysemu/block-backend.h | 13 +++++---
>   include/sysemu/blockdev.h      |  3 ++
>   nbd.c                          | 26 ++++++++++++++--
>   qemu-img.c                     | 39 ++++++++++++------------
>   qemu-io.c                      |  6 ++--
>   qemu-nbd.c                     |  6 ++--
>   11 files changed, 189 insertions(+), 54 deletions(-)

[snip]

> diff --git a/qemu-nbd.c b/qemu-nbd.c
> index ac1e5d6..5e6e4b4 100644
> --- a/qemu-nbd.c
> +++ b/qemu-nbd.c
> @@ -694,7 +694,8 @@ int main(int argc, char **argv)
>       }
>   
>       srcpath = argv[optind];
> -    blk = blk_new_open("hda", srcpath, NULL, options, flags, &local_err);
> +    /* the reference will be passed on nbd_export_new() */
> +    blk = blk_new_open("hda", srcpath, NULL, options, flags, NULL, &local_err);
>       if (!blk) {
>           errx(EXIT_FAILURE, "Failed to blk_new_open '%s': %s", argv[optind],
>                error_get_pretty(local_err));
> @@ -728,7 +729,9 @@ int main(int argc, char **argv)
>           }
>       }
>   
> +    /* nbd_export_new() takes the reference to blk */
>       exp = nbd_export_new(blk, dev_offset, fd_size, nbdflags, nbd_export_closed);
> +    blk_unref(blk, NULL);
>   
>       if (sockpath) {
>           fd = unix_socket_incoming(sockpath);
> @@ -773,7 +776,6 @@ int main(int argc, char **argv)
>           }
>       } while (state != TERMINATED);
>   
> -    blk_unref(blk);
>       if (sockpath) {
>           unlink(sockpath);
>       }

Because qemu-nbd does not install a handler for relinquishing its 
reference, it has to make sure it drops that reference before a 
bdrv_close_all() occurs. Therefore, err() and errx() calls after 
blk_new_open() (except for the if (!blk) path) and before blk_unref(blk, 
NULL) need to be preceded by a blk_unref(blk, NULL).

I'll fix it in v3.

Max
diff mbox

Patch

diff --git a/block/block-backend.c b/block/block-backend.c
index 6d02184..98f4af9 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -76,7 +76,8 @@  static QTAILQ_HEAD(, BlockBackend) blk_backends =
  * Store an error through @errp on failure, unless it's null.
  * Return the new BlockBackend on success, null on failure.
  */
-BlockBackend *blk_new(const char *name, Error **errp)
+BlockBackend *blk_new(const char *name, Notifier *close_all_notifier,
+                      Error **errp)
 {
     BlockBackend *blk;
 
@@ -100,6 +101,9 @@  BlockBackend *blk_new(const char *name, Error **errp)
     blk->name = g_strdup(name);
     blk->refcnt = 1;
     notifier_list_init(&blk->remove_bs_notifiers);
+    if (close_all_notifier) {
+        bdrv_add_close_all_notifier(close_all_notifier);
+    }
     QTAILQ_INSERT_TAIL(&blk_backends, blk, link);
     return blk;
 }
@@ -108,12 +112,13 @@  BlockBackend *blk_new(const char *name, Error **errp)
  * Create a new BlockBackend with a new BlockDriverState attached.
  * Otherwise just like blk_new(), which see.
  */
-BlockBackend *blk_new_with_bs(const char *name, Error **errp)
+BlockBackend *blk_new_with_bs(const char *name, Notifier *close_all_notifier,
+                              Error **errp)
 {
     BlockBackend *blk;
     BlockDriverState *bs;
 
-    blk = blk_new(name, errp);
+    blk = blk_new(name, close_all_notifier, errp);
     if (!blk) {
         return NULL;
     }
@@ -138,12 +143,12 @@  BlockBackend *blk_new_with_bs(const char *name, Error **errp)
  */
 BlockBackend *blk_new_open(const char *name, const char *filename,
                            const char *reference, QDict *options, int flags,
-                           Error **errp)
+                           Notifier *close_all_notifier, Error **errp)
 {
     BlockBackend *blk;
     int ret;
 
-    blk = blk_new_with_bs(name, errp);
+    blk = blk_new_with_bs(name, close_all_notifier, errp);
     if (!blk) {
         QDECREF(options);
         return NULL;
@@ -151,7 +156,7 @@  BlockBackend *blk_new_open(const char *name, const char *filename,
 
     ret = bdrv_open(&blk->bs, filename, reference, options, flags, NULL, errp);
     if (ret < 0) {
-        blk_unref(blk);
+        blk_unref(blk, close_all_notifier);
         return NULL;
     }
 
@@ -191,9 +196,13 @@  static void drive_info_del(DriveInfo *dinfo)
  * Increment @blk's reference count.
  * @blk must not be null.
  */
-void blk_ref(BlockBackend *blk)
+void blk_ref(BlockBackend *blk, Notifier *close_all_notifier)
 {
     blk->refcnt++;
+
+    if (close_all_notifier) {
+        bdrv_add_close_all_notifier(close_all_notifier);
+    }
 }
 
 /*
@@ -201,8 +210,12 @@  void blk_ref(BlockBackend *blk)
  * If this drops it to zero, destroy @blk.
  * For convenience, do nothing if @blk is null.
  */
-void blk_unref(BlockBackend *blk)
+void blk_unref(BlockBackend *blk, Notifier *close_all_notifier)
 {
+    if (close_all_notifier) {
+        notifier_remove(close_all_notifier);
+    }
+
     if (blk) {
         assert(blk->refcnt > 0);
         if (!--blk->refcnt) {
@@ -352,6 +365,21 @@  void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
     bs->blk = blk;
 }
 
+typedef struct DevCloseAllNotifier {
+    Notifier n;
+    BlockBackend *blk;
+    QTAILQ_ENTRY(DevCloseAllNotifier) next;
+} DevCloseAllNotifier;
+
+static QTAILQ_HEAD(, DevCloseAllNotifier) close_all_notifiers =
+    QTAILQ_HEAD_INITIALIZER(close_all_notifiers);
+
+static void dev_close_all_notifier(Notifier *n, void *data)
+{
+    DevCloseAllNotifier *can = DO_UPCAST(DevCloseAllNotifier, n, n);
+    blk_detach_dev(can->blk, can->blk->dev);
+}
+
 /*
  * Attach device model @dev to @blk.
  * Return 0 on success, -EBUSY when a device model is attached already.
@@ -359,10 +387,19 @@  void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
 int blk_attach_dev(BlockBackend *blk, void *dev)
 /* TODO change to DeviceState *dev when all users are qdevified */
 {
+    DevCloseAllNotifier *can;
+
     if (blk->dev) {
         return -EBUSY;
     }
-    blk_ref(blk);
+
+    can = g_new0(DevCloseAllNotifier, 1);
+    can->n.notify = dev_close_all_notifier;
+    can->blk = blk;
+
+    QTAILQ_INSERT_TAIL(&close_all_notifiers, can, next);
+
+    blk_ref(blk, &can->n);
     blk->dev = dev;
     blk_iostatus_reset(blk);
     return 0;
@@ -387,12 +424,24 @@  void blk_attach_dev_nofail(BlockBackend *blk, void *dev)
 void blk_detach_dev(BlockBackend *blk, void *dev)
 /* TODO change to DeviceState *dev when all users are qdevified */
 {
+    DevCloseAllNotifier *can;
+
     assert(blk->dev == dev);
     blk->dev = NULL;
     blk->dev_ops = NULL;
     blk->dev_opaque = NULL;
     blk->guest_block_size = 512;
-    blk_unref(blk);
+
+    QTAILQ_FOREACH(can, &close_all_notifiers, next) {
+        if (can->blk == blk) {
+            break;
+        }
+    }
+    assert(can);
+
+    blk_unref(blk, &can->n);
+    QTAILQ_REMOVE(&close_all_notifiers, can, next);
+    g_free(can);
 }
 
 /*
diff --git a/blockdev.c b/blockdev.c
index f198be6..75baf16 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -47,6 +47,15 @@ 
 #include "trace.h"
 #include "sysemu/arch_init.h"
 
+typedef struct BlockdevCloseAllNotifier {
+    Notifier n;
+    BlockBackend *blk;
+    QTAILQ_ENTRY(BlockdevCloseAllNotifier) next;
+} BlockdevCloseAllNotifier;
+
+static QTAILQ_HEAD(, BlockdevCloseAllNotifier) close_all_notifiers =
+    QTAILQ_HEAD_INITIALIZER(close_all_notifiers);
+
 static const char *const if_name[IF_COUNT] = {
     [IF_NONE] = "none",
     [IF_IDE] = "ide",
@@ -78,6 +87,37 @@  static int if_max_devs[IF_COUNT] = {
     [IF_SCSI] = 7,
 };
 
+static void monitor_blk_unref_with_can(BlockBackend *blk,
+                                       BlockdevCloseAllNotifier *can)
+{
+    if (can) {
+        assert(can->blk == blk);
+    } else {
+        QTAILQ_FOREACH(can, &close_all_notifiers, next) {
+            if (can->blk == blk) {
+                break;
+            }
+        }
+        assert(can);
+    }
+
+    blk_unref(blk, &can->n);
+    QTAILQ_REMOVE(&close_all_notifiers, can, next);
+    g_free(can);
+}
+
+void monitor_blk_unref(BlockBackend *blk)
+{
+    monitor_blk_unref_with_can(blk, NULL);
+}
+
+static void blockdev_close_all_notifier(Notifier *n, void *data)
+{
+    BlockdevCloseAllNotifier *can = DO_UPCAST(BlockdevCloseAllNotifier, n, n);
+
+    monitor_blk_unref_with_can(can->blk, can);
+}
+
 /**
  * Boards may call this to offer board-by-board overrides
  * of the default, global values.
@@ -140,7 +180,7 @@  void blockdev_auto_del(BlockBackend *blk)
     DriveInfo *dinfo = blk_legacy_dinfo(blk);
 
     if (dinfo && dinfo->auto_del) {
-        blk_unref(blk);
+        monitor_blk_unref(blk);
     }
 }
 
@@ -460,6 +500,7 @@  static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
     bool has_driver_specific_opts;
     BlockdevDetectZeroesOptions detect_zeroes =
         BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
+    BlockdevCloseAllNotifier *can;
 
     /* Check common options by copying from bs_opts to opts, all other options
      * stay in bs_opts for processing by bdrv_open(). */
@@ -536,14 +577,21 @@  static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
     }
 
     /* init */
+    can = g_new0(BlockdevCloseAllNotifier, 1);
+    can->n.notify = blockdev_close_all_notifier;
+
     if ((!file || !*file) && !has_driver_specific_opts) {
         BlockBackendRootState *blk_rs;
 
-        blk = blk_new(qemu_opts_id(opts), errp);
+        blk = blk_new(qemu_opts_id(opts), &can->n, errp);
         if (!blk) {
+            g_free(can);
             goto early_err;
         }
 
+        can->blk = blk;
+        QTAILQ_INSERT_TAIL(&close_all_notifiers, can, next);
+
         blk_rs = blk_get_root_state(blk);
         blk_rs->open_flags    = bdrv_flags;
         blk_rs->read_only     = !(bdrv_flags & BDRV_O_RDWR);
@@ -561,12 +609,16 @@  static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
         }
 
         blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags,
-                           errp);
+                           &can->n, errp);
         if (!blk) {
+            g_free(can);
             goto err_no_bs_opts;
         }
         bs = blk_bs(blk);
 
+        can->blk = blk;
+        QTAILQ_INSERT_TAIL(&close_all_notifiers, can, next);
+
         bs->detect_zeroes = detect_zeroes;
 
         /* disk I/O throttling */
@@ -2246,7 +2298,7 @@  int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
         blk_set_on_error(blk, BLOCKDEV_ON_ERROR_REPORT,
                          BLOCKDEV_ON_ERROR_REPORT);
     } else {
-        blk_unref(blk);
+        monitor_blk_unref(blk);
     }
 
     aio_context_release(aio_context);
@@ -3174,7 +3226,7 @@  void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
 
     if (bs && bdrv_key_required(bs)) {
         if (blk) {
-            blk_unref(blk);
+            monitor_blk_unref(blk);
         } else {
             bdrv_unref(bs);
         }
diff --git a/device-hotplug.c b/device-hotplug.c
index 9e38cc4..aa05a71 100644
--- a/device-hotplug.c
+++ b/device-hotplug.c
@@ -77,6 +77,6 @@  void drive_hot_add(Monitor *mon, const QDict *qdict)
 
 err:
     if (dinfo) {
-        blk_unref(blk_by_legacy_dinfo(dinfo));
+        monitor_blk_unref(blk_by_legacy_dinfo(dinfo));
     }
 }
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 2f59b5b..4916ddf 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -908,8 +908,10 @@  static int blk_connect(struct XenDevice *xendev)
 
         /* setup via xenbus -> create new block driver instance */
         xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
+        /* No need to give a close_all_notifier because blk_attach_dev_nofail()
+         * and blk_detach_dev() will keep track of our reference */
         blkdev->blk = blk_new_open(blkdev->dev, blkdev->filename, NULL, options,
-                                   qflags, &local_err);
+                                   qflags, NULL, &local_err);
         if (!blkdev->blk) {
             xen_be_printf(&blkdev->xendev, 0, "error: %s\n",
                           error_get_pretty(local_err));
@@ -925,11 +927,16 @@  static int blk_connect(struct XenDevice *xendev)
             blkdev->blk = NULL;
             return -1;
         }
-        /* blkdev->blk is not create by us, we get a reference
-         * so we can blk_unref() unconditionally */
-        blk_ref(blkdev->blk);
     }
+
     blk_attach_dev_nofail(blkdev->blk, blkdev);
+    if (!blkdev->dinfo) {
+        /* blkdev->blk has just been created; blk_attach_dev_nofail() counts
+         * the reference blkdev->blk, so we do not have to keep track (which
+         * allows us to ignore bdrv_close_all()) */
+        blk_unref(blkdev->blk, NULL);
+    }
+
     blkdev->file_size = blk_getlength(blkdev->blk);
     if (blkdev->file_size < 0) {
         BlockDriverState *bs = blk_bs(blkdev->blk);
@@ -1032,7 +1039,6 @@  static void blk_disconnect(struct XenDevice *xendev)
 
     if (blkdev->blk) {
         blk_detach_dev(blkdev->blk, blkdev);
-        blk_unref(blkdev->blk);
         blkdev->blk = NULL;
     }
     xen_be_unbind_evtchn(&blkdev->xendev);
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index b0172fb..becf0f5 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -184,7 +184,6 @@  int pci_piix3_xen_ide_unplug(DeviceState *dev)
                 blk_detach_dev(blk, ds);
             }
             pci_ide->bus[di->bus].ifs[di->unit].blk = NULL;
-            blk_unref(blk);
         }
     }
     qdev_reset_all(DEVICE(dev));
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index dc1e217..9840fef 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -13,6 +13,7 @@ 
 #ifndef BLOCK_BACKEND_H
 #define BLOCK_BACKEND_H
 
+#include "qemu/notify.h"
 #include "qemu/typedefs.h"
 #include "qapi/error.h"
 
@@ -60,13 +61,15 @@  typedef struct BlockDevOps {
     void (*resize_cb)(void *opaque);
 } BlockDevOps;
 
-BlockBackend *blk_new(const char *name, Error **errp);
-BlockBackend *blk_new_with_bs(const char *name, Error **errp);
+BlockBackend *blk_new(const char *name, Notifier *close_all_notifier,
+                      Error **errp);
+BlockBackend *blk_new_with_bs(const char *name, Notifier *close_all_notifier,
+                              Error **errp);
 BlockBackend *blk_new_open(const char *name, const char *filename,
                            const char *reference, QDict *options, int flags,
-                           Error **errp);
-void blk_ref(BlockBackend *blk);
-void blk_unref(BlockBackend *blk);
+                           Notifier *close_all_notifier, Error **errp);
+void blk_ref(BlockBackend *blk, Notifier *close_all_notifier);
+void blk_unref(BlockBackend *blk, Notifier *close_all_notifier);
 const char *blk_name(BlockBackend *blk);
 BlockBackend *blk_by_name(const char *name);
 BlockBackend *blk_next(BlockBackend *blk);
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
index 2a34332..b6091e0 100644
--- a/include/sysemu/blockdev.h
+++ b/include/sysemu/blockdev.h
@@ -67,4 +67,7 @@  DriveInfo *add_init_drive(const char *opts);
 
 void do_commit(Monitor *mon, const QDict *qdict);
 int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
+void monitor_blk_unref(BlockBackend *blk);
+
 #endif
diff --git a/nbd.c b/nbd.c
index 02ee686..9c44c0f 100644
--- a/nbd.c
+++ b/nbd.c
@@ -973,6 +973,9 @@  typedef struct NBDCloseNotifier {
 static QTAILQ_HEAD(, NBDCloseNotifier) eject_notifiers =
     QTAILQ_HEAD_INITIALIZER(eject_notifiers);
 
+static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers =
+    QTAILQ_HEAD_INITIALIZER(close_notifiers);
+
 static void nbd_close_notifier(Notifier *n, void *data)
 {
     NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n);
@@ -983,6 +986,7 @@  NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size,
                           uint32_t nbdflags, void (*close)(NBDExport *))
 {
     NBDCloseNotifier *eject_notifier = g_new0(NBDCloseNotifier, 1);
+    NBDCloseNotifier *close_notifier = g_new0(NBDCloseNotifier, 1);
     NBDExport *exp = g_malloc0(sizeof(NBDExport));
     exp->refcount = 1;
     QTAILQ_INIT(&exp->clients);
@@ -992,7 +996,12 @@  NBDExport *nbd_export_new(BlockBackend *blk, off_t dev_offset, off_t size,
     exp->size = size == -1 ? blk_getlength(blk) : size;
     exp->close = close;
     exp->ctx = blk_get_aio_context(blk);
-    blk_ref(blk);
+
+    close_notifier->n.notify = nbd_close_notifier;
+    close_notifier->exp = exp;
+    QTAILQ_INSERT_TAIL(&close_notifiers, close_notifier, next);
+
+    blk_ref(blk, &close_notifier->n);
     blk_add_aio_context_notifier(blk, blk_aio_attached, blk_aio_detach, exp);
 
     eject_notifier->n.notify = nbd_close_notifier;
@@ -1045,7 +1054,7 @@  void nbd_export_set_name(NBDExport *exp, const char *name)
 
 void nbd_export_close(NBDExport *exp)
 {
-    NBDCloseNotifier *eject_notifier;
+    NBDCloseNotifier *eject_notifier, *close_notifier;
     NBDClient *client, *next;
 
     nbd_export_get(exp);
@@ -1054,6 +1063,7 @@  void nbd_export_close(NBDExport *exp)
     }
     nbd_export_set_name(exp, NULL);
     nbd_export_put(exp);
+
     if (exp->blk) {
         QTAILQ_FOREACH(eject_notifier, &eject_notifiers, next) {
             if (eject_notifier->exp == exp) {
@@ -1066,10 +1076,20 @@  void nbd_export_close(NBDExport *exp)
         QTAILQ_REMOVE(&eject_notifiers, eject_notifier, next);
         g_free(eject_notifier);
 
+        QTAILQ_FOREACH(close_notifier, &close_notifiers, next) {
+            if (close_notifier->exp == exp) {
+                break;
+            }
+        }
+        assert(close_notifier);
+
         blk_remove_aio_context_notifier(exp->blk, blk_aio_attached,
                                         blk_aio_detach, exp);
-        blk_unref(exp->blk);
+        blk_unref(exp->blk, &close_notifier->n);
         exp->blk = NULL;
+
+        QTAILQ_REMOVE(&close_notifiers, close_notifier, next);
+        g_free(close_notifier);
     }
 }
 
diff --git a/qemu-img.c b/qemu-img.c
index 77fd4e4..56a528e 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -302,7 +302,7 @@  static BlockBackend *img_open(const char *id, const char *filename,
         qdict_put(options, "driver", qstring_from_str(fmt));
     }
 
-    blk = blk_new_open(id, filename, NULL, options, flags, &local_err);
+    blk = blk_new_open(id, filename, NULL, options, flags, NULL, &local_err);
     if (!blk) {
         error_report("Could not open '%s': %s", filename,
                      error_get_pretty(local_err));
@@ -324,7 +324,7 @@  static BlockBackend *img_open(const char *id, const char *filename,
     }
     return blk;
 fail:
-    blk_unref(blk);
+    blk_unref(blk, NULL);
     return NULL;
 }
 
@@ -713,7 +713,7 @@  static int img_check(int argc, char **argv)
 
 fail:
     qapi_free_ImageCheck(check);
-    blk_unref(blk);
+    blk_unref(blk, NULL);
     return ret;
 }
 
@@ -880,7 +880,7 @@  unref_backing:
 done:
     qemu_progress_end();
 
-    blk_unref(blk);
+    blk_unref(blk, NULL);
 
     if (local_err) {
         qerror_report_err(local_err);
@@ -1292,9 +1292,9 @@  static int img_compare(int argc, char **argv)
 out:
     qemu_vfree(buf1);
     qemu_vfree(buf2);
-    blk_unref(blk2);
+    blk_unref(blk2, NULL);
 out2:
-    blk_unref(blk1);
+    blk_unref(blk1, NULL);
 out3:
     qemu_progress_end();
     return ret;
@@ -1862,11 +1862,11 @@  out:
     qemu_opts_free(create_opts);
     qemu_vfree(buf);
     qemu_opts_del(sn_opts);
-    blk_unref(out_blk);
+    blk_unref(out_blk, NULL);
     g_free(bs);
     if (blk) {
         for (bs_i = 0; bs_i < bs_n; bs_i++) {
-            blk_unref(blk[bs_i]);
+            blk_unref(blk[bs_i], NULL);
         }
         g_free(blk);
     }
@@ -2001,7 +2001,7 @@  static ImageInfoList *collect_image_info_list(const char *filename,
         if (err) {
             error_report("%s", error_get_pretty(err));
             error_free(err);
-            blk_unref(blk);
+            blk_unref(blk, NULL);
             goto err;
         }
 
@@ -2010,7 +2010,7 @@  static ImageInfoList *collect_image_info_list(const char *filename,
         *last = elem;
         last = &elem->next;
 
-        blk_unref(blk);
+        blk_unref(blk, NULL);
 
         filename = fmt = NULL;
         if (chain) {
@@ -2298,7 +2298,7 @@  static int img_map(int argc, char **argv)
     dump_map_entry(output_format, &curr, NULL);
 
 out:
-    blk_unref(blk);
+    blk_unref(blk, NULL);
     return ret < 0;
 }
 
@@ -2422,7 +2422,7 @@  static int img_snapshot(int argc, char **argv)
     }
 
     /* Cleanup */
-    blk_unref(blk);
+    blk_unref(blk, NULL);
     if (ret) {
         return 1;
     }
@@ -2546,7 +2546,7 @@  static int img_rebase(int argc, char **argv)
 
         bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
         blk_old_backing = blk_new_open("old_backing", backing_name, NULL,
-                                       options, src_flags, &local_err);
+                                       options, src_flags, NULL, &local_err);
         if (!blk_old_backing) {
             error_report("Could not open old backing file '%s': %s",
                          backing_name, error_get_pretty(local_err));
@@ -2563,7 +2563,8 @@  static int img_rebase(int argc, char **argv)
             }
 
             blk_new_backing = blk_new_open("new_backing", out_baseimg, NULL,
-                                           options, src_flags, &local_err);
+                                           options, src_flags, NULL,
+                                           &local_err);
             if (!blk_new_backing) {
                 error_report("Could not open new backing file '%s': %s",
                              out_baseimg, error_get_pretty(local_err));
@@ -2736,11 +2737,11 @@  out:
     qemu_progress_end();
     /* Cleanup */
     if (!unsafe) {
-        blk_unref(blk_old_backing);
-        blk_unref(blk_new_backing);
+        blk_unref(blk_old_backing, NULL);
+        blk_unref(blk_new_backing, NULL);
     }
 
-    blk_unref(blk);
+    blk_unref(blk, NULL);
     if (ret) {
         return 1;
     }
@@ -2863,7 +2864,7 @@  static int img_resize(int argc, char **argv)
         break;
     }
 out:
-    blk_unref(blk);
+    blk_unref(blk, NULL);
     if (ret) {
         return 1;
     }
@@ -3001,7 +3002,7 @@  static int img_amend(int argc, char **argv)
 out:
     qemu_progress_end();
 
-    blk_unref(blk);
+    blk_unref(blk, NULL);
     qemu_opts_del(opts);
     qemu_opts_free(create_opts);
     g_free(options);
diff --git a/qemu-io.c b/qemu-io.c
index 4a3e719..9c0ad37 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -37,7 +37,7 @@  static ReadLineState *readline_state;
 
 static int close_f(BlockBackend *blk, int argc, char **argv)
 {
-    blk_unref(qemuio_blk);
+    blk_unref(qemuio_blk, NULL);
     qemuio_blk = NULL;
     return 0;
 }
@@ -59,7 +59,7 @@  static int openfile(char *name, int flags, QDict *opts)
         return 1;
     }
 
-    qemuio_blk = blk_new_open("hda", name, NULL, opts, flags, &local_err);
+    qemuio_blk = blk_new_open("hda", name, NULL, opts, flags, NULL, &local_err);
     if (!qemuio_blk) {
         fprintf(stderr, "%s: can't open%s%s: %s\n", progname,
                 name ? " device " : "", name ?: "",
@@ -474,7 +474,7 @@  int main(int argc, char **argv)
      */
     bdrv_drain_all();
 
-    blk_unref(qemuio_blk);
+    blk_unref(qemuio_blk, NULL);
     g_free(readline_state);
     return 0;
 }
diff --git a/qemu-nbd.c b/qemu-nbd.c
index ac1e5d6..5e6e4b4 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -694,7 +694,8 @@  int main(int argc, char **argv)
     }
 
     srcpath = argv[optind];
-    blk = blk_new_open("hda", srcpath, NULL, options, flags, &local_err);
+    /* the reference will be passed on nbd_export_new() */
+    blk = blk_new_open("hda", srcpath, NULL, options, flags, NULL, &local_err);
     if (!blk) {
         errx(EXIT_FAILURE, "Failed to blk_new_open '%s': %s", argv[optind],
              error_get_pretty(local_err));
@@ -728,7 +729,9 @@  int main(int argc, char **argv)
         }
     }
 
+    /* nbd_export_new() takes the reference to blk */
     exp = nbd_export_new(blk, dev_offset, fd_size, nbdflags, nbd_export_closed);
+    blk_unref(blk, NULL);
 
     if (sockpath) {
         fd = unix_socket_incoming(sockpath);
@@ -773,7 +776,6 @@  int main(int argc, char **argv)
         }
     } while (state != TERMINATED);
 
-    blk_unref(blk);
     if (sockpath) {
         unlink(sockpath);
     }