* [RFC PATCH 1/3] fs/drop_caches: do not scan procfs in drop_pagecache_sb()
2026-09-14 6:14 [RFC PATCH 0/3] fs/proc: split the inode list for procfs Huang Shijie
@ 2026-09-14 6:14 ` Huang Shijie
2026-09-14 9:19 ` Alexey Dobriyan
2026-09-14 6:14 ` [RFC PATCH 2/3] fs/super: introduce a helper sb_inodes_empty() Huang Shijie
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Huang Shijie @ 2026-09-14 6:14 UTC (permalink / raw)
To: viro, brauner
Cc: zhongyuan, fangbaoshun, yingzhiwei, jack, dev.jain, ljs,
adobriyan, akpm, hpa, ryan.roberts, mjguzik, joel.granados,
jannh, oleg, aleksa, legion, kees, joannelkoong, tj, libaokun,
ebiggers, sandeen, linux-fsdevel, linux-kernel, Huang Shijie
There is no page cache for the procfs, so do not scan the
inodes in procfs.
Signed-off-by: Huang Shijie <huangsj@hygon.cn>
---
fs/drop_caches.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/drop_caches.c b/fs/drop_caches.c
index 49f56a598ecb..1959090089af 100644
--- a/fs/drop_caches.c
+++ b/fs/drop_caches.c
@@ -5,6 +5,7 @@
#include <linux/pagemap.h>
#include <linux/kernel.h>
+#include <linux/magic.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/writeback.h>
@@ -20,6 +21,9 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
{
struct inode *inode, *toput_inode = NULL;
+ if (sb->s_magic == PROC_SUPER_MAGIC)
+ return;
+
spin_lock(&sb->s_inode_list_lock);
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
spin_lock(&inode->i_lock);
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [RFC PATCH 1/3] fs/drop_caches: do not scan procfs in drop_pagecache_sb()
2026-09-14 6:14 ` [RFC PATCH 1/3] fs/drop_caches: do not scan procfs in drop_pagecache_sb() Huang Shijie
@ 2026-09-14 9:19 ` Alexey Dobriyan
2026-09-14 11:59 ` Huang Shijie
0 siblings, 1 reply; 8+ messages in thread
From: Alexey Dobriyan @ 2026-09-14 9:19 UTC (permalink / raw)
To: Huang Shijie
Cc: viro, brauner, zhongyuan, fangbaoshun, yingzhiwei, jack,
dev.jain, ljs, akpm, hpa, ryan.roberts, mjguzik, joel.granados,
jannh, oleg, aleksa, legion, kees, joannelkoong, tj, libaokun,
ebiggers, sandeen, linux-fsdevel, linux-kernel
On Mon, Sep 14, 2026 at 02:14:47PM +0800, Huang Shijie wrote:
> There is no page cache for the procfs, so do not scan the
> inodes in procfs.
> @@ -20,6 +21,9 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
> {
> struct inode *inode, *toput_inode = NULL;
>
> + if (sb->s_magic == PROC_SUPER_MAGIC)
> + return;
This should be some flag somewhere in superblock.
Other fake filesystems don't support pagecache too.
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [RFC PATCH 1/3] fs/drop_caches: do not scan procfs in drop_pagecache_sb()
2026-09-14 9:19 ` Alexey Dobriyan
@ 2026-09-14 11:59 ` Huang Shijie
2026-09-14 12:10 ` Huang Shijie
0 siblings, 1 reply; 8+ messages in thread
From: Huang Shijie @ 2026-09-14 11:59 UTC (permalink / raw)
To: Alexey Dobriyan
Cc: viro, brauner, zhongyuan, fangbaoshun, yingzhiwei, jack,
dev.jain, ljs, akpm, hpa, ryan.roberts, mjguzik, joel.granados,
jannh, oleg, aleksa, legion, kees, joannelkoong, tj, libaokun,
ebiggers, sandeen, linux-fsdevel, linux-kernel
On Mon, Sep 14, 2026 at 12:19:03PM +0300, Alexey Dobriyan wrote:
> On Mon, Sep 14, 2026 at 02:14:47PM +0800, Huang Shijie wrote:
> > There is no page cache for the procfs, so do not scan the
> > inodes in procfs.
>
> > @@ -20,6 +21,9 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
> > {
> > struct inode *inode, *toput_inode = NULL;
> >
> > + if (sb->s_magic == PROC_SUPER_MAGIC)
> > + return;
>
> This should be some flag somewhere in superblock.
> Other fake filesystems don't support pagecache too.
yes.
It seems it is better to check like this:
if (sb->s_bdi == &noop_backing_dev_inf)
return;
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [RFC PATCH 1/3] fs/drop_caches: do not scan procfs in drop_pagecache_sb()
2026-09-14 11:59 ` Huang Shijie
@ 2026-09-14 12:10 ` Huang Shijie
0 siblings, 0 replies; 8+ messages in thread
From: Huang Shijie @ 2026-09-14 12:10 UTC (permalink / raw)
To: Alexey Dobriyan
Cc: viro, brauner, zhongyuan, fangbaoshun, yingzhiwei, jack,
dev.jain, ljs, akpm, hpa, ryan.roberts, mjguzik, joel.granados,
jannh, oleg, aleksa, legion, kees, joannelkoong, tj, libaokun,
ebiggers, sandeen, linux-fsdevel, linux-kernel
On Mon, Sep 14, 2026 at 07:59:09PM +0800, Huang Shijie wrote:
> On Mon, Sep 14, 2026 at 12:19:03PM +0300, Alexey Dobriyan wrote:
> > On Mon, Sep 14, 2026 at 02:14:47PM +0800, Huang Shijie wrote:
> > > There is no page cache for the procfs, so do not scan the
> > > inodes in procfs.
> >
> > > @@ -20,6 +21,9 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
> > > {
> > > struct inode *inode, *toput_inode = NULL;
> > >
> > > + if (sb->s_magic == PROC_SUPER_MAGIC)
> > > + return;
> >
> > This should be some flag somewhere in superblock.
> > Other fake filesystems don't support pagecache too.
> yes.
>
> It seems it is better to check like this:
> if (sb->s_bdi == &noop_backing_dev_inf)
> return;
>
I find check noop_backing_dev_info is not right, the tmpfs may also use it.
It seems there is no flag in superblock for us.
If we have no choice, I can add a new flag for it.
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC PATCH 2/3] fs/super: introduce a helper sb_inodes_empty()
2026-09-14 6:14 [RFC PATCH 0/3] fs/proc: split the inode list for procfs Huang Shijie
2026-09-14 6:14 ` [RFC PATCH 1/3] fs/drop_caches: do not scan procfs in drop_pagecache_sb() Huang Shijie
@ 2026-09-14 6:14 ` Huang Shijie
2026-09-14 6:14 ` [RFC PATCH 3/3] fs/proc: split the inode list Huang Shijie
2026-09-14 8:50 ` [syzbot ci] Re: fs/proc: split the inode list for procfs syzbot ci
3 siblings, 0 replies; 8+ messages in thread
From: Huang Shijie @ 2026-09-14 6:14 UTC (permalink / raw)
To: viro, brauner
Cc: zhongyuan, fangbaoshun, yingzhiwei, jack, dev.jain, ljs,
adobriyan, akpm, hpa, ryan.roberts, mjguzik, joel.granados,
jannh, oleg, aleksa, legion, kees, joannelkoong, tj, libaokun,
ebiggers, sandeen, linux-fsdevel, linux-kernel, Huang Shijie
Introduce a helper sb_inodes_empty() which is used to
detect if the inodes list is empty.
Signed-off-by: Huang Shijie <huangsj@hygon.cn>
---
fs/super.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/fs/super.c b/fs/super.c
index 05e443173038..4b1314545522 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -724,6 +724,11 @@ void retire_super(struct super_block *sb)
}
EXPORT_SYMBOL(retire_super);
+static bool sb_inodes_empty(struct super_block *sb)
+{
+ return list_empty(&sb->s_inodes);
+}
+
/**
* generic_shutdown_super - common helper for ->kill_sb()
* @sb: superblock to kill
@@ -774,7 +779,7 @@ void generic_shutdown_super(struct super_block *sb)
*/
fscrypt_destroy_keyring(sb);
- if (CHECK_DATA_CORRUPTION(!list_empty(&sb->s_inodes), NULL,
+ if (CHECK_DATA_CORRUPTION(!sb_inodes_empty(sb), NULL,
"VFS: Busy inodes after unmount of %s (%s)",
sb->s_id, sb->s_type->name)) {
/*
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [RFC PATCH 3/3] fs/proc: split the inode list
2026-09-14 6:14 [RFC PATCH 0/3] fs/proc: split the inode list for procfs Huang Shijie
2026-09-14 6:14 ` [RFC PATCH 1/3] fs/drop_caches: do not scan procfs in drop_pagecache_sb() Huang Shijie
2026-09-14 6:14 ` [RFC PATCH 2/3] fs/super: introduce a helper sb_inodes_empty() Huang Shijie
@ 2026-09-14 6:14 ` Huang Shijie
2026-09-14 8:50 ` [syzbot ci] Re: fs/proc: split the inode list for procfs syzbot ci
3 siblings, 0 replies; 8+ messages in thread
From: Huang Shijie @ 2026-09-14 6:14 UTC (permalink / raw)
To: viro, brauner
Cc: zhongyuan, fangbaoshun, yingzhiwei, jack, dev.jain, ljs,
adobriyan, akpm, hpa, ryan.roberts, mjguzik, joel.granados,
jannh, oleg, aleksa, legion, kees, joannelkoong, tj, libaokun,
ebiggers, sandeen, linux-fsdevel, linux-kernel, Huang Shijie
The global s_inode_list_lock is heavily contended in procfs
on a 384-CPU, 12-NUMA-node Hygon machine running Hadoop TestDFSIO:
#hadoop jar xxxx.jar TestDFSIO -read -nrFiles 1000 -size 100MB
The hadoop will create lot of threads during the test.
The perf shows it consuming ~90% of the lock hotspot in procfs.
The lock is hit from both directions:
-- inode creation (~49%) :
getdents64 ->
proc_readfd_common ->
new_inode ->
inode_sb_list_add()
-- inode eviction (~41%):
process exit ->
release_task ->
proc_invalidate_siblings_dcache ->
evict ->
inode_sb_list_del()
This patch spreads the inode list across per-shard locks for procfs:
--- Add "shards" pointer shares a union with s_inodes.
Guard all shard accesses with an explicit s_inode_list_sharded
field in super_block.
--- Add inode_list_add()/inode_list_del() callbacks to super_operations;
procfs implements them to round-robin inodes
onto nr_shards = DIV_ROUND_UP(num_possible_cpus(), 32)
shards allocated at mount time, each protected by its own spinlock.
--- evict_inodes(), generic_shutdown_super()
iterate the shards when the super_block inode list is sharded.
struct inode_shard is cacheline-aligned to avoid false
sharing between shard locks on different NUMA nodes.
This reduces the s_inode_list_lock hotspot from ~90% to ~1% in above
TestDFSIO. And we can improve the hadoop exec performance over 50%.
Signed-off-by: Huang Shijie <huangsj@hygon.cn>
---
fs/inode.c | 80 ++++++++++++++++++++++------------
fs/proc/inode.c | 53 ++++++++++++++++++++++
fs/proc/internal.h | 2 +
fs/proc/root.c | 6 +++
fs/super.c | 40 +++++++++++++----
include/linux/fs/super_types.h | 22 +++++++++-
include/linux/proc_fs.h | 1 +
7 files changed, 167 insertions(+), 37 deletions(-)
diff --git a/fs/inode.c b/fs/inode.c
index ba7da39be4a3..687c2e299258 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -635,6 +635,10 @@ void inode_sb_list_add(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
+ if (sb->s_inode_list_sharded && sb->s_op->inode_list_add) {
+ sb->s_op->inode_list_add(sb, inode);
+ return;
+ }
spin_lock(&sb->s_inode_list_lock);
list_add(&inode->i_sb_list, &sb->s_inodes);
spin_unlock(&sb->s_inode_list_lock);
@@ -646,6 +650,10 @@ static inline void inode_sb_list_del(struct inode *inode)
struct super_block *sb = inode->i_sb;
if (!list_empty(&inode->i_sb_list)) {
+ if (sb->s_inode_list_sharded && sb->s_op->inode_list_del) {
+ sb->s_op->inode_list_del(sb, inode);
+ return;
+ }
spin_lock(&sb->s_inode_list_lock);
list_del_init(&inode->i_sb_list);
spin_unlock(&sb->s_inode_list_lock);
@@ -879,41 +887,57 @@ void evict_inodes(struct super_block *sb)
{
struct inode *inode;
LIST_HEAD(dispose);
+ struct list_head *head;
+ spinlock_t *lock;
+ unsigned int nr, i;
+ const bool sharded = sb->s_inode_list_sharded;
-again:
- spin_lock(&sb->s_inode_list_lock);
- list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
- if (icount_read_once(inode))
- continue;
+ nr = sharded ? sb->nr_shards : 1;
- spin_lock(&inode->i_lock);
- if (icount_read(inode)) {
- spin_unlock(&inode->i_lock);
- continue;
- }
- if (inode_state_read(inode) & (I_NEW | I_FREEING | I_WILL_FREE)) {
- spin_unlock(&inode->i_lock);
- continue;
+ for (i = 0; i < nr; i++) {
+ if (sharded) {
+ head = &sb->shards[i].list;
+ lock = &sb->shards[i].lock;
+ } else {
+ head = &sb->s_inodes;
+ lock = &sb->s_inode_list_lock;
}
- inode_state_set(inode, I_FREEING);
- inode_lru_list_del(inode);
- spin_unlock(&inode->i_lock);
- list_add(&inode->i_lru, &dispose);
+again:
+ spin_lock(lock);
+ list_for_each_entry(inode, head, i_sb_list) {
+ if (icount_read_once(inode))
+ continue;
- /*
- * We can have a ton of inodes to evict at unmount time given
- * enough memory, check to see if we need to go to sleep for a
- * bit so we don't livelock.
- */
- if (need_resched()) {
- spin_unlock(&sb->s_inode_list_lock);
- cond_resched();
- dispose_list(&dispose);
- goto again;
+ spin_lock(&inode->i_lock);
+ if (icount_read(inode)) {
+ spin_unlock(&inode->i_lock);
+ continue;
+ }
+ if (inode_state_read(inode) & (I_NEW | I_FREEING | I_WILL_FREE)) {
+ spin_unlock(&inode->i_lock);
+ continue;
+ }
+
+ inode_state_set(inode, I_FREEING);
+ inode_lru_list_del(inode);
+ spin_unlock(&inode->i_lock);
+ list_add(&inode->i_lru, &dispose);
+
+ /*
+ * We can have a ton of inodes to evict at unmount time given
+ * enough memory, check to see if we need to go to sleep for a
+ * bit so we don't livelock.
+ */
+ if (need_resched()) {
+ spin_unlock(lock);
+ cond_resched();
+ dispose_list(&dispose);
+ goto again;
+ }
}
+ spin_unlock(lock);
}
- spin_unlock(&sb->s_inode_list_lock);
dispose_list(&dispose);
}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index b7634f975d98..d412018b73d9 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -65,6 +65,7 @@ static struct inode *proc_alloc_inode(struct super_block *sb)
ei->sysctl_entry = NULL;
INIT_HLIST_NODE(&ei->sibling_inodes);
ei->ns_ops = NULL;
+ ei->shard_idx = 0;
return &ei->vfs_inode;
}
@@ -80,6 +81,56 @@ static void proc_free_inode(struct inode *inode)
kmem_cache_free(proc_inode_cachep, PROC_I(inode));
}
+static void proc_inode_list_add(struct super_block *sb, struct inode *inode)
+{
+ struct proc_fs_info *fs_info = proc_sb_info(sb);
+ struct proc_inode *ei = PROC_I(inode);
+ struct inode_shard *shard;
+ unsigned int idx, seq;
+
+ seq = atomic_fetch_inc(&fs_info->shard_seq);
+ idx = seq % sb->nr_shards;
+ ei->shard_idx = idx;
+ shard = &sb->shards[idx];
+
+ spin_lock(&shard->lock);
+ list_add(&inode->i_sb_list, &shard->list);
+ spin_unlock(&shard->lock);
+}
+
+static void proc_inode_list_del(struct super_block *sb, struct inode *inode)
+{
+ struct proc_inode *ei = PROC_I(inode);
+ struct inode_shard *shard = &sb->shards[ei->shard_idx];
+
+ spin_lock(&shard->lock);
+ list_del_init(&inode->i_sb_list);
+ spin_unlock(&shard->lock);
+}
+
+#define PROC_LIST_ALIGN 32
+int proc_init_inode_shards(struct super_block *sb)
+{
+ struct inode_shard *shards;
+ unsigned int nr_shards;
+ int i;
+
+ nr_shards = DIV_ROUND_UP(num_possible_cpus(), PROC_LIST_ALIGN);
+ shards = kcalloc(nr_shards, sizeof(*shards), GFP_KERNEL);
+ if (!shards)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_shards; i++) {
+ INIT_LIST_HEAD(&shards[i].list);
+ spin_lock_init(&shards[i].lock);
+ }
+
+ sb->shards = shards;
+ sb->nr_shards = nr_shards;
+ sb->s_inode_list_sharded = true;
+ return 0;
+}
+
static void init_once(void *foo)
{
struct proc_inode *ei = (struct proc_inode *) foo;
@@ -191,6 +242,8 @@ const struct super_operations proc_sops = {
.evict_inode = proc_evict_inode,
.statfs = simple_statfs,
.show_options = proc_show_options,
+ .inode_list_add = proc_inode_list_add,
+ .inode_list_del = proc_inode_list_del,
};
enum {BIAS = -1U<<31};
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 04bd6c9e65a7..edbe357263c2 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -127,6 +127,7 @@ struct proc_inode {
struct hlist_node sibling_inodes;
const struct proc_ns_operations *ns_ops;
struct inode vfs_inode;
+ unsigned int shard_idx;
} __randomize_layout;
/*
@@ -317,6 +318,7 @@ void proc_init_kmemcache(void);
void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock);
void set_proc_pid_nlink(void);
extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *);
+extern int proc_init_inode_shards(struct super_block *);
extern void proc_entry_rundown(struct proc_dir_entry *);
/*
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 99adddfeb4a4..4bd916b88cdf 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -275,6 +275,10 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc)
s->s_time_gran = 1;
s->s_fs_info = fs_info;
+ ret = proc_init_inode_shards(s);
+ if (ret)
+ return ret;
+
if (fs_info->pidonly == PROC_PIDONLY_ON)
s->s_iflags |= SB_I_RESTRICTED_VARIANT;
@@ -359,6 +363,8 @@ static void proc_kill_sb(struct super_block *sb)
struct proc_fs_info *fs_info = proc_sb_info(sb);
kill_anon_super(sb);
+ if (sb->s_inode_list_sharded)
+ kfree(sb->shards);
if (fs_info) {
put_pid_ns(fs_info->pid_ns);
put_cred(fs_info->mounter_cred);
diff --git a/fs/super.c b/fs/super.c
index 4b1314545522..38a452e78ca2 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -726,7 +726,16 @@ EXPORT_SYMBOL(retire_super);
static bool sb_inodes_empty(struct super_block *sb)
{
- return list_empty(&sb->s_inodes);
+ unsigned int i;
+
+ if (!sb->s_inode_list_sharded)
+ return list_empty(&sb->s_inodes);
+
+ for (i = 0; i < sb->nr_shards; i++)
+ if (!list_empty(&sb->shards[i].list))
+ return false;
+
+ return true;
}
/**
@@ -788,14 +797,29 @@ void generic_shutdown_super(struct super_block *sb)
* iput_final() or such crashes cleanly.
*/
struct inode *inode;
-
- spin_lock(&sb->s_inode_list_lock);
- list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
- inode->i_op = VFS_PTR_POISON;
- inode->i_sb = VFS_PTR_POISON;
- inode->i_mapping = VFS_PTR_POISON;
+ struct list_head *head;
+ spinlock_t *lock;
+ unsigned int nr, i;
+ const bool sharded = sb->s_inode_list_sharded;
+
+ nr = sharded ? sb->nr_shards : 1;
+ for (i = 0; i < nr; i++) {
+ if (sharded) {
+ head = &sb->shards[i].list;
+ lock = &sb->shards[i].lock;
+ } else {
+ head = &sb->s_inodes;
+ lock = &sb->s_inode_list_lock;
+ }
+
+ spin_lock(lock);
+ list_for_each_entry(inode, head, i_sb_list) {
+ inode->i_op = VFS_PTR_POISON;
+ inode->i_sb = VFS_PTR_POISON;
+ inode->i_mapping = VFS_PTR_POISON;
+ }
+ spin_unlock(lock);
}
- spin_unlock(&sb->s_inode_list_lock);
}
}
/*
diff --git a/include/linux/fs/super_types.h b/include/linux/fs/super_types.h
index ecd96aeb1cee..6d6aae2d1fbc 100644
--- a/include/linux/fs/super_types.h
+++ b/include/linux/fs/super_types.h
@@ -130,8 +130,20 @@ struct super_operations {
/* Report a filesystem error */
void (*report_error)(const struct fserror_event *event);
+
+ void (*inode_list_add)(struct super_block *sb, struct inode *inode);
+ void (*inode_list_del)(struct super_block *sb, struct inode *inode);
};
+/*
+ * Sharded inode list used by procfs to spread s_inode_list_lock contention
+ * across per-shard locks.
+ */
+struct inode_shard {
+ struct list_head list;
+ spinlock_t lock;
+} ____cacheline_aligned_in_smp;
+
struct super_block {
struct list_head s_list; /* Keep this first */
dev_t s_dev; /* search index; _not_ kdev_t */
@@ -269,9 +281,17 @@ struct super_block {
*/
int s_stack_depth;
+ bool s_inode_list_sharded;
+
/* s_inode_list_lock protects s_inodes */
spinlock_t s_inode_list_lock ____cacheline_aligned_in_smp;
- struct list_head s_inodes; /* all inodes */
+ union {
+ struct list_head s_inodes; /* all inodes */
+ struct {
+ struct inode_shard *shards; /* used by procfs */
+ unsigned int nr_shards;
+ };
+ };
spinlock_t s_inode_wblist_lock;
struct list_head s_inodes_wb; /* writeback inodes */
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 47d7deaeed8f..37eed34f3a93 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -70,6 +70,7 @@ struct proc_fs_info {
const struct cred *mounter_cred;
enum proc_hidepid hide_pid;
enum proc_pidonly pidonly;
+ atomic_t shard_seq;
struct rcu_head rcu;
};
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [syzbot ci] Re: fs/proc: split the inode list for procfs
2026-09-14 6:14 [RFC PATCH 0/3] fs/proc: split the inode list for procfs Huang Shijie
` (2 preceding siblings ...)
2026-09-14 6:14 ` [RFC PATCH 3/3] fs/proc: split the inode list Huang Shijie
@ 2026-09-14 8:50 ` syzbot ci
3 siblings, 0 replies; 8+ messages in thread
From: syzbot ci @ 2026-09-14 8:50 UTC (permalink / raw)
To: adobriyan, akpm, aleksa, brauner, dev.jain, ebiggers,
fangbaoshun, hpa, huangsj, jack, jannh, joannelkoong,
joel.granados, kees, legion, libaokun, linux-fsdevel,
linux-kernel, ljs, mjguzik, oleg, ryan.roberts, sandeen, tj,
viro, yingzhiwei, zhongyuan
Cc: syzbot, syzkaller-bugs
syzbot ci has tested the following series
[v1] fs/proc: split the inode list for procfs
https://lore.kernel.org/all/20260914061449.4024632-1-huangsj@hygon.cn
* [RFC PATCH 1/3] fs/drop_caches: do not scan procfs in drop_pagecache_sb()
* [RFC PATCH 2/3] fs/super: introduce a helper sb_inodes_empty()
* [RFC PATCH 3/3] fs/proc: split the inode list
and found the following issue:
KASAN: slab-out-of-bounds Read in hook_sb_delete
Full report is available here:
https://ci.syzbot.org/series/736afa16-0dc2-40e7-9a6c-74db419044d7
***
KASAN: slab-out-of-bounds Read in hook_sb_delete
tree: vfs
URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/vfs/vfs.git
base: 15aa70de9f706fb0e3852f636b8a0a9d5bc048ab
arch: amd64
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
config: https://ci.syzbot.org/builds/cd4bf6c8-aad6-4b38-b003-31dcd0a8a4bf/config
ima: No TPM chip found, activating TPM-bypass!
Loading compiled-in module X.509 certificates
Loaded X.509 cert 'Build time autogenerated kernel key: affe42cfbb2369724f6c4c4a3fe3f0b2fe4692dc'
ima: Allocated hash algorithm: sha256
ima: No architecture policies found
evm: Initialising EVM extended attributes:
evm: security.selinux (disabled)
evm: security.SMACK64 (disabled)
evm: security.SMACK64EXEC (disabled)
evm: security.SMACK64TRANSMUTE (disabled)
evm: security.SMACK64MMAP (disabled)
evm: security.apparmor
evm: security.ima
evm: security.capability
evm: HMAC attrs: 0x1
PM: Magic number: 10:739:371
usb usb44-port5: hash matches
udc dummy_udc.27: hash matches
dummy_udc dummy_udc.27: hash matches
usb usb12-port1: hash matches
netconsole: network logging started
gtp: GTP module loaded (pdp ctx size 128 bytes)
rdma_rxe: loaded
cfg80211: Loading compiled-in X.509 certificates for regulatory database
Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
Loaded X.509 cert 'wens: 61c038651aabdcf94bd0ac7ff06c7248db18c600'
clk: Disabling unused clocks
ALSA device list:
#0: Dummy 1
#1: Loopback 1
#2: Virtual MIDI Card 1
md: Waiting for all devices to be available before autodetect
md: If you don't use raid, use raid=noautodetect
md: Autodetecting RAID arrays.
md: autorun ...
md: ... autorun DONE.
EXT4-fs (sda1): mounted filesystem b4773fba-1738-4da0-8a90-0fe043d0a496 ro with ordered data mode. Quota mode: none.
VFS: Mounted root (ext4 filesystem) readonly on device 8:1.
devtmpfs: mounted
VFS: Pivoted into new rootfs
Freeing unused kernel image (initmem) memory: 27172K
Write protecting the kernel read-only data: 223232k
Freeing unused kernel image (text/rodata gap) memory: 1552K
Freeing unused kernel image (rodata/data gap) memory: 804K
x86/mm: Checked W+X mappings: passed, no W+X pages found.
x86/mm: Checking user space page tables
x86/mm: Checked W+X mappings: passed, no W+X pages found.
Failed to set sysctl parameter 'max_rcu_stall_to_panic=1': parameter not found
Run /sbin/init as init process
==================================================================
BUG: KASAN: slab-out-of-bounds in _raw_spin_lock+0x2e/0x40
Read of size 1 at addr ffff88810eea9ce0 by task init/1
CPU: 0 UID: 0 PID: 1 Comm: init Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0xe8/0x150
print_address_description+0x55/0x1e0
print_report+0x58/0x70
kasan_report+0x117/0x150
__kasan_check_byte+0x2a/0x40
lock_acquire+0x7d/0x350
_raw_spin_lock+0x2e/0x40
hook_sb_delete+0x15d/0xd10
security_sb_delete+0x76/0x110
generic_shutdown_super+0xb2/0x3d0
kill_anon_super+0x3b/0x70
proc_kill_sb+0x47/0x180
deactivate_locked_super+0xbc/0x110
cleanup_mnt+0x3d3/0x460
mntput_no_expire_slowpath+0xa58/0xbf0
__fput+0x6a4/0xa50
task_work_run+0x1d9/0x270
exit_to_user_mode_loop+0x204/0x770
ret_from_fork+0x593/0xb70
ret_from_fork_asm+0x1a/0x30
</TASK>
Allocated by task 1:
kasan_save_track+0x3e/0x80
__kasan_kmalloc+0x93/0xb0
__kmalloc_flags_noprof+0x532/0x7a0
__alloc_empty_sheaf+0x28/0x40
__pcs_replace_empty_main+0x43b/0x6c0
kmem_cache_alloc_noprof+0x399/0x600
bio_alloc_bioset+0x271/0xc60
ext4_mpage_readpages+0x12a7/0x1c40
read_pages+0x193/0x5a0
page_cache_ra_unbounded+0x754/0x9d0
page_cache_ra_order+0xb47/0xee0
filemap_get_pages+0x86d/0x1ec0
filemap_read+0x426/0x11e0
ext4_file_read_iter+0x553/0xad0
__kernel_read+0x4ca/0x960
integrity_kernel_read+0x89/0xd0
ima_calc_file_hash+0x451/0x890
ima_collect_measurement+0x51b/0xa00
process_measurement+0x1272/0x1c10
ima_file_mmap+0x1b0/0x200
security_mmap_file+0x773/0xa20
vm_mmap_pgoff+0x134/0x4e0
elf_load+0x237/0x6a0
load_elf_interp+0x4da/0xb50
load_elf_binary+0x1bda/0x28d0
bprm_execve+0x930/0x1590
kernel_execve+0x8c3/0x9c0
try_to_run_init_process+0x13/0x60
kernel_init+0xb2/0x1d0
ret_from_fork+0x514/0xb70
ret_from_fork_asm+0x1a/0x30
The buggy address belongs to the object at ffff88810eea9c00
which belongs to the cache kmalloc-128 of size 128
The buggy address is located 96 bytes to the right of
allocated 128-byte region [ffff88810eea9c00, ffff88810eea9c80)
The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x10eea9
flags: 0x17ff00000000000(node=0|zone=2|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 017ff00000000000 ffff888100041a00 dead000000000122 0000000000000000
raw: 0000000000000000 0000000000100010 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0xd2c40(GFP_NOFS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 1, tgid 1 (swapper/0), ts 18944299736
post_alloc_hook+0x1f9/0x250
get_page_from_freelist+0x2209/0x2280
__alloc_frozen_pages_noprof+0x217/0x5a0
allocate_slab+0x7d/0x620
refill_objects+0x2d5/0x350
__pcs_replace_empty_main+0x2c8/0x6c0
__kmalloc_noprof+0x47b/0x720
tomoyo_commit_ok+0x29/0x1d0
tomoyo_update_domain+0x4ea/0x7e0
tomoyo_update_mount_acl+0x11c/0x2d0
tomoyo_write_file+0xae4/0xc50
tomoyo_supervisor+0xff8/0x1560
tomoyo_mount_permission+0x670/0x9e0
security_sb_mount+0xe4/0x320
path_mount+0xbc/0x1050
init_mount+0xc3/0x110
page_owner free stack trace missing
Memory state around the buggy address:
ffff88810eea9b80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff88810eea9c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>ffff88810eea9c80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
^
ffff88810eea9d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
ffff88810eea9d80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================
***
If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
Tested-by: syzbot@syzkaller.appspotmail.com
---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.
To test a fix for this bug, please reply with `#syz test`
(on a separate line) and attach the patch to the email.
Notes:
- The patch will be applied on top of the tested series (as an
incremental fix).
- To test a new version of the whole series, please send it directly
to syzbot@lists.linux.dev.
- Arguments like custom git repos and branches are not supported.
^ permalink raw reply [flat|nested] 8+ messages in thread