linux kernel 2.6.18-20 bug: rcu_read_unlock in __sock_create
Subsystems (5)
A message that is not in the archive (sent off-list or not yet received): [email protected]
Hello
There is a bug in __sock_create() function (net/socket.c). If an error occur in LSM hook security_socket_post_create, then unneeded rcu_read_unlock() is made in __sock_create.
I wish to be personally CC'ed the answers/comments posted
Quoted 4 lines · oleg 123 <[email protected]> wrote:
There is a bug in
__sock_create()function (net/socket.c). If an error occur in LSM hooksecurity_socket_post_create, then unneededrcu_read_unlock()is made in__sock_create.
Well spotted! Please cc [email protected] for networking issues.
[NET]: Fix unbalanced rcu_read_unlock in __sock_create
The recent RCU work created an unbalanced rcu_read_unlock in __sock_create. This patch fixes that. Reported by oleg 123.
Thanks,
Signature · 5 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--net/socket.c +1 -1
@@ -1168,7 +1168,7 @@ static int __sock_create(int family, int type, int protocol,module_put (pf->owner); err =security_socket_post_create (sock, family, type, protocol, kern);if (err) - goto out_release; + goto out_sock_release; *res = sock;return 0 ;
David Miller
maintainerFrom: Herbert Xu <[email protected]>
Date: Wed, 15 Aug 2007 16:33:35 +0800
Quoted 7 lines
[NET]: Fix unbalanced
rcu_read_unlockin__sock_createThe recent RCU work created an unbalanced
rcu_read_unlockin__sock_create. This patch fixes that. Reported by oleg 123.Signed-off-by Herbert Xu <[email protected]>
Patch applied, thanks Herbert.
Peter Zijlstra
maintainerPATCH 1/1 lockdep: annotate rcu_read_{,un}lock()
There seem to be some unbalanced rcu_read_{,un}lock() issues of late, how about doing something like this:
--- include/linux/lockdep.h | 7 +++++++ include/linux/rcupdate.h | 12 ++++++++++++ kernel/rcupdate.c | 8 ++++++++ 3 files changed, 27 insertions(+)
include/linux/lockdep.h +7 -0
@@ -252,6 +252,13 @@ extern void lockdep_init_map(struct lock struct lock_class_key *key, int subclass);/* +* To initialize a lockdep_map statically use this macro. +* Note that _name must not be NULL. +*/ +#define STATIC_LOCKDEP_MAP_INIT (_name, _key) \ + { .name = (_name), .key = (void *)(_key), } + +/* * Reinitialize a lock key - for cases where there is special locking or * special initialization of locks so that the validator gets the scope * of dependencies wrong: they are either too broad (they need a class-split)
include/linux/rcupdate.h +12 -0
@@ -41,6 +41,7 @@#include <linux/percpu.h> #include <linux/cpumask.h> #include <linux/seqlock.h> +#include <linux/lockdep.h> /** * struct rcu_head - callback structure for use with RCU
@@ -133,6 +134,15 @@ static inline void rcu_bh_qsctr_inc(intextern int rcu_pending (int cpu);extern int rcu_needs_cpu (int cpu); +#ifdef CONFIG_DEBUG_LOCK_ALLOC +extern struct lockdep_map rcu_lock_map; +# define rcu_read_acquire () lock_acquire(&rcu_lock_map, 0, 0, 2, 1, _THIS_IP_) +# define rcu_read_release () lock_release(&rcu_lock_map, 1, _THIS_IP_) +#else +# define rcu_read_acquire () do { } while (0) +# define rcu_read_release () do { } while (0) +#endif +/** * rcu_read_lock - mark the beginning of an RCU read-side critical section. *
@@ -166,6 +176,7 @@ extern int rcu_needs_cpu(int cpu);do { \preempt_disable (); \__acquire (RCU ); \ +rcu_read_acquire (); \ }while (0 )/**
@@ -175,6 +186,7 @@ extern int rcu_needs_cpu(int cpu);*/ #define rcu_read_unlock () \ do { \ + rcu_read_release(); \ __release(RCU); \ preempt_enable(); \ } while(0)
kernel/rcupdate.c +8 -0
@@ -49,6 +49,14 @@#include <linux/cpu.h> #include <linux/mutex.h> +#ifdef CONFIG_DEBUG_LOCK_ALLOC +static struct lock_class_key rcu_lock_key; +struct lockdep_map rcu_lock_map = +STATIC_LOCKDEP_MAP_INIT ("rcu_read_lock" , &rcu_lock_key); + +EXPORT_SYMBOL_GPL (rcu_lock_map); +#endif +/* Definition for rcupdate control block. */ static struct rcu_ctrlblk rcu_ctrlblk = { .cur =-300 ,
Re: [PATCH] lockdep: annotate rcu_read_{,un}lock()
Quoted 3 lines · Peter Zijlstra
There seem to be some unbalanced rcu_read_{,un}lock() issues of late, how about doing something like this:
This will break when rcu_read_lock() and rcu_read_unlock() are invoked from NMI/SMI handlers -- the raw_local_irq_save() in lock_acquire() will not mask NMIs or SMIs.
One approach would be to check for being in an NMI/SMI handler, and to avoid calling lock_acquire() and lock_release() in those cases. Another approach would be to use sparse, which has checks for rcu_read_lock()/rcu_read_unlock() nesting.
Thanx, Paul
Quoted 94 lines
Signed-off-by Peter Zijlstra <[email protected]>--- include/linux/lockdep.h | 7 +++++++ include/linux/rcupdate.h | 12 ++++++++++++ kernel/rcupdate.c | 8 ++++++++ 3 files changed, 27 insertions(+)Index:
linux-2.6/include/linux/lockdep.h
===================================================================include/linux/lockdep.h +7
-0@@ -252,6 +252,13 @@ extern void lockdep_init_map(struct lock struct lock_class_key *key, int subclass);/* +* To initialize a lockdep_map statically use this macro. +* Note that _name must not be NULL. +*/ +#define STATIC_LOCKDEP_MAP_INIT (_name, _key) \ + { .name = (_name), .key = (void *)(_key), } + +/* * Reinitialize a lock key - for cases where there is special locking or * special initialization of locks so that the validator gets the scope * of dependencies wrong: they are either too broad (they need a class-split) Index:
linux-2.6/include/linux/rcupdate.h
===================================================================include/linux/rcupdate.h +12
-0@@ -41,6 +41,7 @@#include <linux/percpu.h> #include <linux/cpumask.h> #include <linux/seqlock.h> +#include <linux/lockdep.h> /** * struct rcu_head - callback structure for use with RCU @@ -133,6 +134,15 @@ static inline void rcu_bh_qsctr_inc(intextern int rcu_pending (int cpu);extern int rcu_needs_cpu (int cpu); +#ifdef CONFIG_DEBUG_LOCK_ALLOC +extern struct lockdep_map rcu_lock_map; +# define rcu_read_acquire () lock_acquire(&rcu_lock_map, 0, 0, 2, 1, _THIS_IP_) +# define rcu_read_release () lock_release(&rcu_lock_map, 1, _THIS_IP_) +#else +# define rcu_read_acquire () do { } while (0) +# define rcu_read_release () do { } while (0) +#endif +/** * rcu_read_lock - mark the beginning of an RCU read-side critical section. * @@ -166,6 +176,7 @@ extern int rcu_needs_cpu(int cpu);do { \preempt_disable (); \__acquire (RCU ); \ +rcu_read_acquire (); \ }while (0 )/** @@ -175,6 +186,7 @@ extern int rcu_needs_cpu(int cpu);*/ #define rcu_read_unlock () \ do { \ + rcu_read_release(); \ __release(RCU); \ preempt_enable(); \ } while(0)Index:
linux-2.6/kernel/rcupdate.c
===================================================================kernel/rcupdate.c +8
-1@@ -49,6 +49,14 @@#include <linux/cpu.h> #include <linux/mutex.h> +#ifdef CONFIG_DEBUG_LOCK_ALLOC +static struct lock_class_key rcu_lock_key; +struct lockdep_map rcu_lock_map = +STATIC_LOCKDEP_MAP_INIT ("rcu_read_lock" , &rcu_lock_key); + +EXPORT_SYMBOL_GPL (rcu_lock_map); +#endif +/* Definition for rcupdate control block. */ static struct rcu_ctrlblk rcu_ctrlblk = { .cur =-300 , -To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Peter Zijlstra
maintainerRe: [PATCH] lockdep: annotate rcu_read_{,un}lock()
Quoted 11 lines · Paul E. McKenney
Quoted 3 lines · Peter Zijlstra
There seem to be some unbalanced rcu_read_{,un}lock() issues of late, how about doing something like this:
This will break when
rcu_read_lock()andrcu_read_unlock()are invoked from NMI/SMI handlers -- theraw_local_irq_save()inlock_acquire()will not mask NMIs or SMIs.One approach would be to check for being in an NMI/SMI handler, and to avoid calling
lock_acquire()andlock_release()in those cases.
It seems:
#define nmi_enter() do { lockdep_off(); __irq_enter(); } while (0)
#define nmi_exit() do { __irq_exit(); lockdep_on(); } while (0)
Should make it all work out just fine. (for NMIs at least, /me fully ignorant of the workings of SMIs)
Quoted 2 lines
Another approach would be to use sparse, which has checks for rcu_read_lock()/rcu_read_unlock() nesting.
Yeah, but one more method can never hurt, no? :-)
Re: [PATCH] lockdep: annotate rcu_read_{,un}lock()
Quoted 13 lines · Peter Zijlstra
Quoted 11 lines · Paul E. McKenney
Quoted 3 lines · Peter Zijlstra
There seem to be some unbalanced rcu_read_{,un}lock() issues of late, how about doing something like this:
This will break when
rcu_read_lock()andrcu_read_unlock()are invoked from NMI/SMI handlers -- theraw_local_irq_save()inlock_acquire()will not mask NMIs or SMIs.One approach would be to check for being in an NMI/SMI handler, and to avoid calling
lock_acquire()andlock_release()in those cases.
Quoted 7 lines
It seems:
#define
nmi_enter()do {lockdep_off();__irq_enter(); } while (0)
#definenmi_exit()do {__irq_exit();lockdep_on(); } while (0)Should make it all work out just fine. (for NMIs at least, /me fully ignorant of the workings of SMIs)
Very good point, at least for NMIs on i386 and x86_64. Can't say that I know much about SMIs myself. Or about whatever equivalents to NMIs and SMIs might exist on other platforms. :-/ Of course, the other platforms could be handled by making the RCU lockdep operate only on i386 and x86_64 if required.
Corey, any advice on SMI handlers? Is there something like nmi_enter() and nmi_exit() that allows disabing lockdep?
Quoted 4 lines
Quoted 2 lines
Another approach would be to use sparse, which has checks for rcu_read_lock()/rcu_read_unlock() nesting.
Yeah, but one more method can never hurt, no? :-)
Excellent point!
I guess the next thing for me is to do a performance check. Looks like CONFIG_DEBUG_LOCK_ALLOC is not on by default, so not violently worried about performance, but would be good to know.
Thanx, Paul
Re: [PATCH] lockdep: annotate rcu_read_{,un}lock()
Quoted 25 lines · Paul E. McKenney
Quoted 14 lines · Peter Zijlstra
Quoted 5 lines · Paul E. McKenney
Quoted 3 lines · Peter Zijlstra
There seem to be some unbalanced rcu_read_{,un}lock() issues of late, how about doing something like this:
Quoted 7 lines
This will break when
rcu_read_lock()andrcu_read_unlock()are invoked from NMI/SMI handlers -- theraw_local_irq_save()inlock_acquire()will not mask NMIs or SMIs.One approach would be to check for being in an NMI/SMI handler, and to avoid calling
lock_acquire()andlock_release()in those cases.Quoted 8 lines
It seems:
#define
nmi_enter()do {lockdep_off();__irq_enter(); } while (0)
#definenmi_exit()do {__irq_exit();lockdep_on(); } while (0)Should make it all work out just fine. (for NMIs at least, /me fully ignorant of the workings of SMIs)
Quoted 9 lines
Very good point, at least for NMIs on i386 and
x86_64. Can't say that I know much about SMIs myself. Or about whatever equivalents to NMIs and SMIs might exist on other platforms. :-/ Of course, the other platforms could be handled by making the RCU lockdep operate only on i386 andx86_64if required.Corey, any advice on SMI handlers? Is there something like
nmi_enter()andnmi_exit()that allows disabing lockdep?
You will certainly need something like nmi_enter() and nmi_exit() for SMIs, since they can occur at any time like NMIs. As far as anything else, you just have to be extremely careful and remember that it can occur anyplace. But you already know that :).
It would be nice if the PowerPC board vendors would tie watchdog pretimeouts and some type of timer into the SMI input. It would make debugging certain problems much easier. And all those Marvell bridge chips have a watchdog pretimeout and I haven't seen any board vendor wire it up :(.
-corey
Re: [PATCH] lockdep: annotate rcu_read_{,un}lock()
Quoted 33 lines · Corey Minyard
Quoted 32 lines · Paul E. McKenney
Quoted 14 lines · Peter Zijlstra
Quoted 5 lines · Paul E. McKenney
Quoted 3 lines · Peter Zijlstra
There seem to be some unbalanced rcu_read_{,un}lock() issues of late, how about doing something like this:
Quoted 7 lines
This will break when
rcu_read_lock()andrcu_read_unlock()are invoked from NMI/SMI handlers -- theraw_local_irq_save()inlock_acquire()will not mask NMIs or SMIs.One approach would be to check for being in an NMI/SMI handler, and to avoid calling
lock_acquire()andlock_release()in those cases.Quoted 9 lines
It seems:
#define
nmi_enter()do {lockdep_off();__irq_enter(); } while
(0)
#definenmi_exit()do {__irq_exit();lockdep_on(); } while (0)Should make it all work out just fine. (for NMIs at least, /me fully ignorant of the workings of SMIs)
Very good point, at least for NMIs on i386 and
x86_64. Can't say that I know much about SMIs myself. Or about whatever equivalents to NMIs and SMIs might exist on other platforms. :-/ Of course, the other platforms could be handled by making the RCU lockdep operate only on i386 andx86_64if required.
Quoted 7 lines
Quoted 3 lines
Corey, any advice on SMI handlers? Is there something like
nmi_enter()andnmi_exit()that allows disabing lockdep?You will certainly need something like
nmi_enter()andnmi_exit()for SMIs, since they can occur at any time like NMIs. As far as anything else, you just have to be extremely careful and remember that it can occur anyplace. But you already know that :).
So we would need to create an smi_enter() and smi_exit() an place them appropriately. Any preferences?
Quoted 5 lines
It would be nice if the PowerPC board vendors would tie watchdog pretimeouts and some type of timer into the SMI input. It would make debugging certain problems much easier. And all those Marvell bridge chips have a watchdog pretimeout and I haven't seen any board vendor wire it up :(.
Can't say that I have much influence over them, but I must agree that debuggability is a very good thing!
Thanx, Paul
Re: [PATCH] lockdep: annotate rcu_read_{,un}lock()
In reply to Paul E. McKenneyQuoted 34 lines · Paul E. McKenney
Quoted 13 lines · Peter Zijlstra
Quoted 11 lines · Paul E. McKenney
Quoted 3 lines · Peter Zijlstra
There seem to be some unbalanced rcu_read_{,un}lock() issues of late, how about doing something like this:
This will break when
rcu_read_lock()andrcu_read_unlock()are invoked from NMI/SMI handlers -- theraw_local_irq_save()inlock_acquire()will not mask NMIs or SMIs.One approach would be to check for being in an NMI/SMI handler, and to avoid calling
lock_acquire()andlock_release()in those cases.Quoted 7 lines
It seems:
#define
nmi_enter()do {lockdep_off();__irq_enter(); } while (0)
#definenmi_exit()do {__irq_exit();lockdep_on(); } while (0)Should make it all work out just fine. (for NMIs at least, /me fully ignorant of the workings of SMIs)
Very good point, at least for NMIs on i386 and
x86_64. Can't say that I know much about SMIs myself. Or about whatever equivalents to NMIs and SMIs might exist on other platforms. :-/ Of course, the other platforms could be handled by making the RCU lockdep operate only on i386 andx86_64if required.Corey, any advice on SMI handlers? Is there something like
nmi_enter()andnmi_exit()that allows disabing lockdep?Quoted 3 lines
Quoted 2 lines
Another approach would be to use sparse, which has checks for rcu_read_lock()/rcu_read_unlock() nesting.
Quoted 7 lines
Quoted 1 line
Yeah, but one more method can never hurt, no? :-)
Excellent point!
I guess the next thing for me is to do a performance check. Looks like
CONFIG_DEBUG_LOCK_ALLOCis not on by default, so not violently worried about performance, but would be good to know.
4-CPU 1.8GHz Opteron 844 running 2.6.22 CONFIG_PREEMPT_NONE with Peter's patch running rcu_read_lock()/rcu_read_unlock() in a tight loop:
1 CPU: 91.7ns
2 CPU: 335.2ns
3 CPU: 534.3ns (But bimodal: two CPUs at 640.7ns, one at 321.6ns) 4 CPU: 784.0ns (again bimodal: three CPUs at 895.9ns, one at 448.2ns)
Running without Peter's patch measures the loop overhead of about 1.2ns.
So not crippling, but definitely a debug-only option that is not enabled by default in production.
In summary, seems like an eminently reasonable approach to me, assuming that the NMI/SMI issues can be resolved across the platforms that have them. Good stuff, Peter!!!
Thanx, Paul