qemu-devel
[Top][All Lists]
Advanced

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

[PATCH v6 09/10] migration/yank: Keep track of registered yank instances


From: Fabiano Rosas
Subject: [PATCH v6 09/10] migration/yank: Keep track of registered yank instances
Date: Mon, 11 Sep 2023 14:13:19 -0300

The core yank code is strict about balanced registering and
unregistering of yank functions.

This creates a difficulty because the migration code registers one
yank function per QIOChannel, but each QIOChannel can be referenced by
more than one QEMUFile. The yank function should not be removed until
all QEMUFiles have been closed.

Keep a reference count of how many QEMUFiles are using a QIOChannel
that has a yank function. Only unregister the yank function when all
QEMUFiles have been closed.

This improves the current code by removing the need for the programmer
to know which QEMUFile is the last one to be cleaned up and fixes the
theoretical issue of removing the yank function while another QEMUFile
could still be using the ioc and require a yank.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
 migration/yank_functions.c | 81 ++++++++++++++++++++++++++++++++++----
 migration/yank_functions.h |  8 ++++
 2 files changed, 81 insertions(+), 8 deletions(-)

diff --git a/migration/yank_functions.c b/migration/yank_functions.c
index 979e60c762..afdeef30ff 100644
--- a/migration/yank_functions.c
+++ b/migration/yank_functions.c
@@ -10,9 +10,32 @@
 #include "qemu/osdep.h"
 #include "io/channel.h"
 #include "yank_functions.h"
+#include "qemu/lockable.h"
 #include "qemu/yank.h"
 #include "qemu-file.h"
 
+static QemuMutex ioc_list_lock;
+static QLIST_HEAD(, Yankable) yankable_ioc_list
+    = QLIST_HEAD_INITIALIZER(yankable_ioc_list);
+
+static void __attribute__((constructor)) ioc_list_lock_init(void)
+{
+    qemu_mutex_init(&ioc_list_lock);
+}
+
+static void yankable_ref(Yankable *yankable)
+{
+    assert(yankable->refcnt > 0);
+    yankable->refcnt++;
+    assert(yankable->refcnt < INT_MAX);
+}
+
+static void yankable_unref(Yankable *yankable)
+{
+    assert(yankable->refcnt > 0);
+    yankable->refcnt--;
+}
+
 void migration_yank_iochannel(void *opaque)
 {
     QIOChannel *ioc = QIO_CHANNEL(opaque);
@@ -28,20 +51,62 @@ static bool migration_ioc_yank_supported(QIOChannel *ioc)
 
 void migration_ioc_register_yank(QIOChannel *ioc)
 {
-    if (migration_ioc_yank_supported(ioc)) {
-        yank_register_function(MIGRATION_YANK_INSTANCE,
-                               migration_yank_iochannel,
-                               ioc);
+    Yankable *new, *entry;
+
+    if (!ioc || !migration_ioc_yank_supported(ioc)) {
+        return;
     }
+
+    WITH_QEMU_LOCK_GUARD(&ioc_list_lock) {
+        QLIST_FOREACH(entry, &yankable_ioc_list, next) {
+            if (entry->opaque == ioc) {
+                yankable_ref(entry);
+                return;
+            }
+        }
+
+        new = g_new0(Yankable, 1);
+        new->refcnt = 1;
+        new->opaque = ioc;
+        object_ref(ioc);
+
+        QLIST_INSERT_HEAD(&yankable_ioc_list, new, next);
+    }
+
+    yank_register_function(MIGRATION_YANK_INSTANCE,
+                           migration_yank_iochannel,
+                           ioc);
 }
 
 void migration_ioc_unregister_yank(QIOChannel *ioc)
 {
-    if (migration_ioc_yank_supported(ioc)) {
-        yank_unregister_function(MIGRATION_YANK_INSTANCE,
-                                 migration_yank_iochannel,
-                                 ioc);
+    Yankable *entry, *tmp;
+
+    if (!ioc || !migration_ioc_yank_supported(ioc)) {
+        return;
     }
+
+    WITH_QEMU_LOCK_GUARD(&ioc_list_lock) {
+        QLIST_FOREACH_SAFE(entry, &yankable_ioc_list, next, tmp) {
+            if (entry->opaque == ioc) {
+                yankable_unref(entry);
+
+                if (!entry->refcnt) {
+                    QLIST_REMOVE(entry, next);
+                    g_free(entry);
+                    goto unreg;
+                }
+            }
+        }
+    }
+
+    return;
+
+unreg:
+    yank_unregister_function(MIGRATION_YANK_INSTANCE,
+                             migration_yank_iochannel,
+                             ioc);
+    object_unref(ioc);
 }
 
 void migration_ioc_unregister_yank_from_file(QEMUFile *file)
diff --git a/migration/yank_functions.h b/migration/yank_functions.h
index a7577955ed..c928a46f68 100644
--- a/migration/yank_functions.h
+++ b/migration/yank_functions.h
@@ -7,6 +7,14 @@
  * See the COPYING file in the top-level directory.
  */
 
+struct Yankable {
+    void *opaque;
+    int refcnt;
+    QLIST_ENTRY(Yankable) next;
+};
+
+typedef struct Yankable Yankable;
+
 /**
  * migration_yank_iochannel: yank function for iochannel
  *
-- 
2.35.3




reply via email to

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