Patchwork [v2,14/22] kvm: Fix race between timer signals and vcpu entry under !IOTHREAD

login
register
mail settings
Submitter Jan Kiszka
Date Jan. 27, 2011, 2:20 p.m.
Message ID <4D417F1F.7020302@siemens.com>
Download mbox | patch
Permalink /patch/80700/
State New
Headers show

Comments

Jan Kiszka - Jan. 27, 2011, 2:20 p.m.
Found by Stefan Hajnoczi: There is a race in kvm_cpu_exec between
checking for exit_request on vcpu entry and timer signals arriving
before KVM starts to catch them. Plug it by blocking both timer related
signals also on !CONFIG_IOTHREAD and process those via signalfd.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
CC: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
---

Added blocking of SIGIO/SIGALRM which was missing in previous version.
Stefan just provided a test case, and that now passes.

However, I realized (and checked) that this fix does not work with
signalfd_compat: The signals will be swallowed by the helper thread.
That affects all host kernels < 2.6.22. Given that we require 2.6.29 as
baseline (unless kvm-kmod is used) and that !CONFIG_IOTHREAD is not that
important for KVM mode, I tend to catch and reject
CONFIG_KVM+!CONFIG_IOTHREAD+!CONFIG_SIGNALFD as unsupported during
configure. Comments?

 cpus.c |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)

Patch

diff --git a/cpus.c b/cpus.c
index fc3f222..f9d9f9e 100644
--- a/cpus.c
+++ b/cpus.c
@@ -254,6 +254,10 @@  static void qemu_kvm_init_cpu_signals(CPUState *env)
     pthread_sigmask(SIG_BLOCK, NULL, &set);
     sigdelset(&set, SIG_IPI);
     sigdelset(&set, SIGBUS);
+#ifndef CONFIG_IOTHREAD
+    sigdelset(&set, SIGIO);
+    sigdelset(&set, SIGALRM);
+#endif
     r = kvm_set_signal_mask(env, &set);
     if (r) {
         fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r));
@@ -351,6 +355,12 @@  static void qemu_kvm_eat_signals(CPUState *env)
             exit(1);
         }
     } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
+
+#ifndef CONFIG_IOTHREAD
+    if (sigismember(&chkset, SIGIO) || sigismember(&chkset, SIGALRM)) {
+        qemu_notify_event();
+    }
+#endif
 }
 
 #else /* _WIN32 */
@@ -398,6 +408,14 @@  int qemu_init_main_loop(void)
     int ret;
 
     sigemptyset(&blocked_signals);
+    if (kvm_enabled()) {
+        /*
+         * We need to process timer signals synchronously to avoid a race
+         * between exit_request check and KVM vcpu entry.
+         */
+        sigaddset(&blocked_signals, SIGIO);
+        sigaddset(&blocked_signals, SIGALRM);
+    }
 
     ret = qemu_signalfd_init(blocked_signals);
     if (ret) {
@@ -535,6 +553,8 @@  static sigset_t block_io_signals(void)
     sigaddset(&set, SIGALRM);
     sigaddset(&set, SIG_IPI);
     sigaddset(&set, SIGBUS);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
     pthread_sigmask(SIG_BLOCK, &set, NULL);
 
     memset(&action, 0, sizeof(action));