qemu-devel
[Top][All Lists]
Advanced

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

Re: [RFC PATCH] mpqemu: Remove unlock/lock of iothread in mpqemu-link se


From: Jag Raman
Subject: Re: [RFC PATCH] mpqemu: Remove unlock/lock of iothread in mpqemu-link send and recv functions
Date: Mon, 23 May 2022 22:56:41 +0000


> On May 23, 2022, at 11:09 AM, Alexander Duyck <alexander.duyck@gmail.com> 
> wrote:
> 
> From: Alexander Duyck <alexanderduyck@fb.com>
> 
> When I run Multi-process QEMU with an e1000 as the remote device and SMP
> enabled I see the combination lock up and become unresponsive. The QEMU build
> is a fairly standard x86_64-softmmu setup. After doing some digging I tracked
> the lockup down to the what appears to be a race with the mpqemu-link msg_send
> and msg_receive functions and the reacquisition of the lock.
> 
> I am assuming the issue is some sort of lock inversion though I haven't
> identified exactly what the other lock involved is yet. For now removing
> the logic to unlock the iothread and then reacquire the lock seems to
> resolve the issue. I am assuming the releasing of the lock was some form of
> optimization but I am not certain so I am submitting this as an RFC.

Hi Alexander,

We are working on moving away from Multi-process QEMU and to using vfio-user
based approach. The vfio-user patches are under review. I believe we would drop
the Multi-process support once vfio-user is merged.

We release the lock here while communicating with the remote process via the
QIOChannel. It is to prevent lockup of the VM in case the QIOChannel hangs.

I was able to reproduce this issue at my end. There is a deadlock between
"mpqemu_msg_send() -> qemu_mutex_lock_iothread()" and
"mpqemu_msg_send_and_await_reply() -> QEMU_LOCK_GUARD(&pdev->io_mutex)”.

From what I can tell, as soon as one vcpu thread drops the iothread lock, 
another
thread running mpqemu_msg_send_and_await_reply() holds on to it. That prevents
the first thread from completing. Attaching backtrace below.

To avoid the deadlock, I think we should drop both the iothread lock and 
io_mutex
and reacquire them in the correct order - first iothread and then io_mutex. 
Given
multiprocess QEMU would be dropped in the near future, I suppose we don’t have
to proceed further along these lines.

I tested your patch, and that fixes the e1000 issue at my end also. I believe we
could adopt it.

Thank you!
--
Jag

Thread 6 (Thread 0x7f2d12281700 (LWP 31758)):
#0  0x00007f2d9b7ac54d in __lll_lock_wait () at /lib64/libpthread.so.0
#1  0x00007f2d9b7a7e9b in _L_lock_883 () at /lib64/libpthread.so.0
#2  0x00007f2d9b7a7d68 in pthread_mutex_lock () at /lib64/libpthread.so.0
#3  0x000055bdeb48663f in qemu_mutex_lock_impl (mutex=0x55bdebf68800 
<qemu_global_mutex>, file=0x55bdeb5c5c5a "../hw/remote/mpqemu-link.c", line=79) 
at ../util/qemu-thread-posix.c:88
#4  0x000055bdeb006546 in qemu_mutex_lock_iothread_impl (file=0x55bdeb5c5c5a 
"../hw/remote/mpqemu-link.c", line=79) at ../softmmu/cpus.c:502
#5  0x000055bdeafed3ff in mpqemu_msg_send (msg=0x7f2d12280430, 
ioc=0x55bdeeb02600, errp=0x7f2d12280420) at ../hw/remote/mpqemu-link.c:79
#6  0x000055bdeafed93c in mpqemu_msg_send_and_await_reply (msg=0x7f2d12280430, 
pdev=0x55bdeeaff8e0, errp=0x7f2d12280420) at ../hw/remote/mpqemu-link.c:198
#7  0x000055bdeafefe0e in send_bar_access_msg (pdev=0x55bdeeaff8e0, 
mr=0x55bdeeb00460, write=false, addr=192, val=0x7f2d12280578, size=4, 
memory=true) at ../hw/remote/proxy.c:256
#8  0x000055bdeafeff3e in proxy_bar_read (opaque=0x55bdeeb00450, addr=192, 
size=4) at ../hw/remote/proxy.c:280
#9  0x000055bdeb1f3759 in memory_region_read_accessor (mr=0x55bdeeb00460, 
addr=192, value=0x7f2d12280750, size=4, shift=0, mask=4294967295, attrs=...) at 
../softmmu/memory.c:440
#10 0x000055bdeb1f3c8e in access_with_adjusted_size (addr=192, 
value=0x7f2d12280750, size=4, access_size_min=1, access_size_max=8, 
access_fn=0x55bdeb1f3716 <memory_region_read_accessor>, mr=0x55bdeeb00460, 
attrs=...) at ../softmmu/memory.c:554
#11 0x000055bdeb1f695f in memory_region_dispatch_read1 (mr=0x55bdeeb00460, 
addr=192, pval=0x7f2d12280750, size=4, attrs=...) at ../softmmu/memory.c:1424
#12 0x000055bdeb1f6a79 in memory_region_dispatch_read (mr=0x55bdeeb00460, 
addr=192, pval=0x7f2d12280750, op=MO_32, attrs=...) at ../softmmu/memory.c:1457
#13 0x000055bdeb20451a in flatview_read_continue (fv=0x7f2d0c30ef50, 
addr=4273602752, attrs=..., ptr=0x7f2d9d988028, len=4, addr1=192, l=4, 
mr=0x55bdeeb00460) at ../softmmu/physmem.c:2881
#14 0x000055bdeb204692 in flatview_read (fv=0x7f2d0c30ef50, addr=4273602752, 
attrs=..., buf=0x7f2d9d988028, len=4) at ../softmmu/physmem.c:2923
#15 0x000055bdeb20471b in address_space_read_full (as=0x55bdebf705e0 
<address_space_memory>, addr=4273602752, attrs=..., buf=0x7f2d9d988028, len=4) 
at ../softmmu/physmem.c:2936
#16 0x000055bdeb20483f in address_space_rw (as=0x55bdebf705e0 
<address_space_memory>, addr=4273602752, attrs=..., buf=0x7f2d9d988028, len=4, 
is_write=false) at ../softmmu/physmem.c:2964
#17 0x000055bdeb29a60a in kvm_cpu_exec (cpu=0x55bdedcb0410) at 
../accel/kvm/kvm-all.c:2929
#18 0x000055bdeb29c3fc in kvm_vcpu_thread_fn (arg=0x55bdedcb0410) at 
../accel/kvm/kvm-accel-ops.c:49
#19 0x000055bdeb4872f8 in qemu_thread_start (args=0x55bdedcbf700) at 
../util/qemu-thread-posix.c:504
#20 0x00007f2d9b7a5ea5 in start_thread () at /lib64/libpthread.so.0
#21 0x00007f2d9b4ceb0d in clone () at /lib64/libc.so.6

Thread 3 (Thread 0x7f2d13a84700 (LWP 31753)):
#0  0x00007f2d9b7ac54d in __lll_lock_wait () at /lib64/libpthread.so.0
#1  0x00007f2d9b7a7e9b in _L_lock_883 () at /lib64/libpthread.so.0
#2  0x00007f2d9b7a7d68 in pthread_mutex_lock () at /lib64/libpthread.so.0
#3  0x000055bdeb48663f in qemu_mutex_lock_impl (mutex=0x55bdeeb00308, 
file=0x55bdeb5c5aa0 "/home/qemu-separation/qemu-split/include/qemu/thread.h", 
line=118) at ../util/qemu-thread-posix.c:88
#4  0x000055bdeafecf00 in qemu_mutex_lock (mutex=0x55bdeeb00308) at 
/home/qemu-separation/qemu-split/include/qemu/thread.h:118
#5  0x000055bdeafecf4a in qemu_lockable_lock (x=0x7f2d13a83310) at 
/home/qemu-separation/qemu-split/include/qemu/lockable.h:95
#6  0x000055bdeafecf88 in qemu_lockable_auto_lock (x=0x7f2d13a83310) at 
/home/qemu-separation/qemu-split/include/qemu/lockable.h:105
#7  0x000055bdeafed90e in mpqemu_msg_send_and_await_reply (msg=0x7f2d13a83490, 
pdev=0x55bdeeaff8e0, errp=0x7f2d13a83480) at ../hw/remote/mpqemu-link.c:197
#8  0x000055bdeafefe0e in send_bar_access_msg (pdev=0x55bdeeaff8e0, 
mr=0x55bdeeb00460, write=true, addr=200, val=0x7f2d13a835b8, size=4, 
memory=true) at ../hw/remote/proxy.c:256
#9  0x000055bdeafefec9 in proxy_bar_write (opaque=0x55bdeeb00450, addr=200, 
val=4, size=4) at ../hw/remote/proxy.c:271
#10 0x000055bdeb1f3a48 in memory_region_write_accessor (mr=0x55bdeeb00460, 
addr=200, value=0x7f2d13a836e8, size=4, shift=0, mask=4294967295, attrs=...) at 
../softmmu/memory.c:492
#11 0x000055bdeb1f3c8e in access_with_adjusted_size (addr=200, 
value=0x7f2d13a836e8, size=4, access_size_min=1, access_size_max=8, 
access_fn=0x55bdeb1f3952 <memory_region_write_accessor>, mr=0x55bdeeb00460, 
attrs=...) at ../softmmu/memory.c:554
#12 0x000055bdeb1f6d8b in memory_region_dispatch_write (mr=0x55bdeeb00460, 
addr=200, data=4, op=MO_32, attrs=...) at ../softmmu/memory.c:1514
#13 0x000055bdeb20429f in flatview_write_continue (fv=0x7f2d0c30ef50, 
addr=4273602760, attrs=..., ptr=0x7f2d9d991028, len=4, addr1=200, l=4, 
mr=0x55bdeeb00460) at ../softmmu/physmem.c:2814
#14 0x000055bdeb204402 in flatview_write (fv=0x7f2d0c30ef50, addr=4273602760, 
attrs=..., buf=0x7f2d9d991028, len=4) at ../softmmu/physmem.c:2856
#15 0x000055bdeb2047b2 in address_space_write (as=0x55bdebf705e0 
<address_space_memory>, addr=4273602760, attrs=..., buf=0x7f2d9d991028, len=4) 
at ../softmmu/physmem.c:2952
#16 0x000055bdeb20481f in address_space_rw (as=0x55bdebf705e0 
<address_space_memory>, addr=4273602760, attrs=..., buf=0x7f2d9d991028, len=4, 
is_write=true) at ../softmmu/physmem.c:2962
#17 0x000055bdeb29a60a in kvm_cpu_exec (cpu=0x55bdedc56930) at 
../accel/kvm/kvm-all.c:2929
#18 0x000055bdeb29c3fc in kvm_vcpu_thread_fn (arg=0x55bdedc56930) at 
../accel/kvm/kvm-accel-ops.c:49
#19 0x000055bdeb4872f8 in qemu_thread_start (args=0x55bdedc64fa0) at 
../util/qemu-thread-posix.c:504
#20 0x00007f2d9b7a5ea5 in start_thread () at /lib64/libpthread.so.0
#21 0x00007f2d9b4ceb0d in clone () at /lib64/libc.so.6

> 
> Signed-off-by: Alexander Duyck <alexanderduyck@fb.com>
> ---
> hw/remote/mpqemu-link.c |   25 -------------------------
> 1 file changed, 25 deletions(-)
> 
> diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c
> index 9bd98e82197e..3e7818f54a63 100644
> --- a/hw/remote/mpqemu-link.c
> +++ b/hw/remote/mpqemu-link.c
> @@ -33,7 +33,6 @@
>  */
> bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp)
> {
> -    bool iolock = qemu_mutex_iothread_locked();
>     bool iothread = qemu_in_iothread();
>     struct iovec send[2] = {};
>     int *fds = NULL;
> @@ -57,16 +56,6 @@ bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, 
> Error **errp)
>      */
>     assert(qemu_in_coroutine() || !iothread);
> 
> -    /*
> -     * Skip unlocking/locking iothread lock when the IOThread is running
> -     * in co-routine context. Co-routine context is asserted above
> -     * for IOThread case.
> -     * Also skip lock handling while in a co-routine in the main context.
> -     */
> -    if (iolock && !iothread && !qemu_in_coroutine()) {
> -        qemu_mutex_unlock_iothread();
> -    }
> -
>     if (!qio_channel_writev_full_all(ioc, send, G_N_ELEMENTS(send),
>                                     fds, nfds, 0, errp)) {
>         ret = true;
> @@ -74,11 +63,6 @@ bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, 
> Error **errp)
>         trace_mpqemu_send_io_error(msg->cmd, msg->size, nfds);
>     }
> 
> -    if (iolock && !iothread && !qemu_in_coroutine()) {
> -        /* See above comment why skip locking here. */
> -        qemu_mutex_lock_iothread();
> -    }
> -
>     return ret;
> }
> 
> @@ -96,7 +80,6 @@ static ssize_t mpqemu_read(QIOChannel *ioc, void *buf, 
> size_t len, int **fds,
>                            size_t *nfds, Error **errp)
> {
>     struct iovec iov = { .iov_base = buf, .iov_len = len };
> -    bool iolock = qemu_mutex_iothread_locked();
>     bool iothread = qemu_in_iothread();
>     int ret = -1;
> 
> @@ -106,16 +89,8 @@ static ssize_t mpqemu_read(QIOChannel *ioc, void *buf, 
> size_t len, int **fds,
>      */
>     assert(qemu_in_coroutine() || !iothread);
> 
> -    if (iolock && !iothread && !qemu_in_coroutine()) {
> -        qemu_mutex_unlock_iothread();
> -    }
> -
>     ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, fds, nfds, errp);
> 
> -    if (iolock && !iothread && !qemu_in_coroutine()) {
> -        qemu_mutex_lock_iothread();
> -    }
> -
>     return (ret <= 0) ? ret : iov.iov_len;
> }
> 
> 
> 
> 


reply via email to

[Prev in Thread] Current Thread [Next in Thread]