[PATCH v6 96/99] dma-debug: Convert to XArray
From: Matthew WilcoxThis is an unusual way to use the xarray tags. If any other users come up, we can add an xas_get_tags() / xas_set_tags() API, but until then I don't want to encourage this kind of abuse. Signed-off-by: Matthew Wilcox --- lib/dma-debug.c | 105 +--- 1 file changed, 46 insertions(+), 59 deletions(-) diff --git a/lib/dma-debug.c b/lib/dma-debug.c index fb4af570ce04..965b3837d060 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -465,9 +465,8 @@ EXPORT_SYMBOL(debug_dma_dump_mappings); * At any time debug_dma_assert_idle() can be called to trigger a * warning if any cachelines in the given page are in the active set. */ -static RADIX_TREE(dma_active_cacheline, GFP_NOWAIT); -static DEFINE_SPINLOCK(radix_lock); -#define ACTIVE_CACHELINE_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1) +static DEFINE_XARRAY_FLAGS(dma_active_cacheline, XA_FLAGS_LOCK_IRQ); +#define ACTIVE_CACHELINE_MAX_OVERLAP ((1 << XA_MAX_TAGS) - 1) #define CACHELINE_PER_PAGE_SHIFT (PAGE_SHIFT - L1_CACHE_SHIFT) #define CACHELINES_PER_PAGE (1 << CACHELINE_PER_PAGE_SHIFT) @@ -477,37 +476,40 @@ static phys_addr_t to_cacheline_number(struct dma_debug_entry *entry) (entry->offset >> L1_CACHE_SHIFT); } -static int active_cacheline_read_overlap(phys_addr_t cln) +static unsigned int active_cacheline_read_overlap(struct xa_state *xas) { - int overlap = 0, i; + unsigned int tags = 0; + xa_tag_t tag; - for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--) - if (radix_tree_tag_get(_active_cacheline, cln, i)) - overlap |= 1 << i; - return overlap; + for (tag = 0; tag < XA_MAX_TAGS; tag++) + if (xas_get_tag(xas, tag)) + tags |= 1U << tag; + + return tags; } -static int active_cacheline_set_overlap(phys_addr_t cln, int overlap) +static int active_cacheline_set_overlap(struct xa_state *xas, int overlap) { - int i; + xa_tag_t tag; if (overlap > ACTIVE_CACHELINE_MAX_OVERLAP || overlap < 0) return overlap; - for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--) - if (overlap & 1 << i) - radix_tree_tag_set(_active_cacheline, cln, i); + for (tag = 0; tag < XA_MAX_TAGS; tag++) { + if (overlap & (1U << tag)) + xas_set_tag(xas, tag); else - radix_tree_tag_clear(_active_cacheline, cln, i); + xas_clear_tag(xas, tag); + } return overlap; } -static void active_cacheline_inc_overlap(phys_addr_t cln) +static void active_cacheline_inc_overlap(struct xa_state *xas) { - int overlap = active_cacheline_read_overlap(cln); + int overlap = active_cacheline_read_overlap(xas); - overlap = active_cacheline_set_overlap(cln, ++overlap); + overlap = active_cacheline_set_overlap(xas, ++overlap); /* If we overflowed the overlap counter then we're potentially * leaking dma-mappings. Otherwise, if maps and unmaps are @@ -517,21 +519,22 @@ static void active_cacheline_inc_overlap(phys_addr_t cln) */ WARN_ONCE(overlap > ACTIVE_CACHELINE_MAX_OVERLAP, "DMA-API: exceeded %d overlapping mappings of cacheline %pa\n", - ACTIVE_CACHELINE_MAX_OVERLAP, ); + ACTIVE_CACHELINE_MAX_OVERLAP, >xa_index); } -static int active_cacheline_dec_overlap(phys_addr_t cln) +static int active_cacheline_dec_overlap(struct xa_state *xas) { - int overlap = active_cacheline_read_overlap(cln); + int overlap = active_cacheline_read_overlap(xas); - return active_cacheline_set_overlap(cln, --overlap); + return active_cacheline_set_overlap(xas, --overlap); } static int active_cacheline_insert(struct dma_debug_entry *entry) { phys_addr_t cln = to_cacheline_number(entry); + XA_STATE(xas, _active_cacheline, cln); unsigned long flags; - int rc; + struct dma_debug_entry *exists; /* If the device is not writing memory then we don't have any * concerns about the cpu consuming stale data. This mitigates @@ -540,32 +543,32 @@ static int active_cacheline_insert(struct dma_debug_entry *entry) if (entry->direction == DMA_TO_DEVICE) return 0; - spin_lock_irqsave(_lock, flags); - rc = radix_tree_insert(_active_cacheline, cln, entry); - if (rc == -EEXIST) - active_cacheline_inc_overlap(cln); - spin_unlock_irqrestore(_lock, flags); + xas_lock_irqsave(, flags); + exists = xas_create(); + if (exists) +
[PATCH v6 96/99] dma-debug: Convert to XArray
From: Matthew Wilcox This is an unusual way to use the xarray tags. If any other users come up, we can add an xas_get_tags() / xas_set_tags() API, but until then I don't want to encourage this kind of abuse. Signed-off-by: Matthew Wilcox --- lib/dma-debug.c | 105 +--- 1 file changed, 46 insertions(+), 59 deletions(-) diff --git a/lib/dma-debug.c b/lib/dma-debug.c index fb4af570ce04..965b3837d060 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -465,9 +465,8 @@ EXPORT_SYMBOL(debug_dma_dump_mappings); * At any time debug_dma_assert_idle() can be called to trigger a * warning if any cachelines in the given page are in the active set. */ -static RADIX_TREE(dma_active_cacheline, GFP_NOWAIT); -static DEFINE_SPINLOCK(radix_lock); -#define ACTIVE_CACHELINE_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1) +static DEFINE_XARRAY_FLAGS(dma_active_cacheline, XA_FLAGS_LOCK_IRQ); +#define ACTIVE_CACHELINE_MAX_OVERLAP ((1 << XA_MAX_TAGS) - 1) #define CACHELINE_PER_PAGE_SHIFT (PAGE_SHIFT - L1_CACHE_SHIFT) #define CACHELINES_PER_PAGE (1 << CACHELINE_PER_PAGE_SHIFT) @@ -477,37 +476,40 @@ static phys_addr_t to_cacheline_number(struct dma_debug_entry *entry) (entry->offset >> L1_CACHE_SHIFT); } -static int active_cacheline_read_overlap(phys_addr_t cln) +static unsigned int active_cacheline_read_overlap(struct xa_state *xas) { - int overlap = 0, i; + unsigned int tags = 0; + xa_tag_t tag; - for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--) - if (radix_tree_tag_get(_active_cacheline, cln, i)) - overlap |= 1 << i; - return overlap; + for (tag = 0; tag < XA_MAX_TAGS; tag++) + if (xas_get_tag(xas, tag)) + tags |= 1U << tag; + + return tags; } -static int active_cacheline_set_overlap(phys_addr_t cln, int overlap) +static int active_cacheline_set_overlap(struct xa_state *xas, int overlap) { - int i; + xa_tag_t tag; if (overlap > ACTIVE_CACHELINE_MAX_OVERLAP || overlap < 0) return overlap; - for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--) - if (overlap & 1 << i) - radix_tree_tag_set(_active_cacheline, cln, i); + for (tag = 0; tag < XA_MAX_TAGS; tag++) { + if (overlap & (1U << tag)) + xas_set_tag(xas, tag); else - radix_tree_tag_clear(_active_cacheline, cln, i); + xas_clear_tag(xas, tag); + } return overlap; } -static void active_cacheline_inc_overlap(phys_addr_t cln) +static void active_cacheline_inc_overlap(struct xa_state *xas) { - int overlap = active_cacheline_read_overlap(cln); + int overlap = active_cacheline_read_overlap(xas); - overlap = active_cacheline_set_overlap(cln, ++overlap); + overlap = active_cacheline_set_overlap(xas, ++overlap); /* If we overflowed the overlap counter then we're potentially * leaking dma-mappings. Otherwise, if maps and unmaps are @@ -517,21 +519,22 @@ static void active_cacheline_inc_overlap(phys_addr_t cln) */ WARN_ONCE(overlap > ACTIVE_CACHELINE_MAX_OVERLAP, "DMA-API: exceeded %d overlapping mappings of cacheline %pa\n", - ACTIVE_CACHELINE_MAX_OVERLAP, ); + ACTIVE_CACHELINE_MAX_OVERLAP, >xa_index); } -static int active_cacheline_dec_overlap(phys_addr_t cln) +static int active_cacheline_dec_overlap(struct xa_state *xas) { - int overlap = active_cacheline_read_overlap(cln); + int overlap = active_cacheline_read_overlap(xas); - return active_cacheline_set_overlap(cln, --overlap); + return active_cacheline_set_overlap(xas, --overlap); } static int active_cacheline_insert(struct dma_debug_entry *entry) { phys_addr_t cln = to_cacheline_number(entry); + XA_STATE(xas, _active_cacheline, cln); unsigned long flags; - int rc; + struct dma_debug_entry *exists; /* If the device is not writing memory then we don't have any * concerns about the cpu consuming stale data. This mitigates @@ -540,32 +543,32 @@ static int active_cacheline_insert(struct dma_debug_entry *entry) if (entry->direction == DMA_TO_DEVICE) return 0; - spin_lock_irqsave(_lock, flags); - rc = radix_tree_insert(_active_cacheline, cln, entry); - if (rc == -EEXIST) - active_cacheline_inc_overlap(cln); - spin_unlock_irqrestore(_lock, flags); + xas_lock_irqsave(, flags); + exists = xas_create(); + if (exists) + active_cacheline_inc_overlap(); + else +