mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* question on read_barrier_depends
@ 2014-04-16  7:47 Oliver Neukum
  2014-04-16 15:26 ` Alan Stern
  0 siblings, 1 reply; 9+ messages in thread
From: Oliver Neukum @ 2014-04-16  7:47 UTC (permalink / raw)
  To: Alan Stern; +Cc: linux-kernel

Hi,

I am looking at memory ordering and a question hit me.
I was looking at the kfifo code. kfifo_put() has a barrier:

			)[__kfifo->in & __tmp->kfifo.mask] = \
				(typeof(*__tmp->type))__val; \
			smp_wmb(); \
			__kfifo->in++; \

Looking at kfifo_get() 

		__ret = !kfifo_is_empty(__tmp); \
		if (__ret) { \
			*(typeof(__tmp->type))__val = \
				(__is_kfifo_ptr(__tmp) ? \

A thought struck me. There is no corresponding barrier. I cannot
help myself, but I think there needs to be a smp_read_barrier_depends()
between reading kfifo->in (in kfifo_is empty) and reading val.
What do you think?

	Regards
		Oliver



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

* Re: question on read_barrier_depends
  2014-04-16  7:47 question on read_barrier_depends Oliver Neukum
@ 2014-04-16 15:26 ` Alan Stern
  2014-04-17 15:16   ` Oliver Neukum
  2014-04-21  9:40   ` Oliver Neukum
  0 siblings, 2 replies; 9+ messages in thread
From: Alan Stern @ 2014-04-16 15:26 UTC (permalink / raw)
  To: Oliver Neukum; +Cc: linux-kernel

On Wed, 16 Apr 2014, Oliver Neukum wrote:

> Hi,
> 
> I am looking at memory ordering and a question hit me.
> I was looking at the kfifo code. kfifo_put() has a barrier:
> 
> 			)[__kfifo->in & __tmp->kfifo.mask] = \
> 				(typeof(*__tmp->type))__val; \
> 			smp_wmb(); \
> 			__kfifo->in++; \
> 
> Looking at kfifo_get() 
> 
> 		__ret = !kfifo_is_empty(__tmp); \
> 		if (__ret) { \
> 			*(typeof(__tmp->type))__val = \
> 				(__is_kfifo_ptr(__tmp) ? \
> 
> A thought struck me. There is no corresponding barrier. I cannot
> help myself, but I think there needs to be a smp_read_barrier_depends()
> between reading kfifo->in (in kfifo_is empty) and reading val.
> What do you think?

I think you are right.

In addition, the following code in kfifo_get() does this:

			*(typeof(__tmp->type))__val = \
				(__is_kfifo_ptr(__tmp) ? \
				((typeof(__tmp->type))__kfifo->data) : \
				(__tmp->buf) \
				)[__kfifo->out & __tmp->kfifo.mask]; \
			smp_wmb(); \
			__kfifo->out++; \

It looks like the smp_wmb() should really be smp_mb(), because it 
separates the _read_ for val from the _write_ of kfifo->out.

Alan Stern


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

* Re: question on read_barrier_depends
  2014-04-16 15:26 ` Alan Stern
@ 2014-04-17 15:16   ` Oliver Neukum
  2014-04-17 15:50     ` Alan Stern
  2014-04-21  9:40   ` Oliver Neukum
  1 sibling, 1 reply; 9+ messages in thread
From: Oliver Neukum @ 2014-04-17 15:16 UTC (permalink / raw)
  To: Alan Stern; +Cc: linux-kernel

On Wed, 2014-04-16 at 11:26 -0400, Alan Stern wrote:

> In addition, the following code in kfifo_get() does this:
> 
> 			*(typeof(__tmp->type))__val = \
> 				(__is_kfifo_ptr(__tmp) ? \
> 				((typeof(__tmp->type))__kfifo->data) : \
> 				(__tmp->buf) \
> 				)[__kfifo->out & __tmp->kfifo.mask]; \
> 			smp_wmb(); \
> 			__kfifo->out++; \
> 
> It looks like the smp_wmb() should really be smp_mb(), because it 
> separates the _read_ for val from the _write_ of kfifo->out.

But where is kfifo->out read at all?

	Regards
		Oliver




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

* Re: question on read_barrier_depends
  2014-04-17 15:16   ` Oliver Neukum
@ 2014-04-17 15:50     ` Alan Stern
  2014-04-18 14:02       ` Oliver Neukum
  2014-04-18 17:17       ` Oliver Neukum
  0 siblings, 2 replies; 9+ messages in thread
From: Alan Stern @ 2014-04-17 15:50 UTC (permalink / raw)
  To: Oliver Neukum; +Cc: linux-kernel

On Thu, 17 Apr 2014, Oliver Neukum wrote:

> On Wed, 2014-04-16 at 11:26 -0400, Alan Stern wrote:
> 
> > In addition, the following code in kfifo_get() does this:
> > 
> > 			*(typeof(__tmp->type))__val = \
> > 				(__is_kfifo_ptr(__tmp) ? \
> > 				((typeof(__tmp->type))__kfifo->data) : \
> > 				(__tmp->buf) \
> > 				)[__kfifo->out & __tmp->kfifo.mask]; \
> > 			smp_wmb(); \
> > 			__kfifo->out++; \
> > 
> > It looks like the smp_wmb() should really be smp_mb(), because it 
> > separates the _read_ for val from the _write_ of kfifo->out.
> 
> But where is kfifo->out read at all?

It is read in kfifo_put(), inside the call to kfifo_is_full() -> 
kfifo_len().

Alan Stern


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

* Re: question on read_barrier_depends
  2014-04-17 15:50     ` Alan Stern
@ 2014-04-18 14:02       ` Oliver Neukum
  2014-04-18 18:16         ` Alan Stern
  2014-04-18 17:17       ` Oliver Neukum
  1 sibling, 1 reply; 9+ messages in thread
From: Oliver Neukum @ 2014-04-18 14:02 UTC (permalink / raw)
  To: Alan Stern; +Cc: linux-kernel

On Thu, 2014-04-17 at 11:50 -0400, Alan Stern wrote:
> On Thu, 17 Apr 2014, Oliver Neukum wrote:
> 
> > On Wed, 2014-04-16 at 11:26 -0400, Alan Stern wrote:
> > 
> > > In addition, the following code in kfifo_get() does this:
> > > 
> > > 			*(typeof(__tmp->type))__val = \
> > > 				(__is_kfifo_ptr(__tmp) ? \
> > > 				((typeof(__tmp->type))__kfifo->data) : \
> > > 				(__tmp->buf) \
> > > 				)[__kfifo->out & __tmp->kfifo.mask]; \
> > > 			smp_wmb(); \
> > > 			__kfifo->out++; \
> > > 
> > > It looks like the smp_wmb() should really be smp_mb(), because it 
> > > separates the _read_ for val from the _write_ of kfifo->out.
> > 
> > But where is kfifo->out read at all?
> 
> It is read in kfifo_put(), inside the call to kfifo_is_full() -> 
> kfifo_len().

I had overlooked that. In that case kfifo_put() also needs
smp_read_barrier_depends()

	Regards
		Oliver




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

* Re: question on read_barrier_depends
  2014-04-17 15:50     ` Alan Stern
  2014-04-18 14:02       ` Oliver Neukum
@ 2014-04-18 17:17       ` Oliver Neukum
  1 sibling, 0 replies; 9+ messages in thread
From: Oliver Neukum @ 2014-04-18 17:17 UTC (permalink / raw)
  To: Alan Stern; +Cc: linux-kernel


On Thu, 2014-04-17 at 11:50 -0400, Alan Stern wrote:
> On Thu, 17 Apr 2014, Oliver Neukum wrote:
> 
> > On Wed, 2014-04-16 at 11:26 -0400, Alan Stern wrote:
> > 
> > > In addition, the following code in kfifo_get() does this:
> > > 
> > > 			*(typeof(__tmp->type))__val = \
> > > 				(__is_kfifo_ptr(__tmp) ? \
> > > 				((typeof(__tmp->type))__kfifo->data) : \
> > > 				(__tmp->buf) \
> > > 				)[__kfifo->out & __tmp->kfifo.mask]; \
> > > 			smp_wmb(); \
> > > 			__kfifo->out++; \
> > > 
> > > It looks like the smp_wmb() should really be smp_mb(), because it 
> > > separates the _read_ for val from the _write_ of kfifo->out.
> > 
> > But where is kfifo->out read at all?
> 
> It is read in kfifo_put(), inside the call to kfifo_is_full() -> 
> kfifo_len().

I had overlooked that. In that case kfifo_put() also needs
smp_read_barrier_depends()

	Regards
		Oliver





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

* Re: question on read_barrier_depends
  2014-04-18 14:02       ` Oliver Neukum
@ 2014-04-18 18:16         ` Alan Stern
  0 siblings, 0 replies; 9+ messages in thread
From: Alan Stern @ 2014-04-18 18:16 UTC (permalink / raw)
  To: Oliver Neukum; +Cc: linux-kernel

On Fri, 18 Apr 2014, Oliver Neukum wrote:

> On Thu, 2014-04-17 at 11:50 -0400, Alan Stern wrote:
> > On Thu, 17 Apr 2014, Oliver Neukum wrote:
> > 
> > > On Wed, 2014-04-16 at 11:26 -0400, Alan Stern wrote:
> > > 
> > > > In addition, the following code in kfifo_get() does this:
> > > > 
> > > > 			*(typeof(__tmp->type))__val = \
> > > > 				(__is_kfifo_ptr(__tmp) ? \
> > > > 				((typeof(__tmp->type))__kfifo->data) : \
> > > > 				(__tmp->buf) \
> > > > 				)[__kfifo->out & __tmp->kfifo.mask]; \
> > > > 			smp_wmb(); \
> > > > 			__kfifo->out++; \
> > > > 
> > > > It looks like the smp_wmb() should really be smp_mb(), because it 
> > > > separates the _read_ for val from the _write_ of kfifo->out.
> > > 
> > > But where is kfifo->out read at all?
> > 
> > It is read in kfifo_put(), inside the call to kfifo_is_full() -> 
> > kfifo_len().
> 
> I had overlooked that. In that case kfifo_put() also needs
> smp_read_barrier_depends()

I don't think so.

kfifo_put() uses the read of kfifo->out to determine whether to perform
the store; i.e., it won't store the data if the kfifo is already full.  
No architectures do speculative writes, so the data can never get
stored before kfifo->out is read, even without any memory barriers.  

smp_read_barrier_depends() is meant to prevent speculative _reads_, or
any similar mechanism.

Alan Stern


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

* Re: question on read_barrier_depends
  2014-04-16 15:26 ` Alan Stern
  2014-04-17 15:16   ` Oliver Neukum
@ 2014-04-21  9:40   ` Oliver Neukum
  2014-04-21 14:03     ` Alan Stern
  1 sibling, 1 reply; 9+ messages in thread
From: Oliver Neukum @ 2014-04-21  9:40 UTC (permalink / raw)
  To: Alan Stern; +Cc: linux-kernel

On Wed, 2014-04-16 at 11:26 -0400, Alan Stern wrote:
> On Wed, 16 Apr 2014, Oliver Neukum wrote:
> 
> > Hi,
> > 
> > I am looking at memory ordering and a question hit me.
> > I was looking at the kfifo code. kfifo_put() has a barrier:
> > 
> > 			)[__kfifo->in & __tmp->kfifo.mask] = \
> > 				(typeof(*__tmp->type))__val; \
> > 			smp_wmb(); \
> > 			__kfifo->in++; \
> > 
> > Looking at kfifo_get() 
> > 
> > 		__ret = !kfifo_is_empty(__tmp); \
> > 		if (__ret) { \
> > 			*(typeof(__tmp->type))__val = \
> > 				(__is_kfifo_ptr(__tmp) ? \
> > 
> > A thought struck me. There is no corresponding barrier. I cannot
> > help myself, but I think there needs to be a smp_read_barrier_depends()
> > between reading kfifo->in (in kfifo_is empty) and reading val.
> > What do you think?
> 
> I think you are right.
> 
> In addition, the following code in kfifo_get() does this:
> 
> 			*(typeof(__tmp->type))__val = \
> 				(__is_kfifo_ptr(__tmp) ? \
> 				((typeof(__tmp->type))__kfifo->data) : \
> 				(__tmp->buf) \
> 				)[__kfifo->out & __tmp->kfifo.mask]; \
> 			smp_wmb(); \
> 			__kfifo->out++; \
> 
> It looks like the smp_wmb() should really be smp_mb(), because it 
> separates the _read_ for val from the _write_ of kfifo->out.

On the third hand, I now think wmb() is sufficient, because
there's also a write to __val. It does depend on the read
of buf[out & mask], but if no CPU does speculative writes
it must be correct.

	Regards
		Oliver




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

* Re: question on read_barrier_depends
  2014-04-21  9:40   ` Oliver Neukum
@ 2014-04-21 14:03     ` Alan Stern
  0 siblings, 0 replies; 9+ messages in thread
From: Alan Stern @ 2014-04-21 14:03 UTC (permalink / raw)
  To: Oliver Neukum; +Cc: linux-kernel

On Mon, 21 Apr 2014, Oliver Neukum wrote:

> > In addition, the following code in kfifo_get() does this:
> > 
> > 			*(typeof(__tmp->type))__val = \
> > 				(__is_kfifo_ptr(__tmp) ? \
> > 				((typeof(__tmp->type))__kfifo->data) : \
> > 				(__tmp->buf) \
> > 				)[__kfifo->out & __tmp->kfifo.mask]; \
> > 			smp_wmb(); \
> > 			__kfifo->out++; \
> > 
> > It looks like the smp_wmb() should really be smp_mb(), because it 
> > separates the _read_ for val from the _write_ of kfifo->out.
> 
> On the third hand, I now think wmb() is sufficient, because
> there's also a write to __val. It does depend on the read
> of buf[out & mask], but if no CPU does speculative writes
> it must be correct.

You are right; I missed that.  Good point.

Alan Stern


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

end of thread, other threads:[~2014-04-21 14:03 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-16  7:47 question on read_barrier_depends Oliver Neukum
2014-04-16 15:26 ` Alan Stern
2014-04-17 15:16   ` Oliver Neukum
2014-04-17 15:50     ` Alan Stern
2014-04-18 14:02       ` Oliver Neukum
2014-04-18 18:16         ` Alan Stern
2014-04-18 17:17       ` Oliver Neukum
2014-04-21  9:40   ` Oliver Neukum
2014-04-21 14:03     ` Alan Stern

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®