Browse Source

plugins: add [pre|post]fork helpers to linux-user

Special care needs to be taken in ensuring locks are in a consistent
state across fork events. Add helpers so the plugin system can ensure
that.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Fixes: https://gitlab.com/qemu-project/qemu/-/issues/358
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Tested-by: Daniel P. Berrangé <berrange@redhat.com>
Message-Id: <20221004115221.2174499-1-alex.bennee@linaro.org>
Alex Bennée 2 years ago
parent
commit
f7e15affa8
3 changed files with 46 additions and 0 deletions
  1. 24 0
      include/qemu/plugin.h
  2. 2 0
      linux-user/main.c
  3. 20 0
      plugins/core.c

+ 24 - 0
include/qemu/plugin.h

@@ -224,6 +224,23 @@ void qemu_plugin_disable_mem_helpers(CPUState *cpu);
  */
  */
 void qemu_plugin_user_exit(void);
 void qemu_plugin_user_exit(void);
 
 
+/**
+ * qemu_plugin_user_prefork_lock(): take plugin lock before forking
+ *
+ * This is a user-mode only helper to take the internal plugin lock
+ * before a fork event. This is ensure a consistent lock state
+ */
+void qemu_plugin_user_prefork_lock(void);
+
+/**
+ * qemu_plugin_user_postfork(): reset the plugin lock
+ * @is_child: is this thread the child
+ *
+ * This user-mode only helper resets the lock state after a fork so we
+ * can continue using the plugin interface.
+ */
+void qemu_plugin_user_postfork(bool is_child);
+
 #else /* !CONFIG_PLUGIN */
 #else /* !CONFIG_PLUGIN */
 
 
 static inline void qemu_plugin_add_opts(void)
 static inline void qemu_plugin_add_opts(void)
@@ -287,6 +304,13 @@ static inline void qemu_plugin_disable_mem_helpers(CPUState *cpu)
 
 
 static inline void qemu_plugin_user_exit(void)
 static inline void qemu_plugin_user_exit(void)
 { }
 { }
+
+static inline void qemu_plugin_user_prefork_lock(void)
+{ }
+
+static inline void qemu_plugin_user_postfork(bool is_child)
+{ }
+
 #endif /* !CONFIG_PLUGIN */
 #endif /* !CONFIG_PLUGIN */
 
 
 #endif /* QEMU_PLUGIN_H */
 #endif /* QEMU_PLUGIN_H */

+ 2 - 0
linux-user/main.c

@@ -142,10 +142,12 @@ void fork_start(void)
     start_exclusive();
     start_exclusive();
     mmap_fork_start();
     mmap_fork_start();
     cpu_list_lock();
     cpu_list_lock();
+    qemu_plugin_user_prefork_lock();
 }
 }
 
 
 void fork_end(int child)
 void fork_end(int child)
 {
 {
+    qemu_plugin_user_postfork(child);
     mmap_fork_end(child);
     mmap_fork_end(child);
     if (child) {
     if (child) {
         CPUState *cpu, *next_cpu;
         CPUState *cpu, *next_cpu;

+ 20 - 0
plugins/core.c

@@ -526,6 +526,26 @@ void qemu_plugin_user_exit(void)
     qemu_plugin_atexit_cb();
     qemu_plugin_atexit_cb();
 }
 }
 
 
+/*
+ * Helpers for *-user to ensure locks are sane across fork() events.
+ */
+
+void qemu_plugin_user_prefork_lock(void)
+{
+    qemu_rec_mutex_lock(&plugin.lock);
+}
+
+void qemu_plugin_user_postfork(bool is_child)
+{
+    if (is_child) {
+        /* should we just reset via plugin_init? */
+        qemu_rec_mutex_init(&plugin.lock);
+    } else {
+        qemu_rec_mutex_unlock(&plugin.lock);
+    }
+}
+
+
 /*
 /*
  * Call this function after longjmp'ing to the main loop. It's possible that the
  * Call this function after longjmp'ing to the main loop. It's possible that the
  * last instruction of a TB might have used helpers, and therefore the
  * last instruction of a TB might have used helpers, and therefore the