]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
dma-debug: fix locking bug in check_unmap()
authorAlexander Duyck <alexander.h.duyck@intel.com>
Wed, 20 Mar 2013 04:06:47 +0000 (15:06 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 21 Mar 2013 05:27:10 +0000 (16:27 +1100)
In check_unmap() it is possible to get into a dead-locked state if
dma_mapping_error is called.  The problem is that the bucket is locked in
check_unmap, and locked again by debug_dma_mapping_error which is called
by dma_mapping_error.  To resolve that we must release the lock on the
bucket before making the call to dma_mapping_error.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Cc: Joerg Roedel <joro@8bytes.org>
Reviewed-by: Shuah Khan <shuah.khan@hp.com>
Tested-by: Shuah Khan <shuah.khan@hp.com>
Cc: Jakub Kicinski <kubakici@wp.pl>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
lib/dma-debug.c

index 5e396accd3d02a8dce6d06cc2d6020e311b308b0..724bd4d2c32e25b58757dfa09a3507ca12eb6ec9 100644 (file)
@@ -862,17 +862,18 @@ static void check_unmap(struct dma_debug_entry *ref)
        entry = bucket_find_exact(bucket, ref);
 
        if (!entry) {
+               /* must drop lock before calling dma_mapping_error */
+               put_hash_bucket(bucket, &flags);
+
                if (dma_mapping_error(ref->dev, ref->dev_addr)) {
                        err_printk(ref->dev, NULL,
-                                  "DMA-API: device driver tries "
-                                  "to free an invalid DMA memory address\n");
-                       return;
+                                  "DMA-API: device driver tries to free an invalid DMA memory address\n");
+               } else {
+                       err_printk(ref->dev, NULL,
+                                  "DMA-API: device driver tries to free DMA memory it has not allocated [device address=0x%016llx] [size=%llu bytes]\n",
+                                  ref->dev_addr, ref->size);
                }
-               err_printk(ref->dev, NULL, "DMA-API: device driver tries "
-                          "to free DMA memory it has not allocated "
-                          "[device address=0x%016llx] [size=%llu bytes]\n",
-                          ref->dev_addr, ref->size);
-               goto out;
+               return;
        }
 
        if (ref->size != entry->size) {
@@ -936,7 +937,6 @@ static void check_unmap(struct dma_debug_entry *ref)
        hash_bucket_del(entry);
        dma_entry_free(entry);
 
-out:
        put_hash_bucket(bucket, &flags);
 }