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>
This commit is contained in:
parent
5b9f456772
commit
a209dfc7b0
|
@ -187,7 +187,7 @@ EXPORT_SYMBOL_GPL(anon_inode_getfd);
|
||||||
*/
|
*/
|
||||||
static struct inode *anon_inode_mkinode(void)
|
static struct inode *anon_inode_mkinode(void)
|
||||||
{
|
{
|
||||||
struct inode *inode = new_inode(anon_inode_mnt->mnt_sb);
|
struct inode *inode = new_inode_pseudo(anon_inode_mnt->mnt_sb);
|
||||||
|
|
||||||
if (!inode)
|
if (!inode)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
39
fs/inode.c
39
fs/inode.c
|
@ -362,9 +362,11 @@ EXPORT_SYMBOL_GPL(inode_sb_list_add);
|
||||||
|
|
||||||
static inline void inode_sb_list_del(struct inode *inode)
|
static inline void inode_sb_list_del(struct inode *inode)
|
||||||
{
|
{
|
||||||
spin_lock(&inode_sb_list_lock);
|
if (!list_empty(&inode->i_sb_list)) {
|
||||||
list_del_init(&inode->i_sb_list);
|
spin_lock(&inode_sb_list_lock);
|
||||||
spin_unlock(&inode_sb_list_lock);
|
list_del_init(&inode->i_sb_list);
|
||||||
|
spin_unlock(&inode_sb_list_lock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long hash(struct super_block *sb, unsigned long hashval)
|
static unsigned long hash(struct super_block *sb, unsigned long hashval)
|
||||||
|
@ -796,6 +798,29 @@ unsigned int get_next_ino(void)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(get_next_ino);
|
EXPORT_SYMBOL(get_next_ino);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* new_inode_pseudo - obtain an inode
|
||||||
|
* @sb: superblock
|
||||||
|
*
|
||||||
|
* Allocates a new inode for given superblock.
|
||||||
|
* Inode wont be chained in superblock s_inodes list
|
||||||
|
* This means :
|
||||||
|
* - fs can't be unmount
|
||||||
|
* - quotas, fsnotify, writeback can't work
|
||||||
|
*/
|
||||||
|
struct inode *new_inode_pseudo(struct super_block *sb)
|
||||||
|
{
|
||||||
|
struct inode *inode = alloc_inode(sb);
|
||||||
|
|
||||||
|
if (inode) {
|
||||||
|
spin_lock(&inode->i_lock);
|
||||||
|
inode->i_state = 0;
|
||||||
|
spin_unlock(&inode->i_lock);
|
||||||
|
INIT_LIST_HEAD(&inode->i_sb_list);
|
||||||
|
}
|
||||||
|
return inode;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* new_inode - obtain an inode
|
* new_inode - obtain an inode
|
||||||
* @sb: superblock
|
* @sb: superblock
|
||||||
|
@ -814,13 +839,9 @@ struct inode *new_inode(struct super_block *sb)
|
||||||
|
|
||||||
spin_lock_prefetch(&inode_sb_list_lock);
|
spin_lock_prefetch(&inode_sb_list_lock);
|
||||||
|
|
||||||
inode = alloc_inode(sb);
|
inode = new_inode_pseudo(sb);
|
||||||
if (inode) {
|
if (inode)
|
||||||
spin_lock(&inode->i_lock);
|
|
||||||
inode->i_state = 0;
|
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
inode_sb_list_add(inode);
|
inode_sb_list_add(inode);
|
||||||
}
|
|
||||||
return inode;
|
return inode;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(new_inode);
|
EXPORT_SYMBOL(new_inode);
|
||||||
|
|
|
@ -948,7 +948,7 @@ static const struct dentry_operations pipefs_dentry_operations = {
|
||||||
|
|
||||||
static struct inode * get_pipe_inode(void)
|
static struct inode * get_pipe_inode(void)
|
||||||
{
|
{
|
||||||
struct inode *inode = new_inode(pipe_mnt->mnt_sb);
|
struct inode *inode = new_inode_pseudo(pipe_mnt->mnt_sb);
|
||||||
struct pipe_inode_info *pipe;
|
struct pipe_inode_info *pipe;
|
||||||
|
|
||||||
if (!inode)
|
if (!inode)
|
||||||
|
|
|
@ -2310,7 +2310,8 @@ extern void __iget(struct inode * inode);
|
||||||
extern void iget_failed(struct inode *);
|
extern void iget_failed(struct inode *);
|
||||||
extern void end_writeback(struct inode *);
|
extern void end_writeback(struct inode *);
|
||||||
extern void __destroy_inode(struct inode *);
|
extern void __destroy_inode(struct inode *);
|
||||||
extern struct inode *new_inode(struct super_block *);
|
extern struct inode *new_inode_pseudo(struct super_block *sb);
|
||||||
|
extern struct inode *new_inode(struct super_block *sb);
|
||||||
extern void free_inode_nonrcu(struct inode *inode);
|
extern void free_inode_nonrcu(struct inode *inode);
|
||||||
extern int should_remove_suid(struct dentry *);
|
extern int should_remove_suid(struct dentry *);
|
||||||
extern int file_remove_suid(struct file *);
|
extern int file_remove_suid(struct file *);
|
||||||
|
|
|
@ -467,7 +467,7 @@ static struct socket *sock_alloc(void)
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct socket *sock;
|
struct socket *sock;
|
||||||
|
|
||||||
inode = new_inode(sock_mnt->mnt_sb);
|
inode = new_inode_pseudo(sock_mnt->mnt_sb);
|
||||||
if (!inode)
|
if (!inode)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue