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 + -
显示快捷键?