Commit 2ce8e7ed006a6e86eecf59188da8652b8a3bc4f0

Authored by Florian Fainelli
Committed by Linus Torvalds
1 parent 01ce18b311

dma-debug: prevent early callers from crashing

dma_debug_init() is called by architecture specific code at different
levels, but typically as a fs_initcall due to the debugfs initialization.
Some platforms may have early callers of the DMA-API, running prior to the
fs_initcall() level, which is not much of an issue unless
CONFIG_DMA_API_DEBUG is set.  When the DMA-API debugging facilities are
turned on a caller will go through:

debug_dma_map_{single,page}
  -> dma_mapping_error (inline function usually)
    -> debug_dma_mapping_error
      -> get_hash_bucket

Calling get_hash_bucket() returns a valid hash value since we hash on high
bits of the dma_addr cookie, but we will grab an unitialized spinlock,
which typically won't crash but produce a warning, the real crash will
however happen during the bucket list traversal because the list has not
been initialized yet.

An obvious solution is of course to move some of the offenders to run
after the fs_initcall level, but since this might not always be an option,
we add a flag "dma_debug_initialized" which is set to false by default,
and set to true once dma_debug_init() has had a chance to run.

The dma_debug_disabled() helper function previously introduced just needs
to check for dma_debug_initialized to allow the caller to proceed or not.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Cc: Horia Geanta <horia.geanta@freescale.com>
Cc: Brian Norris <computersforpeace@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 10 additions and 2 deletions Side-by-side Diff

... ... @@ -102,9 +102,12 @@
102 102 /* Global disable flag - will be set in case of an error */
103 103 static u32 global_disable __read_mostly;
104 104  
  105 +/* Early initialization disable flag, set at the end of dma_debug_init */
  106 +static bool dma_debug_initialized __read_mostly;
  107 +
105 108 static inline bool dma_debug_disabled(void)
106 109 {
107   - return global_disable;
  110 + return global_disable || !dma_debug_initialized;
108 111 }
109 112  
110 113 /* Global error count */
... ... @@ -999,7 +1002,10 @@
999 1002 {
1000 1003 int i;
1001 1004  
1002   - if (dma_debug_disabled())
  1005 + /* Do not use dma_debug_initialized here, since we really want to be
  1006 + * called to set dma_debug_initialized
  1007 + */
  1008 + if (global_disable)
1003 1009 return;
1004 1010  
1005 1011 for (i = 0; i < HASH_SIZE; ++i) {
... ... @@ -1025,6 +1031,8 @@
1025 1031 }
1026 1032  
1027 1033 nr_total_entries = num_free_entries;
  1034 +
  1035 + dma_debug_initialized = true;
1028 1036  
1029 1037 pr_info("DMA-API: debugging enabled by kernel config\n");
1030 1038 }