[PATCH v6 96/99] dma-debug: Convert to XArray

2018-01-17 Thread Matthew Wilcox
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)
+   

[PATCH v6 96/99] dma-debug: Convert to XArray

2018-01-17 Thread Matthew Wilcox
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
+