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

Commit 7caf6a49 authored by Joerg Roedel's avatar Joerg Roedel Committed by Ingo Molnar
Browse files

dma-debug: change hash_bucket_find from first-fit to best-fit



Some device drivers map the same physical address multiple times to a
dma address. Without an IOMMU this results in the same dma address being
put into the dma-debug hash multiple times. With a first-fit match in
hash_bucket_find() this function may return the wrong dma_debug_entry.

This can result in false positive warnings. This patch fixes it by
changing the first-fit behavior of hash_bucket_find() into a best-fit
algorithm.

Reported-by: default avatarTorsten Kaiser <just.for.lkml@googlemail.com>
Reported-by: default avatarFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: default avatarJoerg Roedel <joerg.roedel@amd.com>
Cc: lethal@linux-sh.org
Cc: just.for.lkml@googlemail.com
Cc: hancockrwd@gmail.com
Cc: jens.axboe@oracle.com
Cc: bharrosh@panasas.com
Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: <stable@kernel.org>
LKML-Reference: <20090605104132.GE24836@amd.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent fe2245c9
Loading
Loading
Loading
Loading
+39 −4
Original line number Diff line number Diff line
@@ -186,15 +186,50 @@ static void put_hash_bucket(struct hash_bucket *bucket,
static struct dma_debug_entry *hash_bucket_find(struct hash_bucket *bucket,
						struct dma_debug_entry *ref)
{
	struct dma_debug_entry *entry;
	struct dma_debug_entry *entry, *ret = NULL;
	int matches = 0, match_lvl, last_lvl = 0;

	list_for_each_entry(entry, &bucket->list, list) {
		if ((entry->dev_addr == ref->dev_addr) &&
		    (entry->dev == ref->dev))
		if ((entry->dev_addr != ref->dev_addr) ||
		    (entry->dev != ref->dev))
			continue;

		/*
		 * Some drivers map the same physical address multiple
		 * times. Without a hardware IOMMU this results in the
		 * same device addresses being put into the dma-debug
		 * hash multiple times too. This can result in false
		 * positives being reported. Therfore we implement a
		 * best-fit algorithm here which returns the entry from
		 * the hash which fits best to the reference value
		 * instead of the first-fit.
		 */
		matches += 1;
		match_lvl = 0;
		entry->size      == ref->size      ? ++match_lvl : match_lvl;
		entry->type      == ref->type      ? ++match_lvl : match_lvl;
		entry->direction == ref->direction ? ++match_lvl : match_lvl;

		if (match_lvl == 3) {
			/* perfect-fit - return the result */
			return entry;
		} else if (match_lvl > last_lvl) {
			/*
			 * We found an entry that fits better then the
			 * previous one
			 */
			last_lvl = match_lvl;
			ret      = entry;
		}
	}

	return NULL;
	/*
	 * If we have multiple matches but no perfect-fit, just return
	 * NULL.
	 */
	ret = (matches == 1) ? ret : NULL;

	return ret;
}

/*