aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xattr.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 /fs/xattr.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 'fs/xattr.c')
-rw-r--r--fs/xattr.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/fs/xattr.c b/fs/xattr.c
index 4be2e7666d02..f060663ab70c 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -91,7 +91,11 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
91{ 91{
92 struct inode *inode = dentry->d_inode; 92 struct inode *inode = dentry->d_inode;
93 int error = -EOPNOTSUPP; 93 int error = -EOPNOTSUPP;
94 int issec = !strncmp(name, XATTR_SECURITY_PREFIX,
95 XATTR_SECURITY_PREFIX_LEN);
94 96
97 if (issec)
98 inode->i_flags &= ~S_NOSEC;
95 if (inode->i_op->setxattr) { 99 if (inode->i_op->setxattr) {
96 error = inode->i_op->setxattr(dentry, name, value, size, flags); 100 error = inode->i_op->setxattr(dentry, name, value, size, flags);
97 if (!error) { 101 if (!error) {
@@ -99,8 +103,7 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
99 security_inode_post_setxattr(dentry, name, value, 103 security_inode_post_setxattr(dentry, name, value,
100 size, flags); 104 size, flags);
101 } 105 }
102 } else if (!strncmp(name, XATTR_SECURITY_PREFIX, 106 } else if (issec) {
103 XATTR_SECURITY_PREFIX_LEN)) {
104 const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; 107 const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
105 error = security_inode_setsecurity(inode, suffix, value, 108 error = security_inode_setsecurity(inode, suffix, value,
106 size, flags); 109 size, flags);