Skip to content

Commit 95819c0

Browse files
Christoph Hellwigchrismason-xx
authored andcommitted
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 <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent eaa47d8 commit 95819c0

File tree

4 files changed

+104
-170
lines changed

4 files changed

+104
-170
lines changed

fs/btrfs/acl.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,18 @@ static void btrfs_update_cached_acl(struct inode *inode,
4242

4343
static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
4444
{
45-
int size, name_index;
45+
int size;
46+
const char *name;
4647
char *value = NULL;
4748
struct posix_acl *acl = NULL, **p_acl;
4849

4950
switch (type) {
5051
case ACL_TYPE_ACCESS:
51-
name_index = BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS;
52+
name = POSIX_ACL_XATTR_ACCESS;
5253
p_acl = &BTRFS_I(inode)->i_acl;
5354
break;
5455
case ACL_TYPE_DEFAULT:
55-
name_index = BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT;
56+
name = POSIX_ACL_XATTR_DEFAULT;
5657
p_acl = &BTRFS_I(inode)->i_default_acl;
5758
break;
5859
default:
@@ -68,12 +69,12 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
6869
return acl;
6970

7071

71-
size = btrfs_xattr_get(inode, name_index, "", NULL, 0);
72+
size = __btrfs_getxattr(inode, name, "", 0);
7273
if (size > 0) {
7374
value = kzalloc(size, GFP_NOFS);
7475
if (!value)
7576
return ERR_PTR(-ENOMEM);
76-
size = btrfs_xattr_get(inode, name_index, "", value, size);
77+
size = __btrfs_getxattr(inode, name, value, size);
7778
if (size > 0) {
7879
acl = posix_acl_from_xattr(value, size);
7980
btrfs_update_cached_acl(inode, p_acl, acl);
@@ -110,7 +111,8 @@ static int btrfs_xattr_get_acl(struct inode *inode, int type,
110111
*/
111112
static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
112113
{
113-
int ret, name_index = 0, size = 0;
114+
int ret, size = 0;
115+
const char *name;
114116
struct posix_acl **p_acl;
115117
char *value = NULL;
116118
mode_t mode;
@@ -130,13 +132,13 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
130132
return ret;
131133
ret = 0;
132134
inode->i_mode = mode;
133-
name_index = BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS;
135+
name = POSIX_ACL_XATTR_ACCESS;
134136
p_acl = &BTRFS_I(inode)->i_acl;
135137
break;
136138
case ACL_TYPE_DEFAULT:
137139
if (!S_ISDIR(inode->i_mode))
138140
return acl ? -EINVAL : 0;
139-
name_index = BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT;
141+
name = POSIX_ACL_XATTR_DEFAULT;
140142
p_acl = &BTRFS_I(inode)->i_default_acl;
141143
break;
142144
default:
@@ -156,7 +158,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
156158
goto out;
157159
}
158160

159-
ret = btrfs_xattr_set(inode, name_index, "", value, size, 0);
161+
ret = __btrfs_setxattr(inode, name, value, size, 0);
160162

161163
out:
162164
if (value)

fs/btrfs/inode.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "print-tree.h"
4646
#include "volumes.h"
4747
#include "ordered-data.h"
48+
#include "xattr.h"
4849

4950
struct btrfs_iget_args {
5051
u64 ino;
@@ -3667,10 +3668,10 @@ static struct inode_operations btrfs_dir_inode_operations = {
36673668
.symlink = btrfs_symlink,
36683669
.setattr = btrfs_setattr,
36693670
.mknod = btrfs_mknod,
3670-
.setxattr = generic_setxattr,
3671-
.getxattr = generic_getxattr,
3671+
.setxattr = btrfs_setxattr,
3672+
.getxattr = btrfs_getxattr,
36723673
.listxattr = btrfs_listxattr,
3673-
.removexattr = generic_removexattr,
3674+
.removexattr = btrfs_removexattr,
36743675
.permission = btrfs_permission,
36753676
};
36763677
static struct inode_operations btrfs_dir_ro_inode_operations = {
@@ -3728,20 +3729,20 @@ static struct inode_operations btrfs_file_inode_operations = {
37283729
.truncate = btrfs_truncate,
37293730
.getattr = btrfs_getattr,
37303731
.setattr = btrfs_setattr,
3731-
.setxattr = generic_setxattr,
3732-
.getxattr = generic_getxattr,
3732+
.setxattr = btrfs_setxattr,
3733+
.getxattr = btrfs_getxattr,
37333734
.listxattr = btrfs_listxattr,
3734-
.removexattr = generic_removexattr,
3735+
.removexattr = btrfs_removexattr,
37353736
.permission = btrfs_permission,
37363737
};
37373738
static struct inode_operations btrfs_special_inode_operations = {
37383739
.getattr = btrfs_getattr,
37393740
.setattr = btrfs_setattr,
37403741
.permission = btrfs_permission,
3741-
.setxattr = generic_setxattr,
3742-
.getxattr = generic_getxattr,
3742+
.setxattr = btrfs_setxattr,
3743+
.getxattr = btrfs_getxattr,
37433744
.listxattr = btrfs_listxattr,
3744-
.removexattr = generic_removexattr,
3745+
.removexattr = btrfs_removexattr,
37453746
};
37463747
static struct inode_operations btrfs_symlink_inode_operations = {
37473748
.readlink = generic_readlink,

fs/btrfs/xattr.c

Lines changed: 73 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -27,91 +27,20 @@
2727
#include "xattr.h"
2828
#include "disk-io.h"
2929

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-
}
9130

92-
ssize_t btrfs_xattr_get(struct inode *inode, int name_index,
93-
const char *attr_name, void *buffer, size_t size)
31+
ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
32+
void *buffer, size_t size)
9433
{
9534
struct btrfs_dir_item *di;
9635
struct btrfs_root *root = BTRFS_I(inode)->root;
9736
struct btrfs_path *path;
9837
struct extent_buffer *leaf;
99-
struct xattr_handler *handler = btrfs_xattr_handler(name_index);
10038
int ret = 0;
10139
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;
10940

11041
path = btrfs_alloc_path();
111-
if (!path) {
112-
kfree(name);
42+
if (!path)
11343
return -ENOMEM;
114-
}
11544

11645
/* lookup the xattr by name */
11746
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,
14069
ret = btrfs_dir_data_len(leaf, di);
14170

14271
out:
143-
kfree(name);
14472
btrfs_free_path(path);
14573
return ret;
14674
}
14775

148-
int btrfs_xattr_set(struct inode *inode, int name_index,
149-
const char *attr_name, const void *value, size_t size,
150-
int flags)
76+
int __btrfs_setxattr(struct inode *inode, const char *name,
77+
const void *value, size_t size, int flags)
15178
{
15279
struct btrfs_dir_item *di;
15380
struct btrfs_root *root = BTRFS_I(inode)->root;
15481
struct btrfs_trans_handle *trans;
15582
struct btrfs_path *path;
156-
struct xattr_handler *handler = btrfs_xattr_handler(name_index);
157-
char *name;
15883
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;
16484

16585
path = btrfs_alloc_path();
166-
if (!path) {
167-
kfree(name);
86+
if (!path)
16887
return -ENOMEM;
169-
}
17088

17189
trans = btrfs_start_transaction(root, 1);
17290
btrfs_set_trans_block_group(trans, inode);
@@ -221,9 +139,7 @@ int btrfs_xattr_set(struct inode *inode, int name_index,
221139
}
222140

223141
btrfs_end_transaction(trans, root);
224-
kfree(name);
225142
btrfs_free_path(path);
226-
227143
return ret;
228144
}
229145

@@ -329,51 +245,77 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
329245
}
330246

331247
/*
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.
333264
*/
334-
#define BTRFS_XATTR_SETGET_FUNCS(name, index) \
335-
static int btrfs_xattr_##name##_get(struct inode *inode, \
336-
const char *name, void *value, \
337-
size_t size) \
338-
{ \
339-
if (*name == '\0') \
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); \
265+
static bool btrfs_is_valid_xattr(const char *name)
266+
{
267+
return !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) ||
268+
!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) ||
269+
!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
270+
!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
350271
}
351272

352-
BTRFS_XATTR_SETGET_FUNCS(security, BTRFS_XATTR_INDEX_SECURITY);
353-
BTRFS_XATTR_SETGET_FUNCS(system, BTRFS_XATTR_INDEX_SYSTEM);
354-
BTRFS_XATTR_SETGET_FUNCS(user, BTRFS_XATTR_INDEX_USER);
355-
BTRFS_XATTR_SETGET_FUNCS(trusted, BTRFS_XATTR_INDEX_TRUSTED);
273+
ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
274+
void *buffer, size_t size)
275+
{
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);
356283

357-
struct xattr_handler btrfs_xattr_security_handler = {
358-
.prefix = XATTR_SECURITY_PREFIX,
359-
.get = btrfs_xattr_security_get,
360-
.set = btrfs_xattr_security_set,
361-
};
284+
if (!btrfs_is_valid_xattr(name))
285+
return -EOPNOTSUPP;
286+
return __btrfs_getxattr(dentry->d_inode, name, buffer, size);
287+
}
362288

363-
struct xattr_handler btrfs_xattr_system_handler = {
364-
.prefix = XATTR_SYSTEM_PREFIX,
365-
.get = btrfs_xattr_system_get,
366-
.set = btrfs_xattr_system_set,
367-
};
289+
int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
290+
size_t size, int flags)
291+
{
292+
/*
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);
368299

369-
struct xattr_handler btrfs_xattr_user_handler = {
370-
.prefix = XATTR_USER_PREFIX,
371-
.get = btrfs_xattr_user_get,
372-
.set = btrfs_xattr_user_set,
373-
};
300+
if (!btrfs_is_valid_xattr(name))
301+
return -EOPNOTSUPP;
374302

375-
struct xattr_handler btrfs_xattr_trusted_handler = {
376-
.prefix = XATTR_TRUSTED_PREFIX,
377-
.get = btrfs_xattr_trusted_get,
378-
.set = btrfs_xattr_trusted_set,
379-
};
303+
if (size == 0)
304+
value = ""; /* empty EA, do not remove */
305+
return __btrfs_setxattr(dentry->d_inode, name, value, size, flags);
306+
}
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+
}

0 commit comments

Comments
 (0)