[libvirt] [PATCH] hold the reference when call monitor's callback

Wen Congyang wency at cn.fujitsu.com
Thu Mar 15 10:51:49 UTC 2012


When qemu cannot startup, we will call EOF notify callback.
Unfortunately, there is a bug in libvirt, and it will cause
mon->ref to be 0 while we call EOF notify callback. This
bug will cause the libvirt to be deadlock.

We call the other callback while holding the reference. So
I think we should also hold the reference here.

Note: this patch does not fix the bug. The libvirt will be
deadlock in qemuMonitorUnwatch() because the monitor is freed
unexpectedly.

I am still investigating this bug. But if I set a breakpoint
in qemuMonitorUnref(), it does not happen now. If i remove
the breakpoint, it will happen sometime(the probability is
about 20%).

The steps to reproduce this bug:
1. use newest qemu-kvm
2. add a host pci device into guest config file
3. start the guest

The qemu will fail with the following error message:
Failed to assign irq for "hostdev0": Input/output error
Perhaps you are assigning a device that shares an IRQ with another device?

I have reported qemu's problem to qemu maillist.

---
 src/qemu/qemu_monitor.c |   16 ++++++++++++----
 1 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 78eb492..20eb9ea 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -668,10 +668,14 @@ qemuMonitorIO(int watch, int fd, int events, void *opaque) {
 
         /* Make sure anyone waiting wakes up now */
         virCondSignal(&mon->notify);
-        if (qemuMonitorUnref(mon) > 0)
-            qemuMonitorUnlock(mon);
+
+        /* hold the reference when call monitor's callback to avoid deadlock */
+        qemuMonitorUnlock(mon);
         VIR_DEBUG("Triggering EOF callback");
         (eofNotify)(mon, vm);
+        qemuMonitorLock(mon);
+        if (qemuMonitorUnref(mon) > 0)
+            qemuMonitorUnlock(mon);
     } else if (error) {
         void (*errorNotify)(qemuMonitorPtr, virDomainObjPtr)
             = mon->cb->errorNotify;
@@ -679,10 +683,14 @@ qemuMonitorIO(int watch, int fd, int events, void *opaque) {
 
         /* Make sure anyone waiting wakes up now */
         virCondSignal(&mon->notify);
-        if (qemuMonitorUnref(mon) > 0)
-            qemuMonitorUnlock(mon);
+
+        /* hold the reference when call monitor's callback to avoid deadlock */
+        qemuMonitorUnlock(mon);
         VIR_DEBUG("Triggering error callback");
         (errorNotify)(mon, vm);
+        qemuMonitorLock(mon);
+        if (qemuMonitorUnref(mon) > 0)
+            qemuMonitorUnlock(mon);
     } else {
         if (qemuMonitorUnref(mon) > 0)
             qemuMonitorUnlock(mon);
-- 
1.7.1




More information about the libvir-list mailing list