* [RFC PATCH 0/3] fs/proc: split the inode list for procfs
@ 2026-09-14 6:14 Huang Shijie
2026-09-14 6:14 ` [RFC PATCH 1/3] fs/drop_caches: do not scan procfs in drop_pagecache_sb() Huang Shijie
` (3 more replies)
0 siblings, 4 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 set tries to resolve this issue by:
patch 1: "fs/drop_caches: do not scan procfs in drop_pagecache_sb()"
This patch skips the scan for procfs in drop caches.
patch 2: Add a new helper to detect the empty inode list
patch 3: split the inode list.
After this patch, the above TestDFSIO can get over 50% better performance
in exec time. And the procfs lock hotspot becomes nearly 1%.
Huang Shijie (3):
fs/drop_caches: do not scan procfs in drop_pagecache_sb()
fs/super: introduce a helper sb_inodes_empty()
fs/proc: split the inode list
fs/drop_caches.c | 4 ++
fs/inode.c | 80 ++++++++++++++++++++++------------
fs/proc/inode.c | 53 ++++++++++++++++++++++
fs/proc/internal.h | 2 +
fs/proc/root.c | 6 +++
fs/super.c | 45 +++++++++++++++----
include/linux/fs/super_types.h | 22 +++++++++-
include/linux/proc_fs.h | 1 +
8 files changed, 176 insertions(+), 37 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [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 related [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 related [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 related [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
* 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
end of thread, other threads:[~2026-09-14 12:10 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 9:19 ` Alexey Dobriyan
2026-09-14 11:59 ` Huang Shijie
2026-09-14 12:10 ` 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 ` [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
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.