diff options
-rw-r--r-- | include/linux/futex.h | 29 | ||||
-rw-r--r-- | kernel/futex.c | 50 |
2 files changed, 43 insertions, 36 deletions
diff --git a/include/linux/futex.h b/include/linux/futex.h index 3f153b4e156c..820125c628c1 100644 --- a/include/linux/futex.h +++ b/include/linux/futex.h | |||
@@ -100,6 +100,35 @@ long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout, | |||
100 | extern int | 100 | extern int |
101 | handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi); | 101 | handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi); |
102 | 102 | ||
103 | /* | ||
104 | * Futexes are matched on equal values of this key. | ||
105 | * The key type depends on whether it's a shared or private mapping. | ||
106 | * Don't rearrange members without looking at hash_futex(). | ||
107 | * | ||
108 | * offset is aligned to a multiple of sizeof(u32) (== 4) by definition. | ||
109 | * We set bit 0 to indicate if it's an inode-based key. | ||
110 | */ | ||
111 | union futex_key { | ||
112 | struct { | ||
113 | unsigned long pgoff; | ||
114 | struct inode *inode; | ||
115 | int offset; | ||
116 | } shared; | ||
117 | struct { | ||
118 | unsigned long address; | ||
119 | struct mm_struct *mm; | ||
120 | int offset; | ||
121 | } private; | ||
122 | struct { | ||
123 | unsigned long word; | ||
124 | void *ptr; | ||
125 | int offset; | ||
126 | } both; | ||
127 | }; | ||
128 | int get_futex_key(u32 __user *uaddr, union futex_key *key); | ||
129 | void get_futex_key_refs(union futex_key *key); | ||
130 | void drop_futex_key_refs(union futex_key *key); | ||
131 | |||
103 | #ifdef CONFIG_FUTEX | 132 | #ifdef CONFIG_FUTEX |
104 | extern void exit_robust_list(struct task_struct *curr); | 133 | extern void exit_robust_list(struct task_struct *curr); |
105 | extern void exit_pi_state_list(struct task_struct *curr); | 134 | extern void exit_pi_state_list(struct task_struct *curr); |
diff --git a/kernel/futex.c b/kernel/futex.c index 5a270b5e3f95..7ae2f50641ed 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/pagemap.h> | 48 | #include <linux/pagemap.h> |
49 | #include <linux/syscalls.h> | 49 | #include <linux/syscalls.h> |
50 | #include <linux/signal.h> | 50 | #include <linux/signal.h> |
51 | #include <linux/module.h> | ||
51 | #include <asm/futex.h> | 52 | #include <asm/futex.h> |
52 | 53 | ||
53 | #include "rtmutex_common.h" | 54 | #include "rtmutex_common.h" |
@@ -55,32 +56,6 @@ | |||
55 | #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8) | 56 | #define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8) |
56 | 57 | ||
57 | /* | 58 | /* |
58 | * Futexes are matched on equal values of this key. | ||
59 | * The key type depends on whether it's a shared or private mapping. | ||
60 | * Don't rearrange members without looking at hash_futex(). | ||
61 | * | ||
62 | * offset is aligned to a multiple of sizeof(u32) (== 4) by definition. | ||
63 | * We set bit 0 to indicate if it's an inode-based key. | ||
64 | */ | ||
65 | union futex_key { | ||
66 | struct { | ||
67 | unsigned long pgoff; | ||
68 | struct inode *inode; | ||
69 | int offset; | ||
70 | } shared; | ||
71 | struct { | ||
72 | unsigned long address; | ||
73 | struct mm_struct *mm; | ||
74 | int offset; | ||
75 | } private; | ||
76 | struct { | ||
77 | unsigned long word; | ||
78 | void *ptr; | ||
79 | int offset; | ||
80 | } both; | ||
81 | }; | ||
82 | |||
83 | /* | ||
84 | * Priority Inheritance state: | 59 | * Priority Inheritance state: |
85 | */ | 60 | */ |
86 | struct futex_pi_state { | 61 | struct futex_pi_state { |
@@ -175,7 +150,7 @@ static inline int match_futex(union futex_key *key1, union futex_key *key2) | |||
175 | * | 150 | * |
176 | * Should be called with ¤t->mm->mmap_sem but NOT any spinlocks. | 151 | * Should be called with ¤t->mm->mmap_sem but NOT any spinlocks. |
177 | */ | 152 | */ |
178 | static int get_futex_key(u32 __user *uaddr, union futex_key *key) | 153 | int get_futex_key(u32 __user *uaddr, union futex_key *key) |
179 | { | 154 | { |
180 | unsigned long address = (unsigned long)uaddr; | 155 | unsigned long address = (unsigned long)uaddr; |
181 | struct mm_struct *mm = current->mm; | 156 | struct mm_struct *mm = current->mm; |
@@ -246,6 +221,7 @@ static int get_futex_key(u32 __user *uaddr, union futex_key *key) | |||
246 | } | 221 | } |
247 | return err; | 222 | return err; |
248 | } | 223 | } |
224 | EXPORT_SYMBOL_GPL(get_futex_key); | ||
249 | 225 | ||
250 | /* | 226 | /* |
251 | * Take a reference to the resource addressed by a key. | 227 | * Take a reference to the resource addressed by a key. |
@@ -254,7 +230,7 @@ static int get_futex_key(u32 __user *uaddr, union futex_key *key) | |||
254 | * NOTE: mmap_sem MUST be held between get_futex_key() and calling this | 230 | * NOTE: mmap_sem MUST be held between get_futex_key() and calling this |
255 | * function, if it is called at all. mmap_sem keeps key->shared.inode valid. | 231 | * function, if it is called at all. mmap_sem keeps key->shared.inode valid. |
256 | */ | 232 | */ |
257 | static inline void get_key_refs(union futex_key *key) | 233 | inline void get_futex_key_refs(union futex_key *key) |
258 | { | 234 | { |
259 | if (key->both.ptr != 0) { | 235 | if (key->both.ptr != 0) { |
260 | if (key->both.offset & 1) | 236 | if (key->both.offset & 1) |
@@ -263,12 +239,13 @@ static inline void get_key_refs(union futex_key *key) | |||
263 | atomic_inc(&key->private.mm->mm_count); | 239 | atomic_inc(&key->private.mm->mm_count); |
264 | } | 240 | } |
265 | } | 241 | } |
242 | EXPORT_SYMBOL_GPL(get_futex_key_refs); | ||
266 | 243 | ||
267 | /* | 244 | /* |
268 | * Drop a reference to the resource addressed by a key. | 245 | * Drop a reference to the resource addressed by a key. |
269 | * The hash bucket spinlock must not be held. | 246 | * The hash bucket spinlock must not be held. |
270 | */ | 247 | */ |
271 | static void drop_key_refs(union futex_key *key) | 248 | void drop_futex_key_refs(union futex_key *key) |
272 | { | 249 | { |
273 | if (key->both.ptr != 0) { | 250 | if (key->both.ptr != 0) { |
274 | if (key->both.offset & 1) | 251 | if (key->both.offset & 1) |
@@ -277,6 +254,7 @@ static void drop_key_refs(union futex_key *key) | |||
277 | mmdrop(key->private.mm); | 254 | mmdrop(key->private.mm); |
278 | } | 255 | } |
279 | } | 256 | } |
257 | EXPORT_SYMBOL_GPL(drop_futex_key_refs); | ||
280 | 258 | ||
281 | static inline int get_futex_value_locked(u32 *dest, u32 __user *from) | 259 | static inline int get_futex_value_locked(u32 *dest, u32 __user *from) |
282 | { | 260 | { |
@@ -873,7 +851,7 @@ static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2, | |||
873 | this->lock_ptr = &hb2->lock; | 851 | this->lock_ptr = &hb2->lock; |
874 | } | 852 | } |
875 | this->key = key2; | 853 | this->key = key2; |
876 | get_key_refs(&key2); | 854 | get_futex_key_refs(&key2); |
877 | drop_count++; | 855 | drop_count++; |
878 | 856 | ||
879 | if (ret - nr_wake >= nr_requeue) | 857 | if (ret - nr_wake >= nr_requeue) |
@@ -886,9 +864,9 @@ out_unlock: | |||
886 | if (hb1 != hb2) | 864 | if (hb1 != hb2) |
887 | spin_unlock(&hb2->lock); | 865 | spin_unlock(&hb2->lock); |
888 | 866 | ||
889 | /* drop_key_refs() must be called outside the spinlocks. */ | 867 | /* drop_futex_key_refs() must be called outside the spinlocks. */ |
890 | while (--drop_count >= 0) | 868 | while (--drop_count >= 0) |
891 | drop_key_refs(&key1); | 869 | drop_futex_key_refs(&key1); |
892 | 870 | ||
893 | out: | 871 | out: |
894 | up_read(¤t->mm->mmap_sem); | 872 | up_read(¤t->mm->mmap_sem); |
@@ -906,7 +884,7 @@ queue_lock(struct futex_q *q, int fd, struct file *filp) | |||
906 | 884 | ||
907 | init_waitqueue_head(&q->waiters); | 885 | init_waitqueue_head(&q->waiters); |
908 | 886 | ||
909 | get_key_refs(&q->key); | 887 | get_futex_key_refs(&q->key); |
910 | hb = hash_futex(&q->key); | 888 | hb = hash_futex(&q->key); |
911 | q->lock_ptr = &hb->lock; | 889 | q->lock_ptr = &hb->lock; |
912 | 890 | ||
@@ -925,7 +903,7 @@ static inline void | |||
925 | queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb) | 903 | queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb) |
926 | { | 904 | { |
927 | spin_unlock(&hb->lock); | 905 | spin_unlock(&hb->lock); |
928 | drop_key_refs(&q->key); | 906 | drop_futex_key_refs(&q->key); |
929 | } | 907 | } |
930 | 908 | ||
931 | /* | 909 | /* |
@@ -980,7 +958,7 @@ static int unqueue_me(struct futex_q *q) | |||
980 | ret = 1; | 958 | ret = 1; |
981 | } | 959 | } |
982 | 960 | ||
983 | drop_key_refs(&q->key); | 961 | drop_futex_key_refs(&q->key); |
984 | return ret; | 962 | return ret; |
985 | } | 963 | } |
986 | 964 | ||
@@ -999,7 +977,7 @@ static void unqueue_me_pi(struct futex_q *q, struct futex_hash_bucket *hb) | |||
999 | 977 | ||
1000 | spin_unlock(&hb->lock); | 978 | spin_unlock(&hb->lock); |
1001 | 979 | ||
1002 | drop_key_refs(&q->key); | 980 | drop_futex_key_refs(&q->key); |
1003 | } | 981 | } |
1004 | 982 | ||
1005 | static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time) | 983 | static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time) |