2014-03-20 01:26:56 +01:00
|
|
|
From 0e23bd461d077e553b7be5e8d192ca400f4ffbdf Mon Sep 17 00:00:00 2001
|
2012-02-01 00:10:40 +01:00
|
|
|
From: Alexander Graf <agraf@suse.de>
|
|
|
|
Date: Fri, 13 Jan 2012 17:05:41 +0100
|
|
|
|
Subject: [PATCH] linux-user: fix segfault deadlock
|
2013-05-14 22:46:08 +02:00
|
|
|
MIME-Version: 1.0
|
|
|
|
Content-Type: text/plain; charset=UTF-8
|
|
|
|
Content-Transfer-Encoding: 8bit
|
2012-02-01 00:10:40 +01:00
|
|
|
|
|
|
|
When entering the guest we take a lock to ensure that nobody else messes
|
|
|
|
with our TB chaining while we're doing it. If we get a segfault inside that
|
|
|
|
code, we manage to work on, but will not unlock the lock.
|
|
|
|
|
|
|
|
This patch forces unlocking of that lock in the segv handler. I'm not sure
|
|
|
|
this is the right approach though. Maybe we should rather make sure we don't
|
|
|
|
segfault in the code? I would greatly appreciate someone more intelligible
|
|
|
|
than me to look at this :).
|
|
|
|
|
|
|
|
Example code to trigger this is at: http://csgraf.de/tmp/conftest.c
|
|
|
|
|
|
|
|
Reported-by: Fabio Erculiani <lxnay@sabayon.org>
|
|
|
|
Signed-off-by: Alexander Graf <agraf@suse.de>
|
2013-05-14 22:46:08 +02:00
|
|
|
Signed-off-by: Andreas Färber <afaerber@suse.de>
|
2012-02-01 00:10:40 +01:00
|
|
|
---
|
2014-01-17 23:04:30 +01:00
|
|
|
include/exec/spinlock.h | 10 ++++++++++
|
|
|
|
user-exec.c | 4 ++++
|
|
|
|
2 files changed, 14 insertions(+)
|
2012-02-01 00:10:40 +01:00
|
|
|
|
2013-02-10 19:32:29 +01:00
|
|
|
diff --git a/include/exec/spinlock.h b/include/exec/spinlock.h
|
2012-02-01 00:10:40 +01:00
|
|
|
index a72edda..e460e12 100644
|
2013-02-10 19:32:29 +01:00
|
|
|
--- a/include/exec/spinlock.h
|
|
|
|
+++ b/include/exec/spinlock.h
|
2012-02-01 00:10:40 +01:00
|
|
|
@@ -24,6 +24,12 @@
|
|
|
|
#include <pthread.h>
|
|
|
|
#define spin_lock pthread_mutex_lock
|
|
|
|
#define spin_unlock pthread_mutex_unlock
|
|
|
|
+static inline void spin_unlock_safe(pthread_mutex_t *lock)
|
|
|
|
+{
|
|
|
|
+ /* unlocking an unlocked mutex results in undefined behavior */
|
|
|
|
+ pthread_mutex_trylock(lock);
|
|
|
|
+ pthread_mutex_unlock(lock);
|
|
|
|
+}
|
|
|
|
#define spinlock_t pthread_mutex_t
|
|
|
|
#define SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER
|
|
|
|
|
|
|
|
@@ -46,4 +52,8 @@ static inline void spin_unlock(spinlock_t *lock)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
+static inline void spin_unlock_safe(spinlock_t *lock)
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
#endif
|
|
|
|
diff --git a/user-exec.c b/user-exec.c
|
2014-03-20 01:26:56 +01:00
|
|
|
index bc58056..63b3b3d 100644
|
2012-02-01 00:10:40 +01:00
|
|
|
--- a/user-exec.c
|
|
|
|
+++ b/user-exec.c
|
2014-03-20 01:26:56 +01:00
|
|
|
@@ -93,6 +93,10 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
|
2012-02-01 00:10:40 +01:00
|
|
|
qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
|
|
|
pc, address, is_write, *(unsigned long *)old_set);
|
|
|
|
#endif
|
|
|
|
+
|
|
|
|
+ /* Maybe we're still holding the TB fiddling lock? */
|
2013-05-14 22:46:08 +02:00
|
|
|
+ spin_unlock_safe(&tcg_ctx.tb_ctx.tb_lock);
|
2012-02-01 00:10:40 +01:00
|
|
|
+
|
|
|
|
/* XXX: locking issue */
|
2012-05-15 14:58:40 +02:00
|
|
|
if (is_write && h2g_valid(address)
|
|
|
|
&& page_unprotect(h2g(address), pc, puc)) {
|