[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <2025022644-blinked-broadness-c810@gregkh>
Date: Wed, 26 Feb 2025 15:29:45 +0100
From: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
To: viro@...iv.linux.org.uk,
brauner@...nel.org,
jack@...e.cz
Cc: linux-fsdevel@...r.kernel.org,
linux-kernel@...r.kernel.org,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
stable <stable@...nel.org>,
Takashi Iwai <tiwai@...e.de>,
Chuck Lever <chuck.lever@...cle.com>
Subject: [PATCH] Revert "libfs: Use d_children list to iterate simple_offset directories"
This reverts commit b9b588f22a0c049a14885399e27625635ae6ef91.
There are reports of this commit breaking Chrome's rendering mode. As
no one seems to want to do a root-cause, let's just revert it for now as
it is affecting people using the latest release as well as the stable
kernels that it has been backported to.
Link: https://lore.kernel.org/r/874j0lvy89.wl-tiwai@suse.de
Fixes: b9b588f22a0c ("libfs: Use d_children list to iterate simple_offset directories")
Cc: stable <stable@...nel.org>
Reported-by: Takashi Iwai <tiwai@...e.de>
Cc: Chuck Lever <chuck.lever@...cle.com>
Cc: Christian Brauner <brauner@...nel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
---
fs/libfs.c | 90 ++++++++++++++++++------------------------------------
1 file changed, 29 insertions(+), 61 deletions(-)
diff --git a/fs/libfs.c b/fs/libfs.c
index 8444f5cc4064..96f491f82f99 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -247,13 +247,12 @@ EXPORT_SYMBOL(simple_dir_inode_operations);
/* simple_offset_add() never assigns these to a dentry */
enum {
- DIR_OFFSET_FIRST = 2, /* Find first real entry */
DIR_OFFSET_EOD = S32_MAX,
};
/* simple_offset_add() allocation range */
enum {
- DIR_OFFSET_MIN = DIR_OFFSET_FIRST + 1,
+ DIR_OFFSET_MIN = 2,
DIR_OFFSET_MAX = DIR_OFFSET_EOD - 1,
};
@@ -458,82 +457,51 @@ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence)
return vfs_setpos(file, offset, LONG_MAX);
}
-static struct dentry *find_positive_dentry(struct dentry *parent,
- struct dentry *dentry,
- bool next)
+static struct dentry *offset_find_next(struct offset_ctx *octx, loff_t offset)
{
- struct dentry *found = NULL;
-
- spin_lock(&parent->d_lock);
- if (next)
- dentry = d_next_sibling(dentry);
- else if (!dentry)
- dentry = d_first_child(parent);
- hlist_for_each_entry_from(dentry, d_sib) {
- if (!simple_positive(dentry))
- continue;
- spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
- if (simple_positive(dentry))
- found = dget_dlock(dentry);
- spin_unlock(&dentry->d_lock);
- if (likely(found))
- break;
- }
- spin_unlock(&parent->d_lock);
- return found;
-}
-
-static noinline_for_stack struct dentry *
-offset_dir_lookup(struct dentry *parent, loff_t offset)
-{
- struct inode *inode = d_inode(parent);
- struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
+ MA_STATE(mas, &octx->mt, offset, offset);
struct dentry *child, *found = NULL;
- MA_STATE(mas, &octx->mt, offset, offset);
-
- if (offset == DIR_OFFSET_FIRST)
- found = find_positive_dentry(parent, NULL, false);
- else {
- rcu_read_lock();
- child = mas_find(&mas, DIR_OFFSET_MAX);
- found = find_positive_dentry(parent, child, false);
- rcu_read_unlock();
- }
+ rcu_read_lock();
+ child = mas_find(&mas, DIR_OFFSET_MAX);
+ if (!child)
+ goto out;
+ spin_lock(&child->d_lock);
+ if (simple_positive(child))
+ found = dget_dlock(child);
+ spin_unlock(&child->d_lock);
+out:
+ rcu_read_unlock();
return found;
}
static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
+ long offset = dentry2offset(dentry);
- return dir_emit(ctx, dentry->d_name.name, dentry->d_name.len,
- inode->i_ino, fs_umode_to_dtype(inode->i_mode));
+ return ctx->actor(ctx, dentry->d_name.name, dentry->d_name.len, offset,
+ inode->i_ino, fs_umode_to_dtype(inode->i_mode));
}
-static void offset_iterate_dir(struct file *file, struct dir_context *ctx)
+static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx)
{
- struct dentry *dir = file->f_path.dentry;
+ struct offset_ctx *octx = inode->i_op->get_offset_ctx(inode);
struct dentry *dentry;
- dentry = offset_dir_lookup(dir, ctx->pos);
- if (!dentry)
- goto out_eod;
while (true) {
- struct dentry *next;
-
- ctx->pos = dentry2offset(dentry);
- if (!offset_dir_emit(ctx, dentry))
- break;
-
- next = find_positive_dentry(dir, dentry, true);
- dput(dentry);
-
- if (!next)
+ dentry = offset_find_next(octx, ctx->pos);
+ if (!dentry)
goto out_eod;
- dentry = next;
+
+ if (!offset_dir_emit(ctx, dentry)) {
+ dput(dentry);
+ break;
+ }
+
+ ctx->pos = dentry2offset(dentry) + 1;
+ dput(dentry);
}
- dput(dentry);
return;
out_eod:
@@ -572,7 +540,7 @@ static int offset_readdir(struct file *file, struct dir_context *ctx)
if (!dir_emit_dots(file, ctx))
return 0;
if (ctx->pos != DIR_OFFSET_EOD)
- offset_iterate_dir(file, ctx);
+ offset_iterate_dir(d_inode(dir), ctx);
return 0;
}
--
2.48.1
Powered by blists - more mailing lists