* [Qemu-devel] [PATCH] linux-user: wrap fork() in a start/end exclusive section
@ 2017-12-07 12:41 Peter Maydell
2018-01-19 15:22 ` Laurent Vivier
0 siblings, 1 reply; 2+ messages in thread
From: Peter Maydell @ 2017-12-07 12:41 UTC (permalink / raw)
To: qemu-devel
Cc: patches, Riku Voipio, Laurent Vivier, Paolo Bonzini, Stuart Monteith
When we do a fork() in usermode emulation, we need to be in
a start/end exclusive section, so that we can ensure that no
other thread is in an RCU section. Otherwise you can get this
deadlock:
- fork thread: has mmap_lock, waits for rcu_sync_lock
(because rcu_init_lock() is registered as a pthread_atfork() hook)
- RCU thread: has rcu_sync_lock, waits for rcu_read_(un)lock
- another CPU thread: in RCU critical section, waits for mmap_lock
This can show up if you have a heavily multithreaded guest program
that does a fork().
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reported-by: Stuart Monteith <stuart.monteith@linaro.org>
---
Based-on: <1512397331-15238-1-git-send-email-peter.maydell@linaro.org>
(this applies on top of 'linux-user: Fix locking order in fork_start()')
I think this should fix the deadlock that Stuart reports, but I
can't reproduce it, so testing welcome.
linux-user/main.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/linux-user/main.c b/linux-user/main.c
index 146ee3e..ff116fe 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -128,6 +128,7 @@ int cpu_get_pic_interrupt(CPUX86State *env)
/* Make sure everything is in a consistent state for calling fork(). */
void fork_start(void)
{
+ start_exclusive();
mmap_fork_start();
qemu_mutex_lock(&tb_ctx.tb_lock);
cpu_list_lock();
@@ -148,9 +149,13 @@ void fork_end(int child)
qemu_mutex_init(&tb_ctx.tb_lock);
qemu_init_cpu_list();
gdbserver_fork(thread_cpu);
+ /* qemu_init_cpu_list() takes care of reinitializing the
+ * exclusive state, so we don't need to end_exclusive() here.
+ */
} else {
qemu_mutex_unlock(&tb_ctx.tb_lock);
cpu_list_unlock();
+ end_exclusive();
}
}
--
2.7.4
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [Qemu-devel] [PATCH] linux-user: wrap fork() in a start/end exclusive section
2017-12-07 12:41 [Qemu-devel] [PATCH] linux-user: wrap fork() in a start/end exclusive section Peter Maydell
@ 2018-01-19 15:22 ` Laurent Vivier
0 siblings, 0 replies; 2+ messages in thread
From: Laurent Vivier @ 2018-01-19 15:22 UTC (permalink / raw)
To: Peter Maydell, qemu-devel
Cc: Paolo Bonzini, Stuart Monteith, Riku Voipio, patches
Le 07/12/2017 à 13:41, Peter Maydell a écrit :
> When we do a fork() in usermode emulation, we need to be in
> a start/end exclusive section, so that we can ensure that no
> other thread is in an RCU section. Otherwise you can get this
> deadlock:
>
> - fork thread: has mmap_lock, waits for rcu_sync_lock
> (because rcu_init_lock() is registered as a pthread_atfork() hook)
> - RCU thread: has rcu_sync_lock, waits for rcu_read_(un)lock
> - another CPU thread: in RCU critical section, waits for mmap_lock
>
> This can show up if you have a heavily multithreaded guest program
> that does a fork().
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> Reported-by: Stuart Monteith <stuart.monteith@linaro.org>
> ---
> Based-on: <1512397331-15238-1-git-send-email-peter.maydell@linaro.org>
> (this applies on top of 'linux-user: Fix locking order in fork_start()')
>
> I think this should fix the deadlock that Stuart reports, but I
> can't reproduce it, so testing welcome.
>
> linux-user/main.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/linux-user/main.c b/linux-user/main.c
> index 146ee3e..ff116fe 100644
> --- a/linux-user/main.c
> +++ b/linux-user/main.c
> @@ -128,6 +128,7 @@ int cpu_get_pic_interrupt(CPUX86State *env)
> /* Make sure everything is in a consistent state for calling fork(). */
> void fork_start(void)
> {
> + start_exclusive();
> mmap_fork_start();
> qemu_mutex_lock(&tb_ctx.tb_lock);
> cpu_list_lock();
> @@ -148,9 +149,13 @@ void fork_end(int child)
> qemu_mutex_init(&tb_ctx.tb_lock);
> qemu_init_cpu_list();
> gdbserver_fork(thread_cpu);
> + /* qemu_init_cpu_list() takes care of reinitializing the
> + * exclusive state, so we don't need to end_exclusive() here.
> + */
> } else {
> qemu_mutex_unlock(&tb_ctx.tb_lock);
> cpu_list_unlock();
> + end_exclusive();
> }
> }
>
>
Applied to my linux-user branch.
Thanks,
Laurent
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2018-01-19 15:22 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-07 12:41 [Qemu-devel] [PATCH] linux-user: wrap fork() in a start/end exclusive section Peter Maydell
2018-01-19 15:22 ` Laurent Vivier
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.