diff options
Diffstat (limited to 'kernel/lockdep.c')
| -rw-r--r-- | kernel/lockdep.c | 81 |
1 files changed, 43 insertions, 38 deletions
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 2594e1ce41cb..51080807dc8c 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
| @@ -431,20 +431,7 @@ static struct stack_trace lockdep_init_trace = { | |||
| 431 | /* | 431 | /* |
| 432 | * Various lockdep statistics: | 432 | * Various lockdep statistics: |
| 433 | */ | 433 | */ |
| 434 | atomic_t chain_lookup_hits; | 434 | DEFINE_PER_CPU(struct lockdep_stats, lockdep_stats); |
| 435 | atomic_t chain_lookup_misses; | ||
| 436 | atomic_t hardirqs_on_events; | ||
| 437 | atomic_t hardirqs_off_events; | ||
| 438 | atomic_t redundant_hardirqs_on; | ||
| 439 | atomic_t redundant_hardirqs_off; | ||
| 440 | atomic_t softirqs_on_events; | ||
| 441 | atomic_t softirqs_off_events; | ||
| 442 | atomic_t redundant_softirqs_on; | ||
| 443 | atomic_t redundant_softirqs_off; | ||
| 444 | atomic_t nr_unused_locks; | ||
| 445 | atomic_t nr_cyclic_checks; | ||
| 446 | atomic_t nr_find_usage_forwards_checks; | ||
| 447 | atomic_t nr_find_usage_backwards_checks; | ||
| 448 | #endif | 435 | #endif |
| 449 | 436 | ||
| 450 | /* | 437 | /* |
| @@ -748,7 +735,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force) | |||
| 748 | return NULL; | 735 | return NULL; |
| 749 | } | 736 | } |
| 750 | class = lock_classes + nr_lock_classes++; | 737 | class = lock_classes + nr_lock_classes++; |
| 751 | debug_atomic_inc(&nr_unused_locks); | 738 | debug_atomic_inc(nr_unused_locks); |
| 752 | class->key = key; | 739 | class->key = key; |
| 753 | class->name = lock->name; | 740 | class->name = lock->name; |
| 754 | class->subclass = subclass; | 741 | class->subclass = subclass; |
| @@ -818,7 +805,8 @@ static struct lock_list *alloc_list_entry(void) | |||
| 818 | * Add a new dependency to the head of the list: | 805 | * Add a new dependency to the head of the list: |
| 819 | */ | 806 | */ |
| 820 | static int add_lock_to_list(struct lock_class *class, struct lock_class *this, | 807 | static int add_lock_to_list(struct lock_class *class, struct lock_class *this, |
| 821 | struct list_head *head, unsigned long ip, int distance) | 808 | struct list_head *head, unsigned long ip, |
| 809 | int distance, struct stack_trace *trace) | ||
| 822 | { | 810 | { |
| 823 | struct lock_list *entry; | 811 | struct lock_list *entry; |
| 824 | /* | 812 | /* |
| @@ -829,11 +817,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, | |||
| 829 | if (!entry) | 817 | if (!entry) |
| 830 | return 0; | 818 | return 0; |
| 831 | 819 | ||
| 832 | if (!save_trace(&entry->trace)) | ||
| 833 | return 0; | ||
| 834 | |||
| 835 | entry->class = this; | 820 | entry->class = this; |
| 836 | entry->distance = distance; | 821 | entry->distance = distance; |
| 822 | entry->trace = *trace; | ||
| 837 | /* | 823 | /* |
| 838 | * Since we never remove from the dependency list, the list can | 824 | * Since we never remove from the dependency list, the list can |
| 839 | * be walked lockless by other CPUs, it's only allocation | 825 | * be walked lockless by other CPUs, it's only allocation |
| @@ -1205,7 +1191,7 @@ check_noncircular(struct lock_list *root, struct lock_class *target, | |||
| 1205 | { | 1191 | { |
| 1206 | int result; | 1192 | int result; |
| 1207 | 1193 | ||
| 1208 | debug_atomic_inc(&nr_cyclic_checks); | 1194 | debug_atomic_inc(nr_cyclic_checks); |
| 1209 | 1195 | ||
| 1210 | result = __bfs_forwards(root, target, class_equal, target_entry); | 1196 | result = __bfs_forwards(root, target, class_equal, target_entry); |
| 1211 | 1197 | ||
| @@ -1242,7 +1228,7 @@ find_usage_forwards(struct lock_list *root, enum lock_usage_bit bit, | |||
| 1242 | { | 1228 | { |
| 1243 | int result; | 1229 | int result; |
| 1244 | 1230 | ||
| 1245 | debug_atomic_inc(&nr_find_usage_forwards_checks); | 1231 | debug_atomic_inc(nr_find_usage_forwards_checks); |
| 1246 | 1232 | ||
| 1247 | result = __bfs_forwards(root, (void *)bit, usage_match, target_entry); | 1233 | result = __bfs_forwards(root, (void *)bit, usage_match, target_entry); |
| 1248 | 1234 | ||
| @@ -1265,7 +1251,7 @@ find_usage_backwards(struct lock_list *root, enum lock_usage_bit bit, | |||
| 1265 | { | 1251 | { |
| 1266 | int result; | 1252 | int result; |
| 1267 | 1253 | ||
| 1268 | debug_atomic_inc(&nr_find_usage_backwards_checks); | 1254 | debug_atomic_inc(nr_find_usage_backwards_checks); |
| 1269 | 1255 | ||
| 1270 | result = __bfs_backwards(root, (void *)bit, usage_match, target_entry); | 1256 | result = __bfs_backwards(root, (void *)bit, usage_match, target_entry); |
| 1271 | 1257 | ||
| @@ -1635,12 +1621,20 @@ check_deadlock(struct task_struct *curr, struct held_lock *next, | |||
| 1635 | */ | 1621 | */ |
| 1636 | static int | 1622 | static int |
| 1637 | check_prev_add(struct task_struct *curr, struct held_lock *prev, | 1623 | check_prev_add(struct task_struct *curr, struct held_lock *prev, |
| 1638 | struct held_lock *next, int distance) | 1624 | struct held_lock *next, int distance, int trylock_loop) |
| 1639 | { | 1625 | { |
| 1640 | struct lock_list *entry; | 1626 | struct lock_list *entry; |
| 1641 | int ret; | 1627 | int ret; |
| 1642 | struct lock_list this; | 1628 | struct lock_list this; |
| 1643 | struct lock_list *uninitialized_var(target_entry); | 1629 | struct lock_list *uninitialized_var(target_entry); |
| 1630 | /* | ||
| 1631 | * Static variable, serialized by the graph_lock(). | ||
| 1632 | * | ||
| 1633 | * We use this static variable to save the stack trace in case | ||
| 1634 | * we call into this function multiple times due to encountering | ||
| 1635 | * trylocks in the held lock stack. | ||
| 1636 | */ | ||
| 1637 | static struct stack_trace trace; | ||
| 1644 | 1638 | ||
| 1645 | /* | 1639 | /* |
| 1646 | * Prove that the new <prev> -> <next> dependency would not | 1640 | * Prove that the new <prev> -> <next> dependency would not |
| @@ -1688,20 +1682,23 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, | |||
| 1688 | } | 1682 | } |
| 1689 | } | 1683 | } |
| 1690 | 1684 | ||
| 1685 | if (!trylock_loop && !save_trace(&trace)) | ||
| 1686 | return 0; | ||
| 1687 | |||
| 1691 | /* | 1688 | /* |
| 1692 | * Ok, all validations passed, add the new lock | 1689 | * Ok, all validations passed, add the new lock |
| 1693 | * to the previous lock's dependency list: | 1690 | * to the previous lock's dependency list: |
| 1694 | */ | 1691 | */ |
| 1695 | ret = add_lock_to_list(hlock_class(prev), hlock_class(next), | 1692 | ret = add_lock_to_list(hlock_class(prev), hlock_class(next), |
| 1696 | &hlock_class(prev)->locks_after, | 1693 | &hlock_class(prev)->locks_after, |
| 1697 | next->acquire_ip, distance); | 1694 | next->acquire_ip, distance, &trace); |
| 1698 | 1695 | ||
| 1699 | if (!ret) | 1696 | if (!ret) |
| 1700 | return 0; | 1697 | return 0; |
| 1701 | 1698 | ||
| 1702 | ret = add_lock_to_list(hlock_class(next), hlock_class(prev), | 1699 | ret = add_lock_to_list(hlock_class(next), hlock_class(prev), |
| 1703 | &hlock_class(next)->locks_before, | 1700 | &hlock_class(next)->locks_before, |
| 1704 | next->acquire_ip, distance); | 1701 | next->acquire_ip, distance, &trace); |
| 1705 | if (!ret) | 1702 | if (!ret) |
| 1706 | return 0; | 1703 | return 0; |
| 1707 | 1704 | ||
| @@ -1731,6 +1728,7 @@ static int | |||
| 1731 | check_prevs_add(struct task_struct *curr, struct held_lock *next) | 1728 | check_prevs_add(struct task_struct *curr, struct held_lock *next) |
| 1732 | { | 1729 | { |
| 1733 | int depth = curr->lockdep_depth; | 1730 | int depth = curr->lockdep_depth; |
| 1731 | int trylock_loop = 0; | ||
| 1734 | struct held_lock *hlock; | 1732 | struct held_lock *hlock; |
| 1735 | 1733 | ||
| 1736 | /* | 1734 | /* |
| @@ -1756,7 +1754,8 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) | |||
| 1756 | * added: | 1754 | * added: |
| 1757 | */ | 1755 | */ |
| 1758 | if (hlock->read != 2) { | 1756 | if (hlock->read != 2) { |
| 1759 | if (!check_prev_add(curr, hlock, next, distance)) | 1757 | if (!check_prev_add(curr, hlock, next, |
| 1758 | distance, trylock_loop)) | ||
| 1760 | return 0; | 1759 | return 0; |
| 1761 | /* | 1760 | /* |
| 1762 | * Stop after the first non-trylock entry, | 1761 | * Stop after the first non-trylock entry, |
| @@ -1779,6 +1778,7 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) | |||
| 1779 | if (curr->held_locks[depth].irq_context != | 1778 | if (curr->held_locks[depth].irq_context != |
| 1780 | curr->held_locks[depth-1].irq_context) | 1779 | curr->held_locks[depth-1].irq_context) |
| 1781 | break; | 1780 | break; |
| 1781 | trylock_loop = 1; | ||
| 1782 | } | 1782 | } |
| 1783 | return 1; | 1783 | return 1; |
| 1784 | out_bug: | 1784 | out_bug: |
| @@ -1825,7 +1825,7 @@ static inline int lookup_chain_cache(struct task_struct *curr, | |||
| 1825 | list_for_each_entry(chain, hash_head, entry) { | 1825 | list_for_each_entry(chain, hash_head, entry) { |
| 1826 | if (chain->chain_key == chain_key) { | 1826 | if (chain->chain_key == chain_key) { |
| 1827 | cache_hit: | 1827 | cache_hit: |
| 1828 | debug_atomic_inc(&chain_lookup_hits); | 1828 | debug_atomic_inc(chain_lookup_hits); |
| 1829 | if (very_verbose(class)) | 1829 | if (very_verbose(class)) |
| 1830 | printk("\nhash chain already cached, key: " | 1830 | printk("\nhash chain already cached, key: " |
| 1831 | "%016Lx tail class: [%p] %s\n", | 1831 | "%016Lx tail class: [%p] %s\n", |
| @@ -1890,7 +1890,7 @@ cache_hit: | |||
| 1890 | chain_hlocks[chain->base + j] = class - lock_classes; | 1890 | chain_hlocks[chain->base + j] = class - lock_classes; |
| 1891 | } | 1891 | } |
| 1892 | list_add_tail_rcu(&chain->entry, hash_head); | 1892 | list_add_tail_rcu(&chain->entry, hash_head); |
| 1893 | debug_atomic_inc(&chain_lookup_misses); | 1893 | debug_atomic_inc(chain_lookup_misses); |
| 1894 | inc_chains(); | 1894 | inc_chains(); |
| 1895 | 1895 | ||
| 1896 | return 1; | 1896 | return 1; |
| @@ -2311,7 +2311,12 @@ void trace_hardirqs_on_caller(unsigned long ip) | |||
| 2311 | return; | 2311 | return; |
| 2312 | 2312 | ||
| 2313 | if (unlikely(curr->hardirqs_enabled)) { | 2313 | if (unlikely(curr->hardirqs_enabled)) { |
| 2314 | debug_atomic_inc(&redundant_hardirqs_on); | 2314 | /* |
| 2315 | * Neither irq nor preemption are disabled here | ||
| 2316 | * so this is racy by nature but loosing one hit | ||
| 2317 | * in a stat is not a big deal. | ||
| 2318 | */ | ||
| 2319 | __debug_atomic_inc(redundant_hardirqs_on); | ||
| 2315 | return; | 2320 | return; |
| 2316 | } | 2321 | } |
| 2317 | /* we'll do an OFF -> ON transition: */ | 2322 | /* we'll do an OFF -> ON transition: */ |
| @@ -2338,7 +2343,7 @@ void trace_hardirqs_on_caller(unsigned long ip) | |||
| 2338 | 2343 | ||
| 2339 | curr->hardirq_enable_ip = ip; | 2344 | curr->hardirq_enable_ip = ip; |
| 2340 | curr->hardirq_enable_event = ++curr->irq_events; | 2345 | curr->hardirq_enable_event = ++curr->irq_events; |
| 2341 | debug_atomic_inc(&hardirqs_on_events); | 2346 | debug_atomic_inc(hardirqs_on_events); |
| 2342 | } | 2347 | } |
| 2343 | EXPORT_SYMBOL(trace_hardirqs_on_caller); | 2348 | EXPORT_SYMBOL(trace_hardirqs_on_caller); |
| 2344 | 2349 | ||
| @@ -2370,9 +2375,9 @@ void trace_hardirqs_off_caller(unsigned long ip) | |||
| 2370 | curr->hardirqs_enabled = 0; | 2375 | curr->hardirqs_enabled = 0; |
| 2371 | curr->hardirq_disable_ip = ip; | 2376 | curr->hardirq_disable_ip = ip; |
| 2372 | curr->hardirq_disable_event = ++curr->irq_events; | 2377 | curr->hardirq_disable_event = ++curr->irq_events; |
| 2373 | debug_atomic_inc(&hardirqs_off_events); | 2378 | debug_atomic_inc(hardirqs_off_events); |
| 2374 | } else | 2379 | } else |
| 2375 | debug_atomic_inc(&redundant_hardirqs_off); | 2380 | debug_atomic_inc(redundant_hardirqs_off); |
| 2376 | } | 2381 | } |
| 2377 | EXPORT_SYMBOL(trace_hardirqs_off_caller); | 2382 | EXPORT_SYMBOL(trace_hardirqs_off_caller); |
| 2378 | 2383 | ||
| @@ -2396,7 +2401,7 @@ void trace_softirqs_on(unsigned long ip) | |||
| 2396 | return; | 2401 | return; |
| 2397 | 2402 | ||
| 2398 | if (curr->softirqs_enabled) { | 2403 | if (curr->softirqs_enabled) { |
| 2399 | debug_atomic_inc(&redundant_softirqs_on); | 2404 | debug_atomic_inc(redundant_softirqs_on); |
| 2400 | return; | 2405 | return; |
| 2401 | } | 2406 | } |
| 2402 | 2407 | ||
| @@ -2406,7 +2411,7 @@ void trace_softirqs_on(unsigned long ip) | |||
| 2406 | curr->softirqs_enabled = 1; | 2411 | curr->softirqs_enabled = 1; |
| 2407 | curr->softirq_enable_ip = ip; | 2412 | curr->softirq_enable_ip = ip; |
| 2408 | curr->softirq_enable_event = ++curr->irq_events; | 2413 | curr->softirq_enable_event = ++curr->irq_events; |
| 2409 | debug_atomic_inc(&softirqs_on_events); | 2414 | debug_atomic_inc(softirqs_on_events); |
| 2410 | /* | 2415 | /* |
| 2411 | * We are going to turn softirqs on, so set the | 2416 | * We are going to turn softirqs on, so set the |
| 2412 | * usage bit for all held locks, if hardirqs are | 2417 | * usage bit for all held locks, if hardirqs are |
| @@ -2436,10 +2441,10 @@ void trace_softirqs_off(unsigned long ip) | |||
| 2436 | curr->softirqs_enabled = 0; | 2441 | curr->softirqs_enabled = 0; |
| 2437 | curr->softirq_disable_ip = ip; | 2442 | curr->softirq_disable_ip = ip; |
| 2438 | curr->softirq_disable_event = ++curr->irq_events; | 2443 | curr->softirq_disable_event = ++curr->irq_events; |
| 2439 | debug_atomic_inc(&softirqs_off_events); | 2444 | debug_atomic_inc(softirqs_off_events); |
| 2440 | DEBUG_LOCKS_WARN_ON(!softirq_count()); | 2445 | DEBUG_LOCKS_WARN_ON(!softirq_count()); |
| 2441 | } else | 2446 | } else |
| 2442 | debug_atomic_inc(&redundant_softirqs_off); | 2447 | debug_atomic_inc(redundant_softirqs_off); |
| 2443 | } | 2448 | } |
| 2444 | 2449 | ||
| 2445 | static void __lockdep_trace_alloc(gfp_t gfp_mask, unsigned long flags) | 2450 | static void __lockdep_trace_alloc(gfp_t gfp_mask, unsigned long flags) |
| @@ -2644,7 +2649,7 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this, | |||
| 2644 | return 0; | 2649 | return 0; |
| 2645 | break; | 2650 | break; |
| 2646 | case LOCK_USED: | 2651 | case LOCK_USED: |
| 2647 | debug_atomic_dec(&nr_unused_locks); | 2652 | debug_atomic_dec(nr_unused_locks); |
| 2648 | break; | 2653 | break; |
| 2649 | default: | 2654 | default: |
| 2650 | if (!debug_locks_off_graph_unlock()) | 2655 | if (!debug_locks_off_graph_unlock()) |
| @@ -2750,7 +2755,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, | |||
| 2750 | if (!class) | 2755 | if (!class) |
| 2751 | return 0; | 2756 | return 0; |
| 2752 | } | 2757 | } |
| 2753 | debug_atomic_inc((atomic_t *)&class->ops); | 2758 | atomic_inc((atomic_t *)&class->ops); |
| 2754 | if (very_verbose(class)) { | 2759 | if (very_verbose(class)) { |
| 2755 | printk("\nacquire class [%p] %s", class->key, class->name); | 2760 | printk("\nacquire class [%p] %s", class->key, class->name); |
| 2756 | if (class->name_version > 1) | 2761 | if (class->name_version > 1) |
