diff options
Diffstat (limited to 'kernel/lockdep.c')
-rw-r--r-- | kernel/lockdep.c | 80 |
1 files changed, 69 insertions, 11 deletions
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 81a4e4a3f087..d38a64362973 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/irqflags.h> | 39 | #include <linux/irqflags.h> |
40 | #include <linux/utsname.h> | 40 | #include <linux/utsname.h> |
41 | #include <linux/hash.h> | 41 | #include <linux/hash.h> |
42 | #include <linux/ftrace.h> | ||
42 | 43 | ||
43 | #include <asm/sections.h> | 44 | #include <asm/sections.h> |
44 | 45 | ||
@@ -81,6 +82,8 @@ static int graph_lock(void) | |||
81 | __raw_spin_unlock(&lockdep_lock); | 82 | __raw_spin_unlock(&lockdep_lock); |
82 | return 0; | 83 | return 0; |
83 | } | 84 | } |
85 | /* prevent any recursions within lockdep from causing deadlocks */ | ||
86 | current->lockdep_recursion++; | ||
84 | return 1; | 87 | return 1; |
85 | } | 88 | } |
86 | 89 | ||
@@ -89,6 +92,7 @@ static inline int graph_unlock(void) | |||
89 | if (debug_locks && !__raw_spin_is_locked(&lockdep_lock)) | 92 | if (debug_locks && !__raw_spin_is_locked(&lockdep_lock)) |
90 | return DEBUG_LOCKS_WARN_ON(1); | 93 | return DEBUG_LOCKS_WARN_ON(1); |
91 | 94 | ||
95 | current->lockdep_recursion--; | ||
92 | __raw_spin_unlock(&lockdep_lock); | 96 | __raw_spin_unlock(&lockdep_lock); |
93 | return 0; | 97 | return 0; |
94 | } | 98 | } |
@@ -982,7 +986,7 @@ check_noncircular(struct lock_class *source, unsigned int depth) | |||
982 | return 1; | 986 | return 1; |
983 | } | 987 | } |
984 | 988 | ||
985 | #ifdef CONFIG_TRACE_IRQFLAGS | 989 | #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING) |
986 | /* | 990 | /* |
987 | * Forwards and backwards subgraph searching, for the purposes of | 991 | * Forwards and backwards subgraph searching, for the purposes of |
988 | * proving that two subgraphs can be connected by a new dependency | 992 | * proving that two subgraphs can be connected by a new dependency |
@@ -1458,7 +1462,14 @@ out_bug: | |||
1458 | } | 1462 | } |
1459 | 1463 | ||
1460 | unsigned long nr_lock_chains; | 1464 | unsigned long nr_lock_chains; |
1461 | static struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS]; | 1465 | struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS]; |
1466 | int nr_chain_hlocks; | ||
1467 | static u16 chain_hlocks[MAX_LOCKDEP_CHAIN_HLOCKS]; | ||
1468 | |||
1469 | struct lock_class *lock_chain_get_class(struct lock_chain *chain, int i) | ||
1470 | { | ||
1471 | return lock_classes + chain_hlocks[chain->base + i]; | ||
1472 | } | ||
1462 | 1473 | ||
1463 | /* | 1474 | /* |
1464 | * Look up a dependency chain. If the key is not present yet then | 1475 | * Look up a dependency chain. If the key is not present yet then |
@@ -1466,10 +1477,15 @@ static struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS]; | |||
1466 | * validated. If the key is already hashed, return 0. | 1477 | * validated. If the key is already hashed, return 0. |
1467 | * (On return with 1 graph_lock is held.) | 1478 | * (On return with 1 graph_lock is held.) |
1468 | */ | 1479 | */ |
1469 | static inline int lookup_chain_cache(u64 chain_key, struct lock_class *class) | 1480 | static inline int lookup_chain_cache(struct task_struct *curr, |
1481 | struct held_lock *hlock, | ||
1482 | u64 chain_key) | ||
1470 | { | 1483 | { |
1484 | struct lock_class *class = hlock->class; | ||
1471 | struct list_head *hash_head = chainhashentry(chain_key); | 1485 | struct list_head *hash_head = chainhashentry(chain_key); |
1472 | struct lock_chain *chain; | 1486 | struct lock_chain *chain; |
1487 | struct held_lock *hlock_curr, *hlock_next; | ||
1488 | int i, j, n, cn; | ||
1473 | 1489 | ||
1474 | if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) | 1490 | if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) |
1475 | return 0; | 1491 | return 0; |
@@ -1517,6 +1533,32 @@ cache_hit: | |||
1517 | } | 1533 | } |
1518 | chain = lock_chains + nr_lock_chains++; | 1534 | chain = lock_chains + nr_lock_chains++; |
1519 | chain->chain_key = chain_key; | 1535 | chain->chain_key = chain_key; |
1536 | chain->irq_context = hlock->irq_context; | ||
1537 | /* Find the first held_lock of current chain */ | ||
1538 | hlock_next = hlock; | ||
1539 | for (i = curr->lockdep_depth - 1; i >= 0; i--) { | ||
1540 | hlock_curr = curr->held_locks + i; | ||
1541 | if (hlock_curr->irq_context != hlock_next->irq_context) | ||
1542 | break; | ||
1543 | hlock_next = hlock; | ||
1544 | } | ||
1545 | i++; | ||
1546 | chain->depth = curr->lockdep_depth + 1 - i; | ||
1547 | cn = nr_chain_hlocks; | ||
1548 | while (cn + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS) { | ||
1549 | n = cmpxchg(&nr_chain_hlocks, cn, cn + chain->depth); | ||
1550 | if (n == cn) | ||
1551 | break; | ||
1552 | cn = n; | ||
1553 | } | ||
1554 | if (likely(cn + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS)) { | ||
1555 | chain->base = cn; | ||
1556 | for (j = 0; j < chain->depth - 1; j++, i++) { | ||
1557 | int lock_id = curr->held_locks[i].class - lock_classes; | ||
1558 | chain_hlocks[chain->base + j] = lock_id; | ||
1559 | } | ||
1560 | chain_hlocks[chain->base + j] = class - lock_classes; | ||
1561 | } | ||
1520 | list_add_tail_rcu(&chain->entry, hash_head); | 1562 | list_add_tail_rcu(&chain->entry, hash_head); |
1521 | debug_atomic_inc(&chain_lookup_misses); | 1563 | debug_atomic_inc(&chain_lookup_misses); |
1522 | inc_chains(); | 1564 | inc_chains(); |
@@ -1538,7 +1580,7 @@ static int validate_chain(struct task_struct *curr, struct lockdep_map *lock, | |||
1538 | * graph_lock for us) | 1580 | * graph_lock for us) |
1539 | */ | 1581 | */ |
1540 | if (!hlock->trylock && (hlock->check == 2) && | 1582 | if (!hlock->trylock && (hlock->check == 2) && |
1541 | lookup_chain_cache(chain_key, hlock->class)) { | 1583 | lookup_chain_cache(curr, hlock, chain_key)) { |
1542 | /* | 1584 | /* |
1543 | * Check whether last held lock: | 1585 | * Check whether last held lock: |
1544 | * | 1586 | * |
@@ -1680,7 +1722,7 @@ valid_state(struct task_struct *curr, struct held_lock *this, | |||
1680 | static int mark_lock(struct task_struct *curr, struct held_lock *this, | 1722 | static int mark_lock(struct task_struct *curr, struct held_lock *this, |
1681 | enum lock_usage_bit new_bit); | 1723 | enum lock_usage_bit new_bit); |
1682 | 1724 | ||
1683 | #ifdef CONFIG_TRACE_IRQFLAGS | 1725 | #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING) |
1684 | 1726 | ||
1685 | /* | 1727 | /* |
1686 | * print irq inversion bug: | 1728 | * print irq inversion bug: |
@@ -2013,11 +2055,13 @@ void early_boot_irqs_on(void) | |||
2013 | /* | 2055 | /* |
2014 | * Hardirqs will be enabled: | 2056 | * Hardirqs will be enabled: |
2015 | */ | 2057 | */ |
2016 | void trace_hardirqs_on(void) | 2058 | void trace_hardirqs_on_caller(unsigned long a0) |
2017 | { | 2059 | { |
2018 | struct task_struct *curr = current; | 2060 | struct task_struct *curr = current; |
2019 | unsigned long ip; | 2061 | unsigned long ip; |
2020 | 2062 | ||
2063 | time_hardirqs_on(CALLER_ADDR0, a0); | ||
2064 | |||
2021 | if (unlikely(!debug_locks || current->lockdep_recursion)) | 2065 | if (unlikely(!debug_locks || current->lockdep_recursion)) |
2022 | return; | 2066 | return; |
2023 | 2067 | ||
@@ -2055,16 +2099,23 @@ void trace_hardirqs_on(void) | |||
2055 | curr->hardirq_enable_event = ++curr->irq_events; | 2099 | curr->hardirq_enable_event = ++curr->irq_events; |
2056 | debug_atomic_inc(&hardirqs_on_events); | 2100 | debug_atomic_inc(&hardirqs_on_events); |
2057 | } | 2101 | } |
2102 | EXPORT_SYMBOL(trace_hardirqs_on_caller); | ||
2058 | 2103 | ||
2104 | void trace_hardirqs_on(void) | ||
2105 | { | ||
2106 | trace_hardirqs_on_caller(CALLER_ADDR0); | ||
2107 | } | ||
2059 | EXPORT_SYMBOL(trace_hardirqs_on); | 2108 | EXPORT_SYMBOL(trace_hardirqs_on); |
2060 | 2109 | ||
2061 | /* | 2110 | /* |
2062 | * Hardirqs were disabled: | 2111 | * Hardirqs were disabled: |
2063 | */ | 2112 | */ |
2064 | void trace_hardirqs_off(void) | 2113 | void trace_hardirqs_off_caller(unsigned long a0) |
2065 | { | 2114 | { |
2066 | struct task_struct *curr = current; | 2115 | struct task_struct *curr = current; |
2067 | 2116 | ||
2117 | time_hardirqs_off(CALLER_ADDR0, a0); | ||
2118 | |||
2068 | if (unlikely(!debug_locks || current->lockdep_recursion)) | 2119 | if (unlikely(!debug_locks || current->lockdep_recursion)) |
2069 | return; | 2120 | return; |
2070 | 2121 | ||
@@ -2082,7 +2133,12 @@ void trace_hardirqs_off(void) | |||
2082 | } else | 2133 | } else |
2083 | debug_atomic_inc(&redundant_hardirqs_off); | 2134 | debug_atomic_inc(&redundant_hardirqs_off); |
2084 | } | 2135 | } |
2136 | EXPORT_SYMBOL(trace_hardirqs_off_caller); | ||
2085 | 2137 | ||
2138 | void trace_hardirqs_off(void) | ||
2139 | { | ||
2140 | trace_hardirqs_off_caller(CALLER_ADDR0); | ||
2141 | } | ||
2086 | EXPORT_SYMBOL(trace_hardirqs_off); | 2142 | EXPORT_SYMBOL(trace_hardirqs_off); |
2087 | 2143 | ||
2088 | /* | 2144 | /* |
@@ -2246,7 +2302,7 @@ static inline int separate_irq_context(struct task_struct *curr, | |||
2246 | * Mark a lock with a usage bit, and validate the state transition: | 2302 | * Mark a lock with a usage bit, and validate the state transition: |
2247 | */ | 2303 | */ |
2248 | static int mark_lock(struct task_struct *curr, struct held_lock *this, | 2304 | static int mark_lock(struct task_struct *curr, struct held_lock *this, |
2249 | enum lock_usage_bit new_bit) | 2305 | enum lock_usage_bit new_bit) |
2250 | { | 2306 | { |
2251 | unsigned int new_mask = 1 << new_bit, ret = 1; | 2307 | unsigned int new_mask = 1 << new_bit, ret = 1; |
2252 | 2308 | ||
@@ -2650,7 +2706,8 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip) | |||
2650 | */ | 2706 | */ |
2651 | static void check_flags(unsigned long flags) | 2707 | static void check_flags(unsigned long flags) |
2652 | { | 2708 | { |
2653 | #if defined(CONFIG_DEBUG_LOCKDEP) && defined(CONFIG_TRACE_IRQFLAGS) | 2709 | #if defined(CONFIG_PROVE_LOCKING) && defined(CONFIG_DEBUG_LOCKDEP) && \ |
2710 | defined(CONFIG_TRACE_IRQFLAGS) | ||
2654 | if (!debug_locks) | 2711 | if (!debug_locks) |
2655 | return; | 2712 | return; |
2656 | 2713 | ||
@@ -2686,7 +2743,7 @@ static void check_flags(unsigned long flags) | |||
2686 | * and also avoid lockdep recursion: | 2743 | * and also avoid lockdep recursion: |
2687 | */ | 2744 | */ |
2688 | void lock_acquire(struct lockdep_map *lock, unsigned int subclass, | 2745 | void lock_acquire(struct lockdep_map *lock, unsigned int subclass, |
2689 | int trylock, int read, int check, unsigned long ip) | 2746 | int trylock, int read, int check, unsigned long ip) |
2690 | { | 2747 | { |
2691 | unsigned long flags; | 2748 | unsigned long flags; |
2692 | 2749 | ||
@@ -2708,7 +2765,8 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass, | |||
2708 | 2765 | ||
2709 | EXPORT_SYMBOL_GPL(lock_acquire); | 2766 | EXPORT_SYMBOL_GPL(lock_acquire); |
2710 | 2767 | ||
2711 | void lock_release(struct lockdep_map *lock, int nested, unsigned long ip) | 2768 | void lock_release(struct lockdep_map *lock, int nested, |
2769 | unsigned long ip) | ||
2712 | { | 2770 | { |
2713 | unsigned long flags; | 2771 | unsigned long flags; |
2714 | 2772 | ||