Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d640a51 authored by Alexander Duyck's avatar Alexander Duyck Committed by Linus Torvalds
Browse files

dma-debug: fix locking bug in check_unmap()



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.

[akpm@linux-foundation.org: restore 80-col trickery to be consistent with the rest of the file]
Signed-off-by: default avatarAlexander Duyck <alexander.h.duyck@intel.com>
Cc: Joerg Roedel <joro@8bytes.org>
Reviewed-by: default avatarShuah Khan <shuah.khan@hp.com>
Tested-by: default avatarShuah Khan <shuah.khan@hp.com>
Cc: Jakub Kicinski <kubakici@wp.pl>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 0ef1594c
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
@@ -862,17 +862,21 @@ 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;
		}
		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",
				   "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);
		goto out;
		}
		return;
	}

	if (ref->size != entry->size) {
@@ -936,7 +940,6 @@ static void check_unmap(struct dma_debug_entry *ref)
	hash_bucket_del(entry);
	dma_entry_free(entry);

out:
	put_hash_bucket(bucket, &flags);
}