xref: /kernel/linux/linux-5.10/fs/kernfs/inode.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * fs/kernfs/inode.c - kernfs inode implementation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2001-3 Patrick Mochel
68c2ecf20Sopenharmony_ci * Copyright (c) 2007 SUSE Linux Products GmbH
78c2ecf20Sopenharmony_ci * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
118c2ecf20Sopenharmony_ci#include <linux/backing-dev.h>
128c2ecf20Sopenharmony_ci#include <linux/capability.h>
138c2ecf20Sopenharmony_ci#include <linux/errno.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/xattr.h>
168c2ecf20Sopenharmony_ci#include <linux/security.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "kernfs-internal.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic const struct address_space_operations kernfs_aops = {
218c2ecf20Sopenharmony_ci	.readpage	= simple_readpage,
228c2ecf20Sopenharmony_ci	.write_begin	= simple_write_begin,
238c2ecf20Sopenharmony_ci	.write_end	= simple_write_end,
248c2ecf20Sopenharmony_ci};
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic const struct inode_operations kernfs_iops = {
278c2ecf20Sopenharmony_ci	.permission	= kernfs_iop_permission,
288c2ecf20Sopenharmony_ci	.setattr	= kernfs_iop_setattr,
298c2ecf20Sopenharmony_ci	.getattr	= kernfs_iop_getattr,
308c2ecf20Sopenharmony_ci	.listxattr	= kernfs_iop_listxattr,
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic struct kernfs_iattrs *__kernfs_iattrs(struct kernfs_node *kn, int alloc)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	static DEFINE_MUTEX(iattr_mutex);
368c2ecf20Sopenharmony_ci	struct kernfs_iattrs *ret;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	mutex_lock(&iattr_mutex);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (kn->iattr || !alloc)
418c2ecf20Sopenharmony_ci		goto out_unlock;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	kn->iattr = kmem_cache_zalloc(kernfs_iattrs_cache, GFP_KERNEL);
448c2ecf20Sopenharmony_ci	if (!kn->iattr)
458c2ecf20Sopenharmony_ci		goto out_unlock;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	/* assign default attributes */
488c2ecf20Sopenharmony_ci	kn->iattr->ia_uid = GLOBAL_ROOT_UID;
498c2ecf20Sopenharmony_ci	kn->iattr->ia_gid = GLOBAL_ROOT_GID;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	ktime_get_real_ts64(&kn->iattr->ia_atime);
528c2ecf20Sopenharmony_ci	kn->iattr->ia_mtime = kn->iattr->ia_atime;
538c2ecf20Sopenharmony_ci	kn->iattr->ia_ctime = kn->iattr->ia_atime;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	simple_xattrs_init(&kn->iattr->xattrs);
568c2ecf20Sopenharmony_ci	atomic_set(&kn->iattr->nr_user_xattrs, 0);
578c2ecf20Sopenharmony_ci	atomic_set(&kn->iattr->user_xattr_size, 0);
588c2ecf20Sopenharmony_ciout_unlock:
598c2ecf20Sopenharmony_ci	ret = kn->iattr;
608c2ecf20Sopenharmony_ci	mutex_unlock(&iattr_mutex);
618c2ecf20Sopenharmony_ci	return ret;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	return __kernfs_iattrs(kn, 1);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic struct kernfs_iattrs *kernfs_iattrs_noalloc(struct kernfs_node *kn)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	return __kernfs_iattrs(kn, 0);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ciint __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct kernfs_iattrs *attrs;
778c2ecf20Sopenharmony_ci	unsigned int ia_valid = iattr->ia_valid;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	attrs = kernfs_iattrs(kn);
808c2ecf20Sopenharmony_ci	if (!attrs)
818c2ecf20Sopenharmony_ci		return -ENOMEM;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_UID)
848c2ecf20Sopenharmony_ci		attrs->ia_uid = iattr->ia_uid;
858c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_GID)
868c2ecf20Sopenharmony_ci		attrs->ia_gid = iattr->ia_gid;
878c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_ATIME)
888c2ecf20Sopenharmony_ci		attrs->ia_atime = iattr->ia_atime;
898c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_MTIME)
908c2ecf20Sopenharmony_ci		attrs->ia_mtime = iattr->ia_mtime;
918c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_CTIME)
928c2ecf20Sopenharmony_ci		attrs->ia_ctime = iattr->ia_ctime;
938c2ecf20Sopenharmony_ci	if (ia_valid & ATTR_MODE)
948c2ecf20Sopenharmony_ci		kn->mode = iattr->ia_mode;
958c2ecf20Sopenharmony_ci	return 0;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/**
998c2ecf20Sopenharmony_ci * kernfs_setattr - set iattr on a node
1008c2ecf20Sopenharmony_ci * @kn: target node
1018c2ecf20Sopenharmony_ci * @iattr: iattr to set
1028c2ecf20Sopenharmony_ci *
1038c2ecf20Sopenharmony_ci * Returns 0 on success, -errno on failure.
1048c2ecf20Sopenharmony_ci */
1058c2ecf20Sopenharmony_ciint kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	int ret;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	mutex_lock(&kernfs_mutex);
1108c2ecf20Sopenharmony_ci	ret = __kernfs_setattr(kn, iattr);
1118c2ecf20Sopenharmony_ci	mutex_unlock(&kernfs_mutex);
1128c2ecf20Sopenharmony_ci	return ret;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciint kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
1188c2ecf20Sopenharmony_ci	struct kernfs_node *kn = inode->i_private;
1198c2ecf20Sopenharmony_ci	int error;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	if (!kn)
1228c2ecf20Sopenharmony_ci		return -EINVAL;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	mutex_lock(&kernfs_mutex);
1258c2ecf20Sopenharmony_ci	error = setattr_prepare(dentry, iattr);
1268c2ecf20Sopenharmony_ci	if (error)
1278c2ecf20Sopenharmony_ci		goto out;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	error = __kernfs_setattr(kn, iattr);
1308c2ecf20Sopenharmony_ci	if (error)
1318c2ecf20Sopenharmony_ci		goto out;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	/* this ignores size changes */
1348c2ecf20Sopenharmony_ci	setattr_copy(inode, iattr);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ciout:
1378c2ecf20Sopenharmony_ci	mutex_unlock(&kernfs_mutex);
1388c2ecf20Sopenharmony_ci	return error;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cissize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct kernfs_node *kn = kernfs_dentry_node(dentry);
1448c2ecf20Sopenharmony_ci	struct kernfs_iattrs *attrs;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	attrs = kernfs_iattrs(kn);
1478c2ecf20Sopenharmony_ci	if (!attrs)
1488c2ecf20Sopenharmony_ci		return -ENOMEM;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return simple_xattr_list(d_inode(dentry), &attrs->xattrs, buf, size);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic inline void set_default_inode_attr(struct inode *inode, umode_t mode)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	inode->i_mode = mode;
1568c2ecf20Sopenharmony_ci	inode->i_atime = inode->i_mtime =
1578c2ecf20Sopenharmony_ci		inode->i_ctime = current_time(inode);
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic inline void set_inode_attr(struct inode *inode,
1618c2ecf20Sopenharmony_ci				  struct kernfs_iattrs *attrs)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	inode->i_uid = attrs->ia_uid;
1648c2ecf20Sopenharmony_ci	inode->i_gid = attrs->ia_gid;
1658c2ecf20Sopenharmony_ci	inode->i_atime = attrs->ia_atime;
1668c2ecf20Sopenharmony_ci	inode->i_mtime = attrs->ia_mtime;
1678c2ecf20Sopenharmony_ci	inode->i_ctime = attrs->ia_ctime;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	struct kernfs_iattrs *attrs = kn->iattr;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	inode->i_mode = kn->mode;
1758c2ecf20Sopenharmony_ci	if (attrs)
1768c2ecf20Sopenharmony_ci		/*
1778c2ecf20Sopenharmony_ci		 * kernfs_node has non-default attributes get them from
1788c2ecf20Sopenharmony_ci		 * persistent copy in kernfs_node.
1798c2ecf20Sopenharmony_ci		 */
1808c2ecf20Sopenharmony_ci		set_inode_attr(inode, attrs);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (kernfs_type(kn) == KERNFS_DIR)
1838c2ecf20Sopenharmony_ci		set_nlink(inode, kn->dir.subdirs + 2);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ciint kernfs_iop_getattr(const struct path *path, struct kstat *stat,
1878c2ecf20Sopenharmony_ci		       u32 request_mask, unsigned int query_flags)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(path->dentry);
1908c2ecf20Sopenharmony_ci	struct kernfs_node *kn = inode->i_private;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	mutex_lock(&kernfs_mutex);
1938c2ecf20Sopenharmony_ci	kernfs_refresh_inode(kn, inode);
1948c2ecf20Sopenharmony_ci	mutex_unlock(&kernfs_mutex);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	generic_fillattr(inode, stat);
1978c2ecf20Sopenharmony_ci	return 0;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	kernfs_get(kn);
2038c2ecf20Sopenharmony_ci	inode->i_private = kn;
2048c2ecf20Sopenharmony_ci	inode->i_mapping->a_ops = &kernfs_aops;
2058c2ecf20Sopenharmony_ci	inode->i_op = &kernfs_iops;
2068c2ecf20Sopenharmony_ci	inode->i_generation = kernfs_gen(kn);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	set_default_inode_attr(inode, kn->mode);
2098c2ecf20Sopenharmony_ci	kernfs_refresh_inode(kn, inode);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* initialize inode according to type */
2128c2ecf20Sopenharmony_ci	switch (kernfs_type(kn)) {
2138c2ecf20Sopenharmony_ci	case KERNFS_DIR:
2148c2ecf20Sopenharmony_ci		inode->i_op = &kernfs_dir_iops;
2158c2ecf20Sopenharmony_ci		inode->i_fop = &kernfs_dir_fops;
2168c2ecf20Sopenharmony_ci		if (kn->flags & KERNFS_EMPTY_DIR)
2178c2ecf20Sopenharmony_ci			make_empty_dir_inode(inode);
2188c2ecf20Sopenharmony_ci		break;
2198c2ecf20Sopenharmony_ci	case KERNFS_FILE:
2208c2ecf20Sopenharmony_ci		inode->i_size = kn->attr.size;
2218c2ecf20Sopenharmony_ci		inode->i_fop = &kernfs_file_fops;
2228c2ecf20Sopenharmony_ci		break;
2238c2ecf20Sopenharmony_ci	case KERNFS_LINK:
2248c2ecf20Sopenharmony_ci		inode->i_op = &kernfs_symlink_iops;
2258c2ecf20Sopenharmony_ci		break;
2268c2ecf20Sopenharmony_ci	default:
2278c2ecf20Sopenharmony_ci		BUG();
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	unlock_new_inode(inode);
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/**
2348c2ecf20Sopenharmony_ci *	kernfs_get_inode - get inode for kernfs_node
2358c2ecf20Sopenharmony_ci *	@sb: super block
2368c2ecf20Sopenharmony_ci *	@kn: kernfs_node to allocate inode for
2378c2ecf20Sopenharmony_ci *
2388c2ecf20Sopenharmony_ci *	Get inode for @kn.  If such inode doesn't exist, a new inode is
2398c2ecf20Sopenharmony_ci *	allocated and basics are initialized.  New inode is returned
2408c2ecf20Sopenharmony_ci *	locked.
2418c2ecf20Sopenharmony_ci *
2428c2ecf20Sopenharmony_ci *	LOCKING:
2438c2ecf20Sopenharmony_ci *	Kernel thread context (may sleep).
2448c2ecf20Sopenharmony_ci *
2458c2ecf20Sopenharmony_ci *	RETURNS:
2468c2ecf20Sopenharmony_ci *	Pointer to allocated inode on success, NULL on failure.
2478c2ecf20Sopenharmony_ci */
2488c2ecf20Sopenharmony_cistruct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	struct inode *inode;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	inode = iget_locked(sb, kernfs_ino(kn));
2538c2ecf20Sopenharmony_ci	if (inode && (inode->i_state & I_NEW))
2548c2ecf20Sopenharmony_ci		kernfs_init_inode(kn, inode);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	return inode;
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/*
2608c2ecf20Sopenharmony_ci * The kernfs_node serves as both an inode and a directory entry for
2618c2ecf20Sopenharmony_ci * kernfs.  To prevent the kernfs inode numbers from being freed
2628c2ecf20Sopenharmony_ci * prematurely we take a reference to kernfs_node from the kernfs inode.  A
2638c2ecf20Sopenharmony_ci * super_operations.evict_inode() implementation is needed to drop that
2648c2ecf20Sopenharmony_ci * reference upon inode destruction.
2658c2ecf20Sopenharmony_ci */
2668c2ecf20Sopenharmony_civoid kernfs_evict_inode(struct inode *inode)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct kernfs_node *kn = inode->i_private;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	truncate_inode_pages_final(&inode->i_data);
2718c2ecf20Sopenharmony_ci	clear_inode(inode);
2728c2ecf20Sopenharmony_ci	kernfs_put(kn);
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ciint kernfs_iop_permission(struct inode *inode, int mask)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	struct kernfs_node *kn;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (mask & MAY_NOT_BLOCK)
2808c2ecf20Sopenharmony_ci		return -ECHILD;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	kn = inode->i_private;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	mutex_lock(&kernfs_mutex);
2858c2ecf20Sopenharmony_ci	kernfs_refresh_inode(kn, inode);
2868c2ecf20Sopenharmony_ci	mutex_unlock(&kernfs_mutex);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	return generic_permission(inode, mask);
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ciint kernfs_xattr_get(struct kernfs_node *kn, const char *name,
2928c2ecf20Sopenharmony_ci		     void *value, size_t size)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct kernfs_iattrs *attrs = kernfs_iattrs_noalloc(kn);
2958c2ecf20Sopenharmony_ci	if (!attrs)
2968c2ecf20Sopenharmony_ci		return -ENODATA;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	return simple_xattr_get(&attrs->xattrs, name, value, size);
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ciint kernfs_xattr_set(struct kernfs_node *kn, const char *name,
3028c2ecf20Sopenharmony_ci		     const void *value, size_t size, int flags)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct kernfs_iattrs *attrs = kernfs_iattrs(kn);
3058c2ecf20Sopenharmony_ci	if (!attrs)
3068c2ecf20Sopenharmony_ci		return -ENOMEM;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	return simple_xattr_set(&attrs->xattrs, name, value, size, flags, NULL);
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic int kernfs_vfs_xattr_get(const struct xattr_handler *handler,
3128c2ecf20Sopenharmony_ci				struct dentry *unused, struct inode *inode,
3138c2ecf20Sopenharmony_ci				const char *suffix, void *value, size_t size)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	const char *name = xattr_full_name(handler, suffix);
3168c2ecf20Sopenharmony_ci	struct kernfs_node *kn = inode->i_private;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return kernfs_xattr_get(kn, name, value, size);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic int kernfs_vfs_xattr_set(const struct xattr_handler *handler,
3228c2ecf20Sopenharmony_ci				struct dentry *unused, struct inode *inode,
3238c2ecf20Sopenharmony_ci				const char *suffix, const void *value,
3248c2ecf20Sopenharmony_ci				size_t size, int flags)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	const char *name = xattr_full_name(handler, suffix);
3278c2ecf20Sopenharmony_ci	struct kernfs_node *kn = inode->i_private;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return kernfs_xattr_set(kn, name, value, size, flags);
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int kernfs_vfs_user_xattr_add(struct kernfs_node *kn,
3338c2ecf20Sopenharmony_ci				     const char *full_name,
3348c2ecf20Sopenharmony_ci				     struct simple_xattrs *xattrs,
3358c2ecf20Sopenharmony_ci				     const void *value, size_t size, int flags)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	atomic_t *sz = &kn->iattr->user_xattr_size;
3388c2ecf20Sopenharmony_ci	atomic_t *nr = &kn->iattr->nr_user_xattrs;
3398c2ecf20Sopenharmony_ci	ssize_t removed_size;
3408c2ecf20Sopenharmony_ci	int ret;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (atomic_inc_return(nr) > KERNFS_MAX_USER_XATTRS) {
3438c2ecf20Sopenharmony_ci		ret = -ENOSPC;
3448c2ecf20Sopenharmony_ci		goto dec_count_out;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (atomic_add_return(size, sz) > KERNFS_USER_XATTR_SIZE_LIMIT) {
3488c2ecf20Sopenharmony_ci		ret = -ENOSPC;
3498c2ecf20Sopenharmony_ci		goto dec_size_out;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	ret = simple_xattr_set(xattrs, full_name, value, size, flags,
3538c2ecf20Sopenharmony_ci			       &removed_size);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	if (!ret && removed_size >= 0)
3568c2ecf20Sopenharmony_ci		size = removed_size;
3578c2ecf20Sopenharmony_ci	else if (!ret)
3588c2ecf20Sopenharmony_ci		return 0;
3598c2ecf20Sopenharmony_cidec_size_out:
3608c2ecf20Sopenharmony_ci	atomic_sub(size, sz);
3618c2ecf20Sopenharmony_cidec_count_out:
3628c2ecf20Sopenharmony_ci	atomic_dec(nr);
3638c2ecf20Sopenharmony_ci	return ret;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic int kernfs_vfs_user_xattr_rm(struct kernfs_node *kn,
3678c2ecf20Sopenharmony_ci				    const char *full_name,
3688c2ecf20Sopenharmony_ci				    struct simple_xattrs *xattrs,
3698c2ecf20Sopenharmony_ci				    const void *value, size_t size, int flags)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	atomic_t *sz = &kn->iattr->user_xattr_size;
3728c2ecf20Sopenharmony_ci	atomic_t *nr = &kn->iattr->nr_user_xattrs;
3738c2ecf20Sopenharmony_ci	ssize_t removed_size;
3748c2ecf20Sopenharmony_ci	int ret;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	ret = simple_xattr_set(xattrs, full_name, value, size, flags,
3778c2ecf20Sopenharmony_ci			       &removed_size);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	if (removed_size >= 0) {
3808c2ecf20Sopenharmony_ci		atomic_sub(removed_size, sz);
3818c2ecf20Sopenharmony_ci		atomic_dec(nr);
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return ret;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic int kernfs_vfs_user_xattr_set(const struct xattr_handler *handler,
3888c2ecf20Sopenharmony_ci				     struct dentry *unused, struct inode *inode,
3898c2ecf20Sopenharmony_ci				     const char *suffix, const void *value,
3908c2ecf20Sopenharmony_ci				     size_t size, int flags)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	const char *full_name = xattr_full_name(handler, suffix);
3938c2ecf20Sopenharmony_ci	struct kernfs_node *kn = inode->i_private;
3948c2ecf20Sopenharmony_ci	struct kernfs_iattrs *attrs;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (!(kernfs_root(kn)->flags & KERNFS_ROOT_SUPPORT_USER_XATTR))
3978c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	attrs = kernfs_iattrs(kn);
4008c2ecf20Sopenharmony_ci	if (!attrs)
4018c2ecf20Sopenharmony_ci		return -ENOMEM;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	if (value)
4048c2ecf20Sopenharmony_ci		return kernfs_vfs_user_xattr_add(kn, full_name, &attrs->xattrs,
4058c2ecf20Sopenharmony_ci						 value, size, flags);
4068c2ecf20Sopenharmony_ci	else
4078c2ecf20Sopenharmony_ci		return kernfs_vfs_user_xattr_rm(kn, full_name, &attrs->xattrs,
4088c2ecf20Sopenharmony_ci						value, size, flags);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic const struct xattr_handler kernfs_trusted_xattr_handler = {
4138c2ecf20Sopenharmony_ci	.prefix = XATTR_TRUSTED_PREFIX,
4148c2ecf20Sopenharmony_ci	.get = kernfs_vfs_xattr_get,
4158c2ecf20Sopenharmony_ci	.set = kernfs_vfs_xattr_set,
4168c2ecf20Sopenharmony_ci};
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic const struct xattr_handler kernfs_security_xattr_handler = {
4198c2ecf20Sopenharmony_ci	.prefix = XATTR_SECURITY_PREFIX,
4208c2ecf20Sopenharmony_ci	.get = kernfs_vfs_xattr_get,
4218c2ecf20Sopenharmony_ci	.set = kernfs_vfs_xattr_set,
4228c2ecf20Sopenharmony_ci};
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic const struct xattr_handler kernfs_user_xattr_handler = {
4258c2ecf20Sopenharmony_ci	.prefix = XATTR_USER_PREFIX,
4268c2ecf20Sopenharmony_ci	.get = kernfs_vfs_xattr_get,
4278c2ecf20Sopenharmony_ci	.set = kernfs_vfs_user_xattr_set,
4288c2ecf20Sopenharmony_ci};
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ciconst struct xattr_handler *kernfs_xattr_handlers[] = {
4318c2ecf20Sopenharmony_ci	&kernfs_trusted_xattr_handler,
4328c2ecf20Sopenharmony_ci	&kernfs_security_xattr_handler,
4338c2ecf20Sopenharmony_ci	&kernfs_user_xattr_handler,
4348c2ecf20Sopenharmony_ci	NULL
4358c2ecf20Sopenharmony_ci};
436