diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-06-25 12:08:19 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2010-08-19 20:18:02 -0400 |
commit | 4221a9918e38b7494cee341dda7b7b4bb8c04bde (patch) | |
tree | b79ed7629dd526a9c54dc116b7943cc496b3c19e /include/linux | |
parent | 394f99a9007d4274f7076bb8553ab0ff9707688b (diff) |
Add RCU check for find_task_by_vpid().
find_task_by_vpid() says "Must be called under rcu_read_lock().". But due to
commit 3120438 "rcu: Disable lockdep checking in RCU list-traversal primitives",
we are currently unable to catch "find_task_by_vpid() with tasklist_lock held
but RCU lock not held" errors due to the RCU-lockdep checks being
suppressed in the RCU variants of the struct list_head traversals.
This commit therefore places an explicit check for being in an RCU
read-side critical section in find_task_by_pid_ns().
===================================================
[ INFO: suspicious rcu_dereference_check() usage. ]
---------------------------------------------------
kernel/pid.c:386 invoked rcu_dereference_check() without protection!
other info that might help us debug this:
rcu_scheduler_active = 1, debug_locks = 1
1 lock held by rc.sysinit/1102:
#0: (tasklist_lock){.+.+..}, at: [<c1048340>] sys_setpgid+0x40/0x160
stack backtrace:
Pid: 1102, comm: rc.sysinit Not tainted 2.6.35-rc3-dirty #1
Call Trace:
[<c105e714>] lockdep_rcu_dereference+0x94/0xb0
[<c104b4cd>] find_task_by_pid_ns+0x6d/0x70
[<c104b4e8>] find_task_by_vpid+0x18/0x20
[<c1048347>] sys_setpgid+0x47/0x160
[<c1002b50>] sysenter_do_call+0x12/0x36
Commit updated to use a new rcu_lockdep_assert() exported API rather than
the old internal __do_rcu_dereference().
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/rcupdate.h | 14 |
1 files changed, 9 insertions, 5 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index b973dea2d6b0..b124bc6a75ad 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h | |||
@@ -215,7 +215,11 @@ static inline int rcu_read_lock_sched_held(void) | |||
215 | 215 | ||
216 | extern int rcu_my_thread_group_empty(void); | 216 | extern int rcu_my_thread_group_empty(void); |
217 | 217 | ||
218 | #define __do_rcu_dereference_check(c) \ | 218 | /** |
219 | * rcu_lockdep_assert - emit lockdep splat if specified condition not met | ||
220 | * @c: condition to check | ||
221 | */ | ||
222 | #define rcu_lockdep_assert(c) \ | ||
219 | do { \ | 223 | do { \ |
220 | static bool __warned; \ | 224 | static bool __warned; \ |
221 | if (debug_lockdep_rcu_enabled() && !__warned && !(c)) { \ | 225 | if (debug_lockdep_rcu_enabled() && !__warned && !(c)) { \ |
@@ -226,7 +230,7 @@ extern int rcu_my_thread_group_empty(void); | |||
226 | 230 | ||
227 | #else /* #ifdef CONFIG_PROVE_RCU */ | 231 | #else /* #ifdef CONFIG_PROVE_RCU */ |
228 | 232 | ||
229 | #define __do_rcu_dereference_check(c) do { } while (0) | 233 | #define rcu_lockdep_assert(c) do { } while (0) |
230 | 234 | ||
231 | #endif /* #else #ifdef CONFIG_PROVE_RCU */ | 235 | #endif /* #else #ifdef CONFIG_PROVE_RCU */ |
232 | 236 | ||
@@ -247,14 +251,14 @@ extern int rcu_my_thread_group_empty(void); | |||
247 | #define __rcu_dereference_check(p, c, space) \ | 251 | #define __rcu_dereference_check(p, c, space) \ |
248 | ({ \ | 252 | ({ \ |
249 | typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \ | 253 | typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \ |
250 | __do_rcu_dereference_check(c); \ | 254 | rcu_lockdep_assert(c); \ |
251 | (void) (((typeof (*p) space *)p) == p); \ | 255 | (void) (((typeof (*p) space *)p) == p); \ |
252 | smp_read_barrier_depends(); \ | 256 | smp_read_barrier_depends(); \ |
253 | ((typeof(*p) __force __kernel *)(_________p1)); \ | 257 | ((typeof(*p) __force __kernel *)(_________p1)); \ |
254 | }) | 258 | }) |
255 | #define __rcu_dereference_protected(p, c, space) \ | 259 | #define __rcu_dereference_protected(p, c, space) \ |
256 | ({ \ | 260 | ({ \ |
257 | __do_rcu_dereference_check(c); \ | 261 | rcu_lockdep_assert(c); \ |
258 | (void) (((typeof (*p) space *)p) == p); \ | 262 | (void) (((typeof (*p) space *)p) == p); \ |
259 | ((typeof(*p) __force __kernel *)(p)); \ | 263 | ((typeof(*p) __force __kernel *)(p)); \ |
260 | }) | 264 | }) |
@@ -262,7 +266,7 @@ extern int rcu_my_thread_group_empty(void); | |||
262 | #define __rcu_dereference_index_check(p, c) \ | 266 | #define __rcu_dereference_index_check(p, c) \ |
263 | ({ \ | 267 | ({ \ |
264 | typeof(p) _________p1 = ACCESS_ONCE(p); \ | 268 | typeof(p) _________p1 = ACCESS_ONCE(p); \ |
265 | __do_rcu_dereference_check(c); \ | 269 | rcu_lockdep_assert(c); \ |
266 | smp_read_barrier_depends(); \ | 270 | smp_read_barrier_depends(); \ |
267 | (_________p1); \ | 271 | (_________p1); \ |
268 | }) | 272 | }) |