qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH 13/13] nbd: add notifier to close exports when t


From: Paolo Bonzini
Subject: [Qemu-devel] [RFC PATCH 13/13] nbd: add notifier to close exports when the image is closed
Date: Mon, 27 Aug 2012 17:00:26 +0200

Signed-off-by: Paolo Bonzini <address@hidden>
---
 blockdev-nbd.c      | 38 ++++++++++++++++++++++++++++++++++++++
 qapi/opts-visitor.c | 48 ++++++++++++++++++++----------------------------
 2 file modificati, 58 inserzioni(+), 28 rimozioni(-)

diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index 5a415be..c190caa 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -62,12 +62,39 @@ void qmp_nbd_server_start(IPSocketAddress *addr, Error 
**errp)
     qemu_opts_del(opts);
 }
 
+/* Hook into the BlockDriverState notifiers to close the export when
+ * the file is closed.
+ */
+typedef struct NBDCloseNotifier {
+    Notifier n;
+    NBDExport *exp;
+    QTAILQ_ENTRY(NBDCloseNotifier) next;
+} NBDCloseNotifier;
+
+static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers =
+    QTAILQ_HEAD_INITIALIZER(close_notifiers);
+
+static void nbd_close_notifier_remove(NBDCloseNotifier *cn)
+{
+    notifier_remove(&cn->n);
+    QTAILQ_REMOVE(&close_notifiers, cn, next);
+    g_free(cn);
+}
+
+static void nbd_close_notifier(Notifier *n, void *data)
+{
+    NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n);
+
+    nbd_export_close(cn->exp);
+    nbd_close_notifier_remove(cn);
+}
 
 void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
                         Error **errp)
 {
     BlockDriverState *bs;
     NBDExport *exp;
+    NBDCloseNotifier *n;
 
     bs = bdrv_find(device);
     if (!bs) {
@@ -82,10 +109,21 @@ void qmp_nbd_server_add(const char *device, bool 
has_writable, bool writable,
 
     exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY);
     nbd_export_set_name(exp, device);
+
+    n = g_malloc0(sizeof(NBDCloseNotifier));
+    n->n.notify = nbd_close_notifier;
+    n->exp = exp;
+    bdrv_add_close_notifier(bs, &n->n);
+    QTAILQ_INSERT_TAIL(&close_notifiers, n, next);
 }
 
 void qmp_nbd_server_stop(Error **errp)
 {
+    while (!QTAILQ_EMPTY(&close_notifiers)) {
+        NBDCloseNotifier *cn = QTAILQ_FIRST(&close_notifiers);
+        nbd_close_notifier_remove(cn);
+    }
+
     nbd_export_close_all();
     qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL);
     close(server_fd);
diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
index a59d306..6893d62 100644
--- a/qapi/opts-visitor.c
+++ b/qapi/opts-visitor.c
@@ -20,9 +20,6 @@ struct OptsVisitor
 {
     Visitor visitor;
 
-    /* Ownership remains with opts_visitor_new()'s caller. */
-    const QemuOpts *opts_root;
-
     unsigned depth;
 
     /* Non-null iff depth is positive. Each key is a QemuOpt name. Each value
@@ -36,9 +33,9 @@ struct OptsVisitor
     GQueue *repeated_opts;
     bool repeated_opts_first;
 
-    /* If "opts_root->id" is set, reinstantiate it as a fake QemuOpt for
-     * uniformity. Only its "name" and "str" fields are set. "fake_id_opt" does
-     * not survive or escape the OptsVisitor object.
+    /* If the "id" is set on the QemuOpts, reinstantiate it as a fake QemuOpt
+     * for uniformity. Only its "name" and "str" fields are set. "fake_id_opt"
+     * does not survive or escape the OptsVisitor object.
      */
     QemuOpt *fake_id_opt;
 };
@@ -77,29 +74,9 @@ opts_start_struct(Visitor *v, void **obj, const char *kind,
                   const char *name, size_t size, Error **errp)
 {
     OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v);
-    const QemuOpt *opt;
 
     *obj = g_malloc0(size > 0 ? size : 1);
-    if (ov->depth++ > 0) {
-        return;
-    }
-
-    ov->unprocessed_opts = g_hash_table_new_full(&g_str_hash, &g_str_equal,
-                                                 NULL, &destroy_list);
-    QTAILQ_FOREACH(opt, &ov->opts_root->head, next) {
-        /* ensured by qemu-option.c::opts_do_parse() */
-        assert(strcmp(opt->name, "id") != 0);
-
-        opts_visitor_insert(ov->unprocessed_opts, opt);
-    }
-
-    if (ov->opts_root->id != NULL) {
-        ov->fake_id_opt = g_malloc0(sizeof *ov->fake_id_opt);
-
-        ov->fake_id_opt->name = "id";
-        ov->fake_id_opt->str = ov->opts_root->id;
-        opts_visitor_insert(ov->unprocessed_opts, ov->fake_id_opt);
-    }
+    ov->depth++;
 }
 
 
@@ -372,6 +349,7 @@ OptsVisitor *
 opts_visitor_new(const QemuOpts *opts)
 {
     OptsVisitor *ov;
+    const QemuOpt *opt;
 
     ov = g_malloc0(sizeof *ov);
 
@@ -403,8 +381,22 @@ opts_visitor_new(const QemuOpts *opts)
 
     ov->visitor.start_optional = &opts_start_optional;
 
-    ov->opts_root = opts;
+    ov->unprocessed_opts = g_hash_table_new_full(&g_str_hash, &g_str_equal,
+                                                 NULL, &destroy_list);
+    QTAILQ_FOREACH(opt, &opts->head, next) {
+        /* ensured by qemu-option.c::opts_do_parse() */
+        assert(strcmp(opt->name, "id") != 0);
 
+        opts_visitor_insert(ov->unprocessed_opts, opt);
+    }
+
+    if (opts->id != NULL) {
+        ov->fake_id_opt = g_malloc0(sizeof *ov->fake_id_opt);
+
+        ov->fake_id_opt->name = "id";
+        ov->fake_id_opt->str = opts->id;
+        opts_visitor_insert(ov->unprocessed_opts, ov->fake_id_opt);
+    }
     return ov;
 }
 
-- 
1.7.11.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]