Messages in this thread Patch in this message | | | From | Yong Zhang <> | Subject | [PATCH 1/4] lockdep: lock_set_subclass() fix | Date | Fri, 4 Nov 2011 17:26:27 +0800 |
| |
Since commit f59de89 [lockdep: Clear whole lockdep_map on initialization], lockdep_init_map() will clear all the struct. But it will break lock_set_class()/lock_set_subclass(). A typical race condition is like below:
CPU A CPU B lock_set_subclass(lockA); lock_set_class(lockA); lockdep_init_map(lockA); /* lockA->name is cleared */ memset(lockA); __lock_acquire(lockA); /* lockA->class_cache[] is cleared */ register_lock_class(lockA); look_up_lock_class(lockA); WARN_ON_ONCE(class->name != lock->name);
lock->name = name;
Reported-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Reported-by: Borislav Petkov <bp@alien8.de> Signed-off-by: Yong Zhang <yong.zhang0@gmail.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Ingo Molnar <mingo@elte.hu> Cc: Tejun Heo <tj@kernel.org> Cc: David Rientjes <rientjes@google.com> --- include/linux/lockdep.h | 2 +- kernel/lockdep.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index b6a56e3..182fb2d 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -330,7 +330,7 @@ extern void lock_set_class(struct lockdep_map *lock, const char *name, static inline void lock_set_subclass(struct lockdep_map *lock, unsigned int subclass, unsigned long ip) { - lock_set_class(lock, lock->name, lock->key, subclass, ip); + lock_set_class(lock, NULL, NULL, subclass, ip); } extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask); diff --git a/kernel/lockdep.c b/kernel/lockdep.c index e69434b..4a16b0a 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c @@ -3247,7 +3247,6 @@ __lock_set_class(struct lockdep_map *lock, const char *name, { struct task_struct *curr = current; struct held_lock *hlock, *prev_hlock; - struct lock_class *class; unsigned int depth; int i; @@ -3274,9 +3273,11 @@ __lock_set_class(struct lockdep_map *lock, const char *name, return print_unlock_inbalance_bug(curr, lock, ip); found_it: - lockdep_init_map(lock, name, key, 0); - class = register_lock_class(lock, subclass, 0); - hlock->class_idx = class - lock_classes + 1; + /* optimizing for lock_set_subclass() */ + if (key) { + lockdep_init_map(lock, name, key, 0); + register_lock_class(lock, subclass, 0); + } curr->lockdep_depth = i; curr->curr_chain_key = hlock->prev_chain_key; -- 1.7.5.4
| |