diff options
author | Christoph Hellwig <hch@lst.de> | 2008-08-28 06:21:17 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:07 -0400 |
commit | 95819c05732c511338b43c115ffbcee978c02888 (patch) | |
tree | 4622f326207c53e42e7c9e8e8d14960e17190a30 /fs/btrfs/xattr.c | |
parent | eaa47d8612783807ef9703ebc9bf0d0f0455bf62 (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.c | 204 |
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 | ||
30 | static 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 | |||
41 | struct 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 | */ | ||
59 | static 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 | |||
70 | static 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 | ||
92 | ssize_t btrfs_xattr_get(struct inode *inode, int name_index, | 31 | ssize_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 | ||
142 | out: | 71 | out: |
143 | kfree(name); | ||
144 | btrfs_free_path(path); | 72 | btrfs_free_path(path); |
145 | return ret; | 73 | return ret; |
146 | } | 74 | } |
147 | 75 | ||
148 | int btrfs_xattr_set(struct inode *inode, int name_index, | 76 | int __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 | */ | ||
251 | struct 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) \ | 265 | static bool btrfs_is_valid_xattr(const char *name) |
335 | static 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 | } \ | ||
343 | static 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 | ||
352 | BTRFS_XATTR_SETGET_FUNCS(security, BTRFS_XATTR_INDEX_SECURITY); | 273 | ssize_t btrfs_getxattr(struct dentry *dentry, const char *name, |
353 | BTRFS_XATTR_SETGET_FUNCS(system, BTRFS_XATTR_INDEX_SYSTEM); | 274 | void *buffer, size_t size) |
354 | BTRFS_XATTR_SETGET_FUNCS(user, BTRFS_XATTR_INDEX_USER); | 275 | { |
355 | BTRFS_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 | ||
357 | struct 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 | ||
363 | struct xattr_handler btrfs_xattr_system_handler = { | 289 | int 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 | ||
369 | struct 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 | ||
375 | struct 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 | |
308 | int 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 | } | ||