Oops when accessing /proc/lockdep_chains
hi,
with current -git (aka -rc2) i sometime get the following oops when doing a cat /proc/lockdep_chains
The other /proc/lockdep* files dont cause any errors
I dont get it after a fresh reboot :| But was able to reproduce it when running my testscripts, I'll try to narrow it down.
[ 584.458673] BUG: unable to handle kernel paging request at d1a27580 [ 584.459010] IP: [<c049403e>] strnlen+0xe/0x20 [ 584.459340] Oops: 0000 [#1] DEBUG_PAGEALLOC [ 584.459596] Modules linked in: [last unloaded: rcutorture] [ 584.459923] [ 584.460038] Pid: 9047, comm: cat Not tainted (2.6.27-rc2 #26) [ 584.460245] EIP: 0060:[<c049403e>] EFLAGS: 00010297 CPU: 0 [ 584.460394] EIP is at strnlen+0xe/0x20 [ 584.460532] EAX: d1a27580 EBX: c86efca8 ECX: d1a27580 EDX: fffffffe [ 584.460682] ESI: 00000000 EDI: c86f0000 EBP: c87fdce8 ESP: c87fdce8 [ 584.460890] DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068 [ 584.461035] Process cat (pid: 9047, ti=c87fd000 task=c87d2420 task.ti=c87fd000) [ 584.461193] Stack: c87fdd04 c0493036 c010317c d1a27580 c86efca8 00000000 c87fde5c c87fde34 [ 584.462138] c0493457 ffffffff ffffffff 00000000 ffffffff ffffffff 00000000 00000358 [ 584.463021] c86efca8 ffffffff c86f0000 ffffffff ffffffff ffffffff 0000000f c0a3b725 [ 584.463964] Call Trace: [ 584.464173] [<c0493036>] ? string+0x26/0xa0 [ 584.464510] [<c010317c>] ? restore_nocheck_notrace+0x0/0xe [ 584.464859] [<c0493457>] ? vsnprintf+0x3a7/0x6a0 [ 584.465141] [<c04940ac>] ? trace_hardirqs_on_thunk+0xc/0x10 [ 584.465219] [<c01059de>] ? do_softirq+0x3e/0xb0 [ 584.465219] [<c010317c>] ? restore_nocheck_notrace+0x0/0xe [ 584.465219] [<c04934c4>] ? vsnprintf+0x414/0x6a0 [ 584.465219] [<c0149837>] ? __lock_acquire+0x257/0xe50 [ 584.465219] [<c01b46c2>] ? seq_printf+0x32/0x60 [ 584.465219] [<c014aa81>] ? print_name+0x31/0xb0 [ 584.465219] [<c0149260>] ? mark_held_locks+0x40/0x80 [ 584.465219] [<c01494ab>] ? trace_hardirqs_on+0xb/0x10 [ 584.465219] [<c0149409>] ? trace_hardirqs_on_caller+0xc9/0x160 [ 584.465219] [<c0830f64>] ? __mutex_lock_common+0x1e4/0x2e0 [ 584.465219] [<c01b4c1a>] ? seq_read+0x2a/0x2a0 [ 584.465219] [<c01b46c2>] ? seq_printf+0x32/0x60 [ 584.465219] [<c014ab6f>] ? lc_show+0x6f/0xc0 [ 584.465219] [<c01b4d5f>] ? seq_read+0x16f/0x2a0 [ 584.465219] [<c01b4bf0>] ? seq_read+0x0/0x2a0 [ 584.465219] [<c01d58f2>] ? proc_reg_read+0x62/0x90 [ 584.465219] [<c0199269>] ? vfs_read+0x99/0x160 [ 584.465219] [<c01d5890>] ? proc_reg_read+0x0/0x90 [ 584.465219] [<c0199842>] ? sys_read+0x42/0x70 [ 584.465219] [<c0103059>] ? sysenter_do_call+0x12/0x31 [ 584.465219] ======================= [ 584.465219] Code: 57 0f 1f 44 00 00 85 c9 89 c7 89 d0 74 05 f2 ae 75 01 4f 89 f8 5f 5d c3 90 8d 74 26 00 55 89 e5 0f 1f 44 00 00 89 c1 89 c8 eb 06 <80> 38 00 74 07 40 4a 83 fa ff 75 f4 29 c8 5d c3 90 90 55 89 e5 [ 584.465219] EIP: [<c049403e>] strnlen+0xe/0x20 SS:ESP 0068:c87fdce8 [ 584.465219] ---[ end trace 560310b80b6f2ef3 ]---
[ 657.508210] BUG: unable to handle kernel paging request at d1a27580 [ 657.508546] IP: [<c049403e>] strnlen+0xe/0x20 [ 657.508827] *pde = 0ef53067 *pte = 00000000 [ 657.509067] Oops: 0000 [#2] DEBUG_PAGEALLOC [ 657.509364] Modules linked in: [last unloaded: rcutorture] [ 657.509382] [ 657.509382] Pid: 14555, comm: cat Tainted: G D (2.6.27-rc2 #26) [ 657.509382] EIP: 0060:[<c049403e>] EFLAGS: 00010297 CPU: 0 [ 657.509382] EIP is at strnlen+0xe/0x20 [ 657.509382] EAX: d1a27580 EBX: c86ef36c ECX: d1a27580 EDX: fffffffe [ 657.509382] ESI: 00000000 EDI: c86f0000 EBP: c867fce8 ESP: c867fce8 [ 657.509382] DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068 [ 657.509382] Process cat (pid: 14555, ti=c867f000 task=c86a4420 task.ti=c867f000) [ 657.509382] Stack: c867fd04 c0493036 00000000 d1a27580 c86ef36c 00000000 c867fe5c c867fe34 [ 657.509382] c0493457 ffffffff ffffffff 00000000 00000000 c867fd44 00000046 00000c94 [ 657.509382] c86ef36c ffffffff c86f0000 ffffffff ffffffff ffffffff 0000000f c0a3b725 [ 657.509382] Call Trace: [ 657.509382] [<c0493036>] ? string+0x26/0xa0 [ 657.509382] [<c0493457>] ? vsnprintf+0x3a7/0x6a0 [ 657.509382] [<c012417b>] ? try_to_wake_up+0x6b/0xf0 [ 657.509382] [<c04934c4>] ? vsnprintf+0x414/0x6a0 [ 657.509382] [<c0514aed>] ? n_tty_receive_buf+0x63d/0x1230 [ 657.509382] [<c01189ff>] ? __change_page_attr_set_clr+0xcf/0x4e0 [ 657.509382] [<c0164ef0>] ? handle_level_irq+0x0/0xd0 [ 657.509382] [<c0146d84>] ? trace_hardirqs_off_caller+0x14/0xa0 [ 657.509382] [<c01b46c2>] ? seq_printf+0x32/0x60 [ 657.509382] [<c014aa81>] ? print_name+0x31/0xb0 [ 657.509382] [<c0146d84>] ? trace_hardirqs_off_caller+0x14/0xa0 [ 657.509382] [<c0149355>] ? trace_hardirqs_on_caller+0x15/0x160 [ 657.509382] [<c0830f64>] ? __mutex_lock_common+0x1e4/0x2e0 [ 657.509382] [<c01b4c1a>] ? seq_read+0x2a/0x2a0 [ 657.509382] [<c01b46c2>] ? seq_printf+0x32/0x60 [ 657.509382] [<c014ab6f>] ? lc_show+0x6f/0xc0 [ 657.509382] [<c01b4d5f>] ? seq_read+0x16f/0x2a0 [ 657.509382] [<c01b4bf0>] ? seq_read+0x0/0x2a0 [ 657.509382] [<c01d58f2>] ? proc_reg_read+0x62/0x90 [ 657.509382] [<c0199269>] ? vfs_read+0x99/0x160 [ 657.509382] [<c01d5890>] ? proc_reg_read+0x0/0x90 [ 657.509382] [<c0199842>] ? sys_read+0x42/0x70 [ 657.509382] [<c0103059>] ? sysenter_do_call+0x12/0x31 [ 657.509382] [<c0124abf>] ? __cleanup_sighand+0x1f/0x30 [ 657.509382] ======================= [ 657.509382] Code: 57 0f 1f 44 00 00 85 c9 89 c7 89 d0 74 05 f2 ae 75 01 4f 89 f8 5f 5d c3 90 8d 74 26 00 55 89 e5 0f 1f 44 00 00 89 c1 89 c8 eb 06 <80> 38 00 74 07 40 4a 83 fa ff 75 f4 29 c8 5d c3 90 90 55 89 e5 [ 657.509382] EIP: [<c049403e>] strnlen+0xe/0x20 SS:ESP 0068:c867fce8 [ 657.510433] ---[ end trace 560310b80b6f2ef3 ]---
Greetings, Eric
Quoted 8 lines · * Eric Sesterhenn ([email protected]) wrote:
hi,
with current -git (aka -rc2) i sometime get the following oops when doing a cat
/proc/lockdep_chains
The other/proc/lockdep*files dont cause any errorsI dont get it after a fresh reboot :| But was able to reproduce it when running my testscripts, I'll try to narrow it down.
I can easily reproduce this with
modprobe rcutorture; sleep 10s; rmmod rcutorture; cat /proc/lockdep_chains > /dev/null
Greetings, Eric
Quoted 7 lines · Eric Sesterhenn
Quoted 6 lines · * Eric Sesterhenn ([email protected]) wrote:
hi,
with current -git (aka -rc2) i sometime get the following oops when doing a cat
/proc/lockdep_chains
The other/proc/lockdep*files dont cause any errors
Quoted 7 lines
Quoted 2 lines
I dont get it after a fresh reboot :| But was able to reproduce it when running my testscripts, I'll try to narrow it down.
I can easily reproduce this with
modprobe rcutorture; sleep 10s; rmmod rcutorture; cat
/proc/lockdep_chains>/dev/null
Indeed, it oopses after any module which creates a lock is unloaded. I'll send a patch for this shortly.
Rabin
PATCH 1/1 lockdep: handle chains involving classes defined in modules
/proc/lockdep_chains currently oopses after any module which creates and uses a lock is unloaded. This is because one of the chains involves a class which was defined in the module just unloaded.
The classes are already correctly taken care of using the all_lock_classes which keeps track of all active lock classses. Add a similar all_lock_chains list and use it for keeping track of chains.
--- include/linux/lockdep.h | 3 +- kernel/lockdep.c | 53 ++++++++++++++++++++++++++++++++++++++----- kernel/lockdep_internals.h | 2 +- kernel/lockdep_proc.c | 17 ++++++++++---- 4 files changed, 61 insertions(+), 14 deletions(-)
include/linux/lockdep.h +2 -1
@@ -185,7 +185,8 @@ struct lock_chain {u8 irq_context;u8 depth;u16 base; -struct list_head entry; +struct list_head hash_entry; +struct list_head lock_entry;u64 chain_key; };
kernel/lockdep.c +46 -7
115 lines not on this page · raw message
kernel/lockdep_internals.h +1 -1
@@ -32,7 +32,7 @@#define MAX_STACK_TRACE_ENTRIES 262144ULextern struct list_head all_lock_classes; -extern struct lock_chain lock_chains[]; +extern struct list_head all_lock_chains;extern void get_usage_chars (struct lock_class *class,char *c1,char *c2,char *c3,char *c4);
kernel/lockdep_proc.c +12 -5
@@ -190,8 +190,9 @@ static void *lc_next(struct seq_file *m, void *v, loff_t *pos)else { chain = v; -if (*pos < nr_lock_chains) - chain = lock_chains + *pos; +if (chain->lock_entry.next != &all_lock_chains) + chain =list_entry (chain->lock_entry.next, + struct lock_chain, lock_entry);else chain =NULL ; }
@@ -201,11 +202,16 @@ static void *lc_next(struct seq_file *m, void *v, loff_t *pos)static void *lc_start (struct seq_file *m,loff_t *pos) { +struct lock_chain *chain; +loff_t i =0 ; +if (*pos ==0 )return SEQ_START_TOKEN ; -if (*pos < nr_lock_chains) -return lock_chains + *pos; +list_for_each_entry (chain, &all_lock_chains, lock_entry) { +if (++i == *pos) +return chain; + }return NULL ; }
@@ -252,7 +258,8 @@ static int lockdep_chains_open(struct inode *inode, struct file *file)struct seq_file *m = file->private_data;if (nr_lock_chains) - m->private = lock_chains; + m->private =list_entry (all_lock_chains.next, + struct lock_chain, lock_entry);else m->private =NULL ; }
Signature · 1 line
1.5.6.3
Re: [PATCH] lockdep: handle chains involving classes defined in modules
Hi, Rabin,
I think there is a simpler method to deal with this.
- Mark class as useless during zap_class()
- When output lock_chain, if some classes are useless, do not output the class.
Best Regards,
Huang Ying
Quoted 216 lines · Rabin Vincent
/proc/lockdep_chainscurrently oopses after any module which creates and uses a lock is unloaded. This is because one of the chains involves a class which was defined in the module just unloaded.The classes are already correctly taken care of using the
all_lock_classeswhich keeps track of all active lock classses. Add a similarall_lock_chainslist and use it for keeping track of chains.Reported-by Eric Sesterhenn <[email protected]>Signed-off-by Rabin Vincent <[email protected]>--- include/linux/lockdep.h | 3 +- kernel/lockdep.c | 53 ++++++++++++++++++++++++++++++++++++++----- kernel/lockdep_internals.h | 2 +- kernel/lockdep_proc.c | 17 ++++++++++---- 4 files changed, 61 insertions(+), 14 deletions(-)include/linux/lockdep.h +2
-1@@ -185,7 +185,8 @@ struct lock_chain {u8 irq_context;u8 depth;u16 base; -struct list_head entry; +struct list_head hash_entry; +struct list_head lock_entry;u64 chain_key; };kernel/lockdep.c +46
-7@@ -253,6 +253,11 @@ LIST_HEAD(all_lock_classes);static struct list_head classhash_table[CLASSHASH_SIZE ];/* +* We also keep a global list of all lock chains. +*/ +LIST_HEAD (all_lock_chains); + +/* * We put the lock dependency chains into a hash-table as well, to cache * their existence: */ @@ -1462,7 +1467,7 @@ out_bug: }unsigned long nr_lock_chains; -struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS ]; +static struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS ];int nr_chain_hlocks;static u16 chain_hlocks[MAX_LOCKDEP_CHAIN_HLOCKS ];@@ -1493,7 +1498,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,* We can walk it lock-free, because entries only get added * to the hash: */ -list_for_each_entry (chain, hash_head, entry) { +list_for_each_entry (chain, hash_head, hash_entry) {if (chain->chain_key == chain_key) { cache_hit:debug_atomic_inc (&chain_lookup_hits);@@ -1517,7 +1522,7 @@ cache_hit:/* * We have to walk the chain again locked - to avoid duplicates: */ -list_for_each_entry (chain, hash_head, entry) { +list_for_each_entry (chain, hash_head, hash_entry) {if (chain->chain_key == chain_key) {graph_unlock (); goto cache_hit;@@ -1559,7 +1564,8 @@ cache_hit: } chain_hlocks[chain->base + j] = class - lock_classes; } -list_add_tail_rcu (&chain->entry, hash_head); +list_add_tail_rcu (&chain->hash_entry, hash_head); +list_add_tail_rcu (&chain->lock_entry, &all_lock_chains);debug_atomic_inc (&chain_lookup_misses);inc_chains ();@@ -2967,6 +2973,8 @@ void lockdep_reset(void) debug_locks =1 ;for (i =0 ; i <CHAINHASH_SIZE ; i++)INIT_LIST_HEAD (chainhash_table + i); +for (i =0 ; i <CLASSHASH_SIZE ; i++) +INIT_LIST_HEAD (classhash_table + i);raw_local_irq_restore (flags); }@@ -2990,6 +2998,15 @@ static void zap_class(struct lock_class *class) } +static void zap_chain (struct lock_chain *chain) +{ +/* +* Unhash the chain and remove it from the all_lock_chains list: +*/ +list_del_rcu (&chain->hash_entry); +list_del_rcu (&chain->lock_entry); +} +static inline int within (const void *addr,void *start,unsigned long size) {return addr >= start && addr < start + size;@@ -2997,23 +3014,45 @@ static inline int within(const void *addr, void *start, unsigned long size)void lockdep_free_key_range (void *start,unsigned long size) { -struct lock_class *class, *next; +struct lock_class *class, *nextclass; +struct lock_chain *chain, *nextchain;struct list_head *head;unsigned long flags; -int i; +int i, j;int locked;raw_local_irq_save (flags); locked =graph_lock ();/* +* Unhash all chains that involve classes created by this module: +*/ +for (i =0 ; i <CHAINHASH_SIZE ; i++) { + head = chainhash_table + i; +if (list_empty (head)) +continue ; +list_for_each_entry_safe (chain, nextchain, head, hash_entry) { +for (j =0 ; j < chain->depth; j++) { + class = lock_classes + + chain_hlocks[chain->base + j]; + +if (within (class->key, start, size) || +within (class->name, start, size)) { +zap_chain (chain); +break ; + } + } + } + } + +/* * Unhash all classes that were created by this module: */ for (i =0 ; i <CLASSHASH_SIZE ; i++) { head = classhash_table + i;if (list_empty (head))continue ; -list_for_each_entry_safe (class, next, head, hash_entry) { +list_for_each_entry_safe (class, nextclass, head, hash_entry) {if (within (class->key, start, size))zap_class (class);else if (within (class->name, start, size))kernel/lockdep_internals.h +1
-1@@ -32,7 +32,7 @@#define MAX_STACK_TRACE_ENTRIES 262144ULextern struct list_head all_lock_classes; -extern struct lock_chain lock_chains[]; +extern struct list_head all_lock_chains;extern void get_usage_chars (struct lock_class *class,char *c1,char *c2,char *c3,char *c4);kernel/lockdep_proc.c +12
-5@@ -190,8 +190,9 @@ static void *lc_next(struct seq_file *m, void *v, loff_t *pos)else { chain = v; -if (*pos < nr_lock_chains) - chain = lock_chains + *pos; +if (chain->lock_entry.next != &all_lock_chains) + chain =list_entry (chain->lock_entry.next, + struct lock_chain, lock_entry);else chain =NULL ; }@@ -201,11 +202,16 @@ static void *lc_next(struct seq_file *m, void *v, loff_t *pos)static void *lc_start (struct seq_file *m,loff_t *pos) { +struct lock_chain *chain; +loff_t i =0 ; +if (*pos ==0 )return SEQ_START_TOKEN ; -if (*pos < nr_lock_chains) -return lock_chains + *pos; +list_for_each_entry (chain, &all_lock_chains, lock_entry) { +if (++i == *pos) +return chain; + }return NULL ; }@@ -252,7 +258,8 @@ static int lockdep_chains_open(struct inode *inode, struct file *file)struct seq_file *m = file->private_data;if (nr_lock_chains) - m->private = lock_chains; + m->private =list_entry (all_lock_chains.next, + struct lock_chain, lock_entry);else m->private =NULL ; }
Re: [PATCH] lockdep: handle chains involving classes defined in modules
Quoted 9 lines · Huang Ying
Quoted 8 lines · Rabin Vincent
/proc/lockdep_chainscurrently oopses after any module which creates and uses a lock is unloaded. This is because one of the chains involves a class which was defined in the module just unloaded.The classes are already correctly taken care of using the
all_lock_classeswhich keeps track of all active lock classses. Add a similarall_lock_chainslist and use it for keeping track of chains.
[...]
Quoted 2 lines
I think there is a simpler method to deal with this.
Yes. I went with the all_lock_chains list approach because there was similar code already being used to keep track of lock_class structures.
Quoted 3 lines
- Mark class as useless during
zap_class()
- When outputlock_chain, if some classes are useless, do not output the class.
Like the patch below? I set ->key to NULL after zapping the class and use that as a condition to not print the class' information. The only issue is that with this patch there will be some chains output with no locks listed under them.
---
lockdep: handle chains involving classes defined in modules
/proc/lockdep_chains currently oopses after any module which creates and uses a lock is unloaded. This is because one of the chains involves a class which was defined in the module just unloaded.
Solve this by marking the classes as unused and not printing information about the unused classes.
kernel/lockdep.c +1 -0
@@ -2988,6 +2988,7 @@ static void zap_class(struct lock_class *class)list_del_rcu (&class->hash_entry);list_del_rcu (&class->lock_entry); + class->key =NULL ; }static inline int within (const void *addr,void *start,unsigned long size)
kernel/lockdep_proc.c +3 -0
@@ -229,6 +229,9 @@ static int lc_show(struct seq_file *m, void *v)for (i =0 ; i < chain->depth; i++) { class =lock_chain_get_class (chain, i); +if (!class->key) +continue ; +seq_printf (m,"[%p] " , class->key);print_name (m, class);seq_puts (m,"\n" );
Huang Ying
Acked-byRe: [PATCH] lockdep: handle chains involving classes defined in modules
Quoted 56 lines · Rabin Vincent
Quoted 9 lines · Huang Ying
Quoted 8 lines · Rabin Vincent
/proc/lockdep_chainscurrently oopses after any module which creates and uses a lock is unloaded. This is because one of the chains involves a class which was defined in the module just unloaded.The classes are already correctly taken care of using the
all_lock_classeswhich keeps track of all active lock classses. Add a similarall_lock_chainslist and use it for keeping track of chains.[...]
Quoted 2 lines
I think there is a simpler method to deal with this.
Yes. I went with the
all_lock_chainslist approach because there was similar code already being used to keep track oflock_classstructures.Quoted 3 lines
- Mark class as useless during
zap_class()
- When outputlock_chain, if some classes are useless, do not output the class.Like the patch below? I set ->key to NULL after zapping the class and use that as a condition to not print the class' information. The only issue is that with this patch there will be some chains output with no locks listed under them.
---
lockdep: handle chains involving classes defined in modules
/proc/lockdep_chainscurrently oopses after any module which creates and uses a lock is unloaded. This is because one of the chains involves a class which was defined in the module just unloaded.Solve this by marking the classes as unused and not printing information about the unused classes.
Reported-by Eric Sesterhenn <[email protected]>Signed-off-by Rabin Vincent <[email protected]>kernel/lockdep.c +1
-0@@ -2988,6 +2988,7 @@ static void zap_class(struct lock_class *class)list_del_rcu (&class->hash_entry);list_del_rcu (&class->lock_entry); + class->key =NULL ; }static inline int within (const void *addr,void *start,unsigned long size)kernel/lockdep_proc.c +0
-0
kernel/lockdep_proc.c static int lc_show(struct seq_file *m, void *v) · line 237
Quoted 9 lines
kernel/lockdep_proc.c +3
-0@@ -229,6 +229,9 @@ static int lc_show(struct seq_file *m, void *v)for (i =0 ; i < chain->depth; i++) { class =lock_chain_get_class (chain, i); +if (!class->key) +continue ; +seq_printf (m,"[%p] " , class->key);print_name (m, class);seq_puts (m,"\n" );
I think this patch is OK.
Best Regards,
Huang Ying
Re: [PATCH] lockdep: handle chains involving classes defined in modules
In reply to Rabin VincentQuoted 10 lines · Rabin Vincent
/proc/lockdep_chainscurrently oopses after any module which creates and uses a lock is unloaded. This is because one of the chains involves a class which was defined in the module just unloaded.The classes are already correctly taken care of using the
all_lock_classeswhich keeps track of all active lock classses. Add a similarall_lock_chainslist and use it for keeping track of chains.Reported-by Eric Sesterhenn <[email protected]>Signed-off-by Rabin Vincent <[email protected]>
Looks good - I was about to start poking at this and then I found your patch in my mailbox, most appreciated!
Quoted 206 lines
--- include/linux/lockdep.h | 3 +- kernel/lockdep.c | 53 ++++++++++++++++++++++++++++++++++++++----- kernel/lockdep_internals.h | 2 +- kernel/lockdep_proc.c | 17 ++++++++++---- 4 files changed, 61 insertions(+), 14 deletions(-)include/linux/lockdep.h +2
-1@@ -185,7 +185,8 @@ struct lock_chain {u8 irq_context;u8 depth;u16 base; -struct list_head entry; +struct list_head hash_entry; +struct list_head lock_entry;u64 chain_key; };kernel/lockdep.c +46
-7@@ -253,6 +253,11 @@ LIST_HEAD(all_lock_classes);static struct list_head classhash_table[CLASSHASH_SIZE ];/* +* We also keep a global list of all lock chains. +*/ +LIST_HEAD (all_lock_chains); + +/* * We put the lock dependency chains into a hash-table as well, to cache * their existence: */ @@ -1462,7 +1467,7 @@ out_bug: }unsigned long nr_lock_chains; -struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS ]; +static struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS ];int nr_chain_hlocks;static u16 chain_hlocks[MAX_LOCKDEP_CHAIN_HLOCKS ];@@ -1493,7 +1498,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,* We can walk it lock-free, because entries only get added * to the hash: */ -list_for_each_entry (chain, hash_head, entry) { +list_for_each_entry (chain, hash_head, hash_entry) {if (chain->chain_key == chain_key) { cache_hit:debug_atomic_inc (&chain_lookup_hits);@@ -1517,7 +1522,7 @@ cache_hit:/* * We have to walk the chain again locked - to avoid duplicates: */ -list_for_each_entry (chain, hash_head, entry) { +list_for_each_entry (chain, hash_head, hash_entry) {if (chain->chain_key == chain_key) {graph_unlock (); goto cache_hit;@@ -1559,7 +1564,8 @@ cache_hit: } chain_hlocks[chain->base + j] = class - lock_classes; } -list_add_tail_rcu (&chain->entry, hash_head); +list_add_tail_rcu (&chain->hash_entry, hash_head); +list_add_tail_rcu (&chain->lock_entry, &all_lock_chains);debug_atomic_inc (&chain_lookup_misses);inc_chains ();@@ -2967,6 +2973,8 @@ void lockdep_reset(void) debug_locks =1 ;for (i =0 ; i <CHAINHASH_SIZE ; i++)INIT_LIST_HEAD (chainhash_table + i); +for (i =0 ; i <CLASSHASH_SIZE ; i++) +INIT_LIST_HEAD (classhash_table + i);raw_local_irq_restore (flags); }@@ -2990,6 +2998,15 @@ static void zap_class(struct lock_class *class) } +static void zap_chain (struct lock_chain *chain) +{ +/* +* Unhash the chain and remove it from the all_lock_chains list: +*/ +list_del_rcu (&chain->hash_entry); +list_del_rcu (&chain->lock_entry); +} +static inline int within (const void *addr,void *start,unsigned long size) {return addr >= start && addr < start + size;@@ -2997,23 +3014,45 @@ static inline int within(const void *addr, void *start, unsigned long size)void lockdep_free_key_range (void *start,unsigned long size) { -struct lock_class *class, *next; +struct lock_class *class, *nextclass; +struct lock_chain *chain, *nextchain;struct list_head *head;unsigned long flags; -int i; +int i, j;int locked;raw_local_irq_save (flags); locked =graph_lock ();/* +* Unhash all chains that involve classes created by this module: +*/ +for (i =0 ; i <CHAINHASH_SIZE ; i++) { + head = chainhash_table + i; +if (list_empty (head)) +continue ; +list_for_each_entry_safe (chain, nextchain, head, hash_entry) { +for (j =0 ; j < chain->depth; j++) { + class = lock_classes + + chain_hlocks[chain->base + j]; + +if (within (class->key, start, size) || +within (class->name, start, size)) { +zap_chain (chain); +break ; + } + } + } + } + +/* * Unhash all classes that were created by this module: */ for (i =0 ; i <CLASSHASH_SIZE ; i++) { head = classhash_table + i;if (list_empty (head))continue ; -list_for_each_entry_safe (class, next, head, hash_entry) { +list_for_each_entry_safe (class, nextclass, head, hash_entry) {if (within (class->key, start, size))zap_class (class);else if (within (class->name, start, size))kernel/lockdep_internals.h +1
-1@@ -32,7 +32,7 @@#define MAX_STACK_TRACE_ENTRIES 262144ULextern struct list_head all_lock_classes; -extern struct lock_chain lock_chains[]; +extern struct list_head all_lock_chains;extern void get_usage_chars (struct lock_class *class,char *c1,char *c2,char *c3,char *c4);kernel/lockdep_proc.c +12
-5@@ -190,8 +190,9 @@ static void *lc_next(struct seq_file *m, void *v, loff_t *pos)else { chain = v; -if (*pos < nr_lock_chains) - chain = lock_chains + *pos; +if (chain->lock_entry.next != &all_lock_chains) + chain =list_entry (chain->lock_entry.next, + struct lock_chain, lock_entry);else chain =NULL ; }@@ -201,11 +202,16 @@ static void *lc_next(struct seq_file *m, void *v, loff_t *pos)static void *lc_start (struct seq_file *m,loff_t *pos) { +struct lock_chain *chain; +loff_t i =0 ; +if (*pos ==0 )return SEQ_START_TOKEN ; -if (*pos < nr_lock_chains) -return lock_chains + *pos; +list_for_each_entry (chain, &all_lock_chains, lock_entry) { +if (++i == *pos) +return chain; + }return NULL ; }@@ -252,7 +258,8 @@ static int lockdep_chains_open(struct inode *inode, struct file *file)struct seq_file *m = file->private_data;if (nr_lock_chains) - m->private = lock_chains; + m->private =list_entry (all_lock_chains.next, + struct lock_chain, lock_entry);else m->private =NULL ; }