lockdep: disable lockdep logging
When lockdep reports a locking error, it disables global debug_locks which results in other lock debugging features getting disabled. Disable only lockdep logging once a locking error is reported. This will help in tracking lock owners and their stacks from ramdumps even when lockdep is not reporting them on console. Change-Id: Ie7b6aa57df84aaa4cf90fc912969d4ca49f77997 Signed-off-by: Prateek Sood <prsood@codeaurora.org>
This commit is contained in:
1 parent
65ab504db4
commit
fbda00ce1d
1 file changed
+76
-47
+76
-47
@@ -73,7 +73,29 @@ module_param(lock_stat, int, 0644);
|
||||
#define lock_stat 0
|
||||
#endif
|
||||
|
||||
static int lockdep_log = 1;
|
||||
|
||||
static int lockdep_logging_off(void)
|
||||
{
|
||||
if (lockdep_log && xchg(&lockdep_log, 0)) {
|
||||
if (!debug_locks_silent)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_ITR 20
|
||||
#define lockdep_warn_on(cond) \
|
||||
({ \
|
||||
int __ret = 0; \
|
||||
\
|
||||
if (!oops_in_progress && unlikely(cond)) { \
|
||||
if (lockdep_logging_off() && !debug_locks_silent) \
|
||||
WARN(1, "lockdep_warn_on(%s)", #cond); \
|
||||
__ret = 1; \
|
||||
} \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
/*
|
||||
* lockdep_lock: protects the lockdep graph, the hashes and the
|
||||
@@ -110,7 +132,7 @@ static inline int graph_unlock(void)
|
||||
* The lockdep graph lock isn't locked while we expect it to
|
||||
* be, we're confused now, bye!
|
||||
*/
|
||||
return DEBUG_LOCKS_WARN_ON(1);
|
||||
return lockdep_warn_on(1);
|
||||
}
|
||||
|
||||
current->lockdep_recursion--;
|
||||
@@ -118,6 +140,14 @@ static inline int graph_unlock(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lockdep_logging_off_graph_unlock(void)
|
||||
{
|
||||
int ret = lockdep_logging_off();
|
||||
|
||||
graph_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn lock debugging off and return with 0 if it was off already,
|
||||
* and also release the graph lock:
|
||||
@@ -149,7 +179,7 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock)
|
||||
/*
|
||||
* Someone passed in garbage, we give up.
|
||||
*/
|
||||
DEBUG_LOCKS_WARN_ON(1);
|
||||
lockdep_warn_on(1);
|
||||
return NULL;
|
||||
}
|
||||
return lock_classes + hlock->class_idx - 1;
|
||||
@@ -416,7 +446,7 @@ static int save_trace(struct stack_trace *trace)
|
||||
nr_stack_trace_entries += trace->nr_entries;
|
||||
|
||||
if (nr_stack_trace_entries >= MAX_STACK_TRACE_ENTRIES-1) {
|
||||
if (!debug_locks_off_graph_unlock())
|
||||
if (!lockdep_logging_off_graph_unlock())
|
||||
return 0;
|
||||
|
||||
print_lockdep_off("BUG: MAX_STACK_TRACE_ENTRIES too low!");
|
||||
@@ -723,10 +753,8 @@ static bool assign_lock_key(struct lockdep_map *lock)
|
||||
lock->key = (void *)lock;
|
||||
else {
|
||||
/* Debug-check: all keys must be persistent! */
|
||||
debug_locks_off();
|
||||
pr_err("INFO: trying to register non-static key.\n");
|
||||
pr_err("the code is fine but needs lockdep annotation.\n");
|
||||
pr_err("turning off the locking correctness validator.\n");
|
||||
dump_stack();
|
||||
return false;
|
||||
}
|
||||
@@ -1196,7 +1224,7 @@ static noinline int print_circular_bug(struct lock_list *this,
|
||||
struct lock_list *first_parent;
|
||||
int depth;
|
||||
|
||||
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
|
||||
if (!lockdep_logging_off_graph_unlock() || debug_locks_silent)
|
||||
return 0;
|
||||
|
||||
if (!save_trace(&this->trace))
|
||||
@@ -1511,7 +1539,7 @@ print_bad_irq_dependency(struct task_struct *curr,
|
||||
enum lock_usage_bit bit2,
|
||||
const char *irqclass)
|
||||
{
|
||||
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
|
||||
if (!lockdep_logging_off_graph_unlock() || debug_locks_silent)
|
||||
return 0;
|
||||
|
||||
pr_warn("\n");
|
||||
@@ -1740,7 +1768,7 @@ static int
|
||||
print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
|
||||
struct held_lock *next)
|
||||
{
|
||||
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
|
||||
if (!lockdep_logging_off_graph_unlock() || debug_locks_silent)
|
||||
return 0;
|
||||
|
||||
pr_warn("\n");
|
||||
@@ -2003,7 +2031,7 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)
|
||||
}
|
||||
return 1;
|
||||
out_bug:
|
||||
if (!debug_locks_off_graph_unlock())
|
||||
if (!lockdep_logging_off_graph_unlock())
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@@ -2133,7 +2161,7 @@ static int check_no_collision(struct task_struct *curr,
|
||||
|
||||
i = get_first_held_lock(curr, hlock);
|
||||
|
||||
if (DEBUG_LOCKS_WARN_ON(chain->depth != curr->lockdep_depth - (i - 1))) {
|
||||
if (lockdep_warn_on(chain->depth != curr->lockdep_depth - (i - 1))) {
|
||||
print_collision(curr, hlock, chain);
|
||||
return 0;
|
||||
}
|
||||
@@ -2141,7 +2169,7 @@ static int check_no_collision(struct task_struct *curr,
|
||||
for (j = 0; j < chain->depth - 1; j++, i++) {
|
||||
id = curr->held_locks[i].class_idx - 1;
|
||||
|
||||
if (DEBUG_LOCKS_WARN_ON(chain_hlocks[chain->base + j] != id)) {
|
||||
if (lockdep_warn_on(chain_hlocks[chain->base + j] != id)) {
|
||||
print_collision(curr, hlock, chain);
|
||||
return 0;
|
||||
}
|
||||
@@ -2510,7 +2538,7 @@ static int
|
||||
print_usage_bug(struct task_struct *curr, struct held_lock *this,
|
||||
enum lock_usage_bit prev_bit, enum lock_usage_bit new_bit)
|
||||
{
|
||||
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
|
||||
if (!lockdep_logging_off_graph_unlock() || debug_locks_silent)
|
||||
return 0;
|
||||
|
||||
pr_warn("\n");
|
||||
@@ -2575,7 +2603,7 @@ print_irq_inversion_bug(struct task_struct *curr,
|
||||
struct lock_list *middle = NULL;
|
||||
int depth;
|
||||
|
||||
if (!debug_locks_off_graph_unlock() || debug_locks_silent)
|
||||
if (!lockdep_logging_off_graph_unlock() || debug_locks_silent)
|
||||
return 0;
|
||||
|
||||
pr_warn("\n");
|
||||
@@ -3135,7 +3163,7 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
|
||||
debug_atomic_dec(nr_unused_locks);
|
||||
break;
|
||||
default:
|
||||
if (!debug_locks_off_graph_unlock())
|
||||
if (!lockdep_logging_off_graph_unlock())
|
||||
return 0;
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
@@ -3174,7 +3202,7 @@ static void __lockdep_init_map(struct lockdep_map *lock, const char *name,
|
||||
/*
|
||||
* Can't be having no nameless bastards around this place!
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(!name)) {
|
||||
if (lockdep_warn_on(!name)) {
|
||||
lock->name = "NULL";
|
||||
return;
|
||||
}
|
||||
@@ -3184,17 +3212,22 @@ static void __lockdep_init_map(struct lockdep_map *lock, const char *name,
|
||||
/*
|
||||
* No key, no joy, we need to hash something.
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(!key))
|
||||
if (lockdep_warn_on(!key))
|
||||
return;
|
||||
/*
|
||||
* Sanity check, the lock-class key must be persistent:
|
||||
*/
|
||||
if (!static_obj(key)) {
|
||||
/*
|
||||
* to make sure register_lock_class returns NULL
|
||||
* for a non static key
|
||||
*/
|
||||
lock->key = key;
|
||||
printk("BUG: key %px not in .data!\n", key);
|
||||
/*
|
||||
* What it says above ^^^^^, I suggest you read it.
|
||||
*/
|
||||
DEBUG_LOCKS_WARN_ON(1);
|
||||
lockdep_warn_on(1);
|
||||
return;
|
||||
}
|
||||
lock->key = key;
|
||||
@@ -3205,7 +3238,7 @@ static void __lockdep_init_map(struct lockdep_map *lock, const char *name,
|
||||
if (subclass) {
|
||||
unsigned long flags;
|
||||
|
||||
if (DEBUG_LOCKS_WARN_ON(current->lockdep_recursion))
|
||||
if (lockdep_warn_on(current->lockdep_recursion))
|
||||
return;
|
||||
|
||||
raw_local_irq_save(flags);
|
||||
@@ -3231,9 +3264,7 @@ print_lock_nested_lock_not_held(struct task_struct *curr,
|
||||
struct held_lock *hlock,
|
||||
unsigned long ip)
|
||||
{
|
||||
if (!debug_locks_off())
|
||||
return 0;
|
||||
if (debug_locks_silent)
|
||||
if (!lockdep_logging_off() || debug_locks_silent)
|
||||
return 0;
|
||||
|
||||
pr_warn("\n");
|
||||
@@ -3378,7 +3409,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
|
||||
* Plain impossible, we just registered it and checked it weren't no
|
||||
* NULL like.. I bet this mushroom I ate was good!
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(!class))
|
||||
if (lockdep_warn_on(!class))
|
||||
return 0;
|
||||
hlock->class_idx = class_idx;
|
||||
hlock->acquire_ip = ip;
|
||||
@@ -3428,7 +3459,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
|
||||
/*
|
||||
* How can we have a chain hash when we ain't got no keys?!
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(chain_key != 0))
|
||||
if (lockdep_warn_on(chain_key != 0))
|
||||
return 0;
|
||||
chain_head = 1;
|
||||
}
|
||||
@@ -3476,9 +3507,7 @@ static int
|
||||
print_unlock_imbalance_bug(struct task_struct *curr, struct lockdep_map *lock,
|
||||
unsigned long ip)
|
||||
{
|
||||
if (!debug_locks_off())
|
||||
return 0;
|
||||
if (debug_locks_silent)
|
||||
if (!lockdep_logging_off() || debug_locks_silent)
|
||||
return 0;
|
||||
|
||||
pr_warn("\n");
|
||||
@@ -3527,7 +3556,7 @@ static int match_held_lock(const struct held_lock *hlock,
|
||||
* State got messed up, follow the sites that change ->references
|
||||
* and try to make sense of it.
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(!hlock->nest_lock))
|
||||
if (lockdep_warn_on(!hlock->nest_lock))
|
||||
return 0;
|
||||
|
||||
if (hlock->class_idx == class - lock_classes + 1)
|
||||
@@ -3608,7 +3637,7 @@ __lock_set_class(struct lockdep_map *lock, const char *name,
|
||||
* This function is about (re)setting the class of a held lock,
|
||||
* yet we're not actually holding any locks. Naughty user!
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(!depth))
|
||||
if (lockdep_warn_on(!depth))
|
||||
return 0;
|
||||
|
||||
hlock = find_held_lock(curr, lock, depth, &i);
|
||||
@@ -3617,6 +3646,9 @@ __lock_set_class(struct lockdep_map *lock, const char *name,
|
||||
|
||||
lockdep_init_map(lock, name, key, 0);
|
||||
class = register_lock_class(lock, subclass, 0);
|
||||
if (!class)
|
||||
return 0;
|
||||
|
||||
hlock->class_idx = class - lock_classes + 1;
|
||||
|
||||
curr->lockdep_depth = i;
|
||||
@@ -3629,7 +3661,7 @@ __lock_set_class(struct lockdep_map *lock, const char *name,
|
||||
* I took it apart and put it back together again, except now I have
|
||||
* these 'spare' parts.. where shall I put them.
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth))
|
||||
if (lockdep_warn_on(curr->lockdep_depth != depth))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -3649,7 +3681,7 @@ static int __lock_downgrade(struct lockdep_map *lock, unsigned long ip)
|
||||
* This function is about (re)setting the class of a held lock,
|
||||
* yet we're not actually holding any locks. Naughty user!
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(!depth))
|
||||
if (lockdep_warn_on(!depth))
|
||||
return 0;
|
||||
|
||||
hlock = find_held_lock(curr, lock, depth, &i);
|
||||
@@ -3671,7 +3703,7 @@ static int __lock_downgrade(struct lockdep_map *lock, unsigned long ip)
|
||||
* I took it apart and put it back together again, except now I have
|
||||
* these 'spare' parts.. where shall I put them.
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth))
|
||||
if (lockdep_warn_on(curr->lockdep_depth != depth))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -3699,8 +3731,8 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip)
|
||||
* So we're all set to release this lock.. wait what lock? We don't
|
||||
* own any locks, you've been drinking again?
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(depth <= 0))
|
||||
return print_unlock_imbalance_bug(curr, lock, ip);
|
||||
if (lockdep_warn_on(depth <= 0))
|
||||
return print_unlock_imbalance_bug(curr, lock, ip);
|
||||
|
||||
/*
|
||||
* Check whether the lock exists in the current stack
|
||||
@@ -3743,7 +3775,7 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip)
|
||||
* We had N bottles of beer on the wall, we drank one, but now
|
||||
* there's not N-1 bottles of beer left on the wall...
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth - 1))
|
||||
if (lockdep_warn_on(curr->lockdep_depth != depth - 1))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -4042,9 +4074,7 @@ static int
|
||||
print_lock_contention_bug(struct task_struct *curr, struct lockdep_map *lock,
|
||||
unsigned long ip)
|
||||
{
|
||||
if (!debug_locks_off())
|
||||
return 0;
|
||||
if (debug_locks_silent)
|
||||
if (!lockdep_logging_off() || debug_locks_silent)
|
||||
return 0;
|
||||
|
||||
pr_warn("\n");
|
||||
@@ -4081,7 +4111,7 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip)
|
||||
* Whee, we contended on this lock, except it seems we're not
|
||||
* actually trying to acquire anything much at all..
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(!depth))
|
||||
if (lockdep_warn_on(!depth))
|
||||
return;
|
||||
|
||||
hlock = find_held_lock(curr, lock, depth, &i);
|
||||
@@ -4123,7 +4153,7 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip)
|
||||
* Yay, we acquired ownership of this lock we didn't try to
|
||||
* acquire, how the heck did that happen?
|
||||
*/
|
||||
if (DEBUG_LOCKS_WARN_ON(!depth))
|
||||
if (lockdep_warn_on(!depth))
|
||||
return;
|
||||
|
||||
hlock = find_held_lock(curr, lock, depth, &i);
|
||||
@@ -4336,7 +4366,7 @@ void lockdep_reset_lock(struct lockdep_map *lock)
|
||||
match |= class == lock->class_cache[j];
|
||||
|
||||
if (unlikely(match)) {
|
||||
if (debug_locks_off_graph_unlock()) {
|
||||
if (lockdep_logging_off_graph_unlock()) {
|
||||
/*
|
||||
* We all just reset everything, how did it match?
|
||||
*/
|
||||
@@ -4385,9 +4415,7 @@ static void
|
||||
print_freed_lock_bug(struct task_struct *curr, const void *mem_from,
|
||||
const void *mem_to, struct held_lock *hlock)
|
||||
{
|
||||
if (!debug_locks_off())
|
||||
return;
|
||||
if (debug_locks_silent)
|
||||
if (!lockdep_logging_off() || debug_locks_silent)
|
||||
return;
|
||||
|
||||
pr_warn("\n");
|
||||
@@ -4443,9 +4471,7 @@ EXPORT_SYMBOL_GPL(debug_check_no_locks_freed);
|
||||
|
||||
static void print_held_locks_bug(void)
|
||||
{
|
||||
if (!debug_locks_off())
|
||||
return;
|
||||
if (debug_locks_silent)
|
||||
if (!lockdep_logging_off() || debug_locks_silent)
|
||||
return;
|
||||
|
||||
pr_warn("\n");
|
||||
@@ -4512,7 +4538,7 @@ asmlinkage __visible void lockdep_sys_exit(void)
|
||||
struct task_struct *curr = current;
|
||||
|
||||
if (unlikely(curr->lockdep_depth)) {
|
||||
if (!debug_locks_off())
|
||||
if (!lockdep_logging_off())
|
||||
return;
|
||||
pr_warn("\n");
|
||||
pr_warn("================================================\n");
|
||||
@@ -4535,6 +4561,9 @@ void lockdep_rcu_suspicious(const char *file, const int line, const char *s)
|
||||
{
|
||||
struct task_struct *curr = current;
|
||||
|
||||
if (!lockdep_logging_off())
|
||||
return;
|
||||
|
||||
/* Note: the following can be executed concurrently, so be careful. */
|
||||
pr_warn("\n");
|
||||
pr_warn("=============================\n");
|
||||
|
||||
Reference in new issue
Block a user