mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	locking/lockdep: Make check_prev_add() able to handle external stack_trace
Currently, a space for stack_trace is pinned in check_prev_add(), that makes us not able to use external stack_trace. The simplest way to achieve it is to pass an external stack_trace as an argument. A more suitable solution is to pass a callback additionally along with a stack_trace so that callers can decide the way to save or whether to save. Actually crossrelease needs to do other than saving a stack_trace. So pass a stack_trace and callback to handle it, to check_prev_add(). Signed-off-by: Byungchul Park <byungchul.park@lge.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: akpm@linux-foundation.org Cc: boqun.feng@gmail.com Cc: kernel-team@lge.com Cc: kirill@shutemov.name Cc: npiggin@gmail.com Cc: walken@google.com Cc: willy@infradead.org Link: http://lkml.kernel.org/r/1502089981-21272-5-git-send-email-byungchul.park@lge.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
		
							parent
							
								
									70911fdc95
								
							
						
					
					
						commit
						ce07a9415f
					
				
					 1 changed files with 19 additions and 21 deletions
				
			
		|  | @ -1824,20 +1824,13 @@ check_deadlock(struct task_struct *curr, struct held_lock *next, | ||||||
|  */ |  */ | ||||||
| static int | static int | ||||||
| check_prev_add(struct task_struct *curr, struct held_lock *prev, | check_prev_add(struct task_struct *curr, struct held_lock *prev, | ||||||
| 	       struct held_lock *next, int distance, int *stack_saved) | 	       struct held_lock *next, int distance, struct stack_trace *trace, | ||||||
|  | 	       int (*save)(struct stack_trace *trace)) | ||||||
| { | { | ||||||
| 	struct lock_list *entry; | 	struct lock_list *entry; | ||||||
| 	int ret; | 	int ret; | ||||||
| 	struct lock_list this; | 	struct lock_list this; | ||||||
| 	struct lock_list *uninitialized_var(target_entry); | 	struct lock_list *uninitialized_var(target_entry); | ||||||
| 	/*
 |  | ||||||
| 	 * Static variable, serialized by the graph_lock(). |  | ||||||
| 	 * |  | ||||||
| 	 * We use this static variable to save the stack trace in case |  | ||||||
| 	 * we call into this function multiple times due to encountering |  | ||||||
| 	 * trylocks in the held lock stack. |  | ||||||
| 	 */ |  | ||||||
| 	static struct stack_trace trace; |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Prove that the new <prev> -> <next> dependency would not | 	 * Prove that the new <prev> -> <next> dependency would not | ||||||
|  | @ -1899,11 +1892,8 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, | ||||||
| 		return print_bfs_bug(ret); | 		return print_bfs_bug(ret); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	if (!*stack_saved) { | 	if (save && !save(trace)) | ||||||
| 		if (!save_trace(&trace)) | 		return 0; | ||||||
| 			return 0; |  | ||||||
| 		*stack_saved = 1; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Ok, all validations passed, add the new lock | 	 * Ok, all validations passed, add the new lock | ||||||
|  | @ -1911,14 +1901,14 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, | ||||||
| 	 */ | 	 */ | ||||||
| 	ret = add_lock_to_list(hlock_class(next), | 	ret = add_lock_to_list(hlock_class(next), | ||||||
| 			       &hlock_class(prev)->locks_after, | 			       &hlock_class(prev)->locks_after, | ||||||
| 			       next->acquire_ip, distance, &trace); | 			       next->acquire_ip, distance, trace); | ||||||
| 
 | 
 | ||||||
| 	if (!ret) | 	if (!ret) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	ret = add_lock_to_list(hlock_class(prev), | 	ret = add_lock_to_list(hlock_class(prev), | ||||||
| 			       &hlock_class(next)->locks_before, | 			       &hlock_class(next)->locks_before, | ||||||
| 			       next->acquire_ip, distance, &trace); | 			       next->acquire_ip, distance, trace); | ||||||
| 	if (!ret) | 	if (!ret) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
|  | @ -1926,8 +1916,6 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, | ||||||
| 	 * Debugging printouts: | 	 * Debugging printouts: | ||||||
| 	 */ | 	 */ | ||||||
| 	if (verbose(hlock_class(prev)) || verbose(hlock_class(next))) { | 	if (verbose(hlock_class(prev)) || verbose(hlock_class(next))) { | ||||||
| 		/* We drop graph lock, so another thread can overwrite trace. */ |  | ||||||
| 		*stack_saved = 0; |  | ||||||
| 		graph_unlock(); | 		graph_unlock(); | ||||||
| 		printk("\n new dependency: "); | 		printk("\n new dependency: "); | ||||||
| 		print_lock_name(hlock_class(prev)); | 		print_lock_name(hlock_class(prev)); | ||||||
|  | @ -1951,8 +1939,9 @@ static int | ||||||
| check_prevs_add(struct task_struct *curr, struct held_lock *next) | check_prevs_add(struct task_struct *curr, struct held_lock *next) | ||||||
| { | { | ||||||
| 	int depth = curr->lockdep_depth; | 	int depth = curr->lockdep_depth; | ||||||
| 	int stack_saved = 0; |  | ||||||
| 	struct held_lock *hlock; | 	struct held_lock *hlock; | ||||||
|  | 	struct stack_trace trace; | ||||||
|  | 	int (*save)(struct stack_trace *trace) = save_trace; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Debugging checks. | 	 * Debugging checks. | ||||||
|  | @ -1977,9 +1966,18 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) | ||||||
| 		 * added: | 		 * added: | ||||||
| 		 */ | 		 */ | ||||||
| 		if (hlock->read != 2 && hlock->check) { | 		if (hlock->read != 2 && hlock->check) { | ||||||
| 			if (!check_prev_add(curr, hlock, next, | 			int ret = check_prev_add(curr, hlock, next, | ||||||
| 						distance, &stack_saved)) | 						distance, &trace, save); | ||||||
|  | 			if (!ret) | ||||||
| 				return 0; | 				return 0; | ||||||
|  | 
 | ||||||
|  | 			/*
 | ||||||
|  | 			 * Stop saving stack_trace if save_trace() was | ||||||
|  | 			 * called at least once: | ||||||
|  | 			 */ | ||||||
|  | 			if (save && ret == 2) | ||||||
|  | 				save = NULL; | ||||||
|  | 
 | ||||||
| 			/*
 | 			/*
 | ||||||
| 			 * Stop after the first non-trylock entry, | 			 * Stop after the first non-trylock entry, | ||||||
| 			 * as non-trylock entries have added their | 			 * as non-trylock entries have added their | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Byungchul Park
						Byungchul Park