diff options
author | Lai Jiangshan <laijs@cn.fujitsu.com> | 2010-12-22 01:18:50 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2011-03-11 15:09:52 -0500 |
commit | 2e12978a9f7a7abd54e8eb9ce70a7718767b8b2c (patch) | |
tree | eb4f298e084b5bcc4922511237cd6ce2e158abdd /kernel/futex.c | |
parent | a5abba989deceb731047425812d268daf7536575 (diff) |
futex,plist: Pass the real head of the priority list to plist_del()
Some plist_del()s in kernel/futex.c are passed a faked head of the
priority list.
It does not fail because the current code does not require the real head
in plist_del(). The current code of plist_del() just uses the head for checking,
so it will not cause a bad result even when we use a faked head.
But it is undocumented usage:
/**
* plist_del - Remove a @node from plist.
*
* @node: &struct plist_node pointer - entry to be removed
* @head: &struct plist_head pointer - list head
*/
The document says that the @head is the "list head" head of the priority list.
In futex code, several places use "plist_del(&q->list, &q->list.plist);",
they pass a fake head. We need to fix them all.
Thanks to Darren Hart for many suggestions.
Acked-by: Darren Hart <dvhart@linux.intel.com>
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
LKML-Reference: <4D11984A.5030203@cn.fujitsu.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index b766d28accd6..6feeea4f8f15 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -775,6 +775,24 @@ retry: | |||
775 | return ret; | 775 | return ret; |
776 | } | 776 | } |
777 | 777 | ||
778 | /** | ||
779 | * __unqueue_futex() - Remove the futex_q from its futex_hash_bucket | ||
780 | * @q: The futex_q to unqueue | ||
781 | * | ||
782 | * The q->lock_ptr must not be NULL and must be held by the caller. | ||
783 | */ | ||
784 | static void __unqueue_futex(struct futex_q *q) | ||
785 | { | ||
786 | struct futex_hash_bucket *hb; | ||
787 | |||
788 | if (WARN_ON(!q->lock_ptr || !spin_is_locked(q->lock_ptr) | ||
789 | || plist_node_empty(&q->list))) | ||
790 | return; | ||
791 | |||
792 | hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock); | ||
793 | plist_del(&q->list, &hb->chain); | ||
794 | } | ||
795 | |||
778 | /* | 796 | /* |
779 | * The hash bucket lock must be held when this is called. | 797 | * The hash bucket lock must be held when this is called. |
780 | * Afterwards, the futex_q must not be accessed. | 798 | * Afterwards, the futex_q must not be accessed. |
@@ -792,7 +810,7 @@ static void wake_futex(struct futex_q *q) | |||
792 | */ | 810 | */ |
793 | get_task_struct(p); | 811 | get_task_struct(p); |
794 | 812 | ||
795 | plist_del(&q->list, &q->list.plist); | 813 | __unqueue_futex(q); |
796 | /* | 814 | /* |
797 | * The waiting task can free the futex_q as soon as | 815 | * The waiting task can free the futex_q as soon as |
798 | * q->lock_ptr = NULL is written, without taking any locks. A | 816 | * q->lock_ptr = NULL is written, without taking any locks. A |
@@ -1100,8 +1118,7 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, | |||
1100 | get_futex_key_refs(key); | 1118 | get_futex_key_refs(key); |
1101 | q->key = *key; | 1119 | q->key = *key; |
1102 | 1120 | ||
1103 | WARN_ON(plist_node_empty(&q->list)); | 1121 | __unqueue_futex(q); |
1104 | plist_del(&q->list, &q->list.plist); | ||
1105 | 1122 | ||
1106 | WARN_ON(!q->rt_waiter); | 1123 | WARN_ON(!q->rt_waiter); |
1107 | q->rt_waiter = NULL; | 1124 | q->rt_waiter = NULL; |
@@ -1504,8 +1521,7 @@ retry: | |||
1504 | spin_unlock(lock_ptr); | 1521 | spin_unlock(lock_ptr); |
1505 | goto retry; | 1522 | goto retry; |
1506 | } | 1523 | } |
1507 | WARN_ON(plist_node_empty(&q->list)); | 1524 | __unqueue_futex(q); |
1508 | plist_del(&q->list, &q->list.plist); | ||
1509 | 1525 | ||
1510 | BUG_ON(q->pi_state); | 1526 | BUG_ON(q->pi_state); |
1511 | 1527 | ||
@@ -1525,8 +1541,7 @@ retry: | |||
1525 | static void unqueue_me_pi(struct futex_q *q) | 1541 | static void unqueue_me_pi(struct futex_q *q) |
1526 | __releases(q->lock_ptr) | 1542 | __releases(q->lock_ptr) |
1527 | { | 1543 | { |
1528 | WARN_ON(plist_node_empty(&q->list)); | 1544 | __unqueue_futex(q); |
1529 | plist_del(&q->list, &q->list.plist); | ||
1530 | 1545 | ||
1531 | BUG_ON(!q->pi_state); | 1546 | BUG_ON(!q->pi_state); |
1532 | free_pi_state(q->pi_state); | 1547 | free_pi_state(q->pi_state); |
@@ -2167,7 +2182,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, | |||
2167 | * We were woken prior to requeue by a timeout or a signal. | 2182 | * We were woken prior to requeue by a timeout or a signal. |
2168 | * Unqueue the futex_q and determine which it was. | 2183 | * Unqueue the futex_q and determine which it was. |
2169 | */ | 2184 | */ |
2170 | plist_del(&q->list, &q->list.plist); | 2185 | plist_del(&q->list, &hb->chain); |
2171 | 2186 | ||
2172 | /* Handle spurious wakeups gracefully */ | 2187 | /* Handle spurious wakeups gracefully */ |
2173 | ret = -EWOULDBLOCK; | 2188 | ret = -EWOULDBLOCK; |