@@ -142,6 +142,7 @@ static __always_inline bool futex_cmd_has_timeout(u32 cmd)
142
142
case FUTEX_LOCK_PI2 :
143
143
case FUTEX_WAIT_BITSET :
144
144
case FUTEX_WAIT_REQUEUE_PI :
145
+ case FUTEX_WAIT_MULTIPLE :
145
146
return true;
146
147
}
147
148
return false;
@@ -154,13 +155,79 @@ futex_init_timeout(u32 cmd, u32 op, struct timespec64 *ts, ktime_t *t)
154
155
return - EINVAL ;
155
156
156
157
* t = timespec64_to_ktime (* ts );
157
- if (cmd == FUTEX_WAIT )
158
+ if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_MULTIPLE )
158
159
* t = ktime_add_safe (ktime_get (), * t );
159
160
else if (cmd != FUTEX_LOCK_PI && !(op & FUTEX_CLOCK_REALTIME ))
160
161
* t = timens_ktime_to_host (CLOCK_MONOTONIC , * t );
161
162
return 0 ;
162
163
}
163
164
165
+ /**
166
+ * futex_read_wait_block - Read an array of futex_wait_block from userspace
167
+ * @uaddr: Userspace address of the block
168
+ * @count: Number of blocks to be read
169
+ *
170
+ * This function creates and allocate an array of futex_q (we zero it to
171
+ * initialize the fields) and then, for each futex_wait_block element from
172
+ * userspace, fill a futex_q element with proper values.
173
+ */
174
+ inline struct futex_vector * futex_read_wait_block (u32 __user * uaddr , u32 count )
175
+ {
176
+ unsigned int i ;
177
+ struct futex_vector * futexv ;
178
+ struct futex_wait_block fwb ;
179
+ struct futex_wait_block __user * entry =
180
+ (struct futex_wait_block __user * )uaddr ;
181
+
182
+ if (!count || count > FUTEX_WAITV_MAX )
183
+ return ERR_PTR (- EINVAL );
184
+
185
+ futexv = kcalloc (count , sizeof (* futexv ), GFP_KERNEL );
186
+ if (!futexv )
187
+ return ERR_PTR (- ENOMEM );
188
+
189
+ for (i = 0 ; i < count ; i ++ ) {
190
+ if (copy_from_user (& fwb , & entry [i ], sizeof (fwb ))) {
191
+ kfree (futexv );
192
+ return ERR_PTR (- EFAULT );
193
+ }
194
+
195
+ futexv [i ].w .flags = FUTEX_32 ;
196
+ futexv [i ].w .val = fwb .val ;
197
+ futexv [i ].w .uaddr = (uintptr_t ) (fwb .uaddr );
198
+ futexv [i ].q = futex_q_init ;
199
+ }
200
+
201
+ return futexv ;
202
+ }
203
+
204
+ int futex_wait_multiple (struct futex_vector * vs , unsigned int count ,
205
+ struct hrtimer_sleeper * to );
206
+
207
+ int futex_opcode_31 (ktime_t * abs_time , u32 __user * uaddr , int count )
208
+ {
209
+ int ret ;
210
+ struct futex_vector * vs ;
211
+ struct hrtimer_sleeper * to = NULL , timeout ;
212
+
213
+ to = futex_setup_timer (abs_time , & timeout , 0 , 0 );
214
+
215
+ vs = futex_read_wait_block (uaddr , count );
216
+
217
+ if (IS_ERR (vs ))
218
+ return PTR_ERR (vs );
219
+
220
+ ret = futex_wait_multiple (vs , count , abs_time ? to : NULL );
221
+ kfree (vs );
222
+
223
+ if (to ) {
224
+ hrtimer_cancel (& to -> timer );
225
+ destroy_hrtimer_on_stack (& to -> timer );
226
+ }
227
+
228
+ return ret ;
229
+ }
230
+
164
231
SYSCALL_DEFINE6 (futex , u32 __user * , uaddr , int , op , u32 , val ,
165
232
const struct __kernel_timespec __user * , utime ,
166
233
u32 __user * , uaddr2 , u32 , val3 )
@@ -180,6 +247,9 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
180
247
tp = & t ;
181
248
}
182
249
250
+ if (cmd == FUTEX_WAIT_MULTIPLE )
251
+ return futex_opcode_31 (tp , uaddr , val );
252
+
183
253
return do_futex (uaddr , op , val , tp , uaddr2 , (unsigned long )utime , val3 );
184
254
}
185
255
@@ -373,6 +443,9 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
373
443
tp = & t ;
374
444
}
375
445
446
+ if (cmd == FUTEX_WAIT_MULTIPLE )
447
+ return futex_opcode_31 (tp , uaddr , val );
448
+
376
449
return do_futex (uaddr , op , val , tp , uaddr2 , (unsigned long )utime , val3 );
377
450
}
378
451
#endif /* CONFIG_COMPAT_32BIT_TIME */
0 commit comments