linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock
@ 2015-05-30  0:03 Davidlohr Bueso
  2015-05-30  0:03 ` [PATCH 2/2] ipc,msg: provide barrier pairings for lockless receive Davidlohr Bueso
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Davidlohr Bueso @ 2015-05-30  0:03 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Manfred Spraul, dave, linux-kernel, Davidlohr Bueso

Upon every shm_lock call, we BUG_ON if an error was returned,
indicating racing either in idr or in RMID. Move this logic
into the locking.

Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
---
 ipc/shm.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/ipc/shm.c b/ipc/shm.c
index 6d76707..3152dea 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -155,8 +155,14 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
 {
 	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
 
-	if (IS_ERR(ipcp))
+	if (IS_ERR(ipcp)) {
+		/*
+		 * We raced in the idr lookup or with RMID,
+		 * either way, the ID is busted.
+		 */
+		BUG_ON(1);
 		return (struct shmid_kernel *)ipcp;
+	}
 
 	return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
@@ -191,7 +197,6 @@ static void shm_open(struct vm_area_struct *vma)
 	struct shmid_kernel *shp;
 
 	shp = shm_lock(sfd->ns, sfd->id);
-	BUG_ON(IS_ERR(shp));
 	shp->shm_atim = get_seconds();
 	shp->shm_lprid = task_tgid_vnr(current);
 	shp->shm_nattch++;
@@ -258,7 +263,6 @@ static void shm_close(struct vm_area_struct *vma)
 	down_write(&shm_ids(ns).rwsem);
 	/* remove from the list of attaches of the shm segment */
 	shp = shm_lock(ns, sfd->id);
-	BUG_ON(IS_ERR(shp));
 	shp->shm_lprid = task_tgid_vnr(current);
 	shp->shm_dtim = get_seconds();
 	shp->shm_nattch--;
@@ -1191,7 +1195,6 @@ out_fput:
 out_nattch:
 	down_write(&shm_ids(ns).rwsem);
 	shp = shm_lock(ns, shmid);
-	BUG_ON(IS_ERR(shp));
 	shp->shm_nattch--;
 	if (shm_may_destroy(ns, shp))
 		shm_destroy(ns, shp);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/2] ipc,msg: provide barrier pairings for lockless receive
  2015-05-30  0:03 [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock Davidlohr Bueso
@ 2015-05-30  0:03 ` Davidlohr Bueso
  2015-06-04 17:57   ` Manfred Spraul
  2015-06-01 22:52 ` [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock Andrew Morton
  2015-06-04 18:35 ` Manfred Spraul
  2 siblings, 1 reply; 11+ messages in thread
From: Davidlohr Bueso @ 2015-05-30  0:03 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Manfred Spraul, dave, linux-kernel, Davidlohr Bueso

We currently use a full barrier on the sender side to
to avoid receiver tasks disappearing on us while still
performing on the sender side wakeup. We lack however,
the proper CPU-CPU interactions pairing on the receiver
side which busy-waits for the message. Similarly, we do
not need a full smp_mb, and can relax the semantics for
the writer and reader sides of the message. This is safe
as we are only ordering loads and stores to r_msg. And in
both smp_wmb and smp_rmb, there are no stores after the
calls _anyway_.

This obviously applies for pipelined_send and expunge_all,
for EIRDM when destroying a queue.

Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
---
 ipc/msg.c | 31 ++++++++++++++++++++++---------
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/ipc/msg.c b/ipc/msg.c
index 2b6fdbb..ac5116e 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -196,7 +196,7 @@ static void expunge_all(struct msg_queue *msq, int res)
 		 * or dealing with -EAGAIN cases. See lockless receive part 1
 		 * and 2 in do_msgrcv().
 		 */
-		smp_mb();
+		smp_wmb();
 		msr->r_msg = ERR_PTR(res);
 	}
 }
@@ -580,7 +580,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
 				/* initialize pipelined send ordering */
 				msr->r_msg = NULL;
 				wake_up_process(msr->r_tsk);
-				smp_mb(); /* see barrier comment below */
+				smp_wmb(); /* see barrier comment below */
 				msr->r_msg = ERR_PTR(-E2BIG);
 			} else {
 				msr->r_msg = NULL;
@@ -589,11 +589,12 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
 				wake_up_process(msr->r_tsk);
 				/*
 				 * Ensure that the wakeup is visible before
-				 * setting r_msg, as the receiving end depends
-				 * on it. See lockless receive part 1 and 2 in
-				 * do_msgrcv().
+				 * 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().
 				 */
-				smp_mb();
+				smp_wmb();
 				msr->r_msg = msg;
 
 				return 1;
@@ -934,10 +935,22 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
 		 * wake_up_process(). There is a race with exit(), see
 		 * ipc/mqueue.c for the details.
 		 */
-		msg = (struct msg_msg *)msr_d.r_msg;
-		while (msg == NULL) {
-			cpu_relax();
+		for (;;) {
+			/*
+			 * Pairs with writer barrier in pipelined_send
+			 * or expunge_all
+			 */
+			smp_rmb();
 			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:
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock
  2015-05-30  0:03 [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock Davidlohr Bueso
  2015-05-30  0:03 ` [PATCH 2/2] ipc,msg: provide barrier pairings for lockless receive Davidlohr Bueso
@ 2015-06-01 22:52 ` Andrew Morton
  2015-06-04  0:24   ` Davidlohr Bueso
  2015-06-04  0:25   ` Davidlohr Bueso
  2015-06-04 18:35 ` Manfred Spraul
  2 siblings, 2 replies; 11+ messages in thread
From: Andrew Morton @ 2015-06-01 22:52 UTC (permalink / raw)
  To: Davidlohr Bueso; +Cc: Manfred Spraul, linux-kernel, Davidlohr Bueso

On Fri, 29 May 2015 17:03:05 -0700 Davidlohr Bueso <dave@stgolabs.net> wrote:

> Upon every shm_lock call, we BUG_ON if an error was returned,
> indicating racing either in idr or in RMID. Move this logic
> into the locking.
> 
> ...
>
> --- a/ipc/shm.c
> +++ b/ipc/shm.c
> @@ -155,8 +155,14 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
>  {
>  	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
>  
> -	if (IS_ERR(ipcp))
> +	if (IS_ERR(ipcp)) {
> +		/*
> +		 * We raced in the idr lookup or with RMID,
> +		 * either way, the ID is busted.
> +		 */
> +		BUG_ON(1);
>  		return (struct shmid_kernel *)ipcp;
> +	}
>  

That's a bit odd.  Why not

--- a/ipc/shm.c~ipcshm-move-bug_on-check-into-shm_lock-fix-2
+++ a/ipc/shm.c
@@ -160,7 +160,7 @@ static inline struct shmid_kernel *shm_l
 		 * We raced in the idr lookup or with RMID,
 		 * either way, the ID is busted.
 		 */
-		BUG_ON(1);
+		BUG();
 		return (struct shmid_kernel *)ipcp;
 	}
 

and/or

--- a/ipc/shm.c~ipcshm-move-bug_on-check-into-shm_lock-fix
+++ a/ipc/shm.c
@@ -155,14 +155,11 @@ static inline struct shmid_kernel *shm_l
 {
 	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
 
-	if (IS_ERR(ipcp)) {
-		/*
-		 * We raced in the idr lookup or with RMID,
-		 * either way, the ID is busted.
-		 */
-		BUG();
-		return (struct shmid_kernel *)ipcp;
-	}
+	/*
+	 * We raced in the idr lookup or with RMID.  Either way, the ID is
+	 * busted.
+	 */
+	BUG_ON(IS_ERR(ipcp));
 
 	return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
_


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock
  2015-06-01 22:52 ` [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock Andrew Morton
@ 2015-06-04  0:24   ` Davidlohr Bueso
  2015-06-04  0:25   ` Davidlohr Bueso
  1 sibling, 0 replies; 11+ messages in thread
From: Davidlohr Bueso @ 2015-06-04  0:24 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Manfred Spraul, linux-kernel

On Mon, 2015-06-01 at 15:52 -0700, Andrew Morton wrote:
> On Fri, 29 May 2015 17:03:05 -0700 Davidlohr Bueso <dave@stgolabs.net> wrote:
> 
> > Upon every shm_lock call, we BUG_ON if an error was returned,
> > indicating racing either in idr or in RMID. Move this logic
> > into the locking.
> > 
> > ...
> >
> > --- a/ipc/shm.c
> > +++ b/ipc/shm.c
> > @@ -155,8 +155,14 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
> >  {
> >  	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
> >  
> > -	if (IS_ERR(ipcp))
> > +	if (IS_ERR(ipcp)) {
> > +		/*
> > +		 * We raced in the idr lookup or with RMID,
> > +		 * either way, the ID is busted.
> > +		 */
> > +		BUG_ON(1);
> >  		return (struct shmid_kernel *)ipcp;
> > +	}
> >  

Sure, this is fine.

Thanks,
Davidlohr


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock
  2015-06-01 22:52 ` [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock Andrew Morton
  2015-06-04  0:24   ` Davidlohr Bueso
@ 2015-06-04  0:25   ` Davidlohr Bueso
  1 sibling, 0 replies; 11+ messages in thread
From: Davidlohr Bueso @ 2015-06-04  0:25 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Manfred Spraul, linux-kernel

On Mon, 2015-06-01 at 15:52 -0700, Andrew Morton wrote:
> On Fri, 29 May 2015 17:03:05 -0700 Davidlohr Bueso <dave@stgolabs.net> wrote:
> 
> > Upon every shm_lock call, we BUG_ON if an error was returned,
> > indicating racing either in idr or in RMID. Move this logic
> > into the locking.
> > 
> > ...
> >
> > --- a/ipc/shm.c
> > +++ b/ipc/shm.c
> > @@ -155,8 +155,14 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
> >  {
> >  	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
> >  
> > -	if (IS_ERR(ipcp))
> > +	if (IS_ERR(ipcp)) {
> > +		/*
> > +		 * We raced in the idr lookup or with RMID,
> > +		 * either way, the ID is busted.
> > +		 */
> > +		BUG_ON(1);
> >  		return (struct shmid_kernel *)ipcp;
> > +	}
> >  
> 
> That's a bit odd.  Why not
> 
> --- a/ipc/shm.c~ipcshm-move-bug_on-check-into-shm_lock-fix-2
> +++ a/ipc/shm.c
> @@ -160,7 +160,7 @@ static inline struct shmid_kernel *shm_l
>  		 * We raced in the idr lookup or with RMID,
>  		 * either way, the ID is busted.
>  		 */
> -		BUG_ON(1);
> +		BUG();
>  		return (struct shmid_kernel *)ipcp;
>  	}

Sure, this is fine.

Thanks,
Davidlohr


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2] ipc,msg: provide barrier pairings for lockless receive
  2015-05-30  0:03 ` [PATCH 2/2] ipc,msg: provide barrier pairings for lockless receive Davidlohr Bueso
@ 2015-06-04 17:57   ` Manfred Spraul
  2015-06-04 18:41     ` Davidlohr Bueso
  0 siblings, 1 reply; 11+ messages in thread
From: Manfred Spraul @ 2015-06-04 17:57 UTC (permalink / raw)
  To: Davidlohr Bueso, Andrew Morton; +Cc: linux-kernel, Davidlohr Bueso

On 05/30/2015 02:03 AM, Davidlohr Bueso wrote:
> We currently use a full barrier on the sender side to
> to avoid receiver tasks disappearing on us while still
> performing on the sender side wakeup. We lack however,
> the proper CPU-CPU interactions pairing on the receiver
> side which busy-waits for the message. Similarly, we do
> not need a full smp_mb, and can relax the semantics for
> the writer and reader sides of the message. This is safe
> as we are only ordering loads and stores to r_msg. And in
> both smp_wmb and smp_rmb, there are no stores after the
> calls _anyway_.
I like the idea, the pairing in ipc is not good.
Another one is still open in sem.

Perhaps we should formalize it a bit more, so that it is easy to find 
which barrier pair belongs together.
It is only an idea, but right now there are too many bugs.

> This obviously applies for pipelined_send and expunge_all,
> for EIRDM when destroying a queue.
>
> Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
> ---
>   ipc/msg.c | 31 ++++++++++++++++++++++---------
>   1 file changed, 22 insertions(+), 9 deletions(-)
>
> diff --git a/ipc/msg.c b/ipc/msg.c
> index 2b6fdbb..ac5116e 100644
> --- a/ipc/msg.c
> +++ b/ipc/msg.c
> @@ -196,7 +196,7 @@ static void expunge_all(struct msg_queue *msq, int res)
>   		 * or dealing with -EAGAIN cases. See lockless receive part 1
>   		 * and 2 in do_msgrcv().
>   		 */
> -		smp_mb();
> +		smp_wmb();
Idea for improvement: Add here /* smp_barrier_pair: ipc_msg_01 */

>   		msr->r_msg = ERR_PTR(res);
>   	}
>   }
> @@ -580,7 +580,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
>   				/* initialize pipelined send ordering */
>   				msr->r_msg = NULL;
>   				wake_up_process(msr->r_tsk);
> -				smp_mb(); /* see barrier comment below */
> +				smp_wmb(); /* see barrier comment below */
>   				msr->r_msg = ERR_PTR(-E2BIG);
>   			} else {
>   				msr->r_msg = NULL;
> @@ -589,11 +589,12 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
>   				wake_up_process(msr->r_tsk);
>   				/*
>   				 * Ensure that the wakeup is visible before
> -				 * setting r_msg, as the receiving end depends
> -				 * on it. See lockless receive part 1 and 2 in
> -				 * do_msgrcv().
> +				 * 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().
>   				 */
> -				smp_mb();
> +				smp_wmb();
Idea for improvement: Add here /* smp_barrier_pair: ipc_msg_02 */
>   				msr->r_msg = msg;
>   
>   				return 1;
> @@ -934,10 +935,22 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
>   		 * wake_up_process(). There is a race with exit(), see
>   		 * ipc/mqueue.c for the details.
>   		 */
> -		msg = (struct msg_msg *)msr_d.r_msg;
> -		while (msg == NULL) {
> -			cpu_relax();
> +		for (;;) {
> +			/*
> +			 * Pairs with writer barrier in pipelined_send
> +			 * or expunge_all
> +			 */
> +			smp_rmb();
And here again /* smp_barrier_pair: for ipc_msg_01 and ipc_msg_02 */

--
     Manfred


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock
  2015-05-30  0:03 [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock Davidlohr Bueso
  2015-05-30  0:03 ` [PATCH 2/2] ipc,msg: provide barrier pairings for lockless receive Davidlohr Bueso
  2015-06-01 22:52 ` [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock Andrew Morton
@ 2015-06-04 18:35 ` Manfred Spraul
  2015-06-04 18:58   ` Davidlohr Bueso
  2015-06-04 20:31   ` Davidlohr Bueso
  2 siblings, 2 replies; 11+ messages in thread
From: Manfred Spraul @ 2015-06-04 18:35 UTC (permalink / raw)
  To: Davidlohr Bueso, Andrew Morton; +Cc: linux-kernel, Davidlohr Bueso

Hi Davidlohr,

On 05/30/2015 02:03 AM, Davidlohr Bueso wrote:
> Upon every shm_lock call, we BUG_ON if an error was returned,
> indicating racing either in idr or in RMID. Move this logic
> into the locking.
>
> Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
> ---
>   ipc/shm.c | 11 +++++++----
>   1 file changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/ipc/shm.c b/ipc/shm.c
> index 6d76707..3152dea 100644
> --- a/ipc/shm.c
> +++ b/ipc/shm.c
> @@ -155,8 +155,14 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
>   {
>   	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
>   
> -	if (IS_ERR(ipcp))
> +	if (IS_ERR(ipcp)) {
> +		/*
> +		 * We raced in the idr lookup or with RMID,
> +		 * either way, the ID is busted.
The comment is wrong:
"We raced in the idr lookup or with shm_destroy()"

shm is not like msg or sem:
RMID merely marks a shmid as deletable (SHM_DEST), delete (i.e.: 
shm_rmid(), then ipc_rmid()) happens only after the last attached 
segment is detatched.

And: (unrelated to the patch)
For do_shmat(), I'm not 100% sure that the BUG can't be triggered.

--
     Manfred


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2] ipc,msg: provide barrier pairings for lockless receive
  2015-06-04 17:57   ` Manfred Spraul
@ 2015-06-04 18:41     ` Davidlohr Bueso
  2015-06-04 18:56       ` Davidlohr Bueso
  0 siblings, 1 reply; 11+ messages in thread
From: Davidlohr Bueso @ 2015-06-04 18:41 UTC (permalink / raw)
  To: Manfred Spraul; +Cc: Andrew Morton, linux-kernel

On Thu, 2015-06-04 at 19:57 +0200, Manfred Spraul wrote:
> On 05/30/2015 02:03 AM, Davidlohr Bueso wrote:
> > We currently use a full barrier on the sender side to
> > to avoid receiver tasks disappearing on us while still
> > performing on the sender side wakeup. We lack however,
> > the proper CPU-CPU interactions pairing on the receiver
> > side which busy-waits for the message. Similarly, we do
> > not need a full smp_mb, and can relax the semantics for
> > the writer and reader sides of the message. This is safe
> > as we are only ordering loads and stores to r_msg. And in
> > both smp_wmb and smp_rmb, there are no stores after the
> > calls _anyway_.
> I like the idea, the pairing in ipc is not good.
> Another one is still open in sem.

Hmm for sems are you referring to spinning on ->status in
get_queue_result() while another task is performing a wakeup in between
wake_up_sem_queue_prepare() and wake_up_sem_queue_do()?

> 
> Perhaps we should formalize it a bit more, so that it is easy to find 
> which barrier pair belongs together.
> It is only an idea, but right now there are too many bugs.

Good point, however, what do you think of the below instead? Makes it
crystal clear, imho.

Thanks,
Davidlohr

diff --git a/ipc/msg.c b/ipc/msg.c
index 2b6fdbb..ce7bf50 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -196,7 +196,7 @@ static void expunge_all(struct msg_queue *msq, int res)
 		 * or dealing with -EAGAIN cases. See lockless receive part 1
 		 * and 2 in do_msgrcv().
 		 */
-		smp_mb();
+		smp_wmb(); /* barrier (B) */
 		msr->r_msg = ERR_PTR(res);
 	}
 }
@@ -580,7 +580,8 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
 				/* initialize pipelined send ordering */
 				msr->r_msg = NULL;
 				wake_up_process(msr->r_tsk);
-				smp_mb(); /* see barrier comment below */
+				/* barrier (B) see barrier comment below */
+				smp_wmb();
 				msr->r_msg = ERR_PTR(-E2BIG);
 			} else {
 				msr->r_msg = NULL;
@@ -589,11 +590,12 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
 				wake_up_process(msr->r_tsk);
 				/*
 				 * Ensure that the wakeup is visible before
-				 * setting r_msg, as the receiving end depends
-				 * on it. See lockless receive part 1 and 2 in
-				 * do_msgrcv().
+				 * 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_mb();
+				smp_wmb();
 				msr->r_msg = msg;
 
 				return 1;
@@ -932,12 +934,38 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
 		/* 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.
+		 * ipc/mqueue.c for the details. The correct serialization
+		 * ensures that a receiver cannot continue without the wakeup
+		 * being visibible _before_ setting r_msg:
+		 *
+		 * CPU 0                             CPU 1
+		 * <loop receiver>
+		 *   smp_rmb(); (A) <-- pair -.      <waker thread>
+		 *   <load ->r_msg>           |        msr->r_msg = NULL;
+		 *                            |        wakeup_process()
+		 * <continue>                 `------> smp_wmb(); (B)
+		 *                                     msr->r_msg = msg;
+		 *
+		 * Where (A) orders the message value read and where (B) orders
+		 * the write to the futex -- done in both pipelined_send and
+		 * expunge_all.		 *
 		 */
-		msg = (struct msg_msg *)msr_d.r_msg;
-		while (msg == NULL) {
-			cpu_relax();
+		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:



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2] ipc,msg: provide barrier pairings for lockless receive
  2015-06-04 18:41     ` Davidlohr Bueso
@ 2015-06-04 18:56       ` Davidlohr Bueso
  0 siblings, 0 replies; 11+ messages in thread
From: Davidlohr Bueso @ 2015-06-04 18:56 UTC (permalink / raw)
  To: Manfred Spraul; +Cc: Andrew Morton, linux-kernel

On Thu, 2015-06-04 at 11:41 -0700, Davidlohr Bueso wrote:
> On Thu, 2015-06-04 at 19:57 +0200, Manfred Spraul wrote:
> > On 05/30/2015 02:03 AM, Davidlohr Bueso wrote:
> > > We currently use a full barrier on the sender side to
> > > to avoid receiver tasks disappearing on us while still
> > > performing on the sender side wakeup. We lack however,
> > > the proper CPU-CPU interactions pairing on the receiver
> > > side which busy-waits for the message. Similarly, we do
> > > not need a full smp_mb, and can relax the semantics for
> > > the writer and reader sides of the message. This is safe
> > > as we are only ordering loads and stores to r_msg. And in
> > > both smp_wmb and smp_rmb, there are no stores after the
> > > calls _anyway_.
> > I like the idea, the pairing in ipc is not good.
> > Another one is still open in sem.
> 
> Hmm for sems are you referring to spinning on ->status in
> get_queue_result() while another task is performing a wakeup in between
> wake_up_sem_queue_prepare() and wake_up_sem_queue_do()?
> 
> > 
> > Perhaps we should formalize it a bit more, so that it is easy to find 
> > which barrier pair belongs together.
> > It is only an idea, but right now there are too many bugs.
> 
> Good point, however, what do you think of the below instead? Makes it
> crystal clear, imho.

We had to do some formalizing in futex too.

> +		 * Where (A) orders the message value read and where (B) orders
> +		 * the write to the futex -- done in both pipelined_send and
                                      ^^ this should be r_msg


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock
  2015-06-04 18:35 ` Manfred Spraul
@ 2015-06-04 18:58   ` Davidlohr Bueso
  2015-06-04 20:31   ` Davidlohr Bueso
  1 sibling, 0 replies; 11+ messages in thread
From: Davidlohr Bueso @ 2015-06-04 18:58 UTC (permalink / raw)
  To: Manfred Spraul; +Cc: Andrew Morton, linux-kernel

On Thu, 2015-06-04 at 20:35 +0200, Manfred Spraul wrote:
> Hi Davidlohr,
> 
> On 05/30/2015 02:03 AM, Davidlohr Bueso wrote:
> > Upon every shm_lock call, we BUG_ON if an error was returned,
> > indicating racing either in idr or in RMID. Move this logic
> > into the locking.
> >
> > Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
> > ---
> >   ipc/shm.c | 11 +++++++----
> >   1 file changed, 7 insertions(+), 4 deletions(-)
> >
> > diff --git a/ipc/shm.c b/ipc/shm.c
> > index 6d76707..3152dea 100644
> > --- a/ipc/shm.c
> > +++ b/ipc/shm.c
> > @@ -155,8 +155,14 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
> >   {
> >   	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
> >   
> > -	if (IS_ERR(ipcp))
> > +	if (IS_ERR(ipcp)) {
> > +		/*
> > +		 * We raced in the idr lookup or with RMID,
> > +		 * either way, the ID is busted.
> The comment is wrong:
> "We raced in the idr lookup or with shm_destroy()"

Yes, you are absolutely right. Thanks for the review.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock
  2015-06-04 18:35 ` Manfred Spraul
  2015-06-04 18:58   ` Davidlohr Bueso
@ 2015-06-04 20:31   ` Davidlohr Bueso
  1 sibling, 0 replies; 11+ messages in thread
From: Davidlohr Bueso @ 2015-06-04 20:31 UTC (permalink / raw)
  To: Manfred Spraul; +Cc: Andrew Morton, linux-kernel

On Thu, 2015-06-04 at 20:35 +0200, Manfred Spraul wrote:
> Hi Davidlohr,
> 
> On 05/30/2015 02:03 AM, Davidlohr Bueso wrote:
> > Upon every shm_lock call, we BUG_ON if an error was returned,
> > indicating racing either in idr or in RMID. Move this logic
> > into the locking.
> >
> > Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
> > ---
> >   ipc/shm.c | 11 +++++++----
> >   1 file changed, 7 insertions(+), 4 deletions(-)
> >
> > diff --git a/ipc/shm.c b/ipc/shm.c
> > index 6d76707..3152dea 100644
> > --- a/ipc/shm.c
> > +++ b/ipc/shm.c
> > @@ -155,8 +155,14 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
> >   {
> >   	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
> >   
> > -	if (IS_ERR(ipcp))
> > +	if (IS_ERR(ipcp)) {
> > +		/*
> > +		 * We raced in the idr lookup or with RMID,
> > +		 * either way, the ID is busted.
> The comment is wrong:
> "We raced in the idr lookup or with shm_destroy()"
> 
> shm is not like msg or sem:
> RMID merely marks a shmid as deletable (SHM_DEST), delete (i.e.: 
> shm_rmid(), then ipc_rmid()) happens only after the last attached 
> segment is detatched.
> 
> And: (unrelated to the patch)
> For do_shmat(), I'm not 100% sure that the BUG can't be triggered.

Could you be referring to the fact that we don't mark the segment
->deleted when doing RMID (do_shm_rmid)? This would certainly cause
checks to ipc_valid_object() to completely screw up. I've actually been
chasing that BUG() in shm_open and shm_close during forking and exiting
(unmapping) respectively.

*Completely untested*

Thanks,
Davidlohr

diff --git a/ipc/shm.c b/ipc/shm.c
index 3323c49..4e78cd2 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -95,6 +95,14 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
 		shp->shm_perm.mode |= SHM_DEST;
 		/* Do not find it any more */
 		shp->shm_perm.key = IPC_PRIVATE;
+		/*
+		 * Mark the object deleted. As opposed to
+		 * sems or msg queues, shm only marks the
+		 * shmid deletable upon RMID, and delays
+		 * the freeing until there are no more
+		 * active users of the segment.
+		 */
+		shp->shm_perm.deleted = true;
 		shm_unlock(shp);
 	} else
 		shm_destroy(ns, shp);



^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2015-06-04 20:31 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-30  0:03 [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock Davidlohr Bueso
2015-05-30  0:03 ` [PATCH 2/2] ipc,msg: provide barrier pairings for lockless receive Davidlohr Bueso
2015-06-04 17:57   ` Manfred Spraul
2015-06-04 18:41     ` Davidlohr Bueso
2015-06-04 18:56       ` Davidlohr Bueso
2015-06-01 22:52 ` [PATCH 1/2] ipc,shm: move BUG_ON check into shm_lock Andrew Morton
2015-06-04  0:24   ` Davidlohr Bueso
2015-06-04  0:25   ` Davidlohr Bueso
2015-06-04 18:35 ` Manfred Spraul
2015-06-04 18:58   ` Davidlohr Bueso
2015-06-04 20:31   ` Davidlohr Bueso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).