- /*
- * The below optimisation is buggy. A sleeping thread that is
- * woken up checks if it got a message and if so, copies it to
- * userspace and just returns without taking any locks.
- * But this return to user space can be faster than the message
- * send, and if the receiver immediately exits the
- * wake_up_process performed by the sender will oops.
+ /* Lockless receive, part 1:
+ * Disable preemption. We don't hold a reference to the queue
+ * and getting a reference would defeat the idea of a lockless
+ * operation, thus the code relies on rcu to guarantee the
+ * existance of msq:
+ * Prior to destruction, expunge_all(-EIRDM) changes r_msg.
+ * Thus if r_msg is -EAGAIN, then the queue not yet destroyed.
+ * rcu_read_lock() prevents preemption between reading r_msg
+ * and the spin_lock() inside ipc_lock_by_ptr().
+ */
+ rcu_read_lock();
+
+ /* Lockless receive, part 2:
+ * Wait until pipelined_send or expunge_all are outside of
+ * wake_up_process(). There is a race with exit(), see
+ * ipc/mqueue.c for the details.