diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2024-09-28 21:31:10 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-10-01 19:40:47 -0400 |
commit | 9ec9b917b3f6cf676226f074fdcdeceebe1a0b29 (patch) | |
tree | 7c71ca81faa20a1e44624f7489fae1264db8e269 /fs/drop_caches.c | |
parent | 32cb8103ecfacdd5ed8e1eb390221c3f8339de6f (diff) |
vfs: use fast_list for superblock's inode listfast_list
Use the new fast_list for super_block.s_inodes.
This gives similar performance to Dave's dlock list approach [1]; lock
contention is now moved to the lru_list locks.
Iteration is now fully lockless - instead we iterate using
rcu_read_lock(), which means we must take care for racing with removal.
Generally this is already handled - code that iterates over s_inodes
takes i_lock and checks i_state, skipping inodes that are
I_WILL_FREE|I_FREEING. However, code may also check for nonzero
i_sb_list_idx if it wishes to iterate over precisely the inodes that are
on the s_inodes list.
[1]: https://lore.kernel.org/linux-fsdevel/20231206060629.2827226-4-david@fromorbit.com/
Cc: Christian Brauner <brauner@kernel.org>
Cc: Dave Chinner <dchinner@redhat.com>
Cc: Waiman Long <longman@redhat.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/drop_caches.c')
-rw-r--r-- | fs/drop_caches.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/fs/drop_caches.c b/fs/drop_caches.c index d45ef541d848..72c59fb22c81 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c @@ -18,10 +18,15 @@ int sysctl_drop_caches; static void drop_pagecache_sb(struct super_block *sb, void *unused) { - struct inode *inode, *toput_inode = NULL; + struct genradix_iter iter; + void **i; + + rcu_read_lock(); + genradix_for_each(&sb->s_inodes.items, iter, i) { + struct inode *inode = *((struct inode **) i); + if (!inode) + continue; - spin_lock(&sb->s_inode_list_lock); - list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { spin_lock(&inode->i_lock); /* * We must skip inodes in unusual state. We may also skip @@ -35,17 +40,15 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) } __iget(inode); spin_unlock(&inode->i_lock); - spin_unlock(&sb->s_inode_list_lock); + rcu_read_unlock(); invalidate_mapping_pages(inode->i_mapping, 0, -1); - iput(toput_inode); - toput_inode = inode; + iput(inode); cond_resched(); - spin_lock(&sb->s_inode_list_lock); + rcu_read_lock(); } - spin_unlock(&sb->s_inode_list_lock); - iput(toput_inode); + rcu_read_unlock(); } int drop_caches_sysctl_handler(const struct ctl_table *table, int write, |