diff options
Diffstat (limited to 'kernel/lockdep.c')
-rw-r--r-- | kernel/lockdep.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 53a68956f131..7b2ffeedcebd 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
@@ -490,6 +490,18 @@ void get_usage_chars(struct lock_class *class, char usage[LOCK_USAGE_CHARS]) | |||
490 | usage[i] = '\0'; | 490 | usage[i] = '\0'; |
491 | } | 491 | } |
492 | 492 | ||
493 | static int __print_lock_name(struct lock_class *class) | ||
494 | { | ||
495 | char str[KSYM_NAME_LEN]; | ||
496 | const char *name; | ||
497 | |||
498 | name = class->name; | ||
499 | if (!name) | ||
500 | name = __get_key_name(class->key, str); | ||
501 | |||
502 | return printk("%s", name); | ||
503 | } | ||
504 | |||
493 | static void print_lock_name(struct lock_class *class) | 505 | static void print_lock_name(struct lock_class *class) |
494 | { | 506 | { |
495 | char str[KSYM_NAME_LEN], usage[LOCK_USAGE_CHARS]; | 507 | char str[KSYM_NAME_LEN], usage[LOCK_USAGE_CHARS]; |
@@ -1325,6 +1337,62 @@ print_shortest_lock_dependencies(struct lock_list *leaf, | |||
1325 | return; | 1337 | return; |
1326 | } | 1338 | } |
1327 | 1339 | ||
1340 | static void | ||
1341 | print_irq_lock_scenario(struct lock_list *safe_entry, | ||
1342 | struct lock_list *unsafe_entry, | ||
1343 | struct held_lock *prev, | ||
1344 | struct held_lock *next) | ||
1345 | { | ||
1346 | struct lock_class *safe_class = safe_entry->class; | ||
1347 | struct lock_class *unsafe_class = unsafe_entry->class; | ||
1348 | struct lock_class *middle_class = hlock_class(prev); | ||
1349 | |||
1350 | if (middle_class == safe_class) | ||
1351 | middle_class = hlock_class(next); | ||
1352 | |||
1353 | /* | ||
1354 | * A direct locking problem where unsafe_class lock is taken | ||
1355 | * directly by safe_class lock, then all we need to show | ||
1356 | * is the deadlock scenario, as it is obvious that the | ||
1357 | * unsafe lock is taken under the safe lock. | ||
1358 | * | ||
1359 | * But if there is a chain instead, where the safe lock takes | ||
1360 | * an intermediate lock (middle_class) where this lock is | ||
1361 | * not the same as the safe lock, then the lock chain is | ||
1362 | * used to describe the problem. Otherwise we would need | ||
1363 | * to show a different CPU case for each link in the chain | ||
1364 | * from the safe_class lock to the unsafe_class lock. | ||
1365 | */ | ||
1366 | if (middle_class != unsafe_class) { | ||
1367 | printk("Chain exists of:\n "); | ||
1368 | __print_lock_name(safe_class); | ||
1369 | printk(" --> "); | ||
1370 | __print_lock_name(middle_class); | ||
1371 | printk(" --> "); | ||
1372 | __print_lock_name(unsafe_class); | ||
1373 | printk("\n\n"); | ||
1374 | } | ||
1375 | |||
1376 | printk(" Possible interrupt unsafe locking scenario:\n\n"); | ||
1377 | printk(" CPU0 CPU1\n"); | ||
1378 | printk(" ---- ----\n"); | ||
1379 | printk(" lock("); | ||
1380 | __print_lock_name(unsafe_class); | ||
1381 | printk(");\n"); | ||
1382 | printk(" local_irq_disable();\n"); | ||
1383 | printk(" lock("); | ||
1384 | __print_lock_name(safe_class); | ||
1385 | printk(");\n"); | ||
1386 | printk(" lock("); | ||
1387 | __print_lock_name(middle_class); | ||
1388 | printk(");\n"); | ||
1389 | printk(" <Interrupt>\n"); | ||
1390 | printk(" lock("); | ||
1391 | __print_lock_name(safe_class); | ||
1392 | printk(");\n"); | ||
1393 | printk("\n *** DEADLOCK ***\n\n"); | ||
1394 | } | ||
1395 | |||
1328 | static int | 1396 | static int |
1329 | print_bad_irq_dependency(struct task_struct *curr, | 1397 | print_bad_irq_dependency(struct task_struct *curr, |
1330 | struct lock_list *prev_root, | 1398 | struct lock_list *prev_root, |
@@ -1376,6 +1444,8 @@ print_bad_irq_dependency(struct task_struct *curr, | |||
1376 | print_stack_trace(forwards_entry->class->usage_traces + bit2, 1); | 1444 | print_stack_trace(forwards_entry->class->usage_traces + bit2, 1); |
1377 | 1445 | ||
1378 | printk("\nother info that might help us debug this:\n\n"); | 1446 | printk("\nother info that might help us debug this:\n\n"); |
1447 | print_irq_lock_scenario(backwards_entry, forwards_entry, prev, next); | ||
1448 | |||
1379 | lockdep_print_held_locks(curr); | 1449 | lockdep_print_held_locks(curr); |
1380 | 1450 | ||
1381 | printk("\nthe dependencies between %s-irq-safe lock", irqclass); | 1451 | printk("\nthe dependencies between %s-irq-safe lock", irqclass); |