@@ -205,15 +205,38 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
205
205
*
206
206
* Memory ordering:
207
207
* Most ordering is enforced by using spin_lock() and spin_unlock().
208
- * The special case is use_global_lock:
208
+ *
209
+ * Exceptions:
210
+ * 1) use_global_lock: (SEM_BARRIER_1)
209
211
* Setting it from non-zero to 0 is a RELEASE, this is ensured by
210
- * using smp_store_release().
212
+ * using smp_store_release(): Immediately after setting it to 0,
213
+ * a simple op can start.
211
214
* Testing if it is non-zero is an ACQUIRE, this is ensured by using
212
215
* smp_load_acquire().
213
216
* Setting it from 0 to non-zero must be ordered with regards to
214
217
* this smp_load_acquire(), this is guaranteed because the smp_load_acquire()
215
218
* is inside a spin_lock() and after a write from 0 to non-zero a
216
219
* spin_lock()+spin_unlock() is done.
220
+ *
221
+ * 2) queue.status: (SEM_BARRIER_2)
222
+ * Initialization is done while holding sem_lock(), so no further barrier is
223
+ * required.
224
+ * Setting it to a result code is a RELEASE, this is ensured by both a
225
+ * smp_store_release() (for case a) and while holding sem_lock()
226
+ * (for case b).
227
+ * The AQUIRE when reading the result code without holding sem_lock() is
228
+ * achieved by using READ_ONCE() + smp_acquire__after_ctrl_dep().
229
+ * (case a above).
230
+ * Reading the result code while holding sem_lock() needs no further barriers,
231
+ * the locks inside sem_lock() enforce ordering (case b above)
232
+ *
233
+ * 3) current->state:
234
+ * current->state is set to TASK_INTERRUPTIBLE while holding sem_lock().
235
+ * The wakeup is handled using the wake_q infrastructure. wake_q wakeups may
236
+ * happen immediately after calling wake_q_add. As wake_q_add_safe() is called
237
+ * when holding sem_lock(), no further barriers are required.
238
+ *
239
+ * See also ipc/mqueue.c for more details on the covered races.
217
240
*/
218
241
219
242
#define sc_semmsl sem_ctls[0]
@@ -344,12 +367,8 @@ static void complexmode_tryleave(struct sem_array *sma)
344
367
return ;
345
368
}
346
369
if (sma -> use_global_lock == 1 ) {
347
- /*
348
- * Immediately after setting use_global_lock to 0,
349
- * a simple op can start. Thus: all memory writes
350
- * performed by the current operation must be visible
351
- * before we set use_global_lock to 0.
352
- */
370
+
371
+ /* See SEM_BARRIER_1 for purpose/pairing */
353
372
smp_store_release (& sma -> use_global_lock , 0 );
354
373
} else {
355
374
sma -> use_global_lock -- ;
@@ -400,7 +419,7 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
400
419
*/
401
420
spin_lock (& sem -> lock );
402
421
403
- /* pairs with smp_store_release() */
422
+ /* see SEM_BARRIER_1 for purpose/pairing */
404
423
if (!smp_load_acquire (& sma -> use_global_lock )) {
405
424
/* fast path successful! */
406
425
return sops -> sem_num ;
@@ -766,15 +785,12 @@ static int perform_atomic_semop(struct sem_array *sma, struct sem_queue *q)
766
785
static inline void wake_up_sem_queue_prepare (struct sem_queue * q , int error ,
767
786
struct wake_q_head * wake_q )
768
787
{
769
- wake_q_add (wake_q , q -> sleeper );
770
- /*
771
- * Rely on the above implicit barrier, such that we can
772
- * ensure that we hold reference to the task before setting
773
- * q->status. Otherwise we could race with do_exit if the
774
- * task is awoken by an external event before calling
775
- * wake_up_process().
776
- */
777
- WRITE_ONCE (q -> status , error );
788
+ get_task_struct (q -> sleeper );
789
+
790
+ /* see SEM_BARRIER_2 for purpuse/pairing */
791
+ smp_store_release (& q -> status , error );
792
+
793
+ wake_q_add_safe (wake_q , q -> sleeper );
778
794
}
779
795
780
796
static void unlink_queue (struct sem_array * sma , struct sem_queue * q )
@@ -2148,9 +2164,11 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops,
2148
2164
}
2149
2165
2150
2166
do {
2167
+ /* memory ordering ensured by the lock in sem_lock() */
2151
2168
WRITE_ONCE (queue .status , - EINTR );
2152
2169
queue .sleeper = current ;
2153
2170
2171
+ /* memory ordering is ensured by the lock in sem_lock() */
2154
2172
__set_current_state (TASK_INTERRUPTIBLE );
2155
2173
sem_unlock (sma , locknum );
2156
2174
rcu_read_unlock ();
@@ -2173,13 +2191,8 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops,
2173
2191
*/
2174
2192
error = READ_ONCE (queue .status );
2175
2193
if (error != - EINTR ) {
2176
- /*
2177
- * User space could assume that semop() is a memory
2178
- * barrier: Without the mb(), the cpu could
2179
- * speculatively read in userspace stale data that was
2180
- * overwritten by the previous owner of the semaphore.
2181
- */
2182
- smp_mb ();
2194
+ /* see SEM_BARRIER_2 for purpose/pairing */
2195
+ smp_acquire__after_ctrl_dep ();
2183
2196
goto out_free ;
2184
2197
}
2185
2198
@@ -2189,6 +2202,9 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops,
2189
2202
if (!ipc_valid_object (& sma -> sem_perm ))
2190
2203
goto out_unlock_free ;
2191
2204
2205
+ /*
2206
+ * No necessity for any barrier: We are protect by sem_lock()
2207
+ */
2192
2208
error = READ_ONCE (queue .status );
2193
2209
2194
2210
/*
0 commit comments