mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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 <gregkh@linuxfoundation.org> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Song Liu <song@kernel.org> Link: https://lore.kernel.org/20250623063854.1896364-2-song@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
		
							parent
							
								
									19272b37aa
								
							
						
					
					
						commit
						d1f4e90260
					
				
					 1 changed files with 38 additions and 32 deletions
				
			
		| 
						 | 
					@ -24,45 +24,46 @@ static const struct inode_operations kernfs_iops = {
 | 
				
			||||||
	.listxattr	= kernfs_iop_listxattr,
 | 
						.listxattr	= kernfs_iop_listxattr,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct kernfs_iattrs *__kernfs_iattrs(struct kernfs_node *kn, int alloc)
 | 
					static struct kernfs_iattrs *__kernfs_iattrs(struct kernfs_node *kn, bool alloc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static DEFINE_MUTEX(iattr_mutex);
 | 
						struct kernfs_iattrs *ret __free(kfree) = NULL;
 | 
				
			||||||
	struct kernfs_iattrs *ret;
 | 
						struct kernfs_iattrs *attr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&iattr_mutex);
 | 
						attr = READ_ONCE(kn->iattr);
 | 
				
			||||||
 | 
						if (attr || !alloc)
 | 
				
			||||||
 | 
							return attr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (kn->iattr || !alloc)
 | 
						ret = kmem_cache_zalloc(kernfs_iattrs_cache, GFP_KERNEL);
 | 
				
			||||||
		goto out_unlock;
 | 
						if (!ret)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
	kn->iattr = kmem_cache_zalloc(kernfs_iattrs_cache, GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (!kn->iattr)
 | 
					 | 
				
			||||||
		goto out_unlock;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* assign default attributes */
 | 
						/* assign default attributes */
 | 
				
			||||||
	kn->iattr->ia_uid = GLOBAL_ROOT_UID;
 | 
						ret->ia_uid = GLOBAL_ROOT_UID;
 | 
				
			||||||
	kn->iattr->ia_gid = GLOBAL_ROOT_GID;
 | 
						ret->ia_gid = GLOBAL_ROOT_GID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ktime_get_real_ts64(&kn->iattr->ia_atime);
 | 
						ktime_get_real_ts64(&ret->ia_atime);
 | 
				
			||||||
	kn->iattr->ia_mtime = kn->iattr->ia_atime;
 | 
						ret->ia_mtime = ret->ia_atime;
 | 
				
			||||||
	kn->iattr->ia_ctime = kn->iattr->ia_atime;
 | 
						ret->ia_ctime = ret->ia_atime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	simple_xattrs_init(&kn->iattr->xattrs);
 | 
						simple_xattrs_init(&ret->xattrs);
 | 
				
			||||||
	atomic_set(&kn->iattr->nr_user_xattrs, 0);
 | 
						atomic_set(&ret->nr_user_xattrs, 0);
 | 
				
			||||||
	atomic_set(&kn->iattr->user_xattr_size, 0);
 | 
						atomic_set(&ret->user_xattr_size, 0);
 | 
				
			||||||
out_unlock:
 | 
					
 | 
				
			||||||
	ret = kn->iattr;
 | 
						/* If someone raced us, recognize it. */
 | 
				
			||||||
	mutex_unlock(&iattr_mutex);
 | 
						if (!try_cmpxchg(&kn->iattr, &attr, ret))
 | 
				
			||||||
	return ret;
 | 
							return READ_ONCE(kn->iattr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return no_free_ptr(ret);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
 | 
					static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return __kernfs_iattrs(kn, 1);
 | 
						return __kernfs_iattrs(kn, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct kernfs_iattrs *kernfs_iattrs_noalloc(struct kernfs_node *kn)
 | 
					static struct kernfs_iattrs *kernfs_iattrs_noalloc(struct kernfs_node *kn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return __kernfs_iattrs(kn, 0);
 | 
						return __kernfs_iattrs(kn, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
 | 
					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)
 | 
				
			||||||
	struct kernfs_node *kn = kernfs_dentry_node(dentry);
 | 
						struct kernfs_node *kn = kernfs_dentry_node(dentry);
 | 
				
			||||||
	struct kernfs_iattrs *attrs;
 | 
						struct kernfs_iattrs *attrs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	attrs = kernfs_iattrs(kn);
 | 
						attrs = kernfs_iattrs_noalloc(kn);
 | 
				
			||||||
	if (!attrs)
 | 
						if (!attrs)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENODATA;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return simple_xattr_list(d_inode(dentry), &attrs->xattrs, buf, size);
 | 
						return simple_xattr_list(d_inode(dentry), &attrs->xattrs, buf, size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -166,9 +167,10 @@ static inline void set_inode_attr(struct inode *inode,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode)
 | 
					static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct kernfs_iattrs *attrs = kn->iattr;
 | 
						struct kernfs_iattrs *attrs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inode->i_mode = kn->mode;
 | 
						inode->i_mode = kn->mode;
 | 
				
			||||||
 | 
						attrs = kernfs_iattrs_noalloc(kn);
 | 
				
			||||||
	if (attrs)
 | 
						if (attrs)
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * kernfs_node has non-default attributes get them from
 | 
							 * kernfs_node has non-default attributes get them from
 | 
				
			||||||
| 
						 | 
					@ -306,7 +308,9 @@ int kernfs_xattr_set(struct kernfs_node *kn, const char *name,
 | 
				
			||||||
		     const void *value, size_t size, int flags)
 | 
							     const void *value, size_t size, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct simple_xattr *old_xattr;
 | 
						struct simple_xattr *old_xattr;
 | 
				
			||||||
	struct kernfs_iattrs *attrs = kernfs_iattrs(kn);
 | 
						struct kernfs_iattrs *attrs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						attrs = kernfs_iattrs(kn);
 | 
				
			||||||
	if (!attrs)
 | 
						if (!attrs)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -345,8 +349,9 @@ static int kernfs_vfs_user_xattr_add(struct kernfs_node *kn,
 | 
				
			||||||
				     struct simple_xattrs *xattrs,
 | 
									     struct simple_xattrs *xattrs,
 | 
				
			||||||
				     const void *value, size_t size, int flags)
 | 
									     const void *value, size_t size, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	atomic_t *sz = &kn->iattr->user_xattr_size;
 | 
						struct kernfs_iattrs *attr = kernfs_iattrs_noalloc(kn);
 | 
				
			||||||
	atomic_t *nr = &kn->iattr->nr_user_xattrs;
 | 
						atomic_t *sz = &attr->user_xattr_size;
 | 
				
			||||||
 | 
						atomic_t *nr = &attr->nr_user_xattrs;
 | 
				
			||||||
	struct simple_xattr *old_xattr;
 | 
						struct simple_xattr *old_xattr;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -384,8 +389,9 @@ static int kernfs_vfs_user_xattr_rm(struct kernfs_node *kn,
 | 
				
			||||||
				    struct simple_xattrs *xattrs,
 | 
									    struct simple_xattrs *xattrs,
 | 
				
			||||||
				    const void *value, size_t size, int flags)
 | 
									    const void *value, size_t size, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	atomic_t *sz = &kn->iattr->user_xattr_size;
 | 
						struct kernfs_iattrs *attr = kernfs_iattrs_noalloc(kn);
 | 
				
			||||||
	atomic_t *nr = &kn->iattr->nr_user_xattrs;
 | 
						atomic_t *sz = &attr->user_xattr_size;
 | 
				
			||||||
 | 
						atomic_t *nr = &attr->nr_user_xattrs;
 | 
				
			||||||
	struct simple_xattr *old_xattr;
 | 
						struct simple_xattr *old_xattr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	old_xattr = simple_xattr_set(xattrs, full_name, value, size, flags);
 | 
						old_xattr = simple_xattr_set(xattrs, full_name, value, size, flags);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue