提交 d96431f9 编写于 作者: W Wen Congyang 提交者: Eric Blake

avoid vm to be deleted if qemuConnectMonitor failed

Steps to reproduce this bug:
1. service libvirtd start
2. virsh start <domain>
3. kill -STOP $(cat /var/run/libvirt/qemu/<domain>.pid)
4. service libvirtd restart
5. kill -9 $(cat /var/run/libvirt/qemu/<domain>.pid)

Then libvirtd will core dump or be in deadlock state.

Make sure that json is built into libvirt and the version
of qemu is newer than 0.13.0.

The reason of libvirtd cores dump is that:
We add vm->refs when we alloc the memory, and decrease it
in the function qemuHandleMonitorEOF() in other thread.

We add vm->refs in the function qemuConnectMonitor() and
decrease it when the vm is inactive.

The libvirtd will block in the function qemuMonitorSetCapabilities()
because the vm is stopped by signal SIGSTOP. Now the vm->refs is 2.

Then we kill the vm by signal SIGKILL. The function
qemuMonitorSetCapabilities() failed, and then we will decrease vm->refs
in the function qemuMonitorClose().
In another thread, mon->fd is broken and the function
qemuHandleMonitorEOF() is called.

If qemuHandleMonitorEOF() decreases vm->refs before qemuConnectMonitor()
returns, vm->refs will be decrease to 0 and the memory is freed.

We will call qemudShutdownVMDaemon() as qemuConnectMonitor() failed.
The memory has been freed, so qemudShutdownVMDaemon() is too dangerous.

We will reference NULL pointer in the function virDomainConfVMNWFilterTeardown():
=============
void
virDomainConfVMNWFilterTeardown(virDomainObjPtr vm) {
    int i;

    if (nwfilterDriver != NULL) {
        for (i = 0; i < vm->def->nnets; i++)
            virDomainConfNWFilterTeardown(vm->def->nets[i]);
    }
}
============
vm->def->nnets is not 0 but vm->def->nets is NULL(We don't set vm->def->nnets
to 0 when we free vm).

We should add an extra reference of vm to avoid vm to be deleted if
qemuConnectMonitor() failed.
Signed-off-by: NWen Congyang <wency@cn.fujitsu.com>
上级 cedf97e7
...@@ -930,6 +930,10 @@ qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaq ...@@ -930,6 +930,10 @@ qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaq
priv = obj->privateData; priv = obj->privateData;
/* Hold an extra reference because we can't allow 'vm' to be
* deleted if qemuConnectMonitor() failed */
virDomainObjRef(obj);
/* XXX check PID liveliness & EXE path */ /* XXX check PID liveliness & EXE path */
if (qemuConnectMonitor(driver, obj) < 0) if (qemuConnectMonitor(driver, obj) < 0)
goto error; goto error;
...@@ -961,18 +965,27 @@ qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaq ...@@ -961,18 +965,27 @@ qemuReconnectDomain(void *payload, const char *name ATTRIBUTE_UNUSED, void *opaq
if (obj->def->id >= driver->nextvmid) if (obj->def->id >= driver->nextvmid)
driver->nextvmid = obj->def->id + 1; driver->nextvmid = obj->def->id + 1;
virDomainObjUnlock(obj); if (virDomainObjUnref(obj) > 0)
virDomainObjUnlock(obj);
return; return;
error: error:
/* We can't get the monitor back, so must kill the VM if (!virDomainObjIsActive(obj)) {
* to remove danger of it ending up running twice if if (virDomainObjUnref(obj) > 0)
* user tries to start it again later */ virDomainObjUnlock(obj);
qemudShutdownVMDaemon(driver, obj, 0); return;
if (!obj->persistent) }
virDomainRemoveInactive(&driver->domains, obj);
else if (virDomainObjUnref(obj) > 0) {
virDomainObjUnlock(obj); /* We can't get the monitor back, so must kill the VM
* to remove danger of it ending up running twice if
* user tries to start it again later */
qemudShutdownVMDaemon(driver, obj, 0);
if (!obj->persistent)
virDomainRemoveInactive(&driver->domains, obj);
else
virDomainObjUnlock(obj);
}
} }
/** /**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册