diff options
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 84 |
1 files changed, 11 insertions, 73 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index b9b8aea5389e..9d260e838cff 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -1120,9 +1120,10 @@ static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time) | |||
1120 | * if there are waiters then it will block, it does PI, etc. (Due to | 1120 | * if there are waiters then it will block, it does PI, etc. (Due to |
1121 | * races the kernel might see a 0 value of the futex too.) | 1121 | * races the kernel might see a 0 value of the futex too.) |
1122 | */ | 1122 | */ |
1123 | static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock, | 1123 | static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec, |
1124 | struct hrtimer_sleeper *to) | 1124 | long nsec, int trylock) |
1125 | { | 1125 | { |
1126 | struct hrtimer_sleeper timeout, *to = NULL; | ||
1126 | struct task_struct *curr = current; | 1127 | struct task_struct *curr = current; |
1127 | struct futex_hash_bucket *hb; | 1128 | struct futex_hash_bucket *hb; |
1128 | u32 uval, newval, curval; | 1129 | u32 uval, newval, curval; |
@@ -1132,6 +1133,13 @@ static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock, | |||
1132 | if (refill_pi_state_cache()) | 1133 | if (refill_pi_state_cache()) |
1133 | return -ENOMEM; | 1134 | return -ENOMEM; |
1134 | 1135 | ||
1136 | if (sec != MAX_SCHEDULE_TIMEOUT) { | ||
1137 | to = &timeout; | ||
1138 | hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS); | ||
1139 | hrtimer_init_sleeper(to, current); | ||
1140 | to->timer.expires = ktime_set(sec, nsec); | ||
1141 | } | ||
1142 | |||
1135 | q.pi_state = NULL; | 1143 | q.pi_state = NULL; |
1136 | retry: | 1144 | retry: |
1137 | down_read(&curr->mm->mmap_sem); | 1145 | down_read(&curr->mm->mmap_sem); |
@@ -1307,7 +1315,7 @@ static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock, | |||
1307 | if (!detect && ret == -EDEADLK && 0) | 1315 | if (!detect && ret == -EDEADLK && 0) |
1308 | force_sig(SIGKILL, current); | 1316 | force_sig(SIGKILL, current); |
1309 | 1317 | ||
1310 | return ret; | 1318 | return ret != -EINTR ? ret : -ERESTARTNOINTR; |
1311 | 1319 | ||
1312 | out_unlock_release_sem: | 1320 | out_unlock_release_sem: |
1313 | queue_unlock(&q, hb); | 1321 | queue_unlock(&q, hb); |
@@ -1342,76 +1350,6 @@ static int do_futex_lock_pi(u32 __user *uaddr, int detect, int trylock, | |||
1342 | } | 1350 | } |
1343 | 1351 | ||
1344 | /* | 1352 | /* |
1345 | * Restart handler | ||
1346 | */ | ||
1347 | static long futex_lock_pi_restart(struct restart_block *restart) | ||
1348 | { | ||
1349 | struct hrtimer_sleeper timeout, *to = NULL; | ||
1350 | int ret; | ||
1351 | |||
1352 | restart->fn = do_no_restart_syscall; | ||
1353 | |||
1354 | if (restart->arg2 || restart->arg3) { | ||
1355 | to = &timeout; | ||
1356 | hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS); | ||
1357 | hrtimer_init_sleeper(to, current); | ||
1358 | to->timer.expires.tv64 = ((u64)restart->arg1 << 32) | | ||
1359 | (u64) restart->arg0; | ||
1360 | } | ||
1361 | |||
1362 | pr_debug("lock_pi restart: %p, %d (%d)\n", | ||
1363 | (u32 __user *)restart->arg0, current->pid); | ||
1364 | |||
1365 | ret = do_futex_lock_pi((u32 __user *)restart->arg0, restart->arg1, | ||
1366 | 0, to); | ||
1367 | |||
1368 | if (ret != -EINTR) | ||
1369 | return ret; | ||
1370 | |||
1371 | restart->fn = futex_lock_pi_restart; | ||
1372 | |||
1373 | /* The other values are filled in */ | ||
1374 | return -ERESTART_RESTARTBLOCK; | ||
1375 | } | ||
1376 | |||
1377 | /* | ||
1378 | * Called from the syscall entry below. | ||
1379 | */ | ||
1380 | static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec, | ||
1381 | long nsec, int trylock) | ||
1382 | { | ||
1383 | struct hrtimer_sleeper timeout, *to = NULL; | ||
1384 | struct restart_block *restart; | ||
1385 | int ret; | ||
1386 | |||
1387 | if (sec != MAX_SCHEDULE_TIMEOUT) { | ||
1388 | to = &timeout; | ||
1389 | hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_ABS); | ||
1390 | hrtimer_init_sleeper(to, current); | ||
1391 | to->timer.expires = ktime_set(sec, nsec); | ||
1392 | } | ||
1393 | |||
1394 | ret = do_futex_lock_pi(uaddr, detect, trylock, to); | ||
1395 | |||
1396 | if (ret != -EINTR) | ||
1397 | return ret; | ||
1398 | |||
1399 | pr_debug("lock_pi interrupted: %p, %d (%d)\n", uaddr, current->pid); | ||
1400 | |||
1401 | restart = ¤t_thread_info()->restart_block; | ||
1402 | restart->fn = futex_lock_pi_restart; | ||
1403 | restart->arg0 = (unsigned long) uaddr; | ||
1404 | restart->arg1 = detect; | ||
1405 | if (to) { | ||
1406 | restart->arg2 = to->timer.expires.tv64 & 0xFFFFFFFF; | ||
1407 | restart->arg3 = to->timer.expires.tv64 >> 32; | ||
1408 | } else | ||
1409 | restart->arg2 = restart->arg3 = 0; | ||
1410 | |||
1411 | return -ERESTART_RESTARTBLOCK; | ||
1412 | } | ||
1413 | |||
1414 | /* | ||
1415 | * Userspace attempted a TID -> 0 atomic transition, and failed. | 1353 | * Userspace attempted a TID -> 0 atomic transition, and failed. |
1416 | * This is the in-kernel slowpath: we look up the PI state (if any), | 1354 | * This is the in-kernel slowpath: we look up the PI state (if any), |
1417 | * and do the rt-mutex unlock. | 1355 | * and do the rt-mutex unlock. |