aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2008-08-28 06:21:17 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:07 -0400
commit95819c05732c511338b43c115ffbcee978c02888 (patch)
tree4622f326207c53e42e7c9e8e8d14960e17190a30
parenteaa47d8612783807ef9703ebc9bf0d0f0455bf62 (diff)
Btrfs: optimize btrget/set/removexattr
btrfs actually stores the whole xattr name, including the prefix ondisk, so using the generic resolver that strips off the prefix is not very helpful. Instead do the real ondisk xattrs manually and only use the generic resolver for synthetic xattrs like ACLs. (Sorry Josef for guiding you towards the wrong direction here intially) Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/acl.c20
-rw-r--r--fs/btrfs/inode.c19
-rw-r--r--fs/btrfs/xattr.c204
-rw-r--r--fs/btrfs/xattr.h31
4 files changed, 104 insertions, 170 deletions
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 2f865311460c..867eaf1f8efb 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -42,17 +42,18 @@ static void btrfs_update_cached_acl(struct inode *inode,
42 42
43static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) 43static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
44{ 44{
45 int size, name_index; 45 int size;
46 const char *name;
46 char *value = NULL; 47 char *value = NULL;
47 struct posix_acl *acl = NULL, **p_acl; 48 struct posix_acl *acl = NULL, **p_acl;
48 49
49 switch (type) { 50 switch (type) {
50 case ACL_TYPE_ACCESS: 51 case ACL_TYPE_ACCESS:
51 name_index = BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS; 52 name = POSIX_ACL_XATTR_ACCESS;
52 p_acl = &BTRFS_I(inode)->i_acl; 53 p_acl = &BTRFS_I(inode)->i_acl;
53 break; 54 break;
54 case ACL_TYPE_DEFAULT: 55 case ACL_TYPE_DEFAULT:
55 name_index = BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT; 56 name = POSIX_ACL_XATTR_DEFAULT;
56 p_acl = &BTRFS_I(inode)->i_default_acl; 57 p_acl = &BTRFS_I(inode)->i_default_acl;
57 break; 58 break;
58 default: 59 default:
@@ -68,12 +69,12 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
68 return acl; 69 return acl;
69 70
70 71
71 size = btrfs_xattr_get(inode, name_index, "", NULL, 0); 72 size = __btrfs_getxattr(inode, name, "", 0);
72 if (size > 0) { 73 if (size > 0) {
73 value = kzalloc(size, GFP_NOFS); 74 value = kzalloc(size, GFP_NOFS);
74 if (!value) 75 if (!value)
75 return ERR_PTR(-ENOMEM); 76 return ERR_PTR(-ENOMEM);
76 size = btrfs_xattr_get(inode, name_index, "", value, size); 77 size = __btrfs_getxattr(inode, name, value, size);
77 if (size > 0) { 78 if (size > 0) {
78 acl = posix_acl_from_xattr(value, size); 79 acl = posix_acl_from_xattr(value, size);
79 btrfs_update_cached_acl(inode, p_acl, acl); 80 btrfs_update_cached_acl(inode, p_acl, acl);
@@ -110,7 +111,8 @@ static int btrfs_xattr_get_acl(struct inode *inode, int type,
110 */ 111 */
111static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) 112static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
112{ 113{
113 int ret, name_index = 0, size = 0; 114 int ret, size = 0;
115 const char *name;
114 struct posix_acl **p_acl; 116 struct posix_acl **p_acl;
115 char *value = NULL; 117 char *value = NULL;
116 mode_t mode; 118 mode_t mode;
@@ -130,13 +132,13 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
130 return ret; 132 return ret;
131 ret = 0; 133 ret = 0;
132 inode->i_mode = mode; 134 inode->i_mode = mode;
133 name_index = BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS; 135 name = POSIX_ACL_XATTR_ACCESS;
134 p_acl = &BTRFS_I(inode)->i_acl; 136 p_acl = &BTRFS_I(inode)->i_acl;
135 break; 137 break;
136 case ACL_TYPE_DEFAULT: 138 case ACL_TYPE_DEFAULT:
137 if (!S_ISDIR(inode->i_mode)) 139 if (!S_ISDIR(inode->i_mode))
138 return acl ? -EINVAL : 0; 140 return acl ? -EINVAL : 0;
139 name_index = BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT; 141 name = POSIX_ACL_XATTR_DEFAULT;
140 p_acl = &BTRFS_I(inode)->i_default_acl; 142 p_acl = &BTRFS_I(inode)->i_default_acl;
141 break; 143 break;
142 default: 144 default:
@@ -156,7 +158,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
156 goto out; 158 goto out;
157 } 159 }
158 160
159 ret = btrfs_xattr_set(inode, name_index, "", value, size, 0); 161 ret = __btrfs_setxattr(inode, name, value, size, 0);
160 162
161out: 163out:
162 if (value) 164 if (value)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 10f26f445328..43d3f2649ca3 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -45,6 +45,7 @@
45#include "print-tree.h" 45#include "print-tree.h"
46#include "volumes.h" 46#include "volumes.h"
47#include "ordered-data.h" 47#include "ordered-data.h"
48#include "xattr.h"
48 49
49struct btrfs_iget_args { 50struct btrfs_iget_args {
50 u64 ino; 51 u64 ino;
@@ -3667,10 +3668,10 @@ static struct inode_operations btrfs_dir_inode_operations = {
3667 .symlink = btrfs_symlink, 3668 .symlink = btrfs_symlink,
3668 .setattr = btrfs_setattr, 3669 .setattr = btrfs_setattr,
3669 .mknod = btrfs_mknod, 3670 .mknod = btrfs_mknod,
3670 .setxattr = generic_setxattr, 3671 .setxattr = btrfs_setxattr,
3671 .getxattr = generic_getxattr, 3672 .getxattr = btrfs_getxattr,
3672 .listxattr = btrfs_listxattr, 3673 .listxattr = btrfs_listxattr,
3673 .removexattr = generic_removexattr, 3674 .removexattr = btrfs_removexattr,
3674 .permission = btrfs_permission, 3675 .permission = btrfs_permission,
3675}; 3676};
3676static struct inode_operations btrfs_dir_ro_inode_operations = { 3677static struct inode_operations btrfs_dir_ro_inode_operations = {
@@ -3728,20 +3729,20 @@ static struct inode_operations btrfs_file_inode_operations = {
3728 .truncate = btrfs_truncate, 3729 .truncate = btrfs_truncate,
3729 .getattr = btrfs_getattr, 3730 .getattr = btrfs_getattr,
3730 .setattr = btrfs_setattr, 3731 .setattr = btrfs_setattr,
3731 .setxattr = generic_setxattr, 3732 .setxattr = btrfs_setxattr,
3732 .getxattr = generic_getxattr, 3733 .getxattr = btrfs_getxattr,
3733 .listxattr = btrfs_listxattr, 3734 .listxattr = btrfs_listxattr,
3734 .removexattr = generic_removexattr, 3735 .removexattr = btrfs_removexattr,
3735 .permission = btrfs_permission, 3736 .permission = btrfs_permission,
3736}; 3737};
3737static struct inode_operations btrfs_special_inode_operations = { 3738static struct inode_operations btrfs_special_inode_operations = {
3738 .getattr = btrfs_getattr, 3739 .getattr = btrfs_getattr,
3739 .setattr = btrfs_setattr, 3740 .setattr = btrfs_setattr,
3740 .permission = btrfs_permission, 3741 .permission = btrfs_permission,
3741 .setxattr = generic_setxattr, 3742 .setxattr = btrfs_setxattr,
3742 .getxattr = generic_getxattr, 3743 .getxattr = btrfs_getxattr,
3743 .listxattr = btrfs_listxattr, 3744 .listxattr = btrfs_listxattr,
3744 .removexattr = generic_removexattr, 3745 .removexattr = btrfs_removexattr,
3745}; 3746};
3746static struct inode_operations btrfs_symlink_inode_operations = { 3747static struct inode_operations btrfs_symlink_inode_operations = {
3747 .readlink = generic_readlink, 3748 .readlink = generic_readlink,
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index fdfece41dd16..adb4b32a9d51 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -27,91 +27,20 @@
27#include "xattr.h" 27#include "xattr.h"
28#include "disk-io.h" 28#include "disk-io.h"
29 29
30static struct xattr_handler *btrfs_xattr_handler_map[] = {
31 [BTRFS_XATTR_INDEX_USER] = &btrfs_xattr_user_handler,
32#ifdef CONFIG_FS_POSIX_ACL
33 [BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS] = &btrfs_xattr_acl_access_handler,
34 [BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &btrfs_xattr_acl_default_handler,
35#endif
36 [BTRFS_XATTR_INDEX_TRUSTED] = &btrfs_xattr_trusted_handler,
37 [BTRFS_XATTR_INDEX_SECURITY] = &btrfs_xattr_security_handler,
38 [BTRFS_XATTR_INDEX_SYSTEM] = &btrfs_xattr_system_handler,
39};
40
41struct xattr_handler *btrfs_xattr_handlers[] = {
42 &btrfs_xattr_user_handler,
43#ifdef CONFIG_FS_POSIX_ACL
44 &btrfs_xattr_acl_access_handler,
45 &btrfs_xattr_acl_default_handler,
46#endif
47 &btrfs_xattr_trusted_handler,
48 &btrfs_xattr_security_handler,
49 &btrfs_xattr_system_handler,
50 NULL,
51};
52
53/*
54 * @param name_index - the index for the xattr handler
55 * @return the xattr_handler if we found it, NULL otherwise
56 *
57 * use this if we know the type of the xattr already
58 */
59static struct xattr_handler *btrfs_xattr_handler(int name_index)
60{
61 struct xattr_handler *handler = NULL;
62
63 if (name_index >= 0 &&
64 name_index < ARRAY_SIZE(btrfs_xattr_handler_map))
65 handler = btrfs_xattr_handler_map[name_index];
66
67 return handler;
68}
69
70static inline char *get_name(const char *name, int name_index)
71{
72 char *ret = NULL;
73 struct xattr_handler *handler = btrfs_xattr_handler(name_index);
74 int prefix_len;
75
76 if (!handler)
77 return ret;
78
79 prefix_len = strlen(handler->prefix);
80
81 ret = kmalloc(strlen(name) + prefix_len + 1, GFP_KERNEL);
82 if (!ret)
83 return ret;
84
85 memcpy(ret, handler->prefix, prefix_len);
86 memcpy(ret+prefix_len, name, strlen(name));
87 ret[prefix_len + strlen(name)] = '\0';
88
89 return ret;
90}
91 30
92ssize_t btrfs_xattr_get(struct inode *inode, int name_index, 31ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
93 const char *attr_name, void *buffer, size_t size) 32 void *buffer, size_t size)
94{ 33{
95 struct btrfs_dir_item *di; 34 struct btrfs_dir_item *di;
96 struct btrfs_root *root = BTRFS_I(inode)->root; 35 struct btrfs_root *root = BTRFS_I(inode)->root;
97 struct btrfs_path *path; 36 struct btrfs_path *path;
98 struct extent_buffer *leaf; 37 struct extent_buffer *leaf;
99 struct xattr_handler *handler = btrfs_xattr_handler(name_index);
100 int ret = 0; 38 int ret = 0;
101 unsigned long data_ptr; 39 unsigned long data_ptr;
102 char *name;
103
104 if (!handler)
105 return -EOPNOTSUPP;
106 name = get_name(attr_name, name_index);
107 if (!name)
108 return -ENOMEM;
109 40
110 path = btrfs_alloc_path(); 41 path = btrfs_alloc_path();
111 if (!path) { 42 if (!path)
112 kfree(name);
113 return -ENOMEM; 43 return -ENOMEM;
114 }
115 44
116 /* lookup the xattr by name */ 45 /* lookup the xattr by name */
117 di = btrfs_lookup_xattr(NULL, root, path, inode->i_ino, name, 46 di = btrfs_lookup_xattr(NULL, root, path, inode->i_ino, name,
@@ -140,33 +69,22 @@ ssize_t btrfs_xattr_get(struct inode *inode, int name_index,
140 ret = btrfs_dir_data_len(leaf, di); 69 ret = btrfs_dir_data_len(leaf, di);
141 70
142out: 71out:
143 kfree(name);
144 btrfs_free_path(path); 72 btrfs_free_path(path);
145 return ret; 73 return ret;
146} 74}
147 75
148int btrfs_xattr_set(struct inode *inode, int name_index, 76int __btrfs_setxattr(struct inode *inode, const char *name,
149 const char *attr_name, const void *value, size_t size, 77 const void *value, size_t size, int flags)
150 int flags)
151{ 78{
152 struct btrfs_dir_item *di; 79 struct btrfs_dir_item *di;
153 struct btrfs_root *root = BTRFS_I(inode)->root; 80 struct btrfs_root *root = BTRFS_I(inode)->root;
154 struct btrfs_trans_handle *trans; 81 struct btrfs_trans_handle *trans;
155 struct btrfs_path *path; 82 struct btrfs_path *path;
156 struct xattr_handler *handler = btrfs_xattr_handler(name_index);
157 char *name;
158 int ret = 0, mod = 0; 83 int ret = 0, mod = 0;
159 if (!handler)
160 return -EOPNOTSUPP;
161 name = get_name(attr_name, name_index);
162 if (!name)
163 return -ENOMEM;
164 84
165 path = btrfs_alloc_path(); 85 path = btrfs_alloc_path();
166 if (!path) { 86 if (!path)
167 kfree(name);
168 return -ENOMEM; 87 return -ENOMEM;
169 }
170 88
171 trans = btrfs_start_transaction(root, 1); 89 trans = btrfs_start_transaction(root, 1);
172 btrfs_set_trans_block_group(trans, inode); 90 btrfs_set_trans_block_group(trans, inode);
@@ -221,9 +139,7 @@ out:
221 } 139 }
222 140
223 btrfs_end_transaction(trans, root); 141 btrfs_end_transaction(trans, root);
224 kfree(name);
225 btrfs_free_path(path); 142 btrfs_free_path(path);
226
227 return ret; 143 return ret;
228} 144}
229 145
@@ -329,51 +245,77 @@ err:
329} 245}
330 246
331/* 247/*
332 * Handler functions 248 * List of handlers for synthetic system.* attributes. All real ondisk
249 * attributes are handled directly.
250 */
251struct xattr_handler *btrfs_xattr_handlers[] = {
252#ifdef CONFIG_FS_POSIX_ACL
253 &btrfs_xattr_acl_access_handler,
254 &btrfs_xattr_acl_default_handler,
255#endif
256 NULL,
257};
258
259/*
260 * Check if the attribute is in a supported namespace.
261 *
262 * This applied after the check for the synthetic attributes in the system
263 * namespace.
333 */ 264 */
334#define BTRFS_XATTR_SETGET_FUNCS(name, index) \ 265static bool btrfs_is_valid_xattr(const char *name)
335static int btrfs_xattr_##name##_get(struct inode *inode, \ 266{
336 const char *name, void *value, \ 267 return !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) ||
337 size_t size) \ 268 !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) ||
338{ \ 269 !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
339 if (*name == '\0') \ 270 !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
340 return -EINVAL; \
341 return btrfs_xattr_get(inode, index, name, value, size); \
342} \
343static int btrfs_xattr_##name##_set(struct inode *inode, \
344 const char *name, const void *value,\
345 size_t size, int flags) \
346{ \
347 if (*name == '\0') \
348 return -EINVAL; \
349 return btrfs_xattr_set(inode, index, name, value, size, flags); \
350} 271}
351 272
352BTRFS_XATTR_SETGET_FUNCS(security, BTRFS_XATTR_INDEX_SECURITY); 273ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
353BTRFS_XATTR_SETGET_FUNCS(system, BTRFS_XATTR_INDEX_SYSTEM); 274 void *buffer, size_t size)
354BTRFS_XATTR_SETGET_FUNCS(user, BTRFS_XATTR_INDEX_USER); 275{
355BTRFS_XATTR_SETGET_FUNCS(trusted, BTRFS_XATTR_INDEX_TRUSTED); 276 /*
277 * If this is a request for a synthetic attribute in the system.*
278 * namespace use the generic infrastructure to resolve a handler
279 * for it via sb->s_xattr.
280 */
281 if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
282 return generic_getxattr(dentry, name, buffer, size);
356 283
357struct xattr_handler btrfs_xattr_security_handler = { 284 if (!btrfs_is_valid_xattr(name))
358 .prefix = XATTR_SECURITY_PREFIX, 285 return -EOPNOTSUPP;
359 .get = btrfs_xattr_security_get, 286 return __btrfs_getxattr(dentry->d_inode, name, buffer, size);
360 .set = btrfs_xattr_security_set, 287}
361};
362 288
363struct xattr_handler btrfs_xattr_system_handler = { 289int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
364 .prefix = XATTR_SYSTEM_PREFIX, 290 size_t size, int flags)
365 .get = btrfs_xattr_system_get, 291{
366 .set = btrfs_xattr_system_set, 292 /*
367}; 293 * If this is a request for a synthetic attribute in the system.*
294 * namespace use the generic infrastructure to resolve a handler
295 * for it via sb->s_xattr.
296 */
297 if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
298 return generic_setxattr(dentry, name, value, size, flags);
368 299
369struct xattr_handler btrfs_xattr_user_handler = { 300 if (!btrfs_is_valid_xattr(name))
370 .prefix = XATTR_USER_PREFIX, 301 return -EOPNOTSUPP;
371 .get = btrfs_xattr_user_get,
372 .set = btrfs_xattr_user_set,
373};
374 302
375struct xattr_handler btrfs_xattr_trusted_handler = { 303 if (size == 0)
376 .prefix = XATTR_TRUSTED_PREFIX, 304 value = ""; /* empty EA, do not remove */
377 .get = btrfs_xattr_trusted_get, 305 return __btrfs_setxattr(dentry->d_inode, name, value, size, flags);
378 .set = btrfs_xattr_trusted_set, 306}
379}; 307
308int btrfs_removexattr(struct dentry *dentry, const char *name)
309{
310 /*
311 * If this is a request for a synthetic attribute in the system.*
312 * namespace use the generic infrastructure to resolve a handler
313 * for it via sb->s_xattr.
314 */
315 if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
316 return generic_removexattr(dentry, name);
317
318 if (!btrfs_is_valid_xattr(name))
319 return -EOPNOTSUPP;
320 return __btrfs_setxattr(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
321}
diff --git a/fs/btrfs/xattr.h b/fs/btrfs/xattr.h
index 825e55bd4960..5b1d08f8e68d 100644
--- a/fs/btrfs/xattr.h
+++ b/fs/btrfs/xattr.h
@@ -20,31 +20,20 @@
20#define __XATTR__ 20#define __XATTR__
21 21
22#include <linux/xattr.h> 22#include <linux/xattr.h>
23#include "ctree.h"
24 23
25/* Name indexes */
26enum {
27 BTRFS_XATTR_INDEX_USER,
28 BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS,
29 BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT,
30 BTRFS_XATTR_INDEX_TRUSTED,
31 BTRFS_XATTR_INDEX_SECURITY,
32 BTRFS_XATTR_INDEX_SYSTEM,
33 BTRFS_XATTR_INDEX_END,
34};
35
36extern struct xattr_handler btrfs_xattr_user_handler;
37extern struct xattr_handler btrfs_xattr_trusted_handler;
38extern struct xattr_handler btrfs_xattr_acl_access_handler; 24extern struct xattr_handler btrfs_xattr_acl_access_handler;
39extern struct xattr_handler btrfs_xattr_acl_default_handler; 25extern struct xattr_handler btrfs_xattr_acl_default_handler;
40extern struct xattr_handler btrfs_xattr_security_handler;
41extern struct xattr_handler btrfs_xattr_system_handler;
42
43extern struct xattr_handler *btrfs_xattr_handlers[]; 26extern struct xattr_handler *btrfs_xattr_handlers[];
44 27
45ssize_t btrfs_xattr_get(struct inode *inode, int name_index, const char *name, 28extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
46 void *buffer, size_t size); 29 void *buffer, size_t size);
47int btrfs_xattr_set(struct inode *inode, int name_index, const char *name, 30extern int __btrfs_setxattr(struct inode *inode, const char *name,
48 const void *value, size_t size, int flags); 31 const void *value, size_t size, int flags);
32
33extern ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
34 void *buffer, size_t size);
35extern int btrfs_setxattr(struct dentry *dentry, const char *name,
36 const void *value, size_t size, int flags);
37extern int btrfs_removexattr(struct dentry *dentry, const char *name);
49 38
50#endif /* __XATTR__ */ 39#endif /* __XATTR__ */