Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932486AbbKCUNG (ORCPT ); Tue, 3 Nov 2015 15:13:06 -0500 Received: from www.linutronix.de ([62.245.132.108]:46603 "EHLO Galois.linutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932354AbbKCUNB (ORCPT ); Tue, 3 Nov 2015 15:13:01 -0500 Subject: Re: [PATCH v2] ipc/msg: Implement lockless pipelined wakeups To: Davidlohr Bueso References: <1446563009-9076-1-git-send-email-bigeasy@linutronix.de> <20151103173021.GE1707@linux-uzut.site> Cc: linux-kernel@vger.kernel.org, George Spelvin , Thomas Gleixner , Peter Zijlstra , Manfred Spraul , Andrew Morton From: Sebastian Andrzej Siewior X-Enigmail-Draft-Status: N1110 Message-ID: <56391547.2040105@linutronix.de> Date: Tue, 3 Nov 2015 21:12:55 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Icedove/38.2.0 MIME-Version: 1.0 In-Reply-To: <20151103173021.GE1707@linux-uzut.site> Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 8bit X-Linutronix-Spam-Score: -1.0 X-Linutronix-Spam-Level: - X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required, ALL_TRUSTED=-1,SHORTCIRCUIT=-0.0001 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5256 Lines: 130 On 11/03/2015 06:30 PM, Davidlohr Bueso wrote: > On Tue, 03 Nov 2015, Sebastian Andrzej Siewior wrote: > >> @@ -577,26 +570,23 @@ static inline int pipelined_send(struct >> msg_queue *msq, struct msg_msg *msg) >> >> list_del(&msr->r_list); >> if (msr->r_maxsize < msg->m_ts) { >> - /* initialize pipelined send ordering */ >> - msr->r_msg = NULL; >> - wake_up_process(msr->r_tsk); >> - /* barrier (B) see barrier comment below */ >> - smp_wmb(); >> + wake_q_add(wake_q, msr->r_tsk); >> msr->r_msg = ERR_PTR(-E2BIG); >> } else { >> - msr->r_msg = NULL; >> msq->q_lrpid = task_pid_vnr(msr->r_tsk); >> msq->q_rtime = get_seconds(); >> - wake_up_process(msr->r_tsk); >> - /* >> - * Ensure that the wakeup is visible before >> - * setting r_msg, as the receiving can otherwise >> - * exit - once r_msg is set, the receiver can >> - * continue. See lockless receive part 1 and 2 >> - * in do_msgrcv(). Barrier (B). >> - */ >> - smp_wmb(); >> + wake_q_add(wake_q, msr->r_tsk); >> msr->r_msg = msg; >> + /* >> + * Rely on the implicit cmpxchg barrier from >> + * wake_q_add such that we can ensure that >> + * updating msr->r_msg is the last write >> + * operation: As once set, the receiver can >> + * continue, and if we don't have the reference >> + * count from the wake_q, yet, at that point we >> + * can later have a use-after-free condition and >> + * bogus wakeup. >> + */ > > Not sure why you placed the comment here. Why not between smp_wmb() and > the r_msg > write as we have it? This follows the scheme we have in pipelined_send(). First wake_q_add() then ->state (here we have the msg instead). > > You might also want to add a reference to this comment in expunge_all(), > which > does the same thing. okay. >> [...] >> >> /* 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. The correct serialization >> - * ensures that a receiver cannot continue without the wakeup >> - * being visibible _before_ setting r_msg: >> + * The work in pipelined_send() and expunge_all(): >> + * - Set pointer to message >> + * - Queue the receiver task for later wakeup >> + * - Wake up the process after the lock is dropped. >> * >> - * CPU 0 CPU 1 >> - * >> - * smp_rmb(); (A) <-- pair -. >> - * r_msg> | msr->r_msg = NULL; >> - * | wake_up_process(); >> - * `------> smp_wmb(); (B) >> - * msr->r_msg = msg; >> - * >> - * Where (A) orders the message value read and where (B) orders >> - * the write to the r_msg -- done in both pipelined_send and >> - * expunge_all. >> + * Should the process wake up before this wakeup (due to a >> + * signal) it will either see the message and continue ... >> */ >> - for (;;) { >> - /* >> - * Pairs with writer barrier in pipelined_send >> - * or expunge_all. >> - */ >> - smp_rmb(); /* barrier (A) */ >> - msg = (struct msg_msg *)msr_d.r_msg; >> - if (msg) >> - break; >> >> - /* >> - * The cpu_relax() call is a compiler barrier >> - * which forces everything in this loop to be >> - * re-loaded. >> - */ >> - cpu_relax(); >> - } >> - >> - /* Lockless receive, part 3: >> - * If there is a message or an error then accept it without >> - * locking. >> - */ >> + msg = msr_d.r_msg; > > But you're getting rid of the barrier pairing (smp_rmb) we have in > pipelined sends > and expunge_all, which is necesary even if we don't busy wait on nil. In pipelined_receive() (mqueue) there is the wake_q_add() with the implicit cmpxchg barrier. The matching barrier pairing should be in wq_sleep() but there is none. Why is it okay to have none there and I need one here? > Likewise, > there's no need to remove the comment above that illustrates this. I did not assume we need a barrier here. If we do, I keep it in the comment / graphic but right I now, I think that it can go. > Thanks, > Davidlohr Sebastian -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/