![Nick Piggin](/assets/img/avatar_default.png)
Here is another version, with the incremental patch rolled up, and added reclaim context annotation to kswapd, and allocation tracing to slab allocators (which may only ever reach the page allocator in rare cases, so it is good to put annotations here too). Haven't tested this version as such, but it should be getting closer to merge worthy ;) -- After noticing some code in mm/filemap.c accidentally perform a __GFP_FS allocation when it should not have been, I thought it might be a good idea to try to catch this kind of thing with lockdep. I coded up a little idea that seems to work. Unfortunately the system has to actually be in __GFP_FS page reclaim, then take the lock, before it will mark it. But at least that might still be some orders of magnitude more common (and more debuggable) than an actual deadlock condition, so we have some improvement I hope (the concept is no less complete than discovery of a lock's interrupt contexts). I guess we could even do the same thing with __GFP_IO (normal reclaim), and even GFP_NOIO locks too... but filesystems will have the most locks and fiddly code paths, so let's start there and see how it goes. It *seems* to work. I did a quick test. ================================= [ INFO: inconsistent lock state ] 2.6.28-rc6-00007-ged31348-dirty #26 --------------------------------- inconsistent {in-reclaim-W} -> {ov-reclaim-W} usage. modprobe/8526 [HC0[0]:SC0[0]:HE1:SE1] takes: (testlock){--..}, at: [<ffffffffa0020055>] brd_init+0x55/0x216 [brd] {in-reclaim-W} state was registered at: [<ffffffff80267bdb>] __lock_acquire+0x75b/0x1a60 [<ffffffff80268f71>] lock_acquire+0x91/0xc0 [<ffffffff8070f0e1>] mutex_lock_nested+0xb1/0x310 [<ffffffffa002002b>] brd_init+0x2b/0x216 [brd] [<ffffffff8020903b>] _stext+0x3b/0x170 [<ffffffff80272ebf>] sys_init_module+0xaf/0x1e0 [<ffffffff8020c3fb>] system_call_fastpath+0x16/0x1b [<ffffffffffffffff>] 0xffffffffffffffff irq event stamp: 3929 hardirqs last enabled at (3929): [<ffffffff8070f2b5>] mutex_lock_nested+0x285/0x310 hardirqs last disabled at (3928): [<ffffffff8070f089>] mutex_lock_nested+0x59/0x310 softirqs last enabled at (3732): [<ffffffff8061f623>] sk_filter+0x83/0xe0 softirqs last disabled at (3730): [<ffffffff8061f5b6>] sk_filter+0x16/0xe0 other info that might help us debug this: 1 lock held by modprobe/8526: #0: (testlock){--..}, at: [<ffffffffa0020055>] brd_init+0x55/0x216 [brd] stack backtrace: Pid: 8526, comm: modprobe Not tainted 2.6.28-rc6-00007-ged31348-dirty #26 Call Trace: [<ffffffff80265483>] print_usage_bug+0x193/0x1d0 [<ffffffff80266530>] mark_lock+0xaf0/0xca0 [<ffffffff80266735>] mark_held_locks+0x55/0xc0 [<ffffffffa0020000>] ? brd_init+0x0/0x216 [brd] [<ffffffff802667ca>] trace_reclaim_fs+0x2a/0x60 [<ffffffff80285005>] __alloc_pages_internal+0x475/0x580 [<ffffffff8070f29e>] ? mutex_lock_nested+0x26e/0x310 [<ffffffffa0020000>] ? brd_init+0x0/0x216 [brd] [<ffffffffa002006a>] brd_init+0x6a/0x216 [brd] [<ffffffffa0020000>] ? brd_init+0x0/0x216 [brd] [<ffffffff8020903b>] _stext+0x3b/0x170 [<ffffffff8070f8b9>] ? mutex_unlock+0x9/0x10 [<ffffffff8070f83d>] ? __mutex_unlock_slowpath+0x10d/0x180 [<ffffffff802669ec>] ? trace_hardirqs_on_caller+0x12c/0x190 [<ffffffff80272ebf>] sys_init_module+0xaf/0x1e0 [<ffffffff8020c3fb>] system_call_fastpath+0x16/0x1b Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Ingo Molnar <mingo@elte.hu>
99 lines
2.9 KiB
C
99 lines
2.9 KiB
C
/*
|
|
* kernel/lockdep_internals.h
|
|
*
|
|
* Runtime locking correctness validator
|
|
*
|
|
* lockdep subsystem internal functions and variables.
|
|
*/
|
|
|
|
/*
|
|
* MAX_LOCKDEP_ENTRIES is the maximum number of lock dependencies
|
|
* we track.
|
|
*
|
|
* We use the per-lock dependency maps in two ways: we grow it by adding
|
|
* every to-be-taken lock to all currently held lock's own dependency
|
|
* table (if it's not there yet), and we check it for lock order
|
|
* conflicts and deadlocks.
|
|
*/
|
|
#define MAX_LOCKDEP_ENTRIES 8192UL
|
|
|
|
#define MAX_LOCKDEP_CHAINS_BITS 14
|
|
#define MAX_LOCKDEP_CHAINS (1UL << MAX_LOCKDEP_CHAINS_BITS)
|
|
|
|
#define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS*5)
|
|
|
|
/*
|
|
* Stack-trace: tightly packed array of stack backtrace
|
|
* addresses. Protected by the hash_lock.
|
|
*/
|
|
#define MAX_STACK_TRACE_ENTRIES 262144UL
|
|
|
|
extern struct list_head all_lock_classes;
|
|
extern struct lock_chain lock_chains[];
|
|
|
|
extern void
|
|
get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3,
|
|
char *c4, char *c5, char *c6);
|
|
|
|
extern const char * __get_key_name(struct lockdep_subclass_key *key, char *str);
|
|
|
|
struct lock_class *lock_chain_get_class(struct lock_chain *chain, int i);
|
|
|
|
extern unsigned long nr_lock_classes;
|
|
extern unsigned long nr_list_entries;
|
|
extern unsigned long nr_lock_chains;
|
|
extern int nr_chain_hlocks;
|
|
extern unsigned long nr_stack_trace_entries;
|
|
|
|
extern unsigned int nr_hardirq_chains;
|
|
extern unsigned int nr_softirq_chains;
|
|
extern unsigned int nr_process_chains;
|
|
extern unsigned int max_lockdep_depth;
|
|
extern unsigned int max_recursion_depth;
|
|
|
|
#ifdef CONFIG_PROVE_LOCKING
|
|
extern unsigned long lockdep_count_forward_deps(struct lock_class *);
|
|
extern unsigned long lockdep_count_backward_deps(struct lock_class *);
|
|
#else
|
|
static inline unsigned long
|
|
lockdep_count_forward_deps(struct lock_class *class)
|
|
{
|
|
return 0;
|
|
}
|
|
static inline unsigned long
|
|
lockdep_count_backward_deps(struct lock_class *class)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_DEBUG_LOCKDEP
|
|
/*
|
|
* Various lockdep statistics:
|
|
*/
|
|
extern atomic_t chain_lookup_hits;
|
|
extern atomic_t chain_lookup_misses;
|
|
extern atomic_t hardirqs_on_events;
|
|
extern atomic_t hardirqs_off_events;
|
|
extern atomic_t redundant_hardirqs_on;
|
|
extern atomic_t redundant_hardirqs_off;
|
|
extern atomic_t softirqs_on_events;
|
|
extern atomic_t softirqs_off_events;
|
|
extern atomic_t redundant_softirqs_on;
|
|
extern atomic_t redundant_softirqs_off;
|
|
extern atomic_t nr_unused_locks;
|
|
extern atomic_t nr_cyclic_checks;
|
|
extern atomic_t nr_cyclic_check_recursions;
|
|
extern atomic_t nr_find_usage_forwards_checks;
|
|
extern atomic_t nr_find_usage_forwards_recursions;
|
|
extern atomic_t nr_find_usage_backwards_checks;
|
|
extern atomic_t nr_find_usage_backwards_recursions;
|
|
# define debug_atomic_inc(ptr) atomic_inc(ptr)
|
|
# define debug_atomic_dec(ptr) atomic_dec(ptr)
|
|
# define debug_atomic_read(ptr) atomic_read(ptr)
|
|
#else
|
|
# define debug_atomic_inc(ptr) do { } while (0)
|
|
# define debug_atomic_dec(ptr) do { } while (0)
|
|
# define debug_atomic_read(ptr) 0
|
|
#endif
|