aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2009-05-19 17:04:59 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-05-20 04:34:32 -0400
commit2070887fdeacd9c13f3e805e3f0086c9f22a4d93 (patch)
treef1695bd701f7a2558e11052bfe6ff42d6dc561df
parent1c840c14906d4ddf66c1f4f5daea059aad951c82 (diff)
futex: fix restart in wait_requeue_pi
If the waiter has been requeued to the outer PI futex and is interrupted by a signal and the thread handles the signal then ERESTART_RESTARTBLOCK is changed to EINTR and the restart block is discarded. That way we return an unexcpected EINTR to user space instead of ending up in futex_lock_pi_restart. But we do not need to restart the syscall because we know that the condition has changed since we have been requeued. If we would simply restart the syscall then we would drop out via the comparison of the user space value with EWOULDBLOCK. The user space side needs to handle EWOULDBLOCK anyway as the enqueueing on the inner futex can race with a requeue/wake. So we can simply return EWOULDBLOCK to user space which also signals that we did not take the outer futex and let user space handle it in the same way it has to handle the requeue/wake race. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--kernel/futex.c49
1 files changed, 9 insertions, 40 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 2aa216e5b594..80b5ce716596 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1507,7 +1507,6 @@ handle_fault:
1507#define FLAGS_HAS_TIMEOUT 0x04 1507#define FLAGS_HAS_TIMEOUT 0x04
1508 1508
1509static long futex_wait_restart(struct restart_block *restart); 1509static long futex_wait_restart(struct restart_block *restart);
1510static long futex_lock_pi_restart(struct restart_block *restart);
1511 1510
1512/** 1511/**
1513 * fixup_owner() - Post lock pi_state and corner case management 1512 * fixup_owner() - Post lock pi_state and corner case management
@@ -1930,21 +1929,6 @@ uaddr_faulted:
1930 goto retry; 1929 goto retry;
1931} 1930}
1932 1931
1933static long futex_lock_pi_restart(struct restart_block *restart)
1934{
1935 u32 __user *uaddr = (u32 __user *)restart->futex.uaddr;
1936 ktime_t t, *tp = NULL;
1937 int fshared = restart->futex.flags & FLAGS_SHARED;
1938
1939 if (restart->futex.flags & FLAGS_HAS_TIMEOUT) {
1940 t.tv64 = restart->futex.time;
1941 tp = &t;
1942 }
1943 restart->fn = do_no_restart_syscall;
1944
1945 return (long)futex_lock_pi(uaddr, fshared, restart->futex.val, tp, 0);
1946}
1947
1948/* 1932/*
1949 * Userspace attempted a TID -> 0 atomic transition, and failed. 1933 * Userspace attempted a TID -> 0 atomic transition, and failed.
1950 * This is the in-kernel slowpath: we look up the PI state (if any), 1934 * This is the in-kernel slowpath: we look up the PI state (if any),
@@ -2141,12 +2125,10 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
2141 struct hrtimer_sleeper timeout, *to = NULL; 2125 struct hrtimer_sleeper timeout, *to = NULL;
2142 struct rt_mutex_waiter rt_waiter; 2126 struct rt_mutex_waiter rt_waiter;
2143 struct rt_mutex *pi_mutex = NULL; 2127 struct rt_mutex *pi_mutex = NULL;
2144 struct restart_block *restart;
2145 struct futex_hash_bucket *hb; 2128 struct futex_hash_bucket *hb;
2146 union futex_key key2; 2129 union futex_key key2;
2147 struct futex_q q; 2130 struct futex_q q;
2148 int res, ret; 2131 int res, ret;
2149 u32 uval;
2150 2132
2151 if (!bitset) 2133 if (!bitset)
2152 return -EINVAL; 2134 return -EINVAL;
@@ -2245,30 +2227,17 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
2245 if (rt_mutex_owner(pi_mutex) == current) 2227 if (rt_mutex_owner(pi_mutex) == current)
2246 rt_mutex_unlock(pi_mutex); 2228 rt_mutex_unlock(pi_mutex);
2247 } else if (ret == -EINTR) { 2229 } else if (ret == -EINTR) {
2248 ret = -EFAULT;
2249 if (get_user(uval, uaddr2))
2250 goto out_put_keys;
2251
2252 /* 2230 /*
2253 * We've already been requeued, so restart by calling 2231 * We've already been requeued, but we have no way to
2254 * futex_lock_pi() directly, rather then returning to this 2232 * restart by calling futex_lock_pi() directly. We
2255 * function. 2233 * could restart the syscall, but that will look at
2234 * the user space value and return right away. So we
2235 * drop back with EWOULDBLOCK to tell user space that
2236 * "val" has been changed. That's the same what the
2237 * restart of the syscall would do in
2238 * futex_wait_setup().
2256 */ 2239 */
2257 ret = -ERESTART_RESTARTBLOCK; 2240 ret = -EWOULDBLOCK;
2258 restart = &current_thread_info()->restart_block;
2259 restart->fn = futex_lock_pi_restart;
2260 restart->futex.uaddr = (u32 *)uaddr2;
2261 restart->futex.val = uval;
2262 restart->futex.flags = 0;
2263 if (abs_time) {
2264 restart->futex.flags |= FLAGS_HAS_TIMEOUT;
2265 restart->futex.time = abs_time->tv64;
2266 }
2267
2268 if (fshared)
2269 restart->futex.flags |= FLAGS_SHARED;
2270 if (clockrt)
2271 restart->futex.flags |= FLAGS_CLOCKRT;
2272 } 2241 }
2273 2242
2274out_put_keys: 2243out_put_keys: