@@ -60,6 +60,14 @@ struct BlockExport {
*/
int refcount;
+ /*
+ * True if one of the references in refcount belongs to the user. After the
+ * user has dropped their reference, they may not e.g. remove the same
+ * export a second time (which would decrease the refcount without having
+ * it incremented first).
+ */
+ bool user_owned;
+
/* The AioContext whose lock protects this BlockExport object. */
AioContext *ctx;
@@ -80,6 +80,7 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
*exp = (BlockExport) {
.drv = drv,
.refcount = 1,
+ .user_owned = true,
.id = g_strdup(export->id),
};
@@ -143,6 +144,11 @@ void blk_exp_request_shutdown(BlockExport *exp)
aio_context_acquire(aio_context);
exp->drv->request_shutdown(exp);
+
+ assert(exp->user_owned);
+ exp->user_owned = false;
+ blk_exp_unref(exp);
+
aio_context_release(aio_context);
}
@@ -235,11 +235,6 @@ int nbd_export_create(BlockExport *exp, BlockExportOptions *exp_args,
goto out;
}
- /* The list of named exports has a strong reference to this export now and
- * our only way of accessing it is through nbd_export_find(), so we can drop
- * the strong reference that is @exp. */
- blk_exp_unref(exp);
-
ret = 0;
out:
aio_context_release(aio_context);
@@ -1616,7 +1616,6 @@ int nbd_export_new(BlockExport *blk_exp, BlockDriverState *bs,
blk_add_aio_context_notifier(blk, blk_aio_attached, blk_aio_detach, exp);
- blk_exp_ref(&exp->common);
QTAILQ_INSERT_TAIL(&exports, exp, next);
return 0;
@@ -1663,7 +1662,6 @@ static void nbd_export_request_shutdown(BlockExport *blk_exp)
client_close(client, true);
}
if (exp->name) {
- blk_exp_unref(&exp->common);
g_free(exp->name);
exp->name = NULL;
QTAILQ_REMOVE(&exports, exp, next);