| .. | .. | 
|---|
| 24 | 24 |   | 
|---|
| 25 | 25 |  #include "lockdep_internals.h" | 
|---|
| 26 | 26 |   | 
|---|
 | 27 | +/*  | 
|---|
 | 28 | + * Since iteration of lock_classes is done without holding the lockdep lock,  | 
|---|
 | 29 | + * it is not safe to iterate all_lock_classes list directly as the iteration  | 
|---|
 | 30 | + * may branch off to free_lock_classes or the zapped list. Iteration is done  | 
|---|
 | 31 | + * directly on the lock_classes array by checking the lock_classes_in_use  | 
|---|
 | 32 | + * bitmap and max_lock_class_idx.  | 
|---|
 | 33 | + */  | 
|---|
 | 34 | +#define iterate_lock_classes(idx, class)				\  | 
|---|
 | 35 | +	for (idx = 0, class = lock_classes; idx <= max_lock_class_idx;	\  | 
|---|
 | 36 | +	     idx++, class++)  | 
|---|
 | 37 | +  | 
|---|
| 27 | 38 |  static void *l_next(struct seq_file *m, void *v, loff_t *pos) | 
|---|
| 28 | 39 |  { | 
|---|
| 29 |  | -	return seq_list_next(v, &all_lock_classes, pos);  | 
|---|
 | 40 | +	struct lock_class *class = v;  | 
|---|
 | 41 | +  | 
|---|
 | 42 | +	++class;  | 
|---|
 | 43 | +	*pos = class - lock_classes;  | 
|---|
 | 44 | +	return (*pos > max_lock_class_idx) ? NULL : class;  | 
|---|
| 30 | 45 |  } | 
|---|
| 31 | 46 |   | 
|---|
| 32 | 47 |  static void *l_start(struct seq_file *m, loff_t *pos) | 
|---|
| 33 | 48 |  { | 
|---|
| 34 |  | -	return seq_list_start_head(&all_lock_classes, *pos);  | 
|---|
 | 49 | +	unsigned long idx = *pos;  | 
|---|
 | 50 | +  | 
|---|
 | 51 | +	if (idx > max_lock_class_idx)  | 
|---|
 | 52 | +		return NULL;  | 
|---|
 | 53 | +	return lock_classes + idx;  | 
|---|
| 35 | 54 |  } | 
|---|
| 36 | 55 |   | 
|---|
| 37 | 56 |  static void l_stop(struct seq_file *m, void *v) | 
|---|
| .. | .. | 
|---|
| 57 | 76 |   | 
|---|
| 58 | 77 |  static int l_show(struct seq_file *m, void *v) | 
|---|
| 59 | 78 |  { | 
|---|
| 60 |  | -	struct lock_class *class = list_entry(v, struct lock_class, lock_entry);  | 
|---|
 | 79 | +	struct lock_class *class = v;  | 
|---|
| 61 | 80 |  	struct lock_list *entry; | 
|---|
| 62 | 81 |  	char usage[LOCK_USAGE_CHARS]; | 
|---|
 | 82 | +	int idx = class - lock_classes;  | 
|---|
| 63 | 83 |   | 
|---|
| 64 |  | -	if (v == &all_lock_classes) {  | 
|---|
 | 84 | +	if (v == lock_classes)  | 
|---|
| 65 | 85 |  		seq_printf(m, "all lock classes:\n"); | 
|---|
 | 86 | +  | 
|---|
 | 87 | +	if (!test_bit(idx, lock_classes_in_use))  | 
|---|
| 66 | 88 |  		return 0; | 
|---|
| 67 |  | -	}  | 
|---|
| 68 | 89 |   | 
|---|
| 69 | 90 |  	seq_printf(m, "%p", class->key); | 
|---|
| 70 | 91 |  #ifdef CONFIG_DEBUG_LOCKDEP | 
|---|
| 71 |  | -	seq_printf(m, " OPS:%8ld", class->ops);  | 
|---|
 | 92 | +	seq_printf(m, " OPS:%8ld", debug_class_ops_read(class));  | 
|---|
| 72 | 93 |  #endif | 
|---|
| 73 | 94 |  #ifdef CONFIG_PROVE_LOCKING | 
|---|
| 74 | 95 |  	seq_printf(m, " FD:%5ld", lockdep_count_forward_deps(class)); | 
|---|
| .. | .. | 
|---|
| 104 | 125 |  #ifdef CONFIG_PROVE_LOCKING | 
|---|
| 105 | 126 |  static void *lc_start(struct seq_file *m, loff_t *pos) | 
|---|
| 106 | 127 |  { | 
|---|
 | 128 | +	if (*pos < 0)  | 
|---|
 | 129 | +		return NULL;  | 
|---|
 | 130 | +  | 
|---|
| 107 | 131 |  	if (*pos == 0) | 
|---|
| 108 | 132 |  		return SEQ_START_TOKEN; | 
|---|
| 109 | 133 |   | 
|---|
| 110 |  | -	if (*pos - 1 < nr_lock_chains)  | 
|---|
| 111 |  | -		return lock_chains + (*pos - 1);  | 
|---|
| 112 |  | -  | 
|---|
| 113 |  | -	return NULL;  | 
|---|
 | 134 | +	return lock_chains + (*pos - 1);  | 
|---|
| 114 | 135 |  } | 
|---|
| 115 | 136 |   | 
|---|
| 116 | 137 |  static void *lc_next(struct seq_file *m, void *v, loff_t *pos) | 
|---|
| 117 | 138 |  { | 
|---|
| 118 |  | -	(*pos)++;  | 
|---|
 | 139 | +	*pos = lockdep_next_lockchain(*pos - 1) + 1;  | 
|---|
| 119 | 140 |  	return lc_start(m, pos); | 
|---|
| 120 | 141 |  } | 
|---|
| 121 | 142 |   | 
|---|
| .. | .. | 
|---|
| 128 | 149 |  	struct lock_chain *chain = v; | 
|---|
| 129 | 150 |  	struct lock_class *class; | 
|---|
| 130 | 151 |  	int i; | 
|---|
 | 152 | +	static const char * const irq_strs[] = {  | 
|---|
 | 153 | +		[0]			     = "0",  | 
|---|
 | 154 | +		[LOCK_CHAIN_HARDIRQ_CONTEXT] = "hardirq",  | 
|---|
 | 155 | +		[LOCK_CHAIN_SOFTIRQ_CONTEXT] = "softirq",  | 
|---|
 | 156 | +		[LOCK_CHAIN_SOFTIRQ_CONTEXT|  | 
|---|
 | 157 | +		 LOCK_CHAIN_HARDIRQ_CONTEXT] = "hardirq|softirq",  | 
|---|
 | 158 | +	};  | 
|---|
| 131 | 159 |   | 
|---|
| 132 | 160 |  	if (v == SEQ_START_TOKEN) { | 
|---|
| 133 |  | -		if (nr_chain_hlocks > MAX_LOCKDEP_CHAIN_HLOCKS)  | 
|---|
 | 161 | +		if (!nr_free_chain_hlocks)  | 
|---|
| 134 | 162 |  			seq_printf(m, "(buggered) "); | 
|---|
| 135 | 163 |  		seq_printf(m, "all lock chains:\n"); | 
|---|
| 136 | 164 |  		return 0; | 
|---|
| 137 | 165 |  	} | 
|---|
| 138 | 166 |   | 
|---|
| 139 |  | -	seq_printf(m, "irq_context: %d\n", chain->irq_context);  | 
|---|
 | 167 | +	seq_printf(m, "irq_context: %s\n", irq_strs[chain->irq_context]);  | 
|---|
| 140 | 168 |   | 
|---|
| 141 | 169 |  	for (i = 0; i < chain->depth; i++) { | 
|---|
| 142 | 170 |  		class = lock_chain_get_class(chain, i); | 
|---|
| .. | .. | 
|---|
| 211 | 239 |   | 
|---|
| 212 | 240 |  #ifdef CONFIG_PROVE_LOCKING | 
|---|
| 213 | 241 |  	struct lock_class *class; | 
|---|
 | 242 | +	unsigned long idx;  | 
|---|
| 214 | 243 |   | 
|---|
| 215 |  | -	list_for_each_entry(class, &all_lock_classes, lock_entry) {  | 
|---|
 | 244 | +	iterate_lock_classes(idx, class) {  | 
|---|
 | 245 | +		if (!test_bit(idx, lock_classes_in_use))  | 
|---|
 | 246 | +			continue;  | 
|---|
| 216 | 247 |   | 
|---|
| 217 | 248 |  		if (class->usage_mask == 0) | 
|---|
| 218 | 249 |  			nr_unused++; | 
|---|
| .. | .. | 
|---|
| 245 | 276 |   | 
|---|
| 246 | 277 |  		sum_forward_deps += lockdep_count_forward_deps(class); | 
|---|
| 247 | 278 |  	} | 
|---|
 | 279 | +  | 
|---|
| 248 | 280 |  #ifdef CONFIG_DEBUG_LOCKDEP | 
|---|
| 249 | 281 |  	DEBUG_LOCKS_WARN_ON(debug_atomic_read(nr_unused_locks) != nr_unused); | 
|---|
| 250 | 282 |  #endif | 
|---|
| .. | .. | 
|---|
| 270 | 302 |   | 
|---|
| 271 | 303 |  #ifdef CONFIG_PROVE_LOCKING | 
|---|
| 272 | 304 |  	seq_printf(m, " dependency chains:             %11lu [max: %lu]\n", | 
|---|
| 273 |  | -			nr_lock_chains, MAX_LOCKDEP_CHAINS);  | 
|---|
| 274 |  | -	seq_printf(m, " dependency chain hlocks:       %11d [max: %lu]\n",  | 
|---|
| 275 |  | -			nr_chain_hlocks, MAX_LOCKDEP_CHAIN_HLOCKS);  | 
|---|
 | 305 | +			lock_chain_count(), MAX_LOCKDEP_CHAINS);  | 
|---|
 | 306 | +	seq_printf(m, " dependency chain hlocks used:  %11lu [max: %lu]\n",  | 
|---|
 | 307 | +			MAX_LOCKDEP_CHAIN_HLOCKS -  | 
|---|
 | 308 | +			(nr_free_chain_hlocks + nr_lost_chain_hlocks),  | 
|---|
 | 309 | +			MAX_LOCKDEP_CHAIN_HLOCKS);  | 
|---|
 | 310 | +	seq_printf(m, " dependency chain hlocks lost:  %11u\n",  | 
|---|
 | 311 | +			nr_lost_chain_hlocks);  | 
|---|
| 276 | 312 |  #endif | 
|---|
| 277 | 313 |   | 
|---|
| 278 | 314 |  #ifdef CONFIG_TRACE_IRQFLAGS | 
|---|
| .. | .. | 
|---|
| 285 | 321 |  			nr_process_chains); | 
|---|
| 286 | 322 |  	seq_printf(m, " stack-trace entries:           %11lu [max: %lu]\n", | 
|---|
| 287 | 323 |  			nr_stack_trace_entries, MAX_STACK_TRACE_ENTRIES); | 
|---|
 | 324 | +#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_PROVE_LOCKING)  | 
|---|
 | 325 | +	seq_printf(m, " number of stack traces:        %11llu\n",  | 
|---|
 | 326 | +		   lockdep_stack_trace_count());  | 
|---|
 | 327 | +	seq_printf(m, " number of stack hash chains:   %11llu\n",  | 
|---|
 | 328 | +		   lockdep_stack_hash_count());  | 
|---|
 | 329 | +#endif  | 
|---|
| 288 | 330 |  	seq_printf(m, " combined max dependencies:     %11u\n", | 
|---|
| 289 | 331 |  			(nr_hardirq_chains + 1) * | 
|---|
| 290 | 332 |  			(nr_softirq_chains + 1) * | 
|---|
| .. | .. | 
|---|
| 326 | 368 |  	seq_printf(m, " max bfs queue depth:           %11u\n", | 
|---|
| 327 | 369 |  			max_bfs_queue_depth); | 
|---|
| 328 | 370 |  #endif | 
|---|
 | 371 | +	seq_printf(m, " max lock class index:          %11lu\n",  | 
|---|
 | 372 | +			max_lock_class_idx);  | 
|---|
| 329 | 373 |  	lockdep_stats_debug_show(m); | 
|---|
| 330 | 374 |  	seq_printf(m, " debug_locks:                   %11u\n", | 
|---|
| 331 | 375 |  			debug_locks); | 
|---|
| 332 | 376 |   | 
|---|
 | 377 | +	/*  | 
|---|
 | 378 | +	 * Zappped classes and lockdep data buffers reuse statistics.  | 
|---|
 | 379 | +	 */  | 
|---|
 | 380 | +	seq_puts(m, "\n");  | 
|---|
 | 381 | +	seq_printf(m, " zapped classes:                %11lu\n",  | 
|---|
 | 382 | +			nr_zapped_classes);  | 
|---|
 | 383 | +#ifdef CONFIG_PROVE_LOCKING  | 
|---|
 | 384 | +	seq_printf(m, " zapped lock chains:            %11lu\n",  | 
|---|
 | 385 | +			nr_zapped_lock_chains);  | 
|---|
 | 386 | +	seq_printf(m, " large chain blocks:            %11u\n",  | 
|---|
 | 387 | +			nr_large_chain_blocks);  | 
|---|
 | 388 | +#endif  | 
|---|
| 333 | 389 |  	return 0; | 
|---|
| 334 | 390 |  } | 
|---|
| 335 | 391 |   | 
|---|
| .. | .. | 
|---|
| 399 | 455 |   | 
|---|
| 400 | 456 |  static void seq_stats(struct seq_file *m, struct lock_stat_data *data) | 
|---|
| 401 | 457 |  { | 
|---|
| 402 |  | -	struct lockdep_subclass_key *ckey;  | 
|---|
 | 458 | +	const struct lockdep_subclass_key *ckey;  | 
|---|
| 403 | 459 |  	struct lock_class_stats *stats; | 
|---|
| 404 | 460 |  	struct lock_class *class; | 
|---|
| 405 | 461 |  	const char *cname; | 
|---|
| .. | .. | 
|---|
| 591 | 647 |  	if (!res) { | 
|---|
| 592 | 648 |  		struct lock_stat_data *iter = data->stats; | 
|---|
| 593 | 649 |  		struct seq_file *m = file->private_data; | 
|---|
 | 650 | +		unsigned long idx;  | 
|---|
| 594 | 651 |   | 
|---|
| 595 |  | -		list_for_each_entry(class, &all_lock_classes, lock_entry) {  | 
|---|
 | 652 | +		iterate_lock_classes(idx, class) {  | 
|---|
 | 653 | +			if (!test_bit(idx, lock_classes_in_use))  | 
|---|
 | 654 | +				continue;  | 
|---|
| 596 | 655 |  			iter->class = class; | 
|---|
| 597 | 656 |  			iter->stats = lock_stats(class); | 
|---|
| 598 | 657 |  			iter++; | 
|---|
| 599 | 658 |  		} | 
|---|
 | 659 | +  | 
|---|
| 600 | 660 |  		data->iter_end = iter; | 
|---|
| 601 | 661 |   | 
|---|
| 602 | 662 |  		sort(data->stats, data->iter_end - data->stats, | 
|---|
| .. | .. | 
|---|
| 614 | 674 |  			       size_t count, loff_t *ppos) | 
|---|
| 615 | 675 |  { | 
|---|
| 616 | 676 |  	struct lock_class *class; | 
|---|
 | 677 | +	unsigned long idx;  | 
|---|
| 617 | 678 |  	char c; | 
|---|
| 618 | 679 |   | 
|---|
| 619 | 680 |  	if (count) { | 
|---|
| .. | .. | 
|---|
| 623 | 684 |  		if (c != '0') | 
|---|
| 624 | 685 |  			return count; | 
|---|
| 625 | 686 |   | 
|---|
| 626 |  | -		list_for_each_entry(class, &all_lock_classes, lock_entry)  | 
|---|
 | 687 | +		iterate_lock_classes(idx, class) {  | 
|---|
 | 688 | +			if (!test_bit(idx, lock_classes_in_use))  | 
|---|
 | 689 | +				continue;  | 
|---|
| 627 | 690 |  			clear_lock_stats(class); | 
|---|
 | 691 | +		}  | 
|---|
| 628 | 692 |  	} | 
|---|
| 629 | 693 |  	return count; | 
|---|
| 630 | 694 |  } | 
|---|
| .. | .. | 
|---|
| 637 | 701 |  	return seq_release(inode, file); | 
|---|
| 638 | 702 |  } | 
|---|
| 639 | 703 |   | 
|---|
| 640 |  | -static const struct file_operations proc_lock_stat_operations = {  | 
|---|
| 641 |  | -	.open		= lock_stat_open,  | 
|---|
| 642 |  | -	.write		= lock_stat_write,  | 
|---|
| 643 |  | -	.read		= seq_read,  | 
|---|
| 644 |  | -	.llseek		= seq_lseek,  | 
|---|
| 645 |  | -	.release	= lock_stat_release,  | 
|---|
 | 704 | +static const struct proc_ops lock_stat_proc_ops = {  | 
|---|
 | 705 | +	.proc_open	= lock_stat_open,  | 
|---|
 | 706 | +	.proc_write	= lock_stat_write,  | 
|---|
 | 707 | +	.proc_read	= seq_read,  | 
|---|
 | 708 | +	.proc_lseek	= seq_lseek,  | 
|---|
 | 709 | +	.proc_release	= lock_stat_release,  | 
|---|
| 646 | 710 |  }; | 
|---|
| 647 | 711 |  #endif /* CONFIG_LOCK_STAT */ | 
|---|
| 648 | 712 |   | 
|---|
| .. | .. | 
|---|
| 654 | 718 |  #endif | 
|---|
| 655 | 719 |  	proc_create_single("lockdep_stats", S_IRUSR, NULL, lockdep_stats_show); | 
|---|
| 656 | 720 |  #ifdef CONFIG_LOCK_STAT | 
|---|
| 657 |  | -	proc_create("lock_stat", S_IRUSR | S_IWUSR, NULL,  | 
|---|
| 658 |  | -		    &proc_lock_stat_operations);  | 
|---|
 | 721 | +	proc_create("lock_stat", S_IRUSR | S_IWUSR, NULL, &lock_stat_proc_ops);  | 
|---|
| 659 | 722 |  #endif | 
|---|
| 660 | 723 |   | 
|---|
| 661 | 724 |  	return 0; | 
|---|