diff mbox

core: fix the use of this_cpu_ptr

Message ID 1364463761-32510-1-git-send-email-roy.qing.li@gmail.com
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Li RongQing March 28, 2013, 9:42 a.m. UTC
From: Li RongQing <roy.qing.li@gmail.com>

flush_tasklet is not percpu var, and percpu is percpu var, and
	this_cpu_ptr(&info->cache->percpu->flush_tasklet)
is not equal to
	&this_cpu_ptr(info->cache->percpu)->flush_tasklet

1f743b076(use this_cpu_ptr per-cpu helper) introduced this bug.

Signed-off-by: Li RongQing <roy.qing.li@gmail.com>
---
 net/core/flow.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Eric Dumazet March 28, 2013, 1:05 p.m. UTC | #1
On Thu, 2013-03-28 at 17:42 +0800, roy.qing.li@gmail.com wrote:
> From: Li RongQing <roy.qing.li@gmail.com>
> 
> flush_tasklet is not percpu var, and percpu is percpu var, and
> 	this_cpu_ptr(&info->cache->percpu->flush_tasklet)
> is not equal to
> 	&this_cpu_ptr(info->cache->percpu)->flush_tasklet
> 
> 1f743b076(use this_cpu_ptr per-cpu helper) introduced this bug.
> 
> Signed-off-by: Li RongQing <roy.qing.li@gmail.com>
> ---
>  net/core/flow.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/net/core/flow.c b/net/core/flow.c
> index 7fae135..e8084b8 100644
> --- a/net/core/flow.c
> +++ b/net/core/flow.c
> @@ -346,7 +346,7 @@ static void flow_cache_flush_per_cpu(void *data)
>  	struct flow_flush_info *info = data;
>  	struct tasklet_struct *tasklet;
>  
> -	tasklet = this_cpu_ptr(&info->cache->percpu->flush_tasklet);
> +	tasklet = &this_cpu_ptr(info->cache->percpu)->flush_tasklet;
>  	tasklet->data = (unsigned long)info;
>  	tasklet_schedule(tasklet);
>  }

Hi

Any reason you dont Cc Shan Wei & Christoph Lameter ?

Christoph, could this kind of error be detected by the compiler or
sparse ?

Thanks


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoph Lameter (Ampere) March 28, 2013, 2:38 p.m. UTC | #2
On Thu, 28 Mar 2013, Eric Dumazet wrote:

> > flush_tasklet is not percpu var, and percpu is percpu var, and
> > 	this_cpu_ptr(&info->cache->percpu->flush_tasklet)
> > is not equal to
> > 	&this_cpu_ptr(info->cache->percpu)->flush_tasklet

&this_cpu_ptr is always an error since you are taking the addresss of an
address.

this_cpu_ptr(&structure) is the right way to get the address of the cpu
instance for this cpu for a per cpu structure.

> Christoph, could this kind of error be detected by the compiler or
> sparse ?

The per cpu variables are marked with __percpu. This should be detected by
sparse.

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Eric Dumazet March 28, 2013, 3:36 p.m. UTC | #3
On Thu, 2013-03-28 at 14:38 +0000, Christoph Lameter wrote:
> On Thu, 28 Mar 2013, Eric Dumazet wrote:

> 
> > Christoph, could this kind of error be detected by the compiler or
> > sparse ?
> 
> The per cpu variables are marked with __percpu. This should be detected by
> sparse.

make C=2 net/core/flow.o

  CHECK   net/core/flow.c

No warning.



--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoph Lameter (Ampere) March 28, 2013, 4:44 p.m. UTC | #4
On Thu, 28 Mar 2013, Eric Dumazet wrote:

> On Thu, 2013-03-28 at 14:38 +0000, Christoph Lameter wrote:
> > On Thu, 28 Mar 2013, Eric Dumazet wrote:
>
> >
> > > Christoph, could this kind of error be detected by the compiler or
> > > sparse ?
> >
> > The per cpu variables are marked with __percpu. This should be detected by
> > sparse.
>
> make C=2 net/core/flow.o
>
>   CHECK   net/core/flow.c
>
> No warning.

huh?

this_cpu_ptr uses SHIFT_PERCPU_PTR


#ifndef SHIFT_PERCPU_PTR
/* Weird cast keeps both GCC and sparse happy. */
#define SHIFT_PERCPU_PTR(__p, __offset) ({                              \
        __verify_pcpu_ptr((__p));                                       \
        RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset));
\
})
#endif

This would mean that __verify_pcpu_ptr is broken.


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Li RongQing March 29, 2013, 1:24 a.m. UTC | #5
2013/3/28 Christoph Lameter <cl@linux.com>:
> On Thu, 28 Mar 2013, Eric Dumazet wrote:
>
>> > flush_tasklet is not percpu var, and percpu is percpu var, and
>> >     this_cpu_ptr(&info->cache->percpu->flush_tasklet)
>> > is not equal to
>> >     &this_cpu_ptr(info->cache->percpu)->flush_tasklet
>
> &this_cpu_ptr is always an error since you are taking the addresss of an
> address.
>

&this_cpu_ptr()->flush_tasklet,   "->" has high priority than "&"
so the result is same as
 &(this_cpu_ptr()->flush_tasklet)
it should not a issue.

flush_tasklet is not a percpu var, it is a member of percpu var.

-Roy

> this_cpu_ptr(&structure) is the right way to get the address of the cpu
> instance for this cpu for a per cpu structure.
>
>> Christoph, could this kind of error be detected by the compiler or
>> sparse ?
>
> The per cpu variables are marked with __percpu. This should be detected by
> sparse.
>
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller March 29, 2013, 7:13 p.m. UTC | #6
From: roy.qing.li@gmail.com
Date: Thu, 28 Mar 2013 17:42:41 +0800

> From: Li RongQing <roy.qing.li@gmail.com>
> 
> flush_tasklet is not percpu var, and percpu is percpu var, and
> 	this_cpu_ptr(&info->cache->percpu->flush_tasklet)
> is not equal to
> 	&this_cpu_ptr(info->cache->percpu)->flush_tasklet
> 
> 1f743b076(use this_cpu_ptr per-cpu helper) introduced this bug.
> 
> Signed-off-by: Li RongQing <roy.qing.li@gmail.com>

Applied.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoph Lameter (Ampere) April 1, 2013, 3:21 p.m. UTC | #7
On Fri, 29 Mar 2013, RongQing Li wrote:

> > &this_cpu_ptr is always an error since you are taking the addresss of an
> > address.
> >
>
> &this_cpu_ptr()->flush_tasklet,   "->" has high priority than "&"
> so the result is same as
>  &(this_cpu_ptr()->flush_tasklet)

Ok. This is the same as

	this_cpu_read(xxx.flush_tasklet)

Looks less confusing to me.

> flush_tasklet is not a percpu var, it is a member of percpu var.

Well then it would be best to use this_cpu_read() instead of this_cpu_ptr.
It also will generate better code.

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Eric Dumazet April 1, 2013, 4:31 p.m. UTC | #8
On Mon, 2013-04-01 at 15:21 +0000, Christoph Lameter wrote:
> On Fri, 29 Mar 2013, RongQing Li wrote:

> > flush_tasklet is not a percpu var, it is a member of percpu var.
> 
> Well then it would be best to use this_cpu_read() instead of this_cpu_ptr.
> It also will generate better code.

I believe we already had this discussion in the past.

flush_tasklet is a structure, and we need its address, not read its
content.

You can not use this_cpu_read() to get its address, and following
code is fine.

tasklet = &this_cpu_ptr(info->cache->percpu)->flush_tasklet;

Similar to this code in mm/page_alloc.c

pcp = &this_cpu_ptr(zone->pageset)->pcp;



--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoph Lameter (Ampere) April 1, 2013, 6:15 p.m. UTC | #9
On Mon, 1 Apr 2013, Eric Dumazet wrote:

> On Mon, 2013-04-01 at 15:21 +0000, Christoph Lameter wrote:
> > On Fri, 29 Mar 2013, RongQing Li wrote:
>
> > > flush_tasklet is not a percpu var, it is a member of percpu var.
> >
> > Well then it would be best to use this_cpu_read() instead of this_cpu_ptr.
> > It also will generate better code.
>
> I believe we already had this discussion in the past.
>
> flush_tasklet is a structure, and we need its address, not read its
> content.
>
> You can not use this_cpu_read() to get its address, and following
> code is fine.
>
> tasklet = &this_cpu_ptr(info->cache->percpu)->flush_tasklet;

that is confusing..

tasklet = this_cpu_ptr(&info->cache->percpu->flushtasklet)

this_cpu_ptr performs an address relocation. The address then is the one
of flushtasklet.

> Similar to this code in mm/page_alloc.c
>
> pcp = &this_cpu_ptr(zone->pageset)->pcp;

Yeah thats my (early) code using these features.

	pcp = this_cpu_ptr(&zone->pageset->pcp)

I need to do a writeup on this one.

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/core/flow.c b/net/core/flow.c
index 7fae135..e8084b8 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -346,7 +346,7 @@  static void flow_cache_flush_per_cpu(void *data)
 	struct flow_flush_info *info = data;
 	struct tasklet_struct *tasklet;
 
-	tasklet = this_cpu_ptr(&info->cache->percpu->flush_tasklet);
+	tasklet = &this_cpu_ptr(info->cache->percpu)->flush_tasklet;
 	tasklet->data = (unsigned long)info;
 	tasklet_schedule(tasklet);
 }