aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-07-26 05:36:34 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-07-26 12:57:09 -0400
commita209dfc7b0d94bd6fa94553c097836a2e6d0f0ba (patch)
tree7dacc92b08264c675a0dfcbae83982b7d3ad5135
parent5b9f4567726513a359e70f85029482c7c3714dbd (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.c2
-rw-r--r--fs/inode.c39
-rw-r--r--fs/pipe.c2
-rw-r--r--include/linux/fs.h3
-rw-r--r--net/socket.c2
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 */
188static struct inode *anon_inode_mkinode(void) 188static 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
363static inline void inode_sb_list_del(struct inode *inode) 363static 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
370static unsigned long hash(struct super_block *sb, unsigned long hashval) 372static unsigned long hash(struct super_block *sb, unsigned long hashval)
@@ -797,6 +799,29 @@ unsigned int get_next_ino(void)
797EXPORT_SYMBOL(get_next_ino); 799EXPORT_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 */
811struct 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}
826EXPORT_SYMBOL(new_inode); 847EXPORT_SYMBOL(new_inode);
diff --git a/fs/pipe.c b/fs/pipe.c
index 1b7f9af67ccf..0e0be1dc0f8e 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -948,7 +948,7 @@ static const struct dentry_operations pipefs_dentry_operations = {
948 948
949static struct inode * get_pipe_inode(void) 949static 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);
2310extern void iget_failed(struct inode *); 2310extern void iget_failed(struct inode *);
2311extern void end_writeback(struct inode *); 2311extern void end_writeback(struct inode *);
2312extern void __destroy_inode(struct inode *); 2312extern void __destroy_inode(struct inode *);
2313extern struct inode *new_inode(struct super_block *); 2313extern struct inode *new_inode_pseudo(struct super_block *sb);
2314extern struct inode *new_inode(struct super_block *sb);
2314extern void free_inode_nonrcu(struct inode *inode); 2315extern void free_inode_nonrcu(struct inode *inode);
2315extern int should_remove_suid(struct dentry *); 2316extern int should_remove_suid(struct dentry *);
2316extern int file_remove_suid(struct file *); 2317extern 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