aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/lockdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/lockdep.c')
-rw-r--r--kernel/lockdep.c555
1 files changed, 290 insertions, 265 deletions
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 06b0c3568f0..81b5f33970b 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -41,6 +41,8 @@
41#include <linux/utsname.h> 41#include <linux/utsname.h>
42#include <linux/hash.h> 42#include <linux/hash.h>
43#include <linux/ftrace.h> 43#include <linux/ftrace.h>
44#include <linux/stringify.h>
45#include <trace/lockdep.h>
44 46
45#include <asm/sections.h> 47#include <asm/sections.h>
46 48
@@ -310,12 +312,14 @@ EXPORT_SYMBOL(lockdep_on);
310#if VERBOSE 312#if VERBOSE
311# define HARDIRQ_VERBOSE 1 313# define HARDIRQ_VERBOSE 1
312# define SOFTIRQ_VERBOSE 1 314# define SOFTIRQ_VERBOSE 1
315# define RECLAIM_VERBOSE 1
313#else 316#else
314# define HARDIRQ_VERBOSE 0 317# define HARDIRQ_VERBOSE 0
315# define SOFTIRQ_VERBOSE 0 318# define SOFTIRQ_VERBOSE 0
319# define RECLAIM_VERBOSE 0
316#endif 320#endif
317 321
318#if VERBOSE || HARDIRQ_VERBOSE || SOFTIRQ_VERBOSE 322#if VERBOSE || HARDIRQ_VERBOSE || SOFTIRQ_VERBOSE || RECLAIM_VERBOSE
319/* 323/*
320 * Quick filtering for interesting events: 324 * Quick filtering for interesting events:
321 */ 325 */
@@ -430,30 +434,24 @@ atomic_t nr_find_usage_forwards_checks;
430atomic_t nr_find_usage_forwards_recursions; 434atomic_t nr_find_usage_forwards_recursions;
431atomic_t nr_find_usage_backwards_checks; 435atomic_t nr_find_usage_backwards_checks;
432atomic_t nr_find_usage_backwards_recursions; 436atomic_t nr_find_usage_backwards_recursions;
433# define debug_atomic_inc(ptr) atomic_inc(ptr)
434# define debug_atomic_dec(ptr) atomic_dec(ptr)
435# define debug_atomic_read(ptr) atomic_read(ptr)
436#else
437# define debug_atomic_inc(ptr) do { } while (0)
438# define debug_atomic_dec(ptr) do { } while (0)
439# define debug_atomic_read(ptr) 0
440#endif 437#endif
441 438
442/* 439/*
443 * Locking printouts: 440 * Locking printouts:
444 */ 441 */
445 442
443#define __USAGE(__STATE) \
444 [LOCK_USED_IN_##__STATE] = "IN-"__stringify(__STATE)"-W", \
445 [LOCK_ENABLED_##__STATE] = __stringify(__STATE)"-ON-W", \
446 [LOCK_USED_IN_##__STATE##_READ] = "IN-"__stringify(__STATE)"-R",\
447 [LOCK_ENABLED_##__STATE##_READ] = __stringify(__STATE)"-ON-R",
448
446static const char *usage_str[] = 449static const char *usage_str[] =
447{ 450{
448 [LOCK_USED] = "initial-use ", 451#define LOCKDEP_STATE(__STATE) __USAGE(__STATE)
449 [LOCK_USED_IN_HARDIRQ] = "in-hardirq-W", 452#include "lockdep_states.h"
450 [LOCK_USED_IN_SOFTIRQ] = "in-softirq-W", 453#undef LOCKDEP_STATE
451 [LOCK_ENABLED_SOFTIRQS] = "softirq-on-W", 454 [LOCK_USED] = "INITIAL USE",
452 [LOCK_ENABLED_HARDIRQS] = "hardirq-on-W",
453 [LOCK_USED_IN_HARDIRQ_READ] = "in-hardirq-R",
454 [LOCK_USED_IN_SOFTIRQ_READ] = "in-softirq-R",
455 [LOCK_ENABLED_SOFTIRQS_READ] = "softirq-on-R",
456 [LOCK_ENABLED_HARDIRQS_READ] = "hardirq-on-R",
457}; 455};
458 456
459const char * __get_key_name(struct lockdep_subclass_key *key, char *str) 457const char * __get_key_name(struct lockdep_subclass_key *key, char *str)
@@ -461,46 +459,45 @@ const char * __get_key_name(struct lockdep_subclass_key *key, char *str)
461 return kallsyms_lookup((unsigned long)key, NULL, NULL, NULL, str); 459 return kallsyms_lookup((unsigned long)key, NULL, NULL, NULL, str);
462} 460}
463 461
464void 462static inline unsigned long lock_flag(enum lock_usage_bit bit)
465get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3, char *c4)
466{ 463{
467 *c1 = '.', *c2 = '.', *c3 = '.', *c4 = '.'; 464 return 1UL << bit;
468 465}
469 if (class->usage_mask & LOCKF_USED_IN_HARDIRQ)
470 *c1 = '+';
471 else
472 if (class->usage_mask & LOCKF_ENABLED_HARDIRQS)
473 *c1 = '-';
474 466
475 if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ) 467static char get_usage_char(struct lock_class *class, enum lock_usage_bit bit)
476 *c2 = '+'; 468{
477 else 469 char c = '.';
478 if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS)
479 *c2 = '-';
480 470
481 if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ) 471 if (class->usage_mask & lock_flag(bit + 2))
482 *c3 = '-'; 472 c = '+';
483 if (class->usage_mask & LOCKF_USED_IN_HARDIRQ_READ) { 473 if (class->usage_mask & lock_flag(bit)) {
484 *c3 = '+'; 474 c = '-';
485 if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ) 475 if (class->usage_mask & lock_flag(bit + 2))
486 *c3 = '?'; 476 c = '?';
487 } 477 }
488 478
489 if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ) 479 return c;
490 *c4 = '-'; 480}
491 if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ_READ) { 481
492 *c4 = '+'; 482void get_usage_chars(struct lock_class *class, char usage[LOCK_USAGE_CHARS])
493 if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ) 483{
494 *c4 = '?'; 484 int i = 0;
495 } 485
486#define LOCKDEP_STATE(__STATE) \
487 usage[i++] = get_usage_char(class, LOCK_USED_IN_##__STATE); \
488 usage[i++] = get_usage_char(class, LOCK_USED_IN_##__STATE##_READ);
489#include "lockdep_states.h"
490#undef LOCKDEP_STATE
491
492 usage[i] = '\0';
496} 493}
497 494
498static void print_lock_name(struct lock_class *class) 495static void print_lock_name(struct lock_class *class)
499{ 496{
500 char str[KSYM_NAME_LEN], c1, c2, c3, c4; 497 char str[KSYM_NAME_LEN], usage[LOCK_USAGE_CHARS];
501 const char *name; 498 const char *name;
502 499
503 get_usage_chars(class, &c1, &c2, &c3, &c4); 500 get_usage_chars(class, usage);
504 501
505 name = class->name; 502 name = class->name;
506 if (!name) { 503 if (!name) {
@@ -513,7 +510,7 @@ static void print_lock_name(struct lock_class *class)
513 if (class->subclass) 510 if (class->subclass)
514 printk("/%d", class->subclass); 511 printk("/%d", class->subclass);
515 } 512 }
516 printk("){%c%c%c%c}", c1, c2, c3, c4); 513 printk("){%s}", usage);
517} 514}
518 515
519static void print_lockdep_cache(struct lockdep_map *lock) 516static void print_lockdep_cache(struct lockdep_map *lock)
@@ -1263,9 +1260,49 @@ check_usage(struct task_struct *curr, struct held_lock *prev,
1263 bit_backwards, bit_forwards, irqclass); 1260 bit_backwards, bit_forwards, irqclass);
1264} 1261}
1265 1262
1266static int 1263static const char *state_names[] = {
1267check_prev_add_irq(struct task_struct *curr, struct held_lock *prev, 1264#define LOCKDEP_STATE(__STATE) \
1268 struct held_lock *next) 1265 __stringify(__STATE),
1266#include "lockdep_states.h"
1267#undef LOCKDEP_STATE
1268};
1269
1270static const char *state_rnames[] = {
1271#define LOCKDEP_STATE(__STATE) \
1272 __stringify(__STATE)"-READ",
1273#include "lockdep_states.h"
1274#undef LOCKDEP_STATE
1275};
1276
1277static inline const char *state_name(enum lock_usage_bit bit)
1278{
1279 return (bit & 1) ? state_rnames[bit >> 2] : state_names[bit >> 2];
1280}
1281
1282static int exclusive_bit(int new_bit)
1283{
1284 /*
1285 * USED_IN
1286 * USED_IN_READ
1287 * ENABLED
1288 * ENABLED_READ
1289 *
1290 * bit 0 - write/read
1291 * bit 1 - used_in/enabled
1292 * bit 2+ state
1293 */
1294
1295 int state = new_bit & ~3;
1296 int dir = new_bit & 2;
1297
1298 /*
1299 * keep state, bit flip the direction and strip read.
1300 */
1301 return state | (dir ^ 2);
1302}
1303
1304static int check_irq_usage(struct task_struct *curr, struct held_lock *prev,
1305 struct held_lock *next, enum lock_usage_bit bit)
1269{ 1306{
1270 /* 1307 /*