From: Liam R. Howlett <Liam.Howlett@oracle.com>
Date: Fri, 10 Feb 2023 21:36:28 +0000 (-0500)
Subject: maple_tree: mas_next() and mas_find() state clean up
X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=9b74b1c635cdb50aa97ef6bea1b573bfbc63924b;p=users%2Fjedix%2Flinux-maple.git

maple_tree: mas_next() and mas_find() state clean up

mas_next() and mas_find() were not properly setting the internal maple
state when the limits of the search were reached.

mas_find() was not treating MAS_NONE as MAS_PAUSE, so an entry could be
skipped if mas_find() was used after a completed mas_prev() that was
empty.

mas_find() was not correctly setting the node to MAS_NONE on a second
mas_find() on a single entry tree of 0 - 0.

Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
---

diff --git a/lib/maple_tree.c b/lib/maple_tree.c
index eb26a2df4696..65e6b811f17a 100644
--- a/lib/maple_tree.c
+++ b/lib/maple_tree.c
@@ -4719,21 +4719,15 @@ retry:
 static inline void *mas_next_entry(struct ma_state *mas, unsigned long limit)
 {
 	void *entry = NULL;
-	struct maple_enode *prev_node;
 	struct maple_node *node;
-	unsigned char offset;
 	unsigned long last;
 	enum maple_type mt;
 
-	if (mas->index > limit) {
-		mas->index = mas->last = limit;
-		mas_pause(mas);
-		return NULL;
-	}
+	if (mas->index > limit)
+		goto limit_reached;
+
 	last = mas->last;
 retry:
-	offset = mas->offset;
-	prev_node = mas->node;
 	node = mas_mn(mas);
 	mt = mte_node_type(mas->node);
 	mas->offset++;
@@ -4753,11 +4747,9 @@ retry:
 			return entry;
 
 		if (unlikely((mas->index > limit)))
-			break;
+			goto limit_reached;
 
 next_node:
-		prev_node = mas->node;
-		offset = mas->offset;
 		if (unlikely(mas_next_node(mas, node, limit))) {
 			mas_rewalk(mas, last);
 			goto retry;
@@ -4767,9 +4759,9 @@ next_node:
 		mt = mte_node_type(mas->node);
 	}
 
+limit_reached:
+	mas->node = MAS_NONE;
 	mas->index = mas->last = limit;
-	mas->offset = offset;
-	mas->node = prev_node;
 	return NULL;
 }
 
@@ -5868,10 +5860,11 @@ void *mas_next(struct ma_state *mas, unsigned long max)
 			mas->index = 1;
 			mas->last = ULONG_MAX;
 		}
+		mas->node = MAS_NONE;
 		return NULL;
 	}
 
-	if (mas->last == ULONG_MAX)
+	if (mas->last >= max)
 		return NULL;
 
 	/* Retries on dead nodes handled by mas_next_entry */
@@ -5997,8 +5990,16 @@ EXPORT_SYMBOL_GPL(mas_pause);
  */
 void *mas_find(struct ma_state *mas, unsigned long max)
 {
+	if (unlikely(mas_is_none(mas))) {
+		if (mas->last >= max)
+			goto none;
+
+		mas->index = mas->last;
+		mas->node = MAS_PAUSE;
+	}
+
 	if (unlikely(mas_is_paused(mas))) {
-		if (unlikely(mas->last == ULONG_MAX)) {
+		if (unlikely(mas->last >= max)) {
 			mas->node = MAS_NONE;
 			return NULL;
 		}
@@ -6006,8 +6007,12 @@ void *mas_find(struct ma_state *mas, unsigned long max)
 		mas->index = ++mas->last;
 	}
 
-	if (unlikely(mas_is_none(mas)))
-		mas->node = MAS_START;
+
+	if (unlikely(mas_is_ptr(mas))) {
+		mas->index = 1;
+		mas->last = ULONG_MAX;
+		goto none;
+	}
 
 	if (unlikely(mas_is_start(mas))) {
 		/* First run or continue */
@@ -6022,10 +6027,17 @@ void *mas_find(struct ma_state *mas, unsigned long max)
 	}
 
 	if (unlikely(!mas_searchable(mas)))
-		return NULL;
+		goto none;
+
+	if (mas->index == max)
+		goto none;
 
 	/* Retries on dead nodes handled by mas_next_entry */
 	return mas_next_entry(mas, max);
+
+none:
+	mas->node = MAS_NONE;
+	return NULL;
 }
 EXPORT_SYMBOL_GPL(mas_find);