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