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. |
