aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/futex.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/futex.c')
-rw-r--r--kernel/futex.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/kernel/futex.c b/kernel/futex.c
index 157bfcd725b8..476603afd147 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -199,6 +199,7 @@ static void drop_futex_key_refs(union futex_key *key)
199 * @uaddr: virtual address of the futex 199 * @uaddr: virtual address of the futex
200 * @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED 200 * @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED
201 * @key: address where result is stored. 201 * @key: address where result is stored.
202 * @rw: mapping needs to be read/write (values: VERIFY_READ, VERIFY_WRITE)
202 * 203 *
203 * Returns a negative error code or 0 204 * Returns a negative error code or 0
204 * The key words are stored in *key on success. 205 * The key words are stored in *key on success.
@@ -209,7 +210,8 @@ static void drop_futex_key_refs(union futex_key *key)
209 * 210 *
210 * lock_page() might sleep, the caller should not hold a spinlock. 211 * lock_page() might sleep, the caller should not hold a spinlock.
211 */ 212 */
212static int get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) 213static int
214get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
213{ 215{
214 unsigned long address = (unsigned long)uaddr; 216 unsigned long address = (unsigned long)uaddr;
215 struct mm_struct *mm = current->mm; 217 struct mm_struct *mm = current->mm;
@@ -232,7 +234,7 @@ static int get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
232 * but access_ok() should be faster than find_vma() 234 * but access_ok() should be faster than find_vma()
233 */ 235 */
234 if (!fshared) { 236 if (!fshared) {
235 if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))) 237 if (unlikely(!access_ok(rw, uaddr, sizeof(u32))))
236 return -EFAULT; 238 return -EFAULT;
237 key->private.mm = mm; 239 key->private.mm = mm;
238 key->private.address = address; 240 key->private.address = address;
@@ -241,7 +243,7 @@ static int get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
241 } 243 }
242 244
243again: 245again:
244 err = get_user_pages_fast(address, 1, 0, &page); 246 err = get_user_pages_fast(address, 1, rw == VERIFY_WRITE, &page);
245 if (err < 0) 247 if (err < 0)
246 return err; 248 return err;
247 249
@@ -834,7 +836,7 @@ static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset)
834 if (!bitset) 836 if (!bitset)
835 return -EINVAL; 837 return -EINVAL;
836 838
837 ret = get_futex_key(uaddr, fshared, &key); 839 ret = get_futex_key(uaddr, fshared, &key, VERIFY_READ);
838 if (unlikely(ret != 0)) 840 if (unlikely(ret != 0))
839 goto out; 841 goto out;
840 842
@@ -880,10 +882,10 @@ futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
880 int ret, op_ret; 882 int ret, op_ret;
881 883
882retry: 884retry:
883 ret = get_futex_key(uaddr1, fshared, &key1); 885 ret = get_futex_key(uaddr1, fshared, &key1, VERIFY_READ);
884 if (unlikely(ret != 0)) 886 if (unlikely(ret != 0))
885 goto out; 887 goto out;
886 ret = get_futex_key(uaddr2, fshared, &key2); 888 ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
887 if (unlikely(ret != 0)) 889 if (unlikely(ret != 0))
888 goto out_put_key1; 890 goto out_put_key1;
889 891
@@ -1131,10 +1133,11 @@ retry:
1131 pi_state = NULL; 1133 pi_state = NULL;
1132 } 1134 }
1133 1135
1134 ret = get_futex_key(uaddr1, fshared, &key1); 1136 ret = get_futex_key(uaddr1, fshared, &key1, VERIFY_READ);
1135 if (unlikely(ret != 0)) 1137 if (unlikely(ret != 0))
1136 goto out; 1138 goto out;
1137 ret = get_futex_key(uaddr2, fshared, &key2); 1139 ret = get_futex_key(uaddr2, fshared, &key2,
1140 requeue_pi ? VERIFY_WRITE : VERIFY_READ);
1138 if (unlikely(ret != 0)) 1141 if (unlikely(ret != 0))
1139 goto out_put_key1; 1142 goto out_put_key1;
1140 1143
@@ -1267,7 +1270,12 @@ retry_private:
1267out_unlock: 1270out_unlock:
1268 double_unlock_hb(hb1, hb2); 1271 double_unlock_hb(hb1, hb2);
1269 1272
1270 /* drop_futex_key_refs() must be called outside the spinlocks. */ 1273 /*
1274 * drop_futex_key_refs() must be called outside the spinlocks. During
1275 * the requeue we moved futex_q's from the hash bucket at key1 to the
1276 * one at key2 and updated their key pointer. We no longer need to
1277 * hold the references to key1.
1278 */
1271 while (--drop_count >= 0) 1279 while (--drop_count >= 0)
1272 drop_futex_key_refs(&key1); 1280 drop_futex_key_refs(&key1);
1273 1281
@@ -1660,7 +1668,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, int fshared,
1660 */ 1668 */
1661retry: 1669retry:
1662 q->key = FUTEX_KEY_INIT; 1670 q->key = FUTEX_KEY_INIT;
1663 ret = get_futex_key(uaddr, fshared, &q->key); 1671 ret = get_futex_key(uaddr, fshared, &q->key, VERIFY_READ);
1664 if (unlikely(ret != 0)) 1672 if (unlikely(ret != 0))
1665 return ret; 1673 return ret;
1666 1674
@@ -1819,7 +1827,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared,
1819 q.rt_waiter = NULL; 1827 q.rt_waiter = NULL;
1820retry: 1828retry:
1821 q.key = FUTEX_KEY_INIT; 1829 q.key = FUTEX_KEY_INIT;
1822 ret = get_futex_key(uaddr, fshared, &q.key); 1830 ret = get_futex_key(uaddr, fshared, &q.key, VERIFY_WRITE);
1823 if (unlikely(ret != 0)) 1831 if (unlikely(ret != 0))
1824 goto out; 1832 goto out;
1825 1833
@@ -1960,7 +1968,7 @@ retry:
1960 if ((uval & FUTEX_TID_MASK) != task_pid_vnr(current)) 1968 if ((uval & FUTEX_TID_MASK) != task_pid_vnr(current))
1961 return -EPERM; 1969 return -EPERM;
1962 1970
1963 ret = get_futex_key(uaddr, fshared, &key); 1971 ret = get_futex_key(uaddr, fshared, &key, VERIFY_WRITE);
1964 if (unlikely(ret != 0)) 1972 if (unlikely(ret != 0))
1965 goto out; 1973 goto out;
1966 1974
@@ -2171,7 +2179,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
2171 q.rt_waiter = &rt_waiter; 2179 q.rt_waiter = &rt_waiter;
2172 2180
2173 key2 = FUTEX_KEY_INIT; 2181 key2 = FUTEX_KEY_INIT;
2174 ret = get_futex_key(uaddr2, fshared, &key2); 2182 ret = get_futex_key(uaddr2, fshared, &key2, VERIFY_WRITE);
2175 if (unlikely(ret != 0)) 2183 if (unlikely(ret != 0))
2176 goto out; 2184 goto out;
2177 2185