Skip to content

Commit a209dfc

Browse files
Eric DumazetAl Viro
Eric Dumazet
authored and
Al Viro
committed
vfs: dont chain pipe/anon/socket on superblock s_inodes list
Workloads using pipes and sockets hit inode_sb_list_lock contention. superblock s_inodes list is needed for quota, dirty, pagecache and fsnotify management. pipe/anon/socket fs are clearly not candidates for these. Signed-off-by: Eric Dumazet <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent 5b9f456 commit a209dfc

File tree

5 files changed

+35
-13
lines changed

5 files changed

+35
-13
lines changed

fs/anon_inodes.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ EXPORT_SYMBOL_GPL(anon_inode_getfd);
187187
*/
188188
static struct inode *anon_inode_mkinode(void)
189189
{
190-
struct inode *inode = new_inode(anon_inode_mnt->mnt_sb);
190+
struct inode *inode = new_inode_pseudo(anon_inode_mnt->mnt_sb);
191191

192192
if (!inode)
193193
return ERR_PTR(-ENOMEM);

fs/inode.c

+30-9
Original file line numberDiff line numberDiff line change
@@ -362,9 +362,11 @@ EXPORT_SYMBOL_GPL(inode_sb_list_add);
362362

363363
static inline void inode_sb_list_del(struct inode *inode)
364364
{
365-
spin_lock(&inode_sb_list_lock);
366-
list_del_init(&inode->i_sb_list);
367-
spin_unlock(&inode_sb_list_lock);
365+
if (!list_empty(&inode->i_sb_list)) {
366+
spin_lock(&inode_sb_list_lock);
367+
list_del_init(&inode->i_sb_list);
368+
spin_unlock(&inode_sb_list_lock);
369+
}
368370
}
369371

370372
static unsigned long hash(struct super_block *sb, unsigned long hashval)
@@ -796,6 +798,29 @@ unsigned int get_next_ino(void)
796798
}
797799
EXPORT_SYMBOL(get_next_ino);
798800

801+
/**
802+
* new_inode_pseudo - obtain an inode
803+
* @sb: superblock
804+
*
805+
* Allocates a new inode for given superblock.
806+
* Inode wont be chained in superblock s_inodes list
807+
* This means :
808+
* - fs can't be unmount
809+
* - quotas, fsnotify, writeback can't work
810+
*/
811+
struct inode *new_inode_pseudo(struct super_block *sb)
812+
{
813+
struct inode *inode = alloc_inode(sb);
814+
815+
if (inode) {
816+
spin_lock(&inode->i_lock);
817+
inode->i_state = 0;
818+
spin_unlock(&inode->i_lock);
819+
INIT_LIST_HEAD(&inode->i_sb_list);
820+
}
821+
return inode;
822+
}
823+
799824
/**
800825
* new_inode - obtain an inode
801826
* @sb: superblock
@@ -814,13 +839,9 @@ struct inode *new_inode(struct super_block *sb)
814839

815840
spin_lock_prefetch(&inode_sb_list_lock);
816841

817-
inode = alloc_inode(sb);
818-
if (inode) {
819-
spin_lock(&inode->i_lock);
820-
inode->i_state = 0;
821-
spin_unlock(&inode->i_lock);
842+
inode = new_inode_pseudo(sb);
843+
if (inode)
822844
inode_sb_list_add(inode);
823-
}
824845
return inode;
825846
}
826847
EXPORT_SYMBOL(new_inode);

fs/pipe.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ static const struct dentry_operations pipefs_dentry_operations = {
948948

949949
static struct inode * get_pipe_inode(void)
950950
{
951-
struct inode *inode = new_inode(pipe_mnt->mnt_sb);
951+
struct inode *inode = new_inode_pseudo(pipe_mnt->mnt_sb);
952952
struct pipe_inode_info *pipe;
953953

954954
if (!inode)

include/linux/fs.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -2310,7 +2310,8 @@ extern void __iget(struct inode * inode);
23102310
extern void iget_failed(struct inode *);
23112311
extern void end_writeback(struct inode *);
23122312
extern void __destroy_inode(struct inode *);
2313-
extern struct inode *new_inode(struct super_block *);
2313+
extern struct inode *new_inode_pseudo(struct super_block *sb);
2314+
extern struct inode *new_inode(struct super_block *sb);
23142315
extern void free_inode_nonrcu(struct inode *inode);
23152316
extern int should_remove_suid(struct dentry *);
23162317
extern int file_remove_suid(struct file *);

net/socket.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ static struct socket *sock_alloc(void)
467467
struct inode *inode;
468468
struct socket *sock;
469469

470-
inode = new_inode(sock_mnt->mnt_sb);
470+
inode = new_inode_pseudo(sock_mnt->mnt_sb);
471471
if (!inode)
472472
return NULL;
473473

0 commit comments

Comments
 (0)