Skip to content
Snippets Groups Projects
lockdep.c 68 KiB
Newer Older
Ingo Molnar's avatar
Ingo Molnar committed
/*
 * kernel/lockdep.c
 *
 * Runtime locking correctness validator
 *
 * Started by Ingo Molnar:
 *
 *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
 *
 * this code maps all the lock dependencies as they occur in a live kernel
 * and will warn about the following classes of locking bugs:
 *
 * - lock inversion scenarios
 * - circular lock dependencies
 * - hardirq/softirq safe/unsafe locking bugs
 *
 * Bugs are reported even if the current locking scenario does not cause
 * any deadlock at this point.
 *
 * I.e. if anytime in the past two locks were taken in a different order,
 * even if it happened for another task, even if those were different
 * locks (but of the same class as this lock), this code will detect it.
 *
 * Thanks to Arjan van de Ven for coming up with the initial idea of
 * mapping lock dependencies runtime.
 */
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
#include <linux/stacktrace.h>
#include <linux/debug_locks.h>
#include <linux/irqflags.h>
#include <linux/utsname.h>
Ingo Molnar's avatar
Ingo Molnar committed

#include <asm/sections.h>

#include "lockdep_internals.h"

/*
 * hash_lock: protects the lockdep hashes and class/list/hash allocators.
 *
 * This is one of the rare exceptions where it's justified
 * to use a raw spinlock - we really dont want the spinlock
 * code to recurse back into the lockdep code.
 */
static raw_spinlock_t hash_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;

static int lockdep_initialized;

unsigned long nr_list_entries;
static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES];

/*
 * Allocate a lockdep entry. (assumes hash_lock held, returns
 * with NULL on failure)
 */
static struct lock_list *alloc_list_entry(void)
{
	if (nr_list_entries >= MAX_LOCKDEP_ENTRIES) {
		__raw_spin_unlock(&hash_lock);
		debug_locks_off();
		printk("BUG: MAX_LOCKDEP_ENTRIES too low!\n");
		printk("turning off the locking correctness validator.\n");
		return NULL;
	}
	return list_entries + nr_list_entries++;
}

/*
 * All data structures here are protected by the global debug_lock.
 *
 * Mutex key structs only get allocated, once during bootup, and never
 * get freed - this significantly simplifies the debugging code.
 */
unsigned long nr_lock_classes;
static struct lock_class lock_classes[MAX_LOCKDEP_KEYS];

/*
 * We keep a global list of all lock classes. The list only grows,
 * never shrinks. The list is only accessed with the lockdep
 * spinlock lock held.
 */
LIST_HEAD(all_lock_classes);

/*
 * The lockdep classes are in a hash-table as well, for fast lookup:
 */
#define CLASSHASH_BITS		(MAX_LOCKDEP_KEYS_BITS - 1)
#define CLASSHASH_SIZE		(1UL << CLASSHASH_BITS)
#define CLASSHASH_MASK		(CLASSHASH_SIZE - 1)
#define __classhashfn(key)	((((unsigned long)key >> CLASSHASH_BITS) + (unsigned long)key) & CLASSHASH_MASK)
#define classhashentry(key)	(classhash_table + __classhashfn((key)))

static struct list_head classhash_table[CLASSHASH_SIZE];

unsigned long nr_lock_chains;
static struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS];

/*
 * We put the lock dependency chains into a hash-table as well, to cache
 * their existence:
 */
#define CHAINHASH_BITS		(MAX_LOCKDEP_CHAINS_BITS-1)
#define CHAINHASH_SIZE		(1UL << CHAINHASH_BITS)
#define CHAINHASH_MASK		(CHAINHASH_SIZE - 1)
#define __chainhashfn(chain) \
		(((chain >> CHAINHASH_BITS) + chain) & CHAINHASH_MASK)
#define chainhashentry(chain)	(chainhash_table + __chainhashfn((chain)))

static struct list_head chainhash_table[CHAINHASH_SIZE];

/*
 * The hash key of the lock dependency chains is a hash itself too:
 * it's a hash of all locks taken up to that lock, including that lock.
 * It's a 64-bit hash, because it's important for the keys to be
 * unique.
 */
#define iterate_chain_key(key1, key2) \
	(((key1) << MAX_LOCKDEP_KEYS_BITS/2) ^ \
	((key1) >> (64-MAX_LOCKDEP_KEYS_BITS/2)) ^ \
	(key2))

void lockdep_off(void)
{
	current->lockdep_recursion++;
}

EXPORT_SYMBOL(lockdep_off);

void lockdep_on(void)
{
	current->lockdep_recursion--;
}

EXPORT_SYMBOL(lockdep_on);

int lockdep_internal(void)
{
	return current->lockdep_recursion != 0;
}

EXPORT_SYMBOL(lockdep_internal);

/*
 * Debugging switches:
 */

#define VERBOSE			0
#ifdef VERBOSE
# define VERY_VERBOSE		0
#endif

#if VERBOSE
# define HARDIRQ_VERBOSE	1
# define SOFTIRQ_VERBOSE	1
#else
# define HARDIRQ_VERBOSE	0
# define SOFTIRQ_VERBOSE	0
#endif

#if VERBOSE || HARDIRQ_VERBOSE || SOFTIRQ_VERBOSE
/*
 * Quick filtering for interesting events:
 */
static int class_filter(struct lock_class *class)
{
#if 0
	/* Example */
Ingo Molnar's avatar
Ingo Molnar committed
	if (class->name_version == 1 &&
			!strcmp(class->name, "lockname"))
Ingo Molnar's avatar
Ingo Molnar committed
		return 1;
	if (class->name_version == 1 &&
			!strcmp(class->name, "&struct->lockfield"))
Ingo Molnar's avatar
Ingo Molnar committed
		return 1;
#endif
	/* Allow everything else. 0 would be filter everything else */
	return 1;
Ingo Molnar's avatar
Ingo Molnar committed
}
#endif

static int verbose(struct lock_class *class)
{
#if VERBOSE
	return class_filter(class);
#endif
	return 0;
}

#ifdef CONFIG_TRACE_IRQFLAGS

static int hardirq_verbose(struct lock_class *class)
{
#if HARDIRQ_VERBOSE
	return class_filter(class);
#endif
	return 0;
}

static int softirq_verbose(struct lock_class *class)
{
#if SOFTIRQ_VERBOSE
	return class_filter(class);
#endif
	return 0;
}

#endif

/*
 * Stack-trace: tightly packed array of stack backtrace
 * addresses. Protected by the hash_lock.
 */
unsigned long nr_stack_trace_entries;
static unsigned long stack_trace[MAX_STACK_TRACE_ENTRIES];

static int save_trace(struct stack_trace *trace)
{
	trace->nr_entries = 0;
	trace->max_entries = MAX_STACK_TRACE_ENTRIES - nr_stack_trace_entries;
	trace->entries = stack_trace + nr_stack_trace_entries;

	trace->skip = 3;
	trace->all_contexts = 0;

	/* Make sure to not recurse in case the the unwinder needs to tak
e	   locks. */
	lockdep_off();
	save_stack_trace(trace, NULL);
Ingo Molnar's avatar
Ingo Molnar committed

	trace->max_entries = trace->nr_entries;

	nr_stack_trace_entries += trace->nr_entries;
	if (DEBUG_LOCKS_WARN_ON(nr_stack_trace_entries > MAX_STACK_TRACE_ENTRIES))
		return 0;

	if (nr_stack_trace_entries == MAX_STACK_TRACE_ENTRIES) {
		__raw_spin_unlock(&hash_lock);
		if (debug_locks_off()) {
			printk("BUG: MAX_STACK_TRACE_ENTRIES too low!\n");
			printk("turning off the locking correctness validator.\n");
			dump_stack();
		}
		return 0;
	}

	return 1;
}

unsigned int nr_hardirq_chains;
unsigned int nr_softirq_chains;
unsigned int nr_process_chains;
unsigned int max_lockdep_depth;
unsigned int max_recursion_depth;

#ifdef CONFIG_DEBUG_LOCKDEP
/*
 * We cannot printk in early bootup code. Not even early_printk()
 * might work. So we mark any initialization errors and printk
 * about it later on, in lockdep_info().
 */
static int lockdep_init_error;

/*
 * Various lockdep statistics:
 */
atomic_t chain_lookup_hits;
atomic_t chain_lookup_misses;
atomic_t hardirqs_on_events;
atomic_t hardirqs_off_events;
atomic_t redundant_hardirqs_on;
atomic_t redundant_hardirqs_off;
atomic_t softirqs_on_events;
atomic_t softirqs_off_events;
atomic_t redundant_softirqs_on;
atomic_t redundant_softirqs_off;
atomic_t nr_unused_locks;
atomic_t nr_cyclic_checks;
atomic_t nr_cyclic_check_recursions;
atomic_t nr_find_usage_forwards_checks;
atomic_t nr_find_usage_forwards_recursions;
atomic_t nr_find_usage_backwards_checks;
atomic_t nr_find_usage_backwards_recursions;
# define debug_atomic_inc(ptr)		atomic_inc(ptr)
# define debug_atomic_dec(ptr)		atomic_dec(ptr)
# define debug_atomic_read(ptr)		atomic_read(ptr)
#else
# define debug_atomic_inc(ptr)		do { } while (0)
# define debug_atomic_dec(ptr)		do { } while (0)
# define debug_atomic_read(ptr)		0
#endif

/*
 * Locking printouts:
 */

static const char *usage_str[] =
{
	[LOCK_USED] =			"initial-use ",
	[LOCK_USED_IN_HARDIRQ] =	"in-hardirq-W",
	[LOCK_USED_IN_SOFTIRQ] =	"in-softirq-W",
	[LOCK_ENABLED_SOFTIRQS] =	"softirq-on-W",
	[LOCK_ENABLED_HARDIRQS] =	"hardirq-on-W",
	[LOCK_USED_IN_HARDIRQ_READ] =	"in-hardirq-R",
	[LOCK_USED_IN_SOFTIRQ_READ] =	"in-softirq-R",
	[LOCK_ENABLED_SOFTIRQS_READ] =	"softirq-on-R",
	[LOCK_ENABLED_HARDIRQS_READ] =	"hardirq-on-R",
};

const char * __get_key_name(struct lockdep_subclass_key *key, char *str)
{
	unsigned long offs, size;
	char *modname;

	return kallsyms_lookup((unsigned long)key, &size, &offs, &modname, str);
}

void
get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3, char *c4)
{
	*c1 = '.', *c2 = '.', *c3 = '.', *c4 = '.';

	if (class->usage_mask & LOCKF_USED_IN_HARDIRQ)
		*c1 = '+';
	else
		if (class->usage_mask & LOCKF_ENABLED_HARDIRQS)
			*c1 = '-';

	if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ)
		*c2 = '+';
	else
		if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS)
			*c2 = '-';

	if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ)
		*c3 = '-';
	if (class->usage_mask & LOCKF_USED_IN_HARDIRQ_READ) {
		*c3 = '+';
		if (class->usage_mask & LOCKF_ENABLED_HARDIRQS_READ)
			*c3 = '?';
	}

	if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ)
		*c4 = '-';
	if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ_READ) {
		*c4 = '+';
		if (class->usage_mask & LOCKF_ENABLED_SOFTIRQS_READ)
			*c4 = '?';
	}
}

static void print_lock_name(struct lock_class *class)
{
	char str[128], c1, c2, c3, c4;
	const char *name;

	get_usage_chars(class, &c1, &c2, &c3, &c4);

	name = class->name;
	if (!name) {
		name = __get_key_name(class->key, str);
		printk(" (%s", name);
	} else {
		printk(" (%s", name);
		if (class->name_version > 1)
			printk("#%d", class->name_version);
		if (class->subclass)
			printk("/%d", class->subclass);
	}
	printk("){%c%c%c%c}", c1, c2, c3, c4);
}

static void print_lockdep_cache(struct lockdep_map *lock)
{
	const char *name;
	char str[128];

	name = lock->name;
	if (!name)
		name = __get_key_name(lock->key->subkeys, str);

	printk("%s", name);
}

static void print_lock(struct held_lock *hlock)
{
	print_lock_name(hlock->class);
	printk(", at: ");
	print_ip_sym(hlock->acquire_ip);
}

static void lockdep_print_held_locks(struct task_struct *curr)
{
	int i, depth = curr->lockdep_depth;

	if (!depth) {
		printk("no locks held by %s/%d.\n", curr->comm, curr->pid);
		return;
	}
	printk("%d lock%s held by %s/%d:\n",
		depth, depth > 1 ? "s" : "", curr->comm, curr->pid);

	for (i = 0; i < depth; i++) {
		printk(" #%d: ", i);
		print_lock(curr->held_locks + i);
	}
}

static void print_lock_class_header(struct lock_class *class, int depth)
{
	int bit;

	printk("%*s->", depth, "");
Ingo Molnar's avatar
Ingo Molnar committed
	print_lock_name(class);
	printk(" ops: %lu", class->ops);
	printk(" {\n");

	for (bit = 0; bit < LOCK_USAGE_STATES; bit++) {
		if (class->usage_mask & (1 << bit)) {
			int len = depth;

			len += printk("%*s   %s", depth, "", usage_str[bit]);
Ingo Molnar's avatar
Ingo Molnar committed
			len += printk(" at:\n");
			print_stack_trace(class->usage_traces + bit, len);
		}
	}
	printk("%*s }\n", depth, "");
Ingo Molnar's avatar
Ingo Molnar committed

	printk("%*s ... key      at: ",depth,"");
Ingo Molnar's avatar
Ingo Molnar committed
	print_ip_sym((unsigned long)class->key);
}

/*
 * printk all lock dependencies starting at <entry>:
 */
static void print_lock_dependencies(struct lock_class *class, int depth)
{
	struct lock_list *entry;

	if (DEBUG_LOCKS_WARN_ON(depth >= 20))
		return;

	print_lock_class_header(class, depth);

	list_for_each_entry(entry, &class->locks_after, entry) {
		DEBUG_LOCKS_WARN_ON(!entry->class);
		print_lock_dependencies(entry->class, depth + 1);

		printk("%*s ... acquired at:\n",depth,"");
Ingo Molnar's avatar
Ingo Molnar committed
		print_stack_trace(&entry->trace, 2);
		printk("\n");
	}
}

/*
 * Add a new dependency to the head of the list:
 */
static int add_lock_to_list(struct lock_class *class, struct lock_class *this,
			    struct list_head *head, unsigned long ip)
{
	struct lock_list *entry;
	/*
	 * Lock not present yet - get a new dependency struct and
	 * add it to the list:
	 */
	entry = alloc_list_entry();
	if (!entry)
		return 0;

	entry->class = this;
	save_trace(&entry->trace);

	/*
	 * Since we never remove from the dependency list, the list can
	 * be walked lockless by other CPUs, it's only allocation
	 * that must be protected by the spinlock. But this also means
	 * we must make new entries visible only once writes to the
	 * entry become visible - hence the RCU op:
	 */
	list_add_tail_rcu(&entry->entry, head);

	return 1;
}

/*
 * Recursive, forwards-direction lock-dependency checking, used for
 * both noncyclic checking and for hardirq-unsafe/softirq-unsafe
 * checking.
 *
 * (to keep the stackframe of the recursive functions small we
 *  use these global variables, and we also mark various helper
 *  functions as noinline.)
 */
static struct held_lock *check_source, *check_target;

/*
 * Print a dependency chain entry (this is only done when a deadlock
 * has been detected):
 */
static noinline int
print_circular_bug_entry(struct lock_list *target, unsigned int depth)
{
	if (debug_locks_silent)
		return 0;
	printk("\n-> #%u", depth);
	print_lock_name(target->class);
	printk(":\n");
	print_stack_trace(&target->trace, 6);

	return 0;
}

static void print_kernel_version(void)
{
	printk("%s %.*s\n", system_utsname.release,
		(int)strcspn(system_utsname.version, " "),
		system_utsname.version);
}

Ingo Molnar's avatar
Ingo Molnar committed
/*
 * When a circular dependency is detected, print the
 * header first:
 */
static noinline int
print_circular_bug_header(struct lock_list *entry, unsigned int depth)
{
	struct task_struct *curr = current;

	__raw_spin_unlock(&hash_lock);
	debug_locks_off();
	if (debug_locks_silent)
		return 0;

	printk("\n=======================================================\n");
	printk(  "[ INFO: possible circular locking dependency detected ]\n");
	print_kernel_version();
Ingo Molnar's avatar
Ingo Molnar committed
	printk(  "-------------------------------------------------------\n");
	printk("%s/%d is trying to acquire lock:\n",
		curr->comm, curr->pid);
	print_lock(check_source);
	printk("\nbut task is already holding lock:\n");
	print_lock(check_target);
	printk("\nwhich lock already depends on the new lock.\n\n");
	printk("\nthe existing dependency chain (in reverse order) is:\n");

	print_circular_bug_entry(entry, depth);

	return 0;
}

static noinline int print_circular_bug_tail(void)
{
	struct task_struct *curr = current;
	struct lock_list this;

	if (debug_locks_silent)
		return 0;

	this.class = check_source->class;
	save_trace(&this.trace);
	print_circular_bug_entry(&this, 0);

	printk("\nother info that might help us debug this:\n\n");
	lockdep_print_held_locks(curr);

	printk("\nstack backtrace:\n");
	dump_stack();

	return 0;
}

static int noinline print_infinite_recursion_bug(void)
{
	__raw_spin_unlock(&hash_lock);
	DEBUG_LOCKS_WARN_ON(1);

	return 0;
}

/*
 * Prove that the dependency graph starting at <entry> can not
 * lead to <target>. Print an error and return 0 if it does.
 */
static noinline int
check_noncircular(struct lock_class *source, unsigned int depth)
{
	struct lock_list *entry;

	debug_atomic_inc(&nr_cyclic_check_recursions);
	if (depth > max_recursion_depth)
		max_recursion_depth = depth;
	if (depth >= 20)
		return print_infinite_recursion_bug();
	/*
	 * Check this lock's dependency list:
	 */
	list_for_each_entry(entry, &source->locks_after, entry) {
		if (entry->class == check_target->class)
			return print_circular_bug_header(entry, depth+1);
		debug_atomic_inc(&nr_cyclic_checks);
		if (!check_noncircular(entry->class, depth+1))
			return print_circular_bug_entry(entry, depth+1);
	}
	return 1;
}

static int very_verbose(struct lock_class *class)
{
#if VERY_VERBOSE
	return class_filter(class);
#endif
	return 0;
}
#ifdef CONFIG_TRACE_IRQFLAGS

/*
 * Forwards and backwards subgraph searching, for the purposes of
 * proving that two subgraphs can be connected by a new dependency
 * without creating any illegal irq-safe -> irq-unsafe lock dependency.
 */
static enum lock_usage_bit find_usage_bit;
static struct lock_class *forwards_match, *backwards_match;

/*
 * Find a node in the forwards-direction dependency sub-graph starting
 * at <source> that matches <find_usage_bit>.
 *
 * Return 2 if such a node exists in the subgraph, and put that node
 * into <forwards_match>.
 *
 * Return 1 otherwise and keep <forwards_match> unchanged.
 * Return 0 on error.
 */
static noinline int
find_usage_forwards(struct lock_class *source, unsigned int depth)
{
	struct lock_list *entry;
	int ret;

	if (depth > max_recursion_depth)
		max_recursion_depth = depth;
	if (depth >= 20)
		return print_infinite_recursion_bug();

	debug_atomic_inc(&nr_find_usage_forwards_checks);
	if (source->usage_mask & (1 << find_usage_bit)) {
		forwards_match = source;
		return 2;
	}

	/*
	 * Check this lock's dependency list:
	 */
	list_for_each_entry(entry, &source->locks_after, entry) {
		debug_atomic_inc(&nr_find_usage_forwards_recursions);
		ret = find_usage_forwards(entry->class, depth+1);
		if (ret == 2 || ret == 0)
			return ret;
	}
	return 1;
}

/*
 * Find a node in the backwards-direction dependency sub-graph starting
 * at <source> that matches <find_usage_bit>.
 *
 * Return 2 if such a node exists in the subgraph, and put that node
 * into <backwards_match>.
 *
 * Return 1 otherwise and keep <backwards_match> unchanged.
 * Return 0 on error.
 */
static noinline int
find_usage_backwards(struct lock_class *source, unsigned int depth)
{
	struct lock_list *entry;
	int ret;

	if (depth > max_recursion_depth)
		max_recursion_depth = depth;
	if (depth >= 20)
		return print_infinite_recursion_bug();

	debug_atomic_inc(&nr_find_usage_backwards_checks);
	if (source->usage_mask & (1 << find_usage_bit)) {
		backwards_match = source;
		return 2;
	}

	/*
	 * Check this lock's dependency list:
	 */
	list_for_each_entry(entry, &source->locks_before, entry) {
		debug_atomic_inc(&nr_find_usage_backwards_recursions);
		ret = find_usage_backwards(entry->class, depth+1);
		if (ret == 2 || ret == 0)
			return ret;
	}
	return 1;
}

static int
print_bad_irq_dependency(struct task_struct *curr,
			 struct held_lock *prev,
			 struct held_lock *next,
			 enum lock_usage_bit bit1,
			 enum lock_usage_bit bit2,
			 const char *irqclass)
{
	__raw_spin_unlock(&hash_lock);
	debug_locks_off();
	if (debug_locks_silent)
		return 0;

	printk("\n======================================================\n");
	printk(  "[ INFO: %s-safe -> %s-unsafe lock order detected ]\n",
		irqclass, irqclass);
	print_kernel_version();
Ingo Molnar's avatar
Ingo Molnar committed
	printk(  "------------------------------------------------------\n");
	printk("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] is trying to acquire:\n",
		curr->comm, curr->pid,
		curr->hardirq_context, hardirq_count() >> HARDIRQ_SHIFT,
		curr->softirq_context, softirq_count() >> SOFTIRQ_SHIFT,
		curr->hardirqs_enabled,
		curr->softirqs_enabled);
	print_lock(next);

	printk("\nand this task is already holding:\n");
	print_lock(prev);
	printk("which would create a new lock dependency:\n");
	print_lock_name(prev->class);
	printk(" ->");
	print_lock_name(next->class);
	printk("\n");

	printk("\nbut this new dependency connects a %s-irq-safe lock:\n",
		irqclass);
	print_lock_name(backwards_match);
	printk("\n... which became %s-irq-safe at:\n", irqclass);

	print_stack_trace(backwards_match->usage_traces + bit1, 1);

	printk("\nto a %s-irq-unsafe lock:\n", irqclass);
	print_lock_name(forwards_match);
	printk("\n... which became %s-irq-unsafe at:\n", irqclass);
	printk("...");

	print_stack_trace(forwards_match->usage_traces + bit2, 1);

	printk("\nother info that might help us debug this:\n\n");
	lockdep_print_held_locks(curr);

	printk("\nthe %s-irq-safe lock's dependencies:\n", irqclass);
	print_lock_dependencies(backwards_match, 0);

	printk("\nthe %s-irq-unsafe lock's dependencies:\n", irqclass);
	print_lock_dependencies(forwards_match, 0);

	printk("\nstack backtrace:\n");
	dump_stack();

	return 0;
}

static int
check_usage(struct task_struct *curr, struct held_lock *prev,
	    struct held_lock *next, enum lock_usage_bit bit_backwards,
	    enum lock_usage_bit bit_forwards, const char *irqclass)
{
	int ret;

	find_usage_bit = bit_backwards;
	/* fills in <backwards_match> */
	ret = find_usage_backwards(prev->class, 0);
	if (!ret || ret == 1)
		return ret;

	find_usage_bit = bit_forwards;
	ret = find_usage_forwards(next->class, 0);
	if (!ret || ret == 1)
		return ret;
	/* ret == 2 */
	return print_bad_irq_dependency(curr, prev, next,
			bit_backwards, bit_forwards, irqclass);
}

#endif

static int
print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
		   struct held_lock *next)
{
	debug_locks_off();
	__raw_spin_unlock(&hash_lock);
	if (debug_locks_silent)
		return 0;

	printk("\n=============================================\n");
	printk(  "[ INFO: possible recursive locking detected ]\n");
	print_kernel_version();
Ingo Molnar's avatar
Ingo Molnar committed
	printk(  "---------------------------------------------\n");
	printk("%s/%d is trying to acquire lock:\n",
		curr->comm, curr->pid);
	print_lock(next);
	printk("\nbut task is already holding lock:\n");
	print_lock(prev);

	printk("\nother info that might help us debug this:\n");
	lockdep_print_held_locks(curr);

	printk("\nstack backtrace:\n");
	dump_stack();

	return 0;
}

/*
 * Check whether we are holding such a class already.
 *
 * (Note that this has to be done separately, because the graph cannot
 * detect such classes of deadlocks.)
 *
 * Returns: 0 on deadlock detected, 1 on OK, 2 on recursive read
 */
static int
check_deadlock(struct task_struct *curr, struct held_lock *next,
	       struct lockdep_map *next_instance, int read)
{
	struct held_lock *prev;
	int i;

	for (i = 0; i < curr->lockdep_depth; i++) {
		prev = curr->held_locks + i;
		if (prev->class != next->class)
			continue;
		/*
		 * Allow read-after-read recursion of the same
		 * lock class (i.e. read_lock(lock)+read_lock(lock)):
Ingo Molnar's avatar
Ingo Molnar committed
		 */
		if ((read == 2) && prev->read)
Ingo Molnar's avatar
Ingo Molnar committed
			return 2;
		return print_deadlock_bug(curr, prev, next);
	}
	return 1;
}

/*
 * There was a chain-cache miss, and we are about to add a new dependency
 * to a previous lock. We recursively validate the following rules:
 *
 *  - would the adding of the <prev> -> <next> dependency create a
 *    circular dependency in the graph? [== circular deadlock]
 *
 *  - does the new prev->next dependency connect any hardirq-safe lock
 *    (in the full backwards-subgraph starting at <prev>) with any
 *    hardirq-unsafe lock (in the full forwards-subgraph starting at
 *    <next>)? [== illegal lock inversion with hardirq contexts]
 *
 *  - does the new prev->next dependency connect any softirq-safe lock
 *    (in the full backwards-subgraph starting at <prev>) with any
 *    softirq-unsafe lock (in the full forwards-subgraph starting at
 *    <next>)? [== illegal lock inversion with softirq contexts]
 *
 * any of these scenarios could lead to a deadlock.
 *
 * Then if all the validations pass, we add the forwards and backwards
 * dependency.
 */
static int
check_prev_add(struct task_struct *curr, struct held_lock *prev,
	       struct held_lock *next)
{
	struct lock_list *entry;
	int ret;

	/*
	 * Prove that the new <prev> -> <next> dependency would not
	 * create a circular dependency in the graph. (We do this by
	 * forward-recursing into the graph starting at <next>, and
	 * checking whether we can reach <prev>.)
	 *
	 * We are using global variables to control the recursion, to
	 * keep the stackframe size of the recursive functions low:
	 */
	check_source = next;
	check_target = prev;
	if (!(check_noncircular(next->class, 0)))
		return print_circular_bug_tail();

#ifdef CONFIG_TRACE_IRQFLAGS
	/*
	 * Prove that the new dependency does not connect a hardirq-safe
	 * lock with a hardirq-unsafe lock - to achieve this we search
	 * the backwards-subgraph starting at <prev>, and the
	 * forwards-subgraph starting at <next>:
	 */
	if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ,
					LOCK_ENABLED_HARDIRQS, "hard"))
		return 0;

	/*
	 * Prove that the new dependency does not connect a hardirq-safe-read
	 * lock with a hardirq-unsafe lock - to achieve this we search
	 * the backwards-subgraph starting at <prev>, and the
	 * forwards-subgraph starting at <next>:
	 */
	if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ_READ,
					LOCK_ENABLED_HARDIRQS, "hard-read"))
		return 0;

	/*
	 * Prove that the new dependency does not connect a softirq-safe
	 * lock with a softirq-unsafe lock - to achieve this we search
	 * the backwards-subgraph starting at <prev>, and the
	 * forwards-subgraph starting at <next>:
	 */
	if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ,
					LOCK_ENABLED_SOFTIRQS, "soft"))
		return 0;
	/*
	 * Prove that the new dependency does not connect a softirq-safe-read
	 * lock with a softirq-unsafe lock - to achieve this we search
	 * the backwards-subgraph starting at <prev>, and the
	 * forwards-subgraph starting at <next>:
	 */
	if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ_READ,
					LOCK_ENABLED_SOFTIRQS, "soft"))
		return 0;
#endif
	/*
	 * For recursive read-locks we do all the dependency checks,
	 * but we dont store read-triggered dependencies (only
	 * write-triggered dependencies). This ensures that only the
	 * write-side dependencies matter, and that if for example a
	 * write-lock never takes any other locks, then the reads are
	 * equivalent to a NOP.
	 */
	if (next->read == 2 || prev->read == 2)
		return 1;
	/*
	 * Is the <prev> -> <next> dependency already present?
	 *
	 * (this may occur even though this is a new chain: consider
	 *  e.g. the L1 -> L2 -> L3 -> L4 and the L5 -> L1 -> L2 -> L3
	 *  chains - the second one will be new, but L1 already has
	 *  L2 added to its dependency list, due to the first chain.)
	 */
	list_for_each_entry(entry, &prev->class->locks_after, entry) {
		if (entry->class == next->class)
			return 2;
	}

	/*
	 * Ok, all validations passed, add the new lock
	 * to the previous lock's dependency list:
	 */
	ret = add_lock_to_list(prev->class, next->class,
			       &prev->class->locks_after, next->acquire_ip);
	if (!ret)
		return 0;
	/*
	 * Return value of 2 signals 'dependency already added',
	 * in that case we dont have to add the backlink either.
	 */
	if (ret == 2)
		return 2;
	ret = add_lock_to_list(next->class, prev->class,
			       &next->class->locks_before, next->acquire_ip);

	/*
	 * Debugging printouts:
	 */
	if (verbose(prev->class) || verbose(next->class)) {
		__raw_spin_unlock(&hash_lock);
		printk("\n new dependency: ");
		print_lock_name(prev->class);
		printk(" => ");
		print_lock_name(next->class);
		printk("\n");
		dump_stack();
		__raw_spin_lock(&hash_lock);
	}
	return 1;
}

/*
 * Add the dependency to all directly-previous locks that are 'relevant'.
 * The ones that are relevant are (in increasing distance from curr):
 * all consecutive trylock entries and the final non-trylock entry - or
 * the end of this context's lock-chain - whichever comes first.
 */
static int
check_prevs_add(struct task_struct *curr, struct held_lock *next)
{