diff options
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 83 |
1 files changed, 49 insertions, 34 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index b911adceb2c4..8e3c3ffe1b9a 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -150,7 +150,8 @@ static struct futex_hash_bucket *hash_futex(union futex_key *key) | |||
150 | */ | 150 | */ |
151 | static inline int match_futex(union futex_key *key1, union futex_key *key2) | 151 | static inline int match_futex(union futex_key *key1, union futex_key *key2) |
152 | { | 152 | { |
153 | return (key1->both.word == key2->both.word | 153 | return (key1 && key2 |
154 | && key1->both.word == key2->both.word | ||
154 | && key1->both.ptr == key2->both.ptr | 155 | && key1->both.ptr == key2->both.ptr |
155 | && key1->both.offset == key2->both.offset); | 156 | && key1->both.offset == key2->both.offset); |
156 | } | 157 | } |
@@ -303,8 +304,14 @@ void put_futex_key(int fshared, union futex_key *key) | |||
303 | */ | 304 | */ |
304 | static int fault_in_user_writeable(u32 __user *uaddr) | 305 | static int fault_in_user_writeable(u32 __user *uaddr) |
305 | { | 306 | { |
306 | int ret = get_user_pages(current, current->mm, (unsigned long)uaddr, | 307 | struct mm_struct *mm = current->mm; |
307 | 1, 1, 0, NULL, NULL); | 308 | int ret; |
309 | |||
310 | down_read(&mm->mmap_sem); | ||
311 | ret = get_user_pages(current, mm, (unsigned long)uaddr, | ||
312 | 1, 1, 0, NULL, NULL); | ||
313 | up_read(&mm->mmap_sem); | ||
314 | |||
308 | return ret < 0 ? ret : 0; | 315 | return ret < 0 ? ret : 0; |
309 | } | 316 | } |
310 | 317 | ||
@@ -396,9 +403,9 @@ static void free_pi_state(struct futex_pi_state *pi_state) | |||
396 | * and has cleaned up the pi_state already | 403 | * and has cleaned up the pi_state already |
397 | */ | 404 | */ |
398 | if (pi_state->owner) { | 405 | if (pi_state->owner) { |
399 | spin_lock_irq(&pi_state->owner->pi_lock); | 406 | raw_spin_lock_irq(&pi_state->owner->pi_lock); |
400 | list_del_init(&pi_state->list); | 407 | list_del_init(&pi_state->list); |
401 | spin_unlock_irq(&pi_state->owner->pi_lock); | 408 | raw_spin_unlock_irq(&pi_state->owner->pi_lock); |
402 | 409 | ||
403 | rt_mutex_proxy_unlock(&pi_state->pi_mutex, pi_state->owner); | 410 | rt_mutex_proxy_unlock(&pi_state->pi_mutex, pi_state->owner); |
404 | } | 411 | } |
@@ -463,18 +470,18 @@ void exit_pi_state_list(struct task_struct *curr) | |||
463 | * pi_state_list anymore, but we have to be careful | 470 | * pi_state_list anymore, but we have to be careful |
464 | * versus waiters unqueueing themselves: | 471 | * versus waiters unqueueing themselves: |
465 | */ | 472 | */ |
466 | spin_lock_irq(&curr->pi_lock); | 473 | raw_spin_lock_irq(&curr->pi_lock); |
467 | while (!list_empty(head)) { | 474 | while (!list_empty(head)) { |
468 | 475 | ||
469 | next = head->next; | 476 | next = head->next; |
470 | pi_state = list_entry(next, struct futex_pi_state, list); | 477 | pi_state = list_entry(next, struct futex_pi_state, list); |
471 | key = pi_state->key; | 478 | key = pi_state->key; |
472 | hb = hash_futex(&key); | 479 | hb = hash_futex(&key); |
473 | spin_unlock_irq(&curr->pi_lock); | 480 | raw_spin_unlock_irq(&curr->pi_lock); |
474 | 481 | ||
475 | spin_lock(&hb->lock); | 482 | spin_lock(&hb->lock); |
476 | 483 | ||
477 | spin_lock_irq(&curr->pi_lock); | 484 | raw_spin_lock_irq(&curr->pi_lock); |
478 | /* | 485 | /* |
479 | * We dropped the pi-lock, so re-check whether this | 486 | * We dropped the pi-lock, so re-check whether this |
480 | * task still owns the PI-state: | 487 | * task still owns the PI-state: |
@@ -488,15 +495,15 @@ void exit_pi_state_list(struct task_struct *curr) | |||
488 | WARN_ON(list_empty(&pi_state->list)); | 495 | WARN_ON(list_empty(&pi_state->list)); |
489 | list_del_init(&pi_state->list); | 496 | list_del_init(&pi_state->list); |
490 | pi_state->owner = NULL; | 497 | pi_state->owner = NULL; |
491 | spin_unlock_irq(&curr->pi_lock); | 498 | raw_spin_unlock_irq(&curr->pi_lock); |
492 | 499 | ||
493 | rt_mutex_unlock(&pi_state->pi_mutex); | 500 | rt_mutex_unlock(&pi_state->pi_mutex); |
494 | 501 | ||
495 | spin_unlock(&hb->lock); | 502 | spin_unlock(&hb->lock); |
496 | 503 | ||
497 | spin_lock_irq(&curr->pi_lock); | 504 | raw_spin_lock_irq(&curr->pi_lock); |
498 | } | 505 | } |
499 | spin_unlock_irq(&curr->pi_lock); | 506 | raw_spin_unlock_irq(&curr->pi_lock); |
500 | } | 507 | } |
501 | 508 | ||
502 | static int | 509 | static int |
@@ -551,7 +558,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, | |||
551 | * change of the task flags, we do this protected by | 558 | * change of the task flags, we do this protected by |
552 | * p->pi_lock: | 559 | * p->pi_lock: |
553 | */ | 560 | */ |
554 | spin_lock_irq(&p->pi_lock); | 561 | raw_spin_lock_irq(&p->pi_lock); |
555 | if (unlikely(p->flags & PF_EXITING)) { | 562 | if (unlikely(p->flags & PF_EXITING)) { |
556 | /* | 563 | /* |
557 | * The task is on the way out. When PF_EXITPIDONE is | 564 | * The task is on the way out. When PF_EXITPIDONE is |
@@ -560,7 +567,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, | |||
560 | */ | 567 | */ |
561 | int ret = (p->flags & PF_EXITPIDONE) ? -ESRCH : -EAGAIN; | 568 | int ret = (p->flags & PF_EXITPIDONE) ? -ESRCH : -EAGAIN; |
562 | 569 | ||
563 | spin_unlock_irq(&p->pi_lock); | 570 | raw_spin_unlock_irq(&p->pi_lock); |
564 | put_task_struct(p); | 571 | put_task_struct(p); |
565 | return ret; | 572 | return ret; |
566 | } | 573 | } |
@@ -579,7 +586,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, | |||
579 | WARN_ON(!list_empty(&pi_state->list)); | 586 | WARN_ON(!list_empty(&pi_state->list)); |
580 | list_add(&pi_state->list, &p->pi_state_list); | 587 | list_add(&pi_state->list, &p->pi_state_list); |
581 | pi_state->owner = p; | 588 | pi_state->owner = p; |
582 | spin_unlock_irq(&p->pi_lock); | 589 | raw_spin_unlock_irq(&p->pi_lock); |
583 | 590 | ||
584 | put_task_struct(p); | 591 | put_task_struct(p); |
585 | 592 | ||
@@ -753,7 +760,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) | |||
753 | if (!pi_state) | 760 | if (!pi_state) |
754 | return -EINVAL; | 761 | return -EINVAL; |
755 | 762 | ||
756 | spin_lock(&pi_state->pi_mutex.wait_lock); | 763 | raw_spin_lock(&pi_state->pi_mutex.wait_lock); |
757 | new_owner = rt_mutex_next_owner(&pi_state->pi_mutex); | 764 | new_owner = rt_mutex_next_owner(&pi_state->pi_mutex); |
758 | 765 | ||
759 | /* | 766 | /* |
@@ -782,23 +789,23 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) | |||
782 | else if (curval != uval) | 789 | else if (curval != uval) |
783 | ret = -EINVAL; | 790 | ret = -EINVAL; |
784 | if (ret) { | 791 | if (ret) { |
785 | spin_unlock(&pi_state->pi_mutex.wait_lock); | 792 | raw_spin_unlock(&pi_state->pi_mutex.wait_lock); |
786 | return ret; | 793 | return ret; |
787 | } | 794 | } |
788 | } | 795 | } |
789 | 796 | ||
790 | spin_lock_irq(&pi_state->owner->pi_lock); | 797 | raw_spin_lock_irq(&pi_state->owner->pi_lock); |
791 | WARN_ON(list_empty(&pi_state->list)); | 798 | WARN_ON(list_empty(&pi_state->list)); |
792 | list_del_init(&pi_state->list); | 799 | list_del_init(&pi_state->list); |
793 | spin_unlock_irq(&pi_state->owner->pi_lock); | 800 | raw_spin_unlock_irq(&pi_state->owner->pi_lock); |
794 | 801 | ||
795 | spin_lock_irq(&new_owner->pi_lock); | 802 | raw_spin_lock_irq(&new_owner->pi_lock); |
796 | WARN_ON(!list_empty(&pi_state->list)); | 803 | WARN_ON(!list_empty(&pi_state->list)); |
797 | list_add(&pi_state->list, &new_owner->pi_state_list); | 804 | list_add(&pi_state->list, &new_owner->pi_state_list); |
798 | pi_state->owner = new_owner; | 805 | pi_state->owner = new_owner; |
799 | spin_unlock_irq(&new_owner->pi_lock); | 806 | raw_spin_unlock_irq(&new_owner->pi_lock); |
800 | 807 | ||
801 | spin_unlock(&pi_state->pi_mutex.wait_lock); | 808 | raw_spin_unlock(&pi_state->pi_mutex.wait_lock); |
802 | rt_mutex_unlock(&pi_state->pi_mutex); | 809 | rt_mutex_unlock(&pi_state->pi_mutex); |
803 | 810 | ||
804 | return 0; | 811 | return 0; |
@@ -916,8 +923,8 @@ retry: | |||
916 | hb1 = hash_futex(&key1); | 923 | hb1 = hash_futex(&key1); |
917 | hb2 = hash_futex(&key2); | 924 | hb2 = hash_futex(&key2); |
918 | 925 | ||
919 | double_lock_hb(hb1, hb2); | ||
920 | retry_private: | 926 | retry_private: |
927 | double_lock_hb(hb1, hb2); | ||
921 | op_ret = futex_atomic_op_inuser(op, uaddr2); | 928 | op_ret = futex_atomic_op_inuser(op, uaddr2); |
922 | if (unlikely(op_ret < 0)) { | 929 | if (unlikely(op_ret < 0)) { |
923 | 930 | ||
@@ -1003,7 +1010,7 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1, | |||
1003 | plist_add(&q->list, &hb2->chain); | 1010 | plist_add(&q->list, &hb2->chain); |
1004 | q->lock_ptr = &hb2->lock; | 1011 | q->lock_ptr = &hb2->lock; |
1005 | #ifdef CONFIG_DEBUG_PI_LIST | 1012 | #ifdef CONFIG_DEBUG_PI_LIST |
1006 | q->list.plist.lock = &hb2->lock; | 1013 | q->list.plist.spinlock = &hb2->lock; |
1007 | #endif | 1014 | #endif |
1008 | } | 1015 | } |
1009 | get_futex_key_refs(key2); | 1016 | get_futex_key_refs(key2); |
@@ -1028,7 +1035,6 @@ static inline | |||
1028 | void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, | 1035 | void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, |
1029 | struct futex_hash_bucket *hb) | 1036 | struct futex_hash_bucket *hb) |
1030 | { | 1037 | { |
1031 | drop_futex_key_refs(&q->key); | ||
1032 | get_futex_key_refs(key); | 1038 | get_futex_key_refs(key); |
1033 | q->key = *key; | 1039 | q->key = *key; |
1034 | 1040 | ||
@@ -1040,7 +1046,7 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, | |||
1040 | 1046 | ||
1041 | q->lock_ptr = &hb->lock; | 1047 | q->lock_ptr = &hb->lock; |
1042 | #ifdef CONFIG_DEBUG_PI_LIST | 1048 | #ifdef CONFIG_DEBUG_PI_LIST |
1043 | q->list.plist.lock = &hb->lock; | 1049 | q->list.plist.spinlock = &hb->lock; |
1044 | #endif | 1050 | #endif |
1045 | 1051 | ||
1046 | wake_up_state(q->task, TASK_NORMAL); | 1052 | wake_up_state(q->task, TASK_NORMAL); |
@@ -1226,6 +1232,7 @@ retry_private: | |||
1226 | */ | 1232 | */ |
1227 | if (ret == 1) { | 1233 | if (ret == 1) { |
1228 | WARN_ON(pi_state); | 1234 | WARN_ON(pi_state); |
1235 | drop_count++; | ||
1229 | task_count++; | 1236 | task_count++; |
1230 | ret = get_futex_value_locked(&curval2, uaddr2); | 1237 | ret = get_futex_value_locked(&curval2, uaddr2); |
1231 | if (!ret) | 1238 | if (!ret) |
@@ -1304,6 +1311,7 @@ retry_private: | |||
1304 | if (ret == 1) { | 1311 | if (ret == 1) { |
1305 | /* We got the lock. */ | 1312 | /* We got the lock. */ |
1306 | requeue_pi_wake_futex(this, &key2, hb2); | 1313 | requeue_pi_wake_futex(this, &key2, hb2); |
1314 | drop_count++; | ||
1307 | continue; | 1315 | continue; |
1308 | } else if (ret) { | 1316 | } else if (ret) { |
1309 | /* -EDEADLK */ | 1317 | /* -EDEADLK */ |
@@ -1386,7 +1394,7 @@ static inline void queue_me(struct futex_q *q, struct futex_hash_bucket *hb) | |||
1386 | 1394 | ||
1387 | plist_node_init(&q->list, prio); | 1395 | plist_node_init(&q->list, prio); |
1388 | #ifdef CONFIG_DEBUG_PI_LIST | 1396 | #ifdef CONFIG_DEBUG_PI_LIST |
1389 | q->list.plist.lock = &hb->lock; | 1397 | q->list.plist.spinlock = &hb->lock; |
1390 | #endif | 1398 | #endif |
1391 | plist_add(&q->list, &hb->chain); | 1399 | plist_add(&q->list, &hb->chain); |
1392 | q->task = current; | 1400 | q->task = current; |
@@ -1521,18 +1529,18 @@ retry: | |||
1521 | * itself. | 1529 | * itself. |
1522 | */ | 1530 | */ |
1523 | if (pi_state->owner != NULL) { | 1531 | if (pi_state->owner != NULL) { |
1524 | spin_lock_irq(&pi_state->owner->pi_lock); | 1532 | raw_spin_lock_irq(&pi_state->owner->pi_lock); |
1525 | WARN_ON(list_empty(&pi_state->list)); | 1533 | WARN_ON(list_empty(&pi_state->list)); |
1526 | list_del_init(&pi_state->list); | 1534 | list_del_init(&pi_state->list); |
1527 | spin_unlock_irq(&pi_state->owner->pi_lock); | 1535 | raw_spin_unlock_irq(&pi_state->owner->pi_lock); |
1528 | } | 1536 | } |
1529 | 1537 | ||
1530 | pi_state->owner = newowner; | 1538 | pi_state->owner = newowner; |
1531 | 1539 | ||
1532 | spin_lock_irq(&newowner->pi_lock); | 1540 | raw_spin_lock_irq(&newowner->pi_lock); |
1533 | WARN_ON(!list_empty(&pi_state->list)); | 1541 | WARN_ON(!list_empty(&pi_state->list)); |
1534 | list_add(&pi_state->list, &newowner->pi_state_list); | 1542 | list_add(&pi_state->list, &newowner->pi_state_list); |
1535 | spin_unlock_irq(&newowner->pi_lock); | 1543 | raw_spin_unlock_irq(&newowner->pi_lock); |
1536 | return 0; | 1544 | return 0; |
1537 | 1545 | ||
1538 | /* | 1546 | /* |
@@ -1791,6 +1799,7 @@ static int futex_wait(u32 __user *uaddr, int fshared, | |||
1791 | current->timer_slack_ns); | 1799 | current->timer_slack_ns); |
1792 | } | 1800 | } |
1793 | 1801 | ||
1802 | retry: | ||
1794 | /* Prepare to wait on uaddr. */ | 1803 | /* Prepare to wait on uaddr. */ |
1795 | ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); | 1804 | ret = futex_wait_setup(uaddr, val, fshared, &q, &hb); |
1796 | if (ret) | 1805 | if (ret) |
@@ -1808,9 +1817,14 @@ static int futex_wait(u32 __user *uaddr, int fshared, | |||
1808 | goto out_put_key; | 1817 | goto out_put_key; |
1809 | 1818 | ||
1810 | /* | 1819 | /* |
1811 | * We expect signal_pending(current), but another thread may | 1820 | * We expect signal_pending(current), but we might be the |
1812 | * have handled it for us already. | 1821 | * victim of a spurious wakeup as well. |
1813 | */ | 1822 | */ |
1823 | if (!signal_pending(current)) { | ||
1824 | put_futex_key(fshared, &q.key); | ||
1825 | goto retry; | ||
1826 | } | ||
1827 | |||
1814 | ret = -ERESTARTSYS; | 1828 | ret = -ERESTARTSYS; |
1815 | if (!abs_time) | 1829 | if (!abs_time) |
1816 | goto out_put_key; | 1830 | goto out_put_key; |
@@ -2117,11 +2131,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, | |||
2117 | * Unqueue the futex_q and determine which it was. | 2131 | * Unqueue the futex_q and determine which it was. |
2118 | */ | 2132 | */ |
2119 | plist_del(&q->list, &q->list.plist); | 2133 | plist_del(&q->list, &q->list.plist); |
2120 | drop_futex_key_refs(&q->key); | ||
2121 | 2134 | ||
2135 | /* Handle spurious wakeups gracefully */ | ||
2136 | ret = -EWOULDBLOCK; | ||
2122 | if (timeout && !timeout->task) | 2137 | if (timeout && !timeout->task) |
2123 | ret = -ETIMEDOUT; | 2138 | ret = -ETIMEDOUT; |
2124 | else | 2139 | else if (signal_pending(current)) |
2125 | ret = -ERESTARTNOINTR; | 2140 | ret = -ERESTARTNOINTR; |
2126 | } | 2141 | } |
2127 | return ret; | 2142 | return ret; |