mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 00:28:52 +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 | ||||
| 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; | ||||
| 	int ret; | ||||
| 	struct lock_list this; | ||||
| 	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 | ||||
|  | @ -1899,11 +1892,8 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, | |||
| 		return print_bfs_bug(ret); | ||||
| 
 | ||||
| 
 | ||||
| 	if (!*stack_saved) { | ||||
| 		if (!save_trace(&trace)) | ||||
| 			return 0; | ||||
| 		*stack_saved = 1; | ||||
| 	} | ||||
| 	if (save && !save(trace)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * 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), | ||||
| 			       &hlock_class(prev)->locks_after, | ||||
| 			       next->acquire_ip, distance, &trace); | ||||
| 			       next->acquire_ip, distance, trace); | ||||
| 
 | ||||
| 	if (!ret) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	ret = add_lock_to_list(hlock_class(prev), | ||||
| 			       &hlock_class(next)->locks_before, | ||||
| 			       next->acquire_ip, distance, &trace); | ||||
| 			       next->acquire_ip, distance, trace); | ||||
| 	if (!ret) | ||||
| 		return 0; | ||||
| 
 | ||||
|  | @ -1926,8 +1916,6 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev, | |||
| 	 * Debugging printouts: | ||||
| 	 */ | ||||
| 	if (verbose(hlock_class(prev)) || verbose(hlock_class(next))) { | ||||
| 		/* We drop graph lock, so another thread can overwrite trace. */ | ||||
| 		*stack_saved = 0; | ||||
| 		graph_unlock(); | ||||
| 		printk("\n new dependency: "); | ||||
| 		print_lock_name(hlock_class(prev)); | ||||
|  | @ -1951,8 +1939,9 @@ static int | |||
| check_prevs_add(struct task_struct *curr, struct held_lock *next) | ||||
| { | ||||
| 	int depth = curr->lockdep_depth; | ||||
| 	int stack_saved = 0; | ||||
| 	struct held_lock *hlock; | ||||
| 	struct stack_trace trace; | ||||
| 	int (*save)(struct stack_trace *trace) = save_trace; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Debugging checks. | ||||
|  | @ -1977,9 +1966,18 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next) | |||
| 		 * added: | ||||
| 		 */ | ||||
| 		if (hlock->read != 2 && hlock->check) { | ||||
| 			if (!check_prev_add(curr, hlock, next, | ||||
| 						distance, &stack_saved)) | ||||
| 			int ret = check_prev_add(curr, hlock, next, | ||||
| 						distance, &trace, save); | ||||
| 			if (!ret) | ||||
| 				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, | ||||
| 			 * as non-trylock entries have added their | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Byungchul Park
						Byungchul Park