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

Commit 59f2e7df authored by Dan Williams's avatar Dan Williams Committed by Linus Torvalds
Browse files

dma-debug: fix overlap detection

Commit 0abdd7a8 ("dma-debug: introduce debug_dma_assert_idle()") was
reworked to expand the overlap counter to the full range expressable by
3 tag bits, but it has a thinko in treating the overlap counter as a
pure reference count for the entry.

Instead of deleting when the reference-count drops to zero, we need to
delete when the overlap-count drops below zero.  Also, when detecting
overflow we can just test the overlap-count > MAX rather than applying
special meaning to 0.

Regression report available here:
http://marc.info/?l=linux-netdev&m=139073373932386&w=2



This patch, now tested on the original net_dma case, sees the expected
handful of reports before the eventual data corruption occurs.

Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Reported-by: default avatarSander Eikelenboom <linux@eikelenboom.it>
Cc: Francois Romieu <romieu@fr.zoreil.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent f544e14f
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -463,7 +463,7 @@ static int active_pfn_set_overlap(unsigned long pfn, int overlap)
	int i;

	if (overlap > ACTIVE_PFN_MAX_OVERLAP || overlap < 0)
		return 0;
		return overlap;

	for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
		if (overlap & 1 << i)
@@ -486,7 +486,7 @@ static void active_pfn_inc_overlap(unsigned long pfn)
	 * debug_dma_assert_idle() as the pfn may be marked idle
	 * prematurely.
	 */
	WARN_ONCE(overlap == 0,
	WARN_ONCE(overlap > ACTIVE_PFN_MAX_OVERLAP,
		  "DMA-API: exceeded %d overlapping mappings of pfn %lx\n",
		  ACTIVE_PFN_MAX_OVERLAP, pfn);
}
@@ -517,7 +517,11 @@ static void active_pfn_remove(struct dma_debug_entry *entry)
	unsigned long flags;

	spin_lock_irqsave(&radix_lock, flags);
	if (active_pfn_dec_overlap(entry->pfn) == 0)
	/* since we are counting overlaps the final put of the
	 * entry->pfn will occur when the overlap count is 0.
	 * active_pfn_dec_overlap() returns -1 in that case
	 */
	if (active_pfn_dec_overlap(entry->pfn) < 0)
		radix_tree_delete(&dma_active_pfn, entry->pfn);
	spin_unlock_irqrestore(&radix_lock, flags);
}