aboutsummaryrefslogtreecommitdiffstats
path: root/mm/filemap.c
diff options
context:
space:
mode:
authorAndi Kleen <ak@linux.intel.com>2011-05-28 11:25:51 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-05-28 12:02:09 -0400
commit69b4573296469fd3f70cf7044693074980517067 (patch)
treeaea41eacb2a0f32748145a59bb8dc300b4485f36 /mm/filemap.c
parentd76ee18a8551e33ad7dbd55cac38bc7b094f3abb (diff)
Cache xattr security drop check for write v2
Some recent benchmarking on btrfs showed that a major scaling bottleneck on large systems on btrfs is currently the xattr lookup on every write. Why xattr lookup on every write I hear you ask? write wants to drop suid and security related xattrs that could set o capabilities for executables. To do that it currently looks up security.capability on EVERY write (even for non executables) to decide whether to drop it or not. In btrfs this causes an additional tree walk, hitting some per file system locks and quite bad scalability. In a simple read workload on a 8S system I saw over 90% CPU time in spinlocks related to that. Chris Mason tells me this is also a problem in ext4, where it hits the global mbcache lock. This patch adds a simple per inode to avoid this problem. We only do the lookup once per file and then if there is no xattr cache the decision. All xattr changes clear the flag. I also used the same flag to avoid the suid check, although that one is pretty cheap. A file system can also set this flag when it creates the inode, if it has a cheap way to do so. This is done for some common file systems in followon patches. With this patch a major part of the lock contention disappears for btrfs. Some testing on smaller systems didn't show significant performance changes, but at least it helps the larger systems and is generally more efficient. v2: Rename is_sgid. add file system helper. Cc: chris.mason@oracle.com Cc: josef@redhat.com Cc: viro@zeniv.linux.org.uk Cc: agruen@linbit.com Cc: Serge E. Hallyn <serue@us.ibm.com> Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'mm/filemap.c')
-rw-r--r--mm/filemap.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/mm/filemap.c b/mm/filemap.c
index dac95a24deac..d7b10578a64b 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1982,16 +1982,26 @@ static int __remove_suid(struct dentry *dentry, int kill)
1982int file_remove_suid(struct file *file) 1982int file_remove_suid(struct file *file)
1983{ 1983{
1984 struct dentry *dentry = file->f_path.dentry; 1984 struct dentry *dentry = file->f_path.dentry;
1985 int killsuid = should_remove_suid(dentry); 1985 struct inode *inode = dentry->d_inode;
1986 int killpriv = security_inode_need_killpriv(dentry); 1986 int killsuid;
1987 int killpriv;
1987 int error = 0; 1988 int error = 0;
1988 1989
1990 /* Fast path for nothing security related */
1991 if (IS_NOSEC(inode))
1992 return 0;
1993
1994 killsuid = should_remove_suid(dentry);
1995 killpriv = security_inode_need_killpriv(dentry);
1996
1989 if (killpriv < 0) 1997 if (killpriv < 0)
1990 return killpriv; 1998 return killpriv;
1991 if (killpriv) 1999 if (killpriv)
1992 error = security_inode_killpriv(dentry); 2000 error = security_inode_killpriv(dentry);
1993 if (!error && killsuid) 2001 if (!error && killsuid)
1994 error = __remove_suid(dentry, killsuid); 2002 error = __remove_suid(dentry, killsuid);
2003 if (!error)
2004 inode->i_flags |= S_NOSEC;
1995 2005
1996 return error; 2006 return error;
1997} 2007}