lockdep.c

来自「Kernel code of linux kernel」· C语言 代码 · 共 2,589 行 · 第 1/5 页

C
2,589
字号
	char str[KSYM_NAME_LEN];	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(hlock));	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, task_pid_nr(curr));		return;	}	printk("%d lock%s held by %s/%d:\n",		depth, depth > 1 ? "s" : "", curr->comm, task_pid_nr(curr));	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, "");	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]);			len += printk(" at:\n");			print_stack_trace(class->usage_traces + bit, len);		}	}	printk("%*s }\n", depth, "");	printk("%*s ... key      at: ",depth,"");	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 (lockdep_dependency_visit(class, depth))		return;	if (DEBUG_LOCKS_WARN_ON(depth >= 20))		return;	print_lock_class_header(class, depth);	list_for_each_entry(entry, &class->locks_after, entry) {		if (DEBUG_LOCKS_WARN_ON(!entry->class))			return;		print_lock_dependencies(entry->class, depth + 1);		printk("%*s ... acquired at:\n",depth,"");		print_stack_trace(&entry->trace, 2);		printk("\n");	}}static void print_kernel_version(void){	printk("%s %.*s\n", init_utsname()->release,		(int)strcspn(init_utsname()->version, " "),		init_utsname()->version);}static int very_verbose(struct lock_class *class){#if VERY_VERBOSE	return class_filter(class);#endif	return 0;}/* * Is this the address of a static object: */static int static_obj(void *obj){	unsigned long start = (unsigned long) &_stext,		      end   = (unsigned long) &_end,		      addr  = (unsigned long) obj;#ifdef CONFIG_SMP	int i;#endif	/*	 * static variable?	 */	if ((addr >= start) && (addr < end))		return 1;#ifdef CONFIG_SMP	/*	 * percpu var?	 */	for_each_possible_cpu(i) {		start = (unsigned long) &__per_cpu_start + per_cpu_offset(i);		end   = (unsigned long) &__per_cpu_start + PERCPU_ENOUGH_ROOM					+ per_cpu_offset(i);		if ((addr >= start) && (addr < end))			return 1;	}#endif	/*	 * module var?	 */	return is_module_address(addr);}/* * To make lock name printouts unique, we calculate a unique * class->name_version generation counter: */static int count_matching_names(struct lock_class *new_class){	struct lock_class *class;	int count = 0;	if (!new_class->name)		return 0;	list_for_each_entry(class, &all_lock_classes, lock_entry) {		if (new_class->key - new_class->subclass == class->key)			return class->name_version;		if (class->name && !strcmp(class->name, new_class->name))			count = max(count, class->name_version);	}	return count + 1;}/* * Register a lock's class in the hash-table, if the class is not present * yet. Otherwise we look it up. We cache the result in the lock object * itself, so actual lookup of the hash should be once per lock object. */static inline struct lock_class *look_up_lock_class(struct lockdep_map *lock, unsigned int subclass){	struct lockdep_subclass_key *key;	struct list_head *hash_head;	struct lock_class *class;#ifdef CONFIG_DEBUG_LOCKDEP	/*	 * If the architecture calls into lockdep before initializing	 * the hashes then we'll warn about it later. (we cannot printk	 * right now)	 */	if (unlikely(!lockdep_initialized)) {		lockdep_init();		lockdep_init_error = 1;		save_stack_trace(&lockdep_init_trace);	}#endif	/*	 * Static locks do not have their class-keys yet - for them the key	 * is the lock object itself:	 */	if (unlikely(!lock->key))		lock->key = (void *)lock;	/*	 * NOTE: the class-key must be unique. For dynamic locks, a static	 * lock_class_key variable is passed in through the mutex_init()	 * (or spin_lock_init()) call - which acts as the key. For static	 * locks we use the lock object itself as the key.	 */	BUILD_BUG_ON(sizeof(struct lock_class_key) >			sizeof(struct lockdep_map));	key = lock->key->subkeys + subclass;	hash_head = classhashentry(key);	/*	 * We can walk the hash lockfree, because the hash only	 * grows, and we are careful when adding entries to the end:	 */	list_for_each_entry(class, hash_head, hash_entry) {		if (class->key == key) {			WARN_ON_ONCE(class->name != lock->name);			return class;		}	}	return NULL;}/* * Register a lock's class in the hash-table, if the class is not present * yet. Otherwise we look it up. We cache the result in the lock object * itself, so actual lookup of the hash should be once per lock object. */static inline struct lock_class *register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force){	struct lockdep_subclass_key *key;	struct list_head *hash_head;	struct lock_class *class;	unsigned long flags;	class = look_up_lock_class(lock, subclass);	if (likely(class))		return class;	/*	 * Debug-check: all keys must be persistent! 	 */	if (!static_obj(lock->key)) {		debug_locks_off();		printk("INFO: trying to register non-static key.\n");		printk("the code is fine but needs lockdep annotation.\n");		printk("turning off the locking correctness validator.\n");		dump_stack();		return NULL;	}	key = lock->key->subkeys + subclass;	hash_head = classhashentry(key);	raw_local_irq_save(flags);	if (!graph_lock()) {		raw_local_irq_restore(flags);		return NULL;	}	/*	 * We have to do the hash-walk again, to avoid races	 * with another CPU:	 */	list_for_each_entry(class, hash_head, hash_entry)		if (class->key == key)			goto out_unlock_set;	/*	 * Allocate a new key from the static array, and add it to	 * the hash:	 */	if (nr_lock_classes >= MAX_LOCKDEP_KEYS) {		if (!debug_locks_off_graph_unlock()) {			raw_local_irq_restore(flags);			return NULL;		}		raw_local_irq_restore(flags);		printk("BUG: MAX_LOCKDEP_KEYS too low!\n");		printk("turning off the locking correctness validator.\n");		return NULL;	}	class = lock_classes + nr_lock_classes++;	debug_atomic_inc(&nr_unused_locks);	class->key = key;	class->name = lock->name;	class->subclass = subclass;	INIT_LIST_HEAD(&class->lock_entry);	INIT_LIST_HEAD(&class->locks_before);	INIT_LIST_HEAD(&class->locks_after);	class->name_version = count_matching_names(class);	/*	 * We use RCU's safe list-add method to make	 * parallel walking of the hash-list safe:	 */	list_add_tail_rcu(&class->hash_entry, hash_head);	/*	 * Add it to the global list of classes:	 */	list_add_tail_rcu(&class->lock_entry, &all_lock_classes);	if (verbose(class)) {		graph_unlock();		raw_local_irq_restore(flags);		printk("\nnew class %p: %s", class->key, class->name);		if (class->name_version > 1)			printk("#%d", class->name_version);		printk("\n");		dump_stack();		raw_local_irq_save(flags);		if (!graph_lock()) {			raw_local_irq_restore(flags);			return NULL;		}	}out_unlock_set:	graph_unlock();	raw_local_irq_restore(flags);	if (!subclass || force)		lock->class_cache = class;	if (DEBUG_LOCKS_WARN_ON(class->subclass != subclass))		return NULL;	return class;}#ifdef CONFIG_PROVE_LOCKING/* * Allocate a lockdep entry. (assumes the graph_lock held, returns * with NULL on failure) */static struct lock_list *alloc_list_entry(void){	if (nr_list_entries >= MAX_LOCKDEP_ENTRIES) {		if (!debug_locks_off_graph_unlock())			return NULL;		printk("BUG: MAX_LOCKDEP_ENTRIES too low!\n");		printk("turning off the locking correctness validator.\n");		return NULL;	}	return list_entries + nr_list_entries++;}/* * 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, int distance){	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;	if (!save_trace(&entry->trace))		return 0;	entry->class = this;	entry->distance = distance;	/*	 * 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 intprint_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;}/* * When a circular dependency is detected, print the * header first: */static noinline intprint_circular_bug_header(struct lock_list *entry, unsigned int depth){	struct task_struct *curr = current;	if (!debug_locks_off_graph_unlock() || debug_locks_silent)		return 0;	printk("\n=======================================================\n");	printk(  "[ INFO: possible circular locking dependency detected ]\n");	print_kernel_version();	printk(  "-------------------------------------------------------\n");	printk("%s/%d is trying to acquire lock:\n",		curr->comm, task_pid_nr(curr));	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 = hlock_class(check_source);	if (!save_trace(&this.trace))		return 0;	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;}#define RECURSION_LIMIT 40static int noinline print_infinite_recursion_bug(void){	if (!debug_locks_off_graph_unlock())		return 0;	WARN_ON(1);	return 0;}unsigned long __lockdep_count_forward_deps(struct lock_class *class,					   unsigned int depth){	struct lock_list *entry;	unsigned long ret = 1;	if (lockdep_dependency_visit(class, depth))		return 0;	/*	 * Recurse this class's dependency list:	 */	list_for_each_entry(entry, &class->locks_after, entry)		ret += __lockdep_count_forward_deps(entry->class, depth + 1);	return ret;}unsigned long lockdep_count_forward_deps(struct lock_class *class){	unsigned long ret, flags;	local_irq_save(flags);	__raw_spin_lock(&lockdep_lock);	ret = __lockdep_count_forward_deps(class, 0);	__raw_spin_unlock(&lockdep_lock);	local_irq_restore(flags);	return ret;}unsigned long __lockdep_count_backward_deps(struct lock_class *class,					    unsigned int depth){	struct lock_list *entry;	unsigned long ret = 1;	if (lockdep_dependency_visit(class, depth))		return 0;	/*	 * Recurse this class's dependency list:	 */	list_for_each_entry(entry, &class->locks_before, entry)		ret += __lockdep_count_backward_deps(entry->class, depth + 1);	return ret;}unsigned long lockdep_count_backward_deps(struct lock_class *class){

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?