]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
maple_tree: Change mas_next() behaviour
authorLiam R. Howlett <Liam.Howlett@Oracle.com>
Mon, 5 Jul 2021 19:30:41 +0000 (15:30 -0400)
committerLiam R. Howlett <Liam.Howlett@Oracle.com>
Mon, 5 Jul 2021 19:30:41 +0000 (15:30 -0400)
Signed-off-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
include/linux/maple_tree.h
lib/maple_tree.c

index eea2d2a0e26e27422d3c1ef298a7f098d20d93e1..7ccca75d4e3bddec9e266e5ad631bf1e2513ca94 100644 (file)
@@ -243,6 +243,7 @@ struct ma_state {
 #define MAS_START      ((struct maple_enode *)1UL)
 #define MAS_ROOT       ((struct maple_enode *)5UL)
 #define MAS_NONE       ((struct maple_enode *)9UL)
+#define MAS_PAUSE      ((struct maple_enode *)17UL)
 #define MA_ERROR(err) \
                ((struct maple_enode *)(((unsigned long)err << 2) | 2UL))
 
@@ -286,6 +287,12 @@ static inline bool mas_is_none(struct ma_state *mas)
        return mas->node == MAS_NONE;
 }
 
+/* Checks if a mas has been paused */
+static inline bool mas_is_paused(struct ma_state *mas)
+{
+       return mas->node == MAS_PAUSE;
+}
+
 void mas_dup_tree(struct ma_state *oldmas, struct ma_state *mas);
 void mas_dup_store(struct ma_state *mas, void *entry);
 /* This finds an empty area from the highest address to the lowest.
index e0e55c861a6e8b2afe27839ceda85b1c8f22a7b4..7e977ac2d63211028248f57f4e7c5918b1718299 100644 (file)
@@ -4800,7 +4800,7 @@ void *mas_walk(struct ma_state *mas)
        unsigned long index = mas->index;
        void *entry;
 
-       if (mas_is_none(mas))
+       if (mas_is_none(mas) || mas_is_paused(mas))
                mas->node = MAS_START;
 
        _mas_walk(mas, &range_min, &range_max);
@@ -5197,7 +5197,7 @@ static inline void *mas_range_load(struct ma_state *mas,
        unsigned long index = mas->index;
        void *entry;
 
-       if (mas_is_none(mas))
+       if (mas_is_none(mas) || mas_is_paused(mas))
                mas->node = MAS_START;
 
        if (_mas_walk(mas, range_min, range_max))
@@ -5226,11 +5226,9 @@ retry:
  */
 static void *_mas_next(struct ma_state *mas, unsigned long limit)
 {
-       void *entry = NULL;
-
-
        if (unlikely(mas_is_start(mas))) {
                /* First run */
+               void *entry = NULL;
                unsigned long range_max;
                unsigned long range_start;
 
@@ -5245,8 +5243,7 @@ static void *_mas_next(struct ma_state *mas, unsigned long limit)
        if (unlikely(!mas_searchable(mas)))
                return NULL;
 
-       entry = __mas_next(mas, limit);
-       return entry;
+       return __mas_next(mas, limit);
 }
 
 /*
@@ -5585,6 +5582,7 @@ void mas_destroy(struct ma_state *mas)
  * @mas: The maple state
  * @max: The maximum index to check.
  *
+ * Returns the next entry after @mas->index.
  * Must hold rcu_read_lock or the write lock.
  * Can return the zero entry.
  *
@@ -5592,14 +5590,29 @@ void mas_destroy(struct ma_state *mas)
  */
 void *mas_next(struct ma_state *mas, unsigned long max)
 {
-       if (mas_is_none(mas))
+       if (mas_is_none(mas) || mas_is_paused(mas))
                mas->node = MAS_START;
 
-       return _mas_next(mas, max);
+       if (unlikely(!mas_searchable(mas)))
+               return NULL;
+
+       if (mas_is_start(mas)) {
+               mas->index = ++mas->last;
+               return mas_find(mas, max);
+       }
+
+       return __mas_next(mas, max);
 }
 EXPORT_SYMBOL_GPL(mas_next);
 
-
+/*
+ * mt_next() - get the next value in the maple tree
+ * @mt: The maple tree
+ * @index: The start index
+ * @max: The maximum index to check
+ *
+ * Returns: The entry at @index or higher, or %NULL if nothing is found.
+ */
 void *mt_next(struct maple_tree *mt, unsigned long index, unsigned long max)
 {
        void *entry = NULL;
@@ -5620,7 +5633,8 @@ EXPORT_SYMBOL_GPL(mt_next);
  * Must hold rcu_read_lock or the write lock.
  * Will reset mas to MAS_START if the node is MAS_NONE.  Will stop on not
  * searchable nodes.  If mas->node is MAS_START, it will first look up the
- * index, then get the previous entry.
+ * index and return.  If there is nothing at mas->index, then the prev entry
+ * will be returned.
  *
  * Return: the previous value or %NULL.
  */
@@ -5634,13 +5648,12 @@ void *mas_prev(struct ma_state *mas, unsigned long min)
                return NULL;
        }
 
-       if (mas_is_none(mas))
+       if (mas_is_none(mas) || mas_is_paused(mas))
                mas->node = MAS_START;
 
        if (!mas_searchable(mas))
                return NULL;
 
-
        if (mas_is_start(mas)) {
                mas_start(mas);
                mas_walk(mas);
@@ -5654,6 +5667,14 @@ void *mas_prev(struct ma_state *mas, unsigned long min)
 }
 EXPORT_SYMBOL_GPL(mas_prev);
 
+/*
+ * mt_prev() - get the previous value in the maple tree
+ * @mt: The maple tree
+ * @index: The start index
+ * @max: The minumum index to check
+ *
+ * Returns: The entry at @index or lower, or %NULL if nothing is found.
+ */
 void *mt_prev(struct maple_tree *mt, unsigned long index, unsigned long min)
 {
        void *entry = NULL;
@@ -5680,18 +5701,27 @@ EXPORT_SYMBOL_GPL(mt_prev);
  */
 void mas_pause(struct ma_state *mas)
 {
-       /* Overflow protection */
-       if (mas->last == ULONG_MAX) {
-               mas->node = MAS_NONE;
-               return;
-       }
-
-       mas_reset(mas);
-       mas->last++;
-       mas->index = mas->last;
+       mas->node = MAS_PAUSE;
 }
 EXPORT_SYMBOL_GPL(mas_pause);
 
+/*
+ * mas_resume_fwd() - resume a forward search.
+ * @mas: The maple state
+ *
+ * Returns: 0 on success, -EFAULT on overflow.
+ */
+static inline int mas_resume_fwd(struct ma_state *mas) {
+       if (mas_is_paused(mas)) {
+               if (unlikely(mas->last == ULONG_MAX)) {
+                       mas->node = MAS_NONE;
+                       return -EFAULT;
+               }
+               mas->node = MAS_START;
+               mas->index = ++mas->last;
+       }
+       return 0;
+}
 
 /*
  * mas_find: If mas->node == MAS_START, find the first
@@ -5714,6 +5744,8 @@ void *mas_find(struct ma_state *mas, unsigned long max)
 
        if (mas_is_start(mas) && (mas->index <= max))
                first = true;
+       else if (mas_resume_fwd(mas))
+               return NULL;
 
 retry:
        while (mas_search_cont(mas, mas->index, max, entry))