Skip to content

Commit d5d8465

Browse files
committed
dma-debug: track cache clean flag in entries
If a driver is buggy and has 2 overlapping mappings but only sets cache clean flag on the 1st one of them, we warn. But if it only does it for the 2nd one, we don't. Fix by tracking cache clean flag in the entry. Message-ID: <0ffb3513d18614539c108b4548cdfbc64274a7d1.1767601130.git.mst@redhat.com> Reviewed-by: Petr Tesarik <ptesarik@suse.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent e21dd66 commit d5d8465

1 file changed

Lines changed: 22 additions & 5 deletions

File tree

kernel/dma/debug.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ enum map_err_types {
6363
* @sg_mapped_ents: 'mapped_ents' from dma_map_sg
6464
* @paddr: physical start address of the mapping
6565
* @map_err_type: track whether dma_mapping_error() was checked
66+
* @is_cache_clean: driver promises not to write to buffer while mapped
6667
* @stack_len: number of backtrace entries in @stack_entries
6768
* @stack_entries: stack of backtrace history
6869
*/
@@ -76,7 +77,8 @@ struct dma_debug_entry {
7677
int sg_call_ents;
7778
int sg_mapped_ents;
7879
phys_addr_t paddr;
79-
enum map_err_types map_err_type;
80+
enum map_err_types map_err_type;
81+
bool is_cache_clean;
8082
#ifdef CONFIG_STACKTRACE
8183
unsigned int stack_len;
8284
unsigned long stack_entries[DMA_DEBUG_STACKTRACE_ENTRIES];
@@ -472,12 +474,15 @@ static int active_cacheline_dec_overlap(phys_addr_t cln)
472474
return active_cacheline_set_overlap(cln, --overlap);
473475
}
474476

475-
static int active_cacheline_insert(struct dma_debug_entry *entry)
477+
static int active_cacheline_insert(struct dma_debug_entry *entry,
478+
bool *overlap_cache_clean)
476479
{
477480
phys_addr_t cln = to_cacheline_number(entry);
478481
unsigned long flags;
479482
int rc;
480483

484+
*overlap_cache_clean = false;
485+
481486
/* If the device is not writing memory then we don't have any
482487
* concerns about the cpu consuming stale data. This mitigates
483488
* legitimate usages of overlapping mappings.
@@ -487,8 +492,16 @@ static int active_cacheline_insert(struct dma_debug_entry *entry)
487492

488493
spin_lock_irqsave(&radix_lock, flags);
489494
rc = radix_tree_insert(&dma_active_cacheline, cln, entry);
490-
if (rc == -EEXIST)
495+
if (rc == -EEXIST) {
496+
struct dma_debug_entry *existing;
497+
491498
active_cacheline_inc_overlap(cln);
499+
existing = radix_tree_lookup(&dma_active_cacheline, cln);
500+
/* A lookup failure here after we got -EEXIST is unexpected. */
501+
WARN_ON(!existing);
502+
if (existing)
503+
*overlap_cache_clean = existing->is_cache_clean;
504+
}
492505
spin_unlock_irqrestore(&radix_lock, flags);
493506

494507
return rc;
@@ -583,20 +596,24 @@ DEFINE_SHOW_ATTRIBUTE(dump);
583596
*/
584597
static void add_dma_entry(struct dma_debug_entry *entry, unsigned long attrs)
585598
{
599+
bool overlap_cache_clean;
586600
struct hash_bucket *bucket;
587601
unsigned long flags;
588602
int rc;
589603

604+
entry->is_cache_clean = !!(attrs & DMA_ATTR_CPU_CACHE_CLEAN);
605+
590606
bucket = get_hash_bucket(entry, &flags);
591607
hash_bucket_add(bucket, entry);
592608
put_hash_bucket(bucket, flags);
593609

594-
rc = active_cacheline_insert(entry);
610+
rc = active_cacheline_insert(entry, &overlap_cache_clean);
595611
if (rc == -ENOMEM) {
596612
pr_err_once("cacheline tracking ENOMEM, dma-debug disabled\n");
597613
global_disable = true;
598614
} else if (rc == -EEXIST &&
599-
!(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_CPU_CACHE_CLEAN)) &&
615+
!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
616+
!(entry->is_cache_clean && overlap_cache_clean) &&
600617
!(IS_ENABLED(CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC) &&
601618
is_swiotlb_active(entry->dev))) {
602619
err_printk(entry->dev, entry,

0 commit comments

Comments
 (0)