@@ -142,6 +142,7 @@ static __always_inline bool futex_cmd_has_timeout(u32 cmd)
142142 case FUTEX_LOCK_PI2 :
143143 case FUTEX_WAIT_BITSET :
144144 case FUTEX_WAIT_REQUEUE_PI :
145+ case FUTEX_WAIT_MULTIPLE :
145146 return true;
146147 }
147148 return false;
@@ -154,13 +155,79 @@ futex_init_timeout(u32 cmd, u32 op, struct timespec64 *ts, ktime_t *t)
154155 return - EINVAL ;
155156
156157 * t = timespec64_to_ktime (* ts );
157- if (cmd == FUTEX_WAIT )
158+ if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_MULTIPLE )
158159 * t = ktime_add_safe (ktime_get (), * t );
159160 else if (cmd != FUTEX_LOCK_PI && !(op & FUTEX_CLOCK_REALTIME ))
160161 * t = timens_ktime_to_host (CLOCK_MONOTONIC , * t );
161162 return 0 ;
162163}
163164
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+
164231SYSCALL_DEFINE6 (futex , u32 __user * , uaddr , int , op , u32 , val ,
165232 const struct __kernel_timespec __user * , utime ,
166233 u32 __user * , uaddr2 , u32 , val3 )
@@ -180,6 +247,9 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
180247 tp = & t ;
181248 }
182249
250+ if (cmd == FUTEX_WAIT_MULTIPLE )
251+ return futex_opcode_31 (tp , uaddr , val );
252+
183253 return do_futex (uaddr , op , val , tp , uaddr2 , (unsigned long )utime , val3 );
184254}
185255
@@ -373,6 +443,9 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
373443 tp = & t ;
374444 }
375445
446+ if (cmd == FUTEX_WAIT_MULTIPLE )
447+ return futex_opcode_31 (tp , uaddr , val );
448+
376449 return do_futex (uaddr , op , val , tp , uaddr2 , (unsigned long )utime , val3 );
377450}
378451#endif /* CONFIG_COMPAT_32BIT_TIME */
0 commit comments