From: Dave Chinner <dchinner@xxxxxxxxxx> For filesytsems that provide their own inode cache that can be traversed, add a sueprblock method that can be used instead of iterating the sb->s_inodes list. This allows these filesystems to avoid having to populate the sb->s_inodes list and hence avoid the scalability limitations that this list imposes. Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> --- fs/super.c | 54 +++++++++++++++++++++++++++++++--------------- include/linux/fs.h | 4 ++++ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/fs/super.c b/fs/super.c index 20a9446d943a..971ad4e996e0 100644 --- a/fs/super.c +++ b/fs/super.c @@ -167,6 +167,31 @@ static void super_wake(struct super_block *sb, unsigned int flag) wake_up_var(&sb->s_flags); } +bool super_iter_iget(struct inode *inode, int flags) +{ + bool ret = false; + + spin_lock(&inode->i_lock); + if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) + goto out_unlock; + + /* + * Skip over zero refcount inode if the caller only wants + * referenced inodes to be iterated. + */ + if ((flags & INO_ITER_REFERENCED) && + !atomic_read(&inode->i_count)) + goto out_unlock; + + __iget(inode); + ret = true; +out_unlock: + spin_unlock(&inode->i_lock); + return ret; + +} +EXPORT_SYMBOL_GPL(super_iter_iget); + /** * super_iter_inodes - iterate all the cached inodes on a superblock * @sb: superblock to iterate @@ -184,26 +209,15 @@ int super_iter_inodes(struct super_block *sb, ino_iter_fn iter_fn, struct inode *inode, *old_inode = NULL; int ret = 0; + if (sb->s_op->iter_vfs_inodes) { + return sb->s_op->iter_vfs_inodes(sb, iter_fn, + private_data, flags); + } + spin_lock(&sb->s_inode_list_lock); list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { - spin_lock(&inode->i_lock); - if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { - spin_unlock(&inode->i_lock); + if (!super_iter_iget(inode, flags)) continue; - } - - /* - * Skip over zero refcount inode if the caller only wants - * referenced inodes to be iterated. - */ - if ((flags & INO_ITER_REFERENCED) && - !atomic_read(&inode->i_count)) { - spin_unlock(&inode->i_lock); - continue; - } - - __iget(inode); - spin_unlock(&inode->i_lock); spin_unlock(&sb->s_inode_list_lock); iput(old_inode); @@ -261,6 +275,12 @@ void super_iter_inodes_unsafe(struct super_block *sb, ino_iter_fn iter_fn, struct inode *inode; int ret; + if (sb->s_op->iter_vfs_inodes) { + sb->s_op->iter_vfs_inodes(sb, iter_fn, + private_data, INO_ITER_UNSAFE); + return; + } + rcu_read_lock(); spin_lock(&sb->s_inode_list_lock); list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { diff --git a/include/linux/fs.h b/include/linux/fs.h index 0a6a462c45ab..8e82e3dc0618 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2224,6 +2224,7 @@ enum freeze_holder { typedef int (*ino_iter_fn)(struct inode *inode, void *priv); int super_iter_inodes(struct super_block *sb, ino_iter_fn iter_fn, void *private_data, int flags); +bool super_iter_iget(struct inode *inode, int flags); struct super_operations { struct inode *(*alloc_inode)(struct super_block *sb); @@ -2258,6 +2259,9 @@ struct super_operations { long (*free_cached_objects)(struct super_block *, struct shrink_control *); void (*shutdown)(struct super_block *sb); + + int (*iter_vfs_inodes)(struct super_block *sb, ino_iter_fn iter_fn, + void *private_data, int flags); }; /* -- 2.45.2