diff options
-rw-r--r-- | include/linux/futex.h | 10 | ||||
-rw-r--r-- | include/linux/thread_info.h | 1 | ||||
-rw-r--r-- | kernel/futex.c | 37 | ||||
-rw-r--r-- | kernel/futex_compat.c | 3 |
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__ |
115 | long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout, | 125 | long 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 | */ |
724 | static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared, | 727 | static 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, | |||
1156 | static long futex_wait_restart(struct restart_block *restart); | 1167 | static long futex_wait_restart(struct restart_block *restart); |
1157 | 1168 | ||
1158 | static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared, | 1169 | static 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 = ¤t->mm->mmap_sem; | 1339 | fshared = ¤t->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)) |