Skip to content

Commit d1f4e90

Browse files
committed
kernfs: remove iattr_mutex
All allocations of struct kernfs_iattrs are serialized through a global mutex. Simply do a racy allocation and let the first one win. I bet most callers are under inode->i_rwsem anyway and it wouldn't be needed but let's not require that. Acked-by: Greg Kroah-Hartman <[email protected]> Acked-by: Tejun Heo <[email protected]> Signed-off-by: Song Liu <[email protected]> Link: https://lore.kernel.org/[email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 19272b3 commit d1f4e90

File tree

1 file changed

+40
-34
lines changed

1 file changed

+40
-34
lines changed

fs/kernfs/inode.c

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,45 +24,46 @@ static const struct inode_operations kernfs_iops = {
2424
.listxattr = kernfs_iop_listxattr,
2525
};
2626

27-
static struct kernfs_iattrs *__kernfs_iattrs(struct kernfs_node *kn, int alloc)
27+
static struct kernfs_iattrs *__kernfs_iattrs(struct kernfs_node *kn, bool alloc)
2828
{
29-
static DEFINE_MUTEX(iattr_mutex);
30-
struct kernfs_iattrs *ret;
29+
struct kernfs_iattrs *ret __free(kfree) = NULL;
30+
struct kernfs_iattrs *attr;
3131

32-
mutex_lock(&iattr_mutex);
32+
attr = READ_ONCE(kn->iattr);
33+
if (attr || !alloc)
34+
return attr;
3335

34-
if (kn->iattr || !alloc)
35-
goto out_unlock;
36-
37-
kn->iattr = kmem_cache_zalloc(kernfs_iattrs_cache, GFP_KERNEL);
38-
if (!kn->iattr)
39-
goto out_unlock;
36+
ret = kmem_cache_zalloc(kernfs_iattrs_cache, GFP_KERNEL);
37+
if (!ret)
38+
return NULL;
4039

4140
/* assign default attributes */
42-
kn->iattr->ia_uid = GLOBAL_ROOT_UID;
43-
kn->iattr->ia_gid = GLOBAL_ROOT_GID;
44-
45-
ktime_get_real_ts64(&kn->iattr->ia_atime);
46-
kn->iattr->ia_mtime = kn->iattr->ia_atime;
47-
kn->iattr->ia_ctime = kn->iattr->ia_atime;
48-
49-
simple_xattrs_init(&kn->iattr->xattrs);
50-
atomic_set(&kn->iattr->nr_user_xattrs, 0);
51-
atomic_set(&kn->iattr->user_xattr_size, 0);
52-
out_unlock:
53-
ret = kn->iattr;
54-
mutex_unlock(&iattr_mutex);
55-
return ret;
41+
ret->ia_uid = GLOBAL_ROOT_UID;
42+
ret->ia_gid = GLOBAL_ROOT_GID;
43+
44+
ktime_get_real_ts64(&ret->ia_atime);
45+
ret->ia_mtime = ret->ia_atime;
46+
ret->ia_ctime = ret->ia_atime;
47+
48+
simple_xattrs_init(&ret->xattrs);
49+
atomic_set(&ret->nr_user_xattrs, 0);
50+
atomic_set(&ret->user_xattr_size, 0);
51+
52+
/* If someone raced us, recognize it. */
53+
if (!try_cmpxchg(&kn->iattr, &attr, ret))
54+
return READ_ONCE(kn->iattr);
55+
56+
return no_free_ptr(ret);
5657
}
5758

5859
static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
5960
{
60-
return __kernfs_iattrs(kn, 1);
61+
return __kernfs_iattrs(kn, true);
6162
}
6263

6364
static struct kernfs_iattrs *kernfs_iattrs_noalloc(struct kernfs_node *kn)
6465
{
65-
return __kernfs_iattrs(kn, 0);
66+
return __kernfs_iattrs(kn, false);
6667
}
6768

6869
int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
@@ -141,9 +142,9 @@ ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size)
141142
struct kernfs_node *kn = kernfs_dentry_node(dentry);
142143
struct kernfs_iattrs *attrs;
143144

144-
attrs = kernfs_iattrs(kn);
145+
attrs = kernfs_iattrs_noalloc(kn);
145146
if (!attrs)
146-
return -ENOMEM;
147+
return -ENODATA;
147148

148149
return simple_xattr_list(d_inode(dentry), &attrs->xattrs, buf, size);
149150
}
@@ -166,9 +167,10 @@ static inline void set_inode_attr(struct inode *inode,
166167

167168
static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode)
168169
{
169-
struct kernfs_iattrs *attrs = kn->iattr;
170+
struct kernfs_iattrs *attrs;
170171

171172
inode->i_mode = kn->mode;
173+
attrs = kernfs_iattrs_noalloc(kn);
172174
if (attrs)
173175
/*
174176
* kernfs_node has non-default attributes get them from
@@ -306,7 +308,9 @@ int kernfs_xattr_set(struct kernfs_node *kn, const char *name,
306308
const void *value, size_t size, int flags)
307309
{
308310
struct simple_xattr *old_xattr;
309-
struct kernfs_iattrs *attrs = kernfs_iattrs(kn);
311+
struct kernfs_iattrs *attrs;
312+
313+
attrs = kernfs_iattrs(kn);
310314
if (!attrs)
311315
return -ENOMEM;
312316

@@ -345,8 +349,9 @@ static int kernfs_vfs_user_xattr_add(struct kernfs_node *kn,
345349
struct simple_xattrs *xattrs,
346350
const void *value, size_t size, int flags)
347351
{
348-
atomic_t *sz = &kn->iattr->user_xattr_size;
349-
atomic_t *nr = &kn->iattr->nr_user_xattrs;
352+
struct kernfs_iattrs *attr = kernfs_iattrs_noalloc(kn);
353+
atomic_t *sz = &attr->user_xattr_size;
354+
atomic_t *nr = &attr->nr_user_xattrs;
350355
struct simple_xattr *old_xattr;
351356
int ret;
352357

@@ -384,8 +389,9 @@ static int kernfs_vfs_user_xattr_rm(struct kernfs_node *kn,
384389
struct simple_xattrs *xattrs,
385390
const void *value, size_t size, int flags)
386391
{
387-
atomic_t *sz = &kn->iattr->user_xattr_size;
388-
atomic_t *nr = &kn->iattr->nr_user_xattrs;
392+
struct kernfs_iattrs *attr = kernfs_iattrs_noalloc(kn);
393+
atomic_t *sz = &attr->user_xattr_size;
394+
atomic_t *nr = &attr->nr_user_xattrs;
389395
struct simple_xattr *old_xattr;
390396

391397
old_xattr = simple_xattr_set(xattrs, full_name, value, size, flags);

0 commit comments

Comments
 (0)