aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/lockdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/lockdep.c')
-rw-r--r--kernel/lockdep.c229
1 files changed, 217 insertions, 12 deletions
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,