[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [BUG] libvirtd on destination crash frequently while migrating vms concurrently



Hello,
I found a problem that libvirtd on destination crash frequently while migrating vms concurrently. For example, if I migrate 10 vms concurrently ceaselessly, then after about 30 minutes the libvirtd on destination will crash. So I analyzed and found two bugs during migration process.
First, during migration prepare phase on destination, libvirtd assigns ports to qemu to be startd on destination. But the port increase operation is not aomic, so there’s a chance that multi vms get the same port, and only the first one can start successfully, others will fail to start. I’ve applied a patch to solve this bug, and I test it, it works well. If only this bug exists, libvirtd will not crash. The second bug is fatal.
Second, I found the libvirtd crash because of segment fault which is produced by accessing vm released. Apparently it’s caused by multi-thread operation, thread A access vm data which has released by thread B. At last I proved my thought right.
 
Step 1. Because of bug one, the port is already occupied, so qemu on destination failed to start and sent a HANGUP signal to libvirtd, then libvirtd received this VIR_EVENT_HANDLE_HANGUP event, thread A dealing with events called qemuProcessHandleMonitorEOF as following:
 
#0  qemuProcessHandleMonitorEOF (mon=0x7f4dcd9c3130, vm=0x7f4dcd9c9780)
    at qemu/qemu_process.c:399
#1  0x00007f4dc18d9e87 in qemuMonitorIO (watch=68, fd=27, events=8,
    opaque=0x7f4dcd9c3130) at qemu/qemu_monitor.c:668
#2  0x00007f4dccae6604 in virEventPollDispatchHandles (nfds=18,
    fds=0x7f4db4017e70) at util/vireventpoll.c:500
#3  0x00007f4dccae7ff2 in virEventPollRunOnce () at util/vireventpoll.c:646
#4  0x00007f4dccae60e4 in virEventRunDefaultImpl () at util/virevent.c:273
#5  0x00007f4dccc40b25 in virNetServerRun (srv=0x7f4dcd8d26b0)
    at rpc/virnetserver.c:1106
#6  0x00007f4dcd6164c9 in main (argc=3, argv=0x7fff8d8f9f88)
    at libvirtd.c:1518
 
 
static int virEventPollDispatchHandles(int nfds, struct pollfd *fds) {
        ……
        /*
deleted flag is still false now, so we pass through to qemuProcessHandleMonitorEOF
*/
        if (eventLoop.handles[i].deleted) {
            EVENT_DEBUG("Skip deleted n=%d w=%d f=%d", i,
                        eventLoop.handles[i].watch, eventLoop.handles[i].fd);
            continue;
        }
 
 
Step 2: Thread B dealing with migration on destination set deleted flag in virEventPollRemoveHandle as following:
 
#0  virEventPollRemoveHandle (watch=74) at util/vireventpoll.c:176
#1  0x00007f4dccae5e6f in virEventRemoveHandle (watch=74)
    at util/virevent.c:97
#2  0x00007f4dc18d8ca8 in qemuMonitorClose (mon=0x7f4dbc030910)
    at qemu/qemu_monitor.c:831
#3  0x00007f4dc18bec63 in qemuProcessStop (driver=0x7f4dcd9bd400,
    vm=0x7f4dbc00ed20, reason=VIR_DOMAIN_SHUTOFF_FAILED, flags=0)
    at qemu/qemu_process.c:4302
#4  0x00007f4dc18c1a83 in qemuProcessStart (conn=0x7f4dbc031020,
    driver=0x7f4dcd9bd400, vm=0x7f4dbc00ed20,
    migrateFrom=0x7f4dbc01af90 "tcp:[::]:49152", stdin_fd=-1,
    stdin_path=0x0, snapshot=0x0,
    vmop=VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START, flags=6)
    at qemu/qemu_process.c:4145
#5  0x00007f4dc18cc688 in qemuMigrationPrepareAny (driver=0x7f4dcd9bd400,
 
Step 3: Thread B cleanup vm in qemuMigrationPrepareAny after qemuProcessStart failed.
 
#0  virDomainObjDispose (obj=0x7f4dcd9c9780) at conf/domain_conf.c:2009
#1  0x00007f4dccb0ccd9 in virObjectUnref (anyobj=0x7f4dcd9c9780)
    at util/virobject.c:266
#2  0x00007f4dccb42340 in virDomainObjListRemove (doms=0x7f4dcd9bd4f0,
    dom=0x7f4dcd9c9780) at conf/domain_conf.c:2342
#3  0x00007f4dc189ac33 in qemuDomainRemoveInactive (driver=0x7f4dcd9bd400,
    vm=0x7f4dcd9c9780) at qemu/qemu_domain.c:1993
#4  0x00007f4dc18ccad5 in qemuMigrationPrepareAny (driver=0x7f4dcd9bd400,
 
Step 4: Thread A access priv which is released by thread B before, then libvirtd crash, bomb!
 
static void
qemuProcessHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                            virDomainObjPtr vm)
{
    virQEMUDriverPtr driver = qemu_driver;
    virDomainEventPtr event = NULL;
    qemuDomainObjPrivatePtr priv;
    int eventReason = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
    int stopReason = VIR_DOMAIN_SHUTOFF_SHUTDOWN;
    const char *auditReason = "shutdown";
 
    VIR_DEBUG("Received EOF on %p '%s'", vm, vm->def->name);
 
    virObjectLock(vm);
 
    priv = vm->privateData;
(gdb) p priv
$1 = (qemuDomainObjPrivatePtr) 0x0
    if (priv->beingDestroyed) {
 
    At last if anything bad happened to make qemuProcessStart failed during migration on destination, we’ll be in the big trouble that accessing some memory freed. I didn’t find any locks or flags exist could stop this happening. Please help me out, thanks a lot.
 
Best Regards,
-WangYufei
 
 
 

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]