diff options
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 | } | ||