aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/xattr.c
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 /fs/btrfs/xattr.c
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>
Diffstat (limited to 'fs/btrfs/xattr.c')
-rw-r--r--fs/btrfs/xattr.c204
1 files changed, 73 insertions, 131 deletions
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}