aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2009-01-21 02:12:39 -0500
committerIngo Molnar <mingo@elte.hu>2009-02-14 17:27:49 -0500
commitcf40bd16fdad42c053040bcd3988f5fdedbb6c57 (patch)
treed97ab25726981712be806d77650b7f65167cfc88
parent6f2b9b9a9d750a9175dc79c74bfed5add840983c (diff)
lockdep: annotate reclaim context (__GFP_NOFS)
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>
-rw-r--r--include/linux/lockdep.h17
-rw-r--r--include/linux/sched.h1
-rw-r--r--kernel/lockdep.c229
-rw-r--r--kernel/lockdep_internals.h3
-rw-r--r--kernel/lockdep_proc.c6
-rw-r--r--mm/page_alloc.c5
-rw-r--r--mm/slab.c4
-rw-r--r--mm/slob.c2
-rw-r--r--mm/slub.c1
-rw-r--r--mm/vmscan.c3
10 files changed, 254 insertions, 17 deletions
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 23bf02fb124f..cc97bdbc7969 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -27,12 +27,16 @@ enum lock_usage_bit
27 LOCK_USED = 0, 27 LOCK_USED = 0,
28 LOCK_USED_IN_HARDIRQ, 28 LOCK_USED_IN_HARDIRQ,
29 LOCK_USED_IN_SOFTIRQ, 29 LOCK_USED_IN_SOFTIRQ,
30 LOCK_USED_IN_RECLAIM_FS,
30 LOCK_ENABLED_SOFTIRQS, 31 LOCK_ENABLED_SOFTIRQS,
31 LOCK_ENABLED_HARDIRQS, 32 LOCK_ENABLED_HARDIRQS,
33 LOCK_HELD_OVER_RECLAIM_FS,
32 LOCK_USED_IN_HARDIRQ_READ, 34 LOCK_USED_IN_HARDIRQ_READ,
33 LOCK_USED_IN_SOFTIRQ_READ, 35 LOCK_USED_IN_SOFTIRQ_READ,
36 LOCK_USED_IN_RECLAIM_FS_READ,
34 LOCK_ENABLED_SOFTIRQS_READ, 37 LOCK_ENABLED_SOFTIRQS_READ,
35 LOCK_ENABLED_HARDIRQS_READ, 38 LOCK_ENABLED_HARDIRQS_READ,
39 LOCK_HELD_OVER_RECLAIM_FS_READ,
36 LOCK_USAGE_STATES 40 LOCK_USAGE_STATES
37}; 41};
38 42
@@ -42,16 +46,20 @@ enum lock_usage_bit
42#define LOCKF_USED (1 << LOCK_USED) 46#define LOCKF_USED (1 << LOCK_USED)
43#define LOCKF_USED_IN_HARDIRQ (1 << LOCK_USED_IN_HARDIRQ) 47#define LOCKF_USED_IN_HARDIRQ (1 << LOCK_USED_IN_HARDIRQ)
44#define LOCKF_USED_IN_SOFTIRQ (1 << LOCK_USED_IN_SOFTIRQ) 48#define LOCKF_USED_IN_SOFTIRQ (1 << LOCK_USED_IN_SOFTIRQ)
49#define LOCKF_USED_IN_RECLAIM_FS (1 << LOCK_USED_IN_RECLAIM_FS)
45#define LOCKF_ENABLED_HARDIRQS (1 << LOCK_ENABLED_HARDIRQS) 50#define LOCKF_ENABLED_HARDIRQS (1 << LOCK_ENABLED_HARDIRQS)
46#define LOCKF_ENABLED_SOFTIRQS (1 << LOCK_ENABLED_SOFTIRQS) 51#define LOCKF_ENABLED_SOFTIRQS (1 << LOCK_ENABLED_SOFTIRQS)
52#define LOCKF_HELD_OVER_RECLAIM_FS (1 << LOCK_HELD_OVER_RECLAIM_FS)
47 53
48#define LOCKF_ENABLED_IRQS (LOCKF_ENABLED_HARDIRQS | LOCKF_ENABLED_SOFTIRQS) 54#define LOCKF_ENABLED_IRQS (LOCKF_ENABLED_HARDIRQS | LOCKF_ENABLED_SOFTIRQS)
49#define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ) 55#define LOCKF_USED_IN_IRQ (LOCKF_USED_IN_HARDIRQ | LOCKF_USED_IN_SOFTIRQ)
50 56
51#define LOCKF_USED_IN_HARDIRQ_READ (1 << LOCK_USED_IN_HARDIRQ_READ) 57#define LOCKF_USED_IN_HARDIRQ_READ (1 << LOCK_USED_IN_HARDIRQ_READ)
52#define LOCKF_USED_IN_SOFTIRQ_READ (1 << LOCK_USED_IN_SOFTIRQ_READ) 58#define LOCKF_USED_IN_SOFTIRQ_READ (1 << LOCK_USED_IN_SOFTIRQ_READ)
59#define LOCKF_USED_IN_RECLAIM_FS_READ (1 << LOCK_USED_IN_RECLAIM_FS_READ)
53#define LOCKF_ENABLED_HARDIRQS_READ (1 << LOCK_ENABLED_HARDIRQS_READ) 60#define LOCKF_ENABLED_HARDIRQS_READ (1 << LOCK_ENABLED_HARDIRQS_READ)
54#define LOCKF_ENABLED_SOFTIRQS_READ (1 << LOCK_ENABLED_SOFTIRQS_READ) 61#define LOCKF_ENABLED_SOFTIRQS_READ (1 << LOCK_ENABLED_SOFTIRQS_READ)
62#define LOCKF_HELD_OVER_RECLAIM_FS_READ (1 << LOCK_HELD_OVER_RECLAIM_FS_READ)
55 63
56#define LOCKF_ENABLED_IRQS_READ \ 64#define LOCKF_ENABLED_IRQS_READ \
57 (LOCKF_ENABLED_HARDIRQS_READ | LOCKF_ENABLED_SOFTIRQS_READ) 65 (LOCKF_ENABLED_HARDIRQS_READ | LOCKF_ENABLED_SOFTIRQS_READ)
@@ -324,7 +332,11 @@ static inline void lock_set_subclass(struct lockdep_map *lock,
324 lock_set_class(lock, lock->name, lock->key, subclass, ip); 332 lock_set_class(lock, lock->name, lock->key, subclass, ip);
325} 333}
326 334
327# define INIT_LOCKDEP .lockdep_recursion = 0, 335extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask);
336extern void lockdep_clear_current_reclaim_state(void);
337extern void lockdep_trace_alloc(gfp_t mask);
338
339# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
328 340
329#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) 341#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
330 342
@@ -342,6 +354,9 @@ static inline void lockdep_on(void)
342# define lock_release(l, n, i) do { } while (0) 354# define lock_release(l, n, i) do { } while (0)
343# define lock_set_class(l, n, k, s, i) do { } while (0) 355# define lock_set_class(l, n, k, s, i) do { } while (0)
344# define lock_set_subclass(l, s, i) do { } while (0) 356# define lock_set_subclass(l, s, i) do { } while (0)
357# define lockdep_set_current_reclaim_state(g) do { } while (0)
358# define lockdep_clear_current_reclaim_state() do { } while (0)
359# define lockdep_trace_alloc(g) do { } while (0)
345# define lockdep_init() do { } while (0) 360# define lockdep_init() do { } while (0)
346# define lockdep_info() do { } while (0) 361# define lockdep_info() do { } while (0)
347# define lockdep_init_map(lock, name, key, sub) \ 362# define lockdep_init_map(lock, name, key, sub) \
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4efb552aca47..b00a77f4999e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1313,6 +1313,7 @@ struct task_struct {
1313 int lockdep_depth; 1313 int lockdep_depth;
1314 unsigned int lockdep_recursion; 1314 unsigned int lockdep_recursion;
1315 struct held_lock held_locks[MAX_LOCK_DEPTH]; 1315 struct held_lock held_locks[MAX_LOCK_DEPTH];
1316 gfp_t lockdep_reclaim_gfp;
1316#endif 1317#endif
1317 1318
1318/* journalling filesystem info */ 1319/* journalling filesystem info */
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 06b0c3568f0b..977f940fd562 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -310,12 +310,14 @@ EXPORT_SYMBOL(lockdep_on);
310#if VERBOSE 310#if VERBOSE
311# define HARDIRQ_VERBOSE 1 311# define HARDIRQ_VERBOSE 1
312# define SOFTIRQ_VERBOSE 1 312# define SOFTIRQ_VERBOSE 1
313# define RECLAIM_VERBOSE 1
313#else 314#else
314# define HARDIRQ_VERBOSE 0 315# define HARDIRQ_VERBOSE 0
315# define SOFTIRQ_VERBOSE 0 316# define SOFTIRQ_VERBOSE 0
317# define RECLAIM_VERBOSE 0
316#endif 318#endif
317 319
318#if VERBOSE || HARDIRQ_VERBOSE || SOFTIRQ_VERBOSE 320#if VERBOSE || HARDIRQ_VERBOSE || SOFTIRQ_VERBOSE || RECLAIM_VERBOSE
319/* 321/*
320 * Quick filtering for interesting events: 322 * Quick filtering for interesting events:
321 */ 323 */
@@ -454,6 +456,10 @@ static const char *usage_str[] =
454 [LOCK_USED_IN_SOFTIRQ_READ] = "in-softirq-R", 456 [LOCK_USED_IN_SOFTIRQ_READ] = "in-softirq-R",
455 [LOCK_ENABLED_SOFTIRQS_READ] = "softirq-on-R", 457 [LOCK_ENABLED_SOFTIRQS_READ] = "softirq-on-R",
456 [LOCK_ENABLED_HARDIRQS_READ] = "hardirq-on-R", 458 [LOCK_ENABLED_HARDIRQS_READ] = "hardirq-on-R",
459 [LOCK_USED_IN_RECLAIM_FS] = "in-reclaim-W",
460 [LOCK_USED_IN_RECLAIM_FS_READ] = "in-reclaim-R",
461 [LOCK_HELD_OVER_RECLAIM_FS] = "ov-reclaim-W",
462 [LOCK_HELD_OVER_RECLAIM_FS_READ] = "ov-reclaim-R",
457}; 463};
458 464
459const char * __get_key_name(struct lockdep_subclass_key *key, char *str) 465const char * __get_key_name(struct lockdep_subclass_key *key, char *str)
@@ -462,9 +468,10 @@ const char * __get_key_name(struct lockdep_subclass_key *key, char *str)
462} 468}
463 469
464void 470void
465get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3, char *c4) 471get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3,
472 char *c4, char *c5, char *c6)
466{ 473{
467 *c1 = '.', *c2 = '.', *c3 = '.', *c4 = '.'; 474 *c1 = '.', *c2 = '.', *c3 = '.', *c4 = '.', *c5 = '.', *c6 = '.';
468 475
469 if (class->usage_mask & LOCKF_USED_IN_HARDIRQ) 476 if (class->usage_mask & LOCKF_USED_IN_HARDIRQ)
470 *c1 = '+'; 477 *c1 = '+';
@@ -493,14 +500,29 @@ get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3, char *c4
493 if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ) 500 if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ)
494 *c4 = '?'; 501 *c4 = '?';
495 } 502 }
503
504 if (class->usage_mask & LOCKF_USED_IN_RECLAIM_FS)
505 *c5 = '+';
506 else
507 if (class->usage_mask & LOCKF_HELD_OVER_RECLAIM_FS)
508 *c5 = '-';
509
510 if (class->usage_mask & LOCKF_HELD_OVER_RECLAIM_FS_READ)
511 *c6 = '-';
512 if (class->usage_mask & LOCKF_USED_IN_RECLAIM_FS_READ) {
513 *c6 = '+';
514 if (class->usage_mask & LOCKF_HELD_OVER_RECLAIM_FS_READ)
515 *c6 = '?';
516 }
517
496} 518}
497 519
498static void print_lock_name(struct lock_class *class) 520static void print_lock_name(struct lock_class *class)
499{ 521{
500 char str[KSYM_NAME_LEN], c1, c2, c3, c4; 522 char str[KSYM_NAME_LEN], c1, c2, c3, c4, c5, c6;
501 const char *name; 523 const char *name;
502 524
503 get_usage_chars(class, &c1, &c2, &c3, &c4); 525 get_usage_chars(class, &c1, &c2, &c3, &c4, &c5, &c6);
504 526
505 name = class->name; 527 name = class->name;
506 if (!name) { 528 if (!name) {
@@ -513,7 +535,7 @@ static void print_lock_name(struct lock_class *class)
513 if (class->subclass) 535 if (class->subclass)
514 printk("/%d", class->subclass); 536 printk("/%d", class->subclass);
515 } 537 }
516 printk("){%c%c%c%c}", c1, c2, c3, c4); 538 printk("){%c%c%c%c%c%c}", c1, c2, c3, c4, c5, c6);
517} 539}
518 540
519static void print_lockdep_cache(struct lockdep_map *lock) 541static void print_lockdep_cache(struct lockdep_map *lock)
@@ -1306,6 +1328,26 @@ check_prev_add_irq(struct task_struct *curr, struct held_lock *prev,
1306 LOCK_ENABLED_SOFTIRQS, "soft")) 1328 LOCK_ENABLED_SOFTIRQS, "soft"))
1307 return 0; 1329 return 0;
1308 1330
1331 /*
1332 * Prove that the new dependency does not connect a reclaim-fs-safe
1333 * lock with a reclaim-fs-unsafe lock - to achieve this we search
1334 * the backwards-subgraph starting at <prev>, and the
1335 * forwards-subgraph starting at <next>:
1336 */
1337 if (!check_usage(curr, prev, next, LOCK_USED_IN_RECLAIM_FS,
1338 LOCK_HELD_OVER_RECLAIM_FS, "reclaim-fs"))
1339 return 0;
1340
1341 /*
1342 * Prove that the new dependency does not connect a reclaim-fs-safe-read
1343 * lock with a reclaim-fs-unsafe lock - to achieve this we search
1344 * the backwards-subgraph starting at <prev>, and the
1345 * forwards-subgraph starting at <next>:
1346 */
1347 if (!check_usage(curr, prev, next, LOCK_USED_IN_RECLAIM_FS_READ,
1348 LOCK_HELD_OVER_RECLAIM_FS, "reclaim-fs-read"))
1349 return 0;
1350
1309 return 1; 1351 return 1;
1310} 1352}
1311 1353
@@ -1949,6 +1991,14 @@ static int softirq_verbose(struct lock_class *class)
1949 return 0; 1991 return 0;
1950} 1992}
1951 1993
1994static int reclaim_verbose(struct lock_class *class)
1995{
1996#if RECLAIM_VERBOSE
1997 return class_filter(class);
1998#endif
1999 return 0;
2000}
2001
1952#define STRICT_READ_CHECKS 1 2002#define STRICT_READ_CHECKS 1
1953 2003
1954static int mark_lock_irq(struct task_struct *curr, struct held_lock *this, 2004static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
@@ -2007,6 +2057,31 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
2007 if (softirq_verbose(hlock_class(this))) 2057 if (softirq_verbose(hlock_class(this)))
2008 ret = 2; 2058 ret = 2;
2009 break; 2059 break;
2060 case LOCK_USED_IN_RECLAIM_FS:
2061 if (!valid_state(curr, this, new_bit, LOCK_HELD_OVER_RECLAIM_FS))
2062 return 0;
2063 if (!valid_state(curr, this, new_bit,
2064 LOCK_HELD_OVER_RECLAIM_FS_READ))
2065 return 0;
2066 /*
2067 * just marked it reclaim-fs-safe, check that this lock
2068 * took no reclaim-fs-unsafe lock in the past:
2069 */
2070 if (!check_usage_forwards(curr, this,
2071 LOCK_HELD_OVER_RECLAIM_FS, "reclaim-fs"))
2072 return 0;
2073#if STRICT_READ_CHECKS
2074 /*
2075 * just marked it reclaim-fs-safe, check that this lock
2076 * took no reclaim-fs-unsafe-read lock in the past:
2077 */
2078 if (!check_usage_forwards(curr, this,
2079 LOCK_HELD_OVER_RECLAIM_FS_READ, "reclaim-fs-read"))
2080 return 0;
2081#endif
2082 if (reclaim_verbose(hlock_class(this)))
2083 ret = 2;
2084 break;
2010 case LOCK_USED_IN_HARDIRQ_READ: 2085 case LOCK_USED_IN_HARDIRQ_READ:
2011 if (!valid_state(curr, this, new_bit, LOCK_ENABLED_HARDIRQS)) 2086 if (!valid_state(curr, this, new_bit, LOCK_ENABLED_HARDIRQS))
2012 return 0; 2087 return 0;
@@ -2033,6 +2108,19 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
2033 if (softirq_verbose(hlock_class(this))) 2108 if (softirq_verbose(hlock_class(this)))
2034 ret = 2; 2109 ret = 2;
2035 break; 2110 break;
2111 case LOCK_USED_IN_RECLAIM_FS_READ:
2112 if (!valid_state(curr, this, new_bit, LOCK_HELD_OVER_RECLAIM_FS))
2113 return 0;
2114 /*
2115 * just marked it reclaim-fs-read-safe, check that this lock
2116 * took no reclaim-fs-unsafe lock in the past:
2117 */
2118 if (!check_usage_forwards(curr, this,
2119 LOCK_HELD_OVER_RECLAIM_FS, "reclaim-fs"))
2120 return 0;
2121 if (reclaim_verbose(hlock_class(this)))
2122 ret = 2;
2123 break;
2036 case LOCK_ENABLED_HARDIRQS: 2124 case LOCK_ENABLED_HARDIRQS:
2037 if (!valid_state(curr, this, new_bit, LOCK_USED_IN_HARDIRQ)) 2125 if (!valid_state(curr, this, new_bit, LOCK_USED_IN_HARDIRQ))
2038 return 0; 2126 return 0;
@@ -2085,6 +2173,32 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
2085 if (softirq_verbose(hlock_class(this))) 2173 if (softirq_verbose(hlock_class(this)))
2086 ret = 2; 2174 ret = 2;
2087 break; 2175 break;
2176 case LOCK_HELD_OVER_RECLAIM_FS:
2177 if (!valid_state(curr, this, new_bit, LOCK_USED_IN_RECLAIM_FS))
2178 return 0;
2179 if (!valid_state(curr, this, new_bit,
2180 LOCK_USED_IN_RECLAIM_FS_READ))
2181 return 0;
2182 /*
2183 * just marked it reclaim-fs-unsafe, check that no reclaim-fs-safe
2184 * lock in the system ever took it in the past:
2185 */
2186 if (!check_usage_backwards(curr, this,
2187 LOCK_USED_IN_RECLAIM_FS, "reclaim-fs"))
2188 return 0;
2189#if STRICT_READ_CHECKS
2190 /*
2191 * just marked it softirq-unsafe, check that no
2192 * softirq-safe-read lock in the system ever took
2193 * it in the past:
2194 */
2195 if (!check_usage_backwards(curr, this,
2196 LOCK_USED_IN_RECLAIM_FS_READ, "reclaim-fs-read"))
2197 return 0;
2198#endif
2199 if (reclaim_verbose(hlock_class(this)))
2200 ret = 2;
2201 break;
2088 case LOCK_ENABLED_HARDIRQS_READ: 2202 case LOCK_ENABLED_HARDIRQS_READ:
2089 if (!valid_state(curr, this, new_bit, LOCK_USED_IN_HARDIRQ)) 2203 if (!valid_state(curr, this, new_bit, LOCK_USED_IN_HARDIRQ))
2090 return 0; 2204 return 0;
@@ -2115,6 +2229,21 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
2115 if (softirq_verbose(hlock_class(this))) 2229 if (softirq_verbose(hlock_class(this)))
2116 ret = 2; 2230 ret = 2;
2117 break; 2231 break;
2232 case LOCK_HELD_OVER_RECLAIM_FS_READ:
2233 if (!valid_state(curr, this, new_bit, LOCK_USED_IN_RECLAIM_FS))
2234 return 0;
2235#if STRICT_READ_CHECKS
2236 /*
2237 * just marked it reclaim-fs-read-unsafe, check that no
2238 * reclaim-fs-safe lock in the system ever took it in the past:
2239 */
2240 if (!check_usage_backwards(curr, this,
2241 LOCK_USED_IN_RECLAIM_FS, "reclaim-fs"))
2242 return 0;
2243#endif
2244 if (reclaim_verbose(hlock_class(this)))
2245 ret = 2;
2246 break;
2118 default: 2247 default:
2119 WARN_ON(1); 2248 WARN_ON(1);
2120 break; 2249 break;
@@ -2123,11 +2252,17 @@ static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
2123 return ret; 2252 return ret;
2124} 2253}
2125 2254
2255enum mark_type {
2256 HARDIRQ,
2257 SOFTIRQ,
2258 RECLAIM_FS,
2259};
2260
2126/* 2261/*
2127 * Mark all held locks with a usage bit: 2262 * Mark all held locks with a usage bit:
2128 */ 2263 */
2129static int 2264static int
2130mark_held_locks(struct task_struct *curr, int hardirq) 2265mark_held_locks(struct task_struct *curr, enum mark_type mark)
2131{ 2266{
2132 enum lock_usage_bit usage_bit; 2267 enum lock_usage_bit usage_bit;
2133 struct held_lock *hlock; 2268 struct held_lock *hlock;
@@ -2136,17 +2271,32 @@ mark_held_locks(struct task_struct *curr, int hardirq)
2136 for (i = 0; i < curr->lockdep_depth; i++) { 2271 for (i = 0; i < curr->lockdep_depth; i++) {
2137 hlock = curr->held_locks + i; 2272 hlock = curr->held_locks + i;
2138 2273
2139 if (hardirq) { 2274 switch (mark) {
2275 case HARDIRQ:
2140 if (hlock->read) 2276 if (hlock->read)
2141 usage_bit = LOCK_ENABLED_HARDIRQS_READ; 2277 usage_bit = LOCK_ENABLED_HARDIRQS_READ;
2142 else 2278 else
2143 usage_bit = LOCK_ENABLED_HARDIRQS; 2279 usage_bit = LOCK_ENABLED_HARDIRQS;
2144 } else { 2280 break;
2281
2282 case SOFTIRQ:
2145 if (hlock->read) 2283 if (hlock->read)
2146 usage_bit = LOCK_ENABLED_SOFTIRQS_READ; 2284 usage_bit = LOCK_ENABLED_SOFTIRQS_READ;
2147 else 2285 else
2148 usage_bit = LOCK_ENABLED_SOFTIRQS; 2286 usage_bit = LOCK_ENABLED_SOFTIRQS;
2287 break;
2288
2289 case RECLAIM_FS:
2290 if (hlock->read)
2291 usage_bit = LOCK_HELD_OVER_RECLAIM_FS_READ;
2292 else
2293 usage_bit = LOCK_HELD_OVER_RECLAIM_FS;
2294 break;
2295
2296 default:
2297 BUG();
2149 } 2298 }
2299
2150 if (!mark_lock(curr, hlock, usage_bit)) 2300 if (!mark_lock(curr, hlock, usage_bit))
2151 return 0; 2301 return 0;
2152 } 2302 }
@@ -2200,7 +2350,7 @@ void trace_hardirqs_on_caller(unsigned long ip)
2200 * We are going to turn hardirqs on, so set the 2350 * We are going to turn hardirqs on, so set the
2201 * usage bit for all held locks: 2351 * usage bit for all held locks:
2202 */ 2352 */
2203 if (!mark_held_locks(curr, 1)) 2353 if (!mark_held_locks(curr, HARDIRQ))
2204 return; 2354 return;
2205 /* 2355 /*
2206 * If we have softirqs enabled, then set the usage 2356 * If we have softirqs enabled, then set the usage
@@ -2208,7 +2358,7 @@ void trace_hardirqs_on_caller(unsigned long ip)
2208 * this bit from being set before) 2358 * this bit from being set before)
2209 */ 2359 */
2210 if (curr->softirqs_enabled) 2360 if (curr->softirqs_enabled)
2211 if (!mark_held_locks(curr, 0)) 2361 if (!mark_held_locks(curr, SOFTIRQ))
2212 return; 2362 return;
2213 2363
2214 curr->hardirq_enable_ip = ip; 2364 curr->hardirq_enable_ip = ip;
@@ -2288,7 +2438,7 @@ void trace_softirqs_on(unsigned long ip)
2288 * enabled too: 2438 * enabled too:
2289 */ 2439 */
2290 if (curr->hardirqs_enabled) 2440 if (curr->hardirqs_enabled)
2291 mark_held_locks(curr, 0); 2441 mark_held_locks(curr, SOFTIRQ);
2292} 2442}
2293 2443
2294/* 2444/*
@@ -2317,6 +2467,31 @@ void trace_softirqs_off(unsigned long ip)
2317 debug_atomic_inc(&redundant_softirqs_off); 2467 debug_atomic_inc(&redundant_softirqs_off);
2318} 2468}
2319 2469
2470void lockdep_trace_alloc(gfp_t gfp_mask)
2471{
2472 struct task_struct *curr = current;
2473
2474 if (unlikely(!debug_locks))
2475 return;
2476
2477 /* no reclaim without waiting on it */
2478 if (!(gfp_mask & __GFP_WAIT))
2479 return;
2480
2481 /* this guy won't enter reclaim */
2482 if ((curr->flags & PF_MEMALLOC) && !(gfp_mask & __GFP_NOMEMALLOC))
2483 return;
2484
2485 /* We're only interested __GFP_FS allocations for now */
2486 if (!(gfp_mask & __GFP_FS))
2487 return;
2488
2489 if (DEBUG_LOCKS_WARN_ON(irqs_disabled()))
2490 return;
2491
2492 mark_held_locks(curr, RECLAIM_FS);
2493}
2494
2320static int mark_irqflags(struct task_struct *curr, struct held_lock *hlock) 2495static int mark_irqflags(struct task_struct *curr, struct held_lock *hlock)
2321{ 2496{
2322 /* 2497 /*
@@ -2362,6 +2537,22 @@ static int mark_irqflags(struct task_struct *curr, struct held_lock *hlock)
2362 } 2537 }
2363 } 2538 }
2364 2539
2540 /*
2541 * We reuse the irq context infrastructure more broadly as a general
2542 * context checking code. This tests GFP_FS recursion (a lock taken
2543 * during reclaim for a GFP_FS allocation is held over a GFP_FS
2544 * allocation).
2545 */
2546 if (!hlock->trylock && (curr->lockdep_reclaim_gfp & __GFP_FS)) {
2547 if (hlock->read) {
2548 if (!mark_lock(curr, hlock, LOCK_USED_IN_RECLAIM_FS_READ))
2549 return 0;
2550 } else {
2551 if (!mark_lock(curr, hlock, LOCK_USED_IN_RECLAIM_FS))
2552 return 0;
2553 }
2554 }
2555
2365 return 1; 2556 return 1;
2366} 2557}
2367 2558
@@ -2453,6 +2644,10 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
2453 case LOCK_ENABLED_SOFTIRQS: 2644 case LOCK_ENABLED_SOFTIRQS:
2454 case LOCK_ENABLED_HARDIRQS_READ: 2645 case LOCK_ENABLED_HARDIRQS_READ:
2455 case LOCK_ENABLED_SOFTIRQS_READ: 2646 case LOCK_ENABLED_SOFTIRQS_READ:
2647 case LOCK_USED_IN_RECLAIM_FS:
2648 case LOCK_USED_IN_RECLAIM_FS_READ:
2649 case LOCK_HELD_OVER_RECLAIM_FS:
2650 case LOCK_HELD_OVER_RECLAIM_FS_READ:
2456 ret = mark_lock_irq(curr, this, new_bit); 2651 ret = mark_lock_irq(curr, this, new_bit);
2457 if (!ret) 2652 if (!ret)
2458 return 0; 2653 return 0;
@@ -2966,6 +3161,16 @@ void lock_release(struct lockdep_map *lock, int nested,
2966} 3161}
2967EXPORT_SYMBOL_GPL(lock_release); 3162EXPORT_SYMBOL_GPL(lock_release);
2968 3163
3164void lockdep_set_current_reclaim_state(gfp_t gfp_mask)
3165{
3166 current->lockdep_reclaim_gfp = gfp_mask;
3167}
3168
3169void lockdep_clear_current_reclaim_state(void)
3170{
3171 current->lockdep_reclaim_gfp = 0;
3172}
3173
2969#ifdef CONFIG_LOCK_STAT 3174#ifdef CONFIG_LOCK_STAT
2970static int 3175static int
2971print_lock_contention_bug(struct task_struct *curr, struct lockdep_map *lock, 3176print_lock_contention_bug(struct task_struct *curr, struct lockdep_map *lock,
diff --git a/kernel/lockdep_internals.h b/kernel/lockdep_internals.h
index 56b196932c08..e887b783244f 100644
--- a/kernel/lockdep_internals.h
+++ b/kernel/lockdep_internals.h
@@ -32,7 +32,8 @@ extern struct list_head all_lock_classes;
32extern struct lock_chain lock_chains[]; 32extern struct lock_chain lock_chains[];
33 33
34extern void 34extern void
35get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3, char *c4); 35get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3,
36 char *c4, char *c5, char *c6);
36 37
37extern const char * __get_key_name(struct lockdep_subclass_key *key, char *str); 38extern const char * __get_key_name(struct lockdep_subclass_key *key, char *str);
38 39
diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c
index 13716b813896..b84a1dfa9077 100644
--- a/kernel/lockdep_proc.c
+++ b/kernel/lockdep_proc.c
@@ -84,7 +84,7 @@ static int l_show(struct seq_file *m, void *v)
84{ 84{
85 struct lock_class *class = v; 85 struct lock_class *class = v;
86 struct lock_list *entry; 86 struct lock_list *entry;
87 char c1, c2, c3, c4; 87 char c1, c2, c3, c4, c5, c6;
88 88
89 if (v == SEQ_START_TOKEN) { 89 if (v == SEQ_START_TOKEN) {
90 seq_printf(m, "all lock classes:\n"); 90 seq_printf(m, "all lock classes:\n");
@@ -100,8 +100,8 @@ static int l_show(struct seq_file *m, void *v)
100 seq_printf(m, " BD:%5ld", lockdep_count_backward_deps(class)); 100 seq_printf(m, " BD:%5ld", lockdep_count_backward_deps(class));
101#endif 101#endif
102 102
103 get_usage_chars(class, &c1, &c2, &c3, &c4); 103 get_usage_chars(class, &c1, &c2, &c3, &c4, &c5, &c6);
104 seq_printf(m, " %c%c%c%c", c1, c2, c3, c4); 104 seq_printf(m, " %c%c%c%c%c%c", c1, c2, c3, c4, c5, c6);
105 105
106 seq_printf(m, ": "); 106 seq_printf(m, ": ");
107 print_name(m, class); 107 print_name(m, class);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 5675b3073854..22b15a4cde8a 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1479,6 +1479,8 @@ __alloc_pages_internal(gfp_t gfp_mask, unsigned int order,
1479 unsigned long did_some_progress; 1479 unsigned long did_some_progress;
1480 unsigned long pages_reclaimed = 0; 1480 unsigned long pages_reclaimed = 0;
1481 1481
1482 lockdep_trace_alloc(gfp_mask);
1483
1482 might_sleep_if(wait); 1484 might_sleep_if(wait);
1483 1485
1484 if (should_fail_alloc_page(gfp_mask, order)) 1486 if (should_fail_alloc_page(gfp_mask, order))
@@ -1578,12 +1580,15 @@ nofail_alloc:
1578 */ 1580 */
1579 cpuset_update_task_memory_state(); 1581 cpuset_update_task_memory_state();
1580 p->flags |= PF_MEMALLOC; 1582 p->flags |= PF_MEMALLOC;
1583
1584 lockdep_set_current_reclaim_state(gfp_mask);
1581 reclaim_state.reclaimed_slab = 0; 1585 reclaim_state.reclaimed_slab = 0;
1582 p->reclaim_state = &reclaim_state; 1586 p->reclaim_state = &reclaim_state;
1583 1587
1584 did_some_progress = try_to_free_pages(zonelist, order, gfp_mask); 1588 did_some_progress = try_to_free_pages(zonelist, order, gfp_mask);
1585 1589
1586 p->reclaim_state = NULL; 1590 p->reclaim_state = NULL;
1591 lockdep_clear_current_reclaim_state();
1587 p->flags &= ~PF_MEMALLOC; 1592 p->flags &= ~PF_MEMALLOC;
1588 1593
1589 cond_resched(); 1594 cond_resched();
diff --git a/mm/slab.c b/mm/slab.c
index ddc41f337d58..6b61de8543ec 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3318,6 +3318,8 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
3318 unsigned long save_flags; 3318 unsigned long save_flags;
3319 void *ptr; 3319 void *ptr;
3320 3320
3321 lockdep_trace_alloc(flags);
3322
3321 if (slab_should_failslab(cachep, flags)) 3323 if (slab_should_failslab(cachep, flags))
3322 return NULL; 3324 return NULL;
3323 3325
@@ -3394,6 +3396,8 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller)
3394 unsigned long save_flags; 3396 unsigned long save_flags;
3395 void *objp; 3397 void *objp;
3396 3398
3399 lockdep_trace_alloc(flags);
3400
3397 if (slab_should_failslab(cachep, flags)) 3401 if (slab_should_failslab(cachep, flags))
3398 return NULL; 3402 return NULL;
3399 3403
diff --git a/mm/slob.c b/mm/slob.c
index bf7e8fc3aed8..1264799df5d1 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -464,6 +464,8 @@ void *__kmalloc_node(size_t size, gfp_t gfp, int node)
464 unsigned int *m; 464 unsigned int *m;
465 int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN); 465 int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
466 466
467 lockdep_trace_alloc(flags);
468
467 if (size < PAGE_SIZE - align) { 469 if (size < PAGE_SIZE - align) {
468 if (!size) 470 if (!size)
469 return ZERO_SIZE_PTR; 471 return ZERO_SIZE_PTR;
diff --git a/mm/slub.c b/mm/slub.c
index bdc9abb08a23..214eb207c513 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1596,6 +1596,7 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
1596 unsigned long flags; 1596 unsigned long flags;
1597 unsigned int objsize; 1597 unsigned int objsize;
1598 1598
1599 lockdep_trace_alloc(gfpflags);
1599 might_sleep_if(gfpflags & __GFP_WAIT); 1600 might_sleep_if(gfpflags & __GFP_WAIT);
1600 1601
1601 if (should_failslab(s->objsize, gfpflags)) 1602 if (should_failslab(s->objsize, gfpflags))
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 9a27c44aa327..303eb658b50b 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1963,6 +1963,9 @@ static int kswapd(void *p)
1963 struct reclaim_state reclaim_state = { 1963 struct reclaim_state reclaim_state = {
1964 .reclaimed_slab = 0, 1964 .reclaimed_slab = 0,
1965 }; 1965 };
1966
1967 lockdep_set_current_reclaim_state(GFP_KERNEL);
1968
1966 node_to_cpumask_ptr(cpumask, pgdat->node_id); 1969 node_to_cpumask_ptr(cpumask, pgdat->node_id);
1967 1970
1968 if (!cpumask_empty(cpumask)) 1971 if (!cpumask_empty(cpumask))