diff options
Diffstat (limited to 'kernel/dma/debug.c')
| -rw-r--r-- | kernel/dma/debug.c | 20 | 
1 files changed, 15 insertions, 5 deletions
| diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c index f190651bcadd..06366acd27b0 100644 --- a/kernel/dma/debug.c +++ b/kernel/dma/debug.c @@ -637,15 +637,19 @@ static struct dma_debug_entry *__dma_entry_alloc(void)  	return entry;  } -static void __dma_entry_alloc_check_leak(void) +/* + * This should be called outside of free_entries_lock scope to avoid potential + * deadlocks with serial consoles that use DMA. + */ +static void __dma_entry_alloc_check_leak(u32 nr_entries)  { -	u32 tmp = nr_total_entries % nr_prealloc_entries; +	u32 tmp = nr_entries % nr_prealloc_entries;  	/* Shout each time we tick over some multiple of the initial pool */  	if (tmp < DMA_DEBUG_DYNAMIC_ENTRIES) {  		pr_info("dma_debug_entry pool grown to %u (%u00%%)\n", -			nr_total_entries, -			(nr_total_entries / nr_prealloc_entries)); +			nr_entries, +			(nr_entries / nr_prealloc_entries));  	}  } @@ -656,8 +660,10 @@ static void __dma_entry_alloc_check_leak(void)   */  static struct dma_debug_entry *dma_entry_alloc(void)  { +	bool alloc_check_leak = false;  	struct dma_debug_entry *entry;  	unsigned long flags; +	u32 nr_entries;  	spin_lock_irqsave(&free_entries_lock, flags);  	if (num_free_entries == 0) { @@ -667,13 +673,17 @@ static struct dma_debug_entry *dma_entry_alloc(void)  			pr_err("debugging out of memory - disabling\n");  			return NULL;  		} -		__dma_entry_alloc_check_leak(); +		alloc_check_leak = true; +		nr_entries = nr_total_entries;  	}  	entry = __dma_entry_alloc();  	spin_unlock_irqrestore(&free_entries_lock, flags); +	if (alloc_check_leak) +		__dma_entry_alloc_check_leak(nr_entries); +  #ifdef CONFIG_STACKTRACE  	entry->stack_len = stack_trace_save(entry->stack_entries,  					    ARRAY_SIZE(entry->stack_entries), |