diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-07-26 05:36:34 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-26 12:57:09 -0400 |
commit | a209dfc7b0d94bd6fa94553c097836a2e6d0f0ba (patch) | |
tree | 7dacc92b08264c675a0dfcbae83982b7d3ad5135 | |
parent | 5b9f4567726513a359e70f85029482c7c3714dbd (diff) |
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 <eric.dumazet@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/anon_inodes.c | 2 | ||||
-rw-r--r-- | fs/inode.c | 39 | ||||
-rw-r--r-- | fs/pipe.c | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 3 | ||||
-rw-r--r-- | net/socket.c | 2 |
5 files changed, 35 insertions, 13 deletions
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 4d433d34736f..f11e43ed907d 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c | |||
@@ -187,7 +187,7 @@ EXPORT_SYMBOL_GPL(anon_inode_getfd); | |||
187 | */ | 187 | */ |
188 | static struct inode *anon_inode_mkinode(void) | 188 | static struct inode *anon_inode_mkinode(void) |
189 | { | 189 | { |
190 | struct inode *inode = new_inode(anon_inode_mnt->mnt_sb); | 190 | struct inode *inode = new_inode_pseudo(anon_inode_mnt->mnt_sb); |
191 | 191 | ||
192 | if (!inode) | 192 | if (!inode) |
193 | return ERR_PTR(-ENOMEM); | 193 | return ERR_PTR(-ENOMEM); |
diff --git a/fs/inode.c b/fs/inode.c index 96c77b81167c..319b93b55570 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -362,9 +362,11 @@ EXPORT_SYMBOL_GPL(inode_sb_list_add); | |||
362 | 362 | ||
363 | static inline void inode_sb_list_del(struct inode *inode) | 363 | static inline void inode_sb_list_del(struct inode *inode) |
364 | { | 364 | { |
365 | spin_lock(&inode_sb_list_lock); | 365 | if (!list_empty(&inode->i_sb_list)) { |
366 | list_del_init(&inode->i_sb_list); | 366 | spin_lock(&inode_sb_list_lock); |
367 | spin_unlock(&inode_sb_list_lock); | 367 | list_del_init(&inode->i_sb_list); |
368 | spin_unlock(&inode_sb_list_lock); | ||
369 | } | ||
368 | } | 370 | } |
369 | 371 | ||
370 | static unsigned long hash(struct super_block *sb, unsigned long hashval) | 372 | static unsigned long hash(struct super_block *sb, unsigned long hashval) |
@@ -797,6 +799,29 @@ unsigned int get_next_ino(void) | |||
797 | EXPORT_SYMBOL(get_next_ino); | 799 | EXPORT_SYMBOL(get_next_ino); |
798 | 800 | ||
799 | /** | 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 | |||
824 | /** | ||
800 | * new_inode - obtain an inode | 825 | * new_inode - obtain an inode |
801 | * @sb: superblock | 826 | * @sb: superblock |
802 | * | 827 | * |
@@ -814,13 +839,9 @@ struct inode *new_inode(struct super_block *sb) | |||
814 | 839 | ||
815 | spin_lock_prefetch(&inode_sb_list_lock); | 840 | spin_lock_prefetch(&inode_sb_list_lock); |
816 | 841 | ||
817 | inode = alloc_inode(sb); | 842 | inode = new_inode_pseudo(sb); |
818 | if (inode) { | 843 | if (inode) |
819 | spin_lock(&inode->i_lock); | ||
820 | inode->i_state = 0; | ||
821 | spin_unlock(&inode->i_lock); | ||
822 | inode_sb_list_add(inode); | 844 | inode_sb_list_add(inode); |
823 | } | ||
824 | return inode; | 845 | return inode; |
825 | } | 846 | } |
826 | EXPORT_SYMBOL(new_inode); | 847 | EXPORT_SYMBOL(new_inode); |
@@ -948,7 +948,7 @@ static const struct dentry_operations pipefs_dentry_operations = { | |||
948 | 948 | ||
949 | static struct inode * get_pipe_inode(void) | 949 | static struct inode * get_pipe_inode(void) |
950 | { | 950 | { |
951 | struct inode *inode = new_inode(pipe_mnt->mnt_sb); | 951 | struct inode *inode = new_inode_pseudo(pipe_mnt->mnt_sb); |
952 | struct pipe_inode_info *pipe; | 952 | struct pipe_inode_info *pipe; |
953 | 953 | ||
954 | if (!inode) | 954 | if (!inode) |
diff --git a/include/linux/fs.h b/include/linux/fs.h index a6658043258a..cc363fa7bb82 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -2310,7 +2310,8 @@ extern void __iget(struct inode * inode); | |||
2310 | extern void iget_failed(struct inode *); | 2310 | extern void iget_failed(struct inode *); |
2311 | extern void end_writeback(struct inode *); | 2311 | extern void end_writeback(struct inode *); |
2312 | extern void __destroy_inode(struct inode *); | 2312 | 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); | ||
2314 | extern void free_inode_nonrcu(struct inode *inode); | 2315 | extern void free_inode_nonrcu(struct inode *inode); |
2315 | extern int should_remove_suid(struct dentry *); | 2316 | extern int should_remove_suid(struct dentry *); |
2316 | extern int file_remove_suid(struct file *); | 2317 | extern int file_remove_suid(struct file *); |
diff --git a/net/socket.c b/net/socket.c index 02dc82db3d23..26ed35c7751e 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -467,7 +467,7 @@ static struct socket *sock_alloc(void) | |||
467 | struct inode *inode; | 467 | struct inode *inode; |
468 | struct socket *sock; | 468 | struct socket *sock; |
469 | 469 | ||
470 | inode = new_inode(sock_mnt->mnt_sb); | 470 | inode = new_inode_pseudo(sock_mnt->mnt_sb); |
471 | if (!inode) | 471 | if (!inode) |
472 | return NULL; | 472 | return NULL; |
473 | 473 | ||