aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/futex.h10
-rw-r--r--include/linux/thread_info.h1
-rw-r--r--kernel/futex.c37
-rw-r--r--kernel/futex_compat.c3
4 files changed, 43 insertions, 8 deletions
diff --git a/include/linux/futex.h b/include/linux/futex.h
index 1a15f8e237a7..90048fb28a38 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -21,6 +21,8 @@ union ktime;
21#define FUTEX_LOCK_PI 6 21#define FUTEX_LOCK_PI 6
22#define FUTEX_UNLOCK_PI 7 22#define FUTEX_UNLOCK_PI 7
23#define FUTEX_TRYLOCK_PI 8 23#define FUTEX_TRYLOCK_PI 8
24#define FUTEX_WAIT_BITSET 9
25#define FUTEX_WAKE_BITSET 10
24 26
25#define FUTEX_PRIVATE_FLAG 128 27#define FUTEX_PRIVATE_FLAG 128
26#define FUTEX_CMD_MASK ~FUTEX_PRIVATE_FLAG 28#define FUTEX_CMD_MASK ~FUTEX_PRIVATE_FLAG
@@ -33,6 +35,8 @@ union ktime;
33#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG) 35#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
34#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) 36#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
35#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG) 37#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
38#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITS | FUTEX_PRIVATE_FLAG)
39#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITS | FUTEX_PRIVATE_FLAG)
36 40
37/* 41/*
38 * Support for robust futexes: the kernel cleans up held futexes at 42 * Support for robust futexes: the kernel cleans up held futexes at
@@ -111,6 +115,12 @@ struct robust_list_head {
111 */ 115 */
112#define ROBUST_LIST_LIMIT 2048 116#define ROBUST_LIST_LIMIT 2048
113 117
118/*
119 * bitset with all bits set for the FUTEX_xxx_BITSET OPs to request a
120 * match of any bit.
121 */
122#define FUTEX_BITSET_MATCH_ANY 0xffffffff
123
114#ifdef __KERNEL__ 124#ifdef __KERNEL__
115long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout, 125long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout,
116 u32 __user *uaddr2, u32 val2, u32 val3); 126 u32 __user *uaddr2, u32 val2, u32 val3);
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index dfbdfb9836f4..421323e5a2d6 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -23,6 +23,7 @@ struct restart_block {
23 u32 *uaddr; 23 u32 *uaddr;
24 u32 val; 24 u32 val;
25 u32 flags; 25 u32 flags;
26 u32 bitset;
26 u64 time; 27 u64 time;
27 } futex; 28 } futex;
28 }; 29 };
diff --git a/kernel/futex.c b/kernel/futex.c
index 0006d64c448e..a6baaec44b8f 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -109,6 +109,9 @@ struct futex_q {
109 /* Optional priority inheritance state: */ 109 /* Optional priority inheritance state: */
110 struct futex_pi_state *pi_state; 110 struct futex_pi_state *pi_state;
111 struct task_struct *task; 111 struct task_struct *task;
112
113 /* Bitset for the optional bitmasked wakeup */
114 u32 bitset;
112}; 115};
113 116
114/* 117/*
@@ -722,7 +725,7 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
722 * to this virtual address: 725 * to this virtual address:
723 */ 726 */
724static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared, 727static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
725 int nr_wake) 728 int nr_wake, u32 bitset)
726{ 729{
727 struct futex_hash_bucket *hb; 730 struct futex_hash_bucket *hb;
728 struct futex_q *this, *next; 731 struct futex_q *this, *next;
@@ -730,6 +733,9 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
730 union futex_key key; 733 union futex_key key;
731 int ret; 734 int ret;
732 735
736 if (!bitset)
737 return -EINVAL;
738
733 futex_lock_mm(fshared); 739 futex_lock_mm(fshared);
734 740
735 ret = get_futex_key(uaddr, fshared, &key); 741 ret = get_futex_key(uaddr, fshared, &key);
@@ -746,6 +752,11 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
746 ret = -EINVAL; 752 ret = -EINVAL;
747 break; 753 break;
748 } 754 }
755
756 /* Check if one of the bits is set in both bitsets */
757 if (!(this->bitset & bitset))
758 continue;
759
749 wake_futex(this); 760 wake_futex(this);
750 if (++ret >= nr_wake) 761 if (++ret >= nr_wake)
751 break; 762 break;
@@ -1156,7 +1167,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
1156static long futex_wait_restart(struct restart_block *restart); 1167static long futex_wait_restart(struct restart_block *restart);
1157 1168
1158static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared, 1169static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
1159 u32 val, ktime_t *abs_time) 1170 u32 val, ktime_t *abs_time, u32 bitset)
1160{ 1171{
1161 struct task_struct *curr = current; 1172 struct task_struct *curr = current;
1162 DECLARE_WAITQUEUE(wait, curr); 1173 DECLARE_WAITQUEUE(wait, curr);
@@ -1167,7 +1178,11 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
1167 struct hrtimer_sleeper t; 1178 struct hrtimer_sleeper t;
1168 int rem = 0; 1179 int rem = 0;
1169 1180
1181 if (!bitset)
1182 return -EINVAL;
1183
1170 q.pi_state = NULL; 1184 q.pi_state = NULL;
1185 q.bitset = bitset;
1171 retry: 1186 retry:
1172 futex_lock_mm(fshared); 1187 futex_lock_mm(fshared);
1173 1188
@@ -1295,6 +1310,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
1295 restart->futex.uaddr = (u32 *)uaddr; 1310 restart->futex.uaddr = (u32 *)uaddr;
1296 restart->futex.val = val; 1311 restart->futex.val = val;
1297 restart->futex.time = abs_time->tv64; 1312 restart->futex.time = abs_time->tv64;
1313 restart->futex.bitset = bitset;
1298 restart->futex.flags = 0; 1314 restart->futex.flags = 0;
1299 1315
1300 if (fshared) 1316 if (fshared)
@@ -1321,7 +1337,8 @@ static long futex_wait_restart(struct restart_block *restart)
1321 restart->fn = do_no_restart_syscall; 1337 restart->fn = do_no_restart_syscall;
1322 if (restart->futex.flags & FLAGS_SHARED) 1338 if (restart->futex.flags & FLAGS_SHARED)
1323 fshared = &current->mm->mmap_sem; 1339 fshared = &current->mm->mmap_sem;
1324 return (long)futex_wait(uaddr, fshared, restart->futex.val, &t); 1340 return (long)futex_wait(uaddr, fshared, restart->futex.val, &t,
1341 restart->futex.bitset);
1325} 1342}
1326 1343
1327 1344
@@ -1942,7 +1959,8 @@ retry:
1942 * PI futexes happens in exit_pi_state(): 1959 * PI futexes happens in exit_pi_state():
1943 */ 1960 */
1944 if (!pi && (uval & FUTEX_WAITERS)) 1961 if (!pi && (uval & FUTEX_WAITERS))
1945 futex_wake(uaddr, &curr->mm->mmap_sem, 1); 1962 futex_wake(uaddr, &curr->mm->mmap_sem, 1,
1963 FUTEX_BITSET_MATCH_ANY);
1946 } 1964 }
1947 return 0; 1965 return 0;
1948} 1966}
@@ -2042,10 +2060,14 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
2042 2060
2043 switch (cmd) { 2061 switch (cmd) {
2044 case FUTEX_WAIT: 2062 case FUTEX_WAIT:
2045 ret = futex_wait(uaddr, fshared, val, timeout); 2063 val3 = FUTEX_BITSET_MATCH_ANY;
2064 case FUTEX_WAIT_BITSET:
2065 ret = futex_wait(uaddr, fshared, val, timeout, val3);
2046 break; 2066 break;
2047 case FUTEX_WAKE: 2067 case FUTEX_WAKE:
2048 ret = futex_wake(uaddr, fshared, val); 2068 val3 = FUTEX_BITSET_MATCH_ANY;
2069 case FUTEX_WAKE_BITSET:
2070 ret = futex_wake(uaddr, fshared, val, val3);
2049 break; 2071 break;
2050 case FUTEX_FD: 2072 case FUTEX_FD:
2051 /* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */ 2073 /* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
@@ -2085,7 +2107,8 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
2085 u32 val2 = 0; 2107 u32 val2 = 0;
2086 int cmd = op & FUTEX_CMD_MASK; 2108 int cmd = op & FUTEX_CMD_MASK;
2087 2109
2088 if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) { 2110 if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
2111 cmd == FUTEX_WAIT_BITSET)) {
2089 if (copy_from_user(&ts, utime, sizeof(ts)) != 0) 2112 if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
2090 return -EFAULT; 2113 return -EFAULT;
2091 if (!timespec_valid(&ts)) 2114 if (!timespec_valid(&ts))
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index 0a43def6fee7..133d558db452 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -167,7 +167,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
167 int val2 = 0; 167 int val2 = 0;
168 int cmd = op & FUTEX_CMD_MASK; 168 int cmd = op & FUTEX_CMD_MASK;
169 169
170 if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) { 170 if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
171 cmd == FUTEX_WAIT_BITSET)) {
171 if (get_compat_timespec(&ts, utime)) 172 if (get_compat_timespec(&ts, utime))
172 return -EFAULT; 173 return -EFAULT;
173 if (!timespec_valid(&ts)) 174 if (!timespec_valid(&ts))