[PATCH v1 05/12] libfs: simplify scan_positives()

NeilBrown <[email protected]> Mon, 3 Aug 2026 11:21:14 +1000
Newsgroups org.kernel.vger.ceph-devel,org.kernel.vger.autofs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-nfs
Message-ID <[email protected]>
From: NeilBrown <[email protected]>

This patch removes explicit use of hlist_node from scan_positives() and
callers, and consistently uses struct dentry instead.

Previously scan_positives() had two args which were closely related: p
and last.
If last was not NULL, p was precisely &last->d_sib.next.
If last WAS NULL, then p was
   &cursor->d_parent->d_children.first or
   &cursor->d_sib.next

If, for the final case, we pass 'cursor' as 'last', then we only need
'last' not 'p'.  For this to work we must dget(cursor) before passing
it, as scan_positives() calls dput() on last.

So now to scan from the start, pass NULL, to scan from a particular
dentry, pass that dentry.

Signed-off-by: NeilBrown <[email protected]>
---
 fs/libfs.c | 29 +++++++++++++----------------
 1 file changed, 13 insertions(+), 16 deletions(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index fc283e0a7c3a..080ca615593c 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -105,16 +105,18 @@ EXPORT_SYMBOL(dcache_dir_close);
  * If no such element exists, NULL is returned.
  */
 static struct dentry *scan_positives(struct dentry *cursor,
-					struct hlist_node **p,
-					loff_t count,
-					struct dentry *last)
+				     struct dentry *last,
+				     loff_t count)
 {
 	struct dentry *dentry = cursor->d_parent, *found = NULL;
+	struct dentry *next;
 
 	spin_lock(&dentry->d_lock);
-	while (*p) {
-		struct dentry *d = hlist_entry(*p, struct dentry, d_sib);
-		p = &d->d_sib.next;
+	next = last ? d_next_sibling(last) : d_first_child(dentry);
+	while (next) {
+		struct dentry *d = next;
+
+		next = d_next_sibling(next);
 		// we must at least skip cursors, to avoid livelocks
 		if (d->d_flags & DCACHE_DENTRY_CURSOR)
 			continue;
@@ -131,10 +133,10 @@ static struct dentry *scan_positives(struct dentry *cursor,
 			if (!hlist_unhashed(&cursor->d_sib))
 				__hlist_del(&cursor->d_sib);
 			hlist_add_behind(&cursor->d_sib, &d->d_sib);
-			p = &cursor->d_sib.next;
 			spin_unlock(&dentry->d_lock);
 			cond_resched();
 			spin_lock(&dentry->d_lock);
+			next = d_next_sibling(cursor);
 		}
 	}
 	spin_unlock(&dentry->d_lock);
@@ -163,8 +165,7 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
 		inode_lock_shared(dentry->d_inode);
 
 		if (offset > 2)
-			to = scan_positives(cursor, &dentry->d_children.first,
-					    offset - 2, NULL);
+			to = scan_positives(cursor, NULL, offset - 2);
 		spin_lock(&dentry->d_lock);
 		hlist_del_init(&cursor->d_sib);
 		if (to)
@@ -191,23 +192,19 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
 	struct dentry *dentry = file->f_path.dentry;
 	struct dentry *cursor = file->private_data;
 	struct dentry *next = NULL;
-	struct hlist_node **p;
 
 	if (!dir_emit_dots(file, ctx))
 		return 0;
 
-	if (ctx->pos == 2)
-		p = &dentry->d_children.first;
-	else
-		p = &cursor->d_sib.next;
+	if (ctx->pos > 2)
+		next = dget(cursor);
 
-	while ((next = scan_positives(cursor, p, 1, next)) != NULL) {
+	while ((next = scan_positives(cursor, next, 1)) != NULL) {
 		if (!dir_emit(ctx, next->d_name.name, next->d_name.len,
 			      d_inode(next)->i_ino,
 			      fs_umode_to_dtype(d_inode(next)->i_mode)))
 			break;
 		ctx->pos++;
-		p = &next->d_sib.next;
 	}
 	spin_lock(&dentry->d_lock);
 	hlist_del_init(&cursor->d_sib);
-- 
2.50.0.107.gf914562f5916.dirty