162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/kernfs/inode.c - kernfs inode implementation 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2001-3 Patrick Mochel 662306a36Sopenharmony_ci * Copyright (c) 2007 SUSE Linux Products GmbH 762306a36Sopenharmony_ci * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/pagemap.h> 1162306a36Sopenharmony_ci#include <linux/backing-dev.h> 1262306a36Sopenharmony_ci#include <linux/capability.h> 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/xattr.h> 1662306a36Sopenharmony_ci#include <linux/security.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "kernfs-internal.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic const struct inode_operations kernfs_iops = { 2162306a36Sopenharmony_ci .permission = kernfs_iop_permission, 2262306a36Sopenharmony_ci .setattr = kernfs_iop_setattr, 2362306a36Sopenharmony_ci .getattr = kernfs_iop_getattr, 2462306a36Sopenharmony_ci .listxattr = kernfs_iop_listxattr, 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic struct kernfs_iattrs *__kernfs_iattrs(struct kernfs_node *kn, int alloc) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci static DEFINE_MUTEX(iattr_mutex); 3062306a36Sopenharmony_ci struct kernfs_iattrs *ret; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci mutex_lock(&iattr_mutex); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (kn->iattr || !alloc) 3562306a36Sopenharmony_ci goto out_unlock; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci kn->iattr = kmem_cache_zalloc(kernfs_iattrs_cache, GFP_KERNEL); 3862306a36Sopenharmony_ci if (!kn->iattr) 3962306a36Sopenharmony_ci goto out_unlock; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* assign default attributes */ 4262306a36Sopenharmony_ci kn->iattr->ia_uid = GLOBAL_ROOT_UID; 4362306a36Sopenharmony_ci kn->iattr->ia_gid = GLOBAL_ROOT_GID; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci ktime_get_real_ts64(&kn->iattr->ia_atime); 4662306a36Sopenharmony_ci kn->iattr->ia_mtime = kn->iattr->ia_atime; 4762306a36Sopenharmony_ci kn->iattr->ia_ctime = kn->iattr->ia_atime; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci simple_xattrs_init(&kn->iattr->xattrs); 5062306a36Sopenharmony_ci atomic_set(&kn->iattr->nr_user_xattrs, 0); 5162306a36Sopenharmony_ci atomic_set(&kn->iattr->user_xattr_size, 0); 5262306a36Sopenharmony_ciout_unlock: 5362306a36Sopenharmony_ci ret = kn->iattr; 5462306a36Sopenharmony_ci mutex_unlock(&iattr_mutex); 5562306a36Sopenharmony_ci return ret; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci return __kernfs_iattrs(kn, 1); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic struct kernfs_iattrs *kernfs_iattrs_noalloc(struct kernfs_node *kn) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci return __kernfs_iattrs(kn, 0); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ciint __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct kernfs_iattrs *attrs; 7162306a36Sopenharmony_ci unsigned int ia_valid = iattr->ia_valid; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci attrs = kernfs_iattrs(kn); 7462306a36Sopenharmony_ci if (!attrs) 7562306a36Sopenharmony_ci return -ENOMEM; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (ia_valid & ATTR_UID) 7862306a36Sopenharmony_ci attrs->ia_uid = iattr->ia_uid; 7962306a36Sopenharmony_ci if (ia_valid & ATTR_GID) 8062306a36Sopenharmony_ci attrs->ia_gid = iattr->ia_gid; 8162306a36Sopenharmony_ci if (ia_valid & ATTR_ATIME) 8262306a36Sopenharmony_ci attrs->ia_atime = iattr->ia_atime; 8362306a36Sopenharmony_ci if (ia_valid & ATTR_MTIME) 8462306a36Sopenharmony_ci attrs->ia_mtime = iattr->ia_mtime; 8562306a36Sopenharmony_ci if (ia_valid & ATTR_CTIME) 8662306a36Sopenharmony_ci attrs->ia_ctime = iattr->ia_ctime; 8762306a36Sopenharmony_ci if (ia_valid & ATTR_MODE) 8862306a36Sopenharmony_ci kn->mode = iattr->ia_mode; 8962306a36Sopenharmony_ci return 0; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/** 9362306a36Sopenharmony_ci * kernfs_setattr - set iattr on a node 9462306a36Sopenharmony_ci * @kn: target node 9562306a36Sopenharmony_ci * @iattr: iattr to set 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * Return: %0 on success, -errno on failure. 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ciint kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci int ret; 10262306a36Sopenharmony_ci struct kernfs_root *root = kernfs_root(kn); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci down_write(&root->kernfs_iattr_rwsem); 10562306a36Sopenharmony_ci ret = __kernfs_setattr(kn, iattr); 10662306a36Sopenharmony_ci up_write(&root->kernfs_iattr_rwsem); 10762306a36Sopenharmony_ci return ret; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ciint kernfs_iop_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 11162306a36Sopenharmony_ci struct iattr *iattr) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 11462306a36Sopenharmony_ci struct kernfs_node *kn = inode->i_private; 11562306a36Sopenharmony_ci struct kernfs_root *root; 11662306a36Sopenharmony_ci int error; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (!kn) 11962306a36Sopenharmony_ci return -EINVAL; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci root = kernfs_root(kn); 12262306a36Sopenharmony_ci down_write(&root->kernfs_iattr_rwsem); 12362306a36Sopenharmony_ci error = setattr_prepare(&nop_mnt_idmap, dentry, iattr); 12462306a36Sopenharmony_ci if (error) 12562306a36Sopenharmony_ci goto out; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci error = __kernfs_setattr(kn, iattr); 12862306a36Sopenharmony_ci if (error) 12962306a36Sopenharmony_ci goto out; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* this ignores size changes */ 13262306a36Sopenharmony_ci setattr_copy(&nop_mnt_idmap, inode, iattr); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ciout: 13562306a36Sopenharmony_ci up_write(&root->kernfs_iattr_rwsem); 13662306a36Sopenharmony_ci return error; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cissize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct kernfs_node *kn = kernfs_dentry_node(dentry); 14262306a36Sopenharmony_ci struct kernfs_iattrs *attrs; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci attrs = kernfs_iattrs(kn); 14562306a36Sopenharmony_ci if (!attrs) 14662306a36Sopenharmony_ci return -ENOMEM; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return simple_xattr_list(d_inode(dentry), &attrs->xattrs, buf, size); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic inline void set_default_inode_attr(struct inode *inode, umode_t mode) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci inode->i_mode = mode; 15462306a36Sopenharmony_ci inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic inline void set_inode_attr(struct inode *inode, 15862306a36Sopenharmony_ci struct kernfs_iattrs *attrs) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci inode->i_uid = attrs->ia_uid; 16162306a36Sopenharmony_ci inode->i_gid = attrs->ia_gid; 16262306a36Sopenharmony_ci inode->i_atime = attrs->ia_atime; 16362306a36Sopenharmony_ci inode->i_mtime = attrs->ia_mtime; 16462306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, attrs->ia_ctime); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct kernfs_iattrs *attrs = kn->iattr; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci inode->i_mode = kn->mode; 17262306a36Sopenharmony_ci if (attrs) 17362306a36Sopenharmony_ci /* 17462306a36Sopenharmony_ci * kernfs_node has non-default attributes get them from 17562306a36Sopenharmony_ci * persistent copy in kernfs_node. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci set_inode_attr(inode, attrs); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (kernfs_type(kn) == KERNFS_DIR) 18062306a36Sopenharmony_ci set_nlink(inode, kn->dir.subdirs + 2); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ciint kernfs_iop_getattr(struct mnt_idmap *idmap, 18462306a36Sopenharmony_ci const struct path *path, struct kstat *stat, 18562306a36Sopenharmony_ci u32 request_mask, unsigned int query_flags) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 18862306a36Sopenharmony_ci struct kernfs_node *kn = inode->i_private; 18962306a36Sopenharmony_ci struct kernfs_root *root = kernfs_root(kn); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci down_read(&root->kernfs_iattr_rwsem); 19262306a36Sopenharmony_ci kernfs_refresh_inode(kn, inode); 19362306a36Sopenharmony_ci generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); 19462306a36Sopenharmony_ci up_read(&root->kernfs_iattr_rwsem); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci kernfs_get(kn); 20262306a36Sopenharmony_ci inode->i_private = kn; 20362306a36Sopenharmony_ci inode->i_mapping->a_ops = &ram_aops; 20462306a36Sopenharmony_ci inode->i_op = &kernfs_iops; 20562306a36Sopenharmony_ci inode->i_generation = kernfs_gen(kn); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci set_default_inode_attr(inode, kn->mode); 20862306a36Sopenharmony_ci kernfs_refresh_inode(kn, inode); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* initialize inode according to type */ 21162306a36Sopenharmony_ci switch (kernfs_type(kn)) { 21262306a36Sopenharmony_ci case KERNFS_DIR: 21362306a36Sopenharmony_ci inode->i_op = &kernfs_dir_iops; 21462306a36Sopenharmony_ci inode->i_fop = &kernfs_dir_fops; 21562306a36Sopenharmony_ci if (kn->flags & KERNFS_EMPTY_DIR) 21662306a36Sopenharmony_ci make_empty_dir_inode(inode); 21762306a36Sopenharmony_ci break; 21862306a36Sopenharmony_ci case KERNFS_FILE: 21962306a36Sopenharmony_ci inode->i_size = kn->attr.size; 22062306a36Sopenharmony_ci inode->i_fop = &kernfs_file_fops; 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci case KERNFS_LINK: 22362306a36Sopenharmony_ci inode->i_op = &kernfs_symlink_iops; 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci default: 22662306a36Sopenharmony_ci BUG(); 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci unlock_new_inode(inode); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci/** 23362306a36Sopenharmony_ci * kernfs_get_inode - get inode for kernfs_node 23462306a36Sopenharmony_ci * @sb: super block 23562306a36Sopenharmony_ci * @kn: kernfs_node to allocate inode for 23662306a36Sopenharmony_ci * 23762306a36Sopenharmony_ci * Get inode for @kn. If such inode doesn't exist, a new inode is 23862306a36Sopenharmony_ci * allocated and basics are initialized. New inode is returned 23962306a36Sopenharmony_ci * locked. 24062306a36Sopenharmony_ci * 24162306a36Sopenharmony_ci * Locking: 24262306a36Sopenharmony_ci * Kernel thread context (may sleep). 24362306a36Sopenharmony_ci * 24462306a36Sopenharmony_ci * Return: 24562306a36Sopenharmony_ci * Pointer to allocated inode on success, %NULL on failure. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_cistruct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct inode *inode; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci inode = iget_locked(sb, kernfs_ino(kn)); 25262306a36Sopenharmony_ci if (inode && (inode->i_state & I_NEW)) 25362306a36Sopenharmony_ci kernfs_init_inode(kn, inode); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return inode; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* 25962306a36Sopenharmony_ci * The kernfs_node serves as both an inode and a directory entry for 26062306a36Sopenharmony_ci * kernfs. To prevent the kernfs inode numbers from being freed 26162306a36Sopenharmony_ci * prematurely we take a reference to kernfs_node from the kernfs inode. A 26262306a36Sopenharmony_ci * super_operations.evict_inode() implementation is needed to drop that 26362306a36Sopenharmony_ci * reference upon inode destruction. 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_civoid kernfs_evict_inode(struct inode *inode) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct kernfs_node *kn = inode->i_private; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci truncate_inode_pages_final(&inode->i_data); 27062306a36Sopenharmony_ci clear_inode(inode); 27162306a36Sopenharmony_ci kernfs_put(kn); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ciint kernfs_iop_permission(struct mnt_idmap *idmap, 27562306a36Sopenharmony_ci struct inode *inode, int mask) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct kernfs_node *kn; 27862306a36Sopenharmony_ci struct kernfs_root *root; 27962306a36Sopenharmony_ci int ret; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (mask & MAY_NOT_BLOCK) 28262306a36Sopenharmony_ci return -ECHILD; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci kn = inode->i_private; 28562306a36Sopenharmony_ci root = kernfs_root(kn); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci down_read(&root->kernfs_iattr_rwsem); 28862306a36Sopenharmony_ci kernfs_refresh_inode(kn, inode); 28962306a36Sopenharmony_ci ret = generic_permission(&nop_mnt_idmap, inode, mask); 29062306a36Sopenharmony_ci up_read(&root->kernfs_iattr_rwsem); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return ret; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ciint kernfs_xattr_get(struct kernfs_node *kn, const char *name, 29662306a36Sopenharmony_ci void *value, size_t size) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct kernfs_iattrs *attrs = kernfs_iattrs_noalloc(kn); 29962306a36Sopenharmony_ci if (!attrs) 30062306a36Sopenharmony_ci return -ENODATA; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return simple_xattr_get(&attrs->xattrs, name, value, size); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ciint kernfs_xattr_set(struct kernfs_node *kn, const char *name, 30662306a36Sopenharmony_ci const void *value, size_t size, int flags) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct simple_xattr *old_xattr; 30962306a36Sopenharmony_ci struct kernfs_iattrs *attrs = kernfs_iattrs(kn); 31062306a36Sopenharmony_ci if (!attrs) 31162306a36Sopenharmony_ci return -ENOMEM; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci old_xattr = simple_xattr_set(&attrs->xattrs, name, value, size, flags); 31462306a36Sopenharmony_ci if (IS_ERR(old_xattr)) 31562306a36Sopenharmony_ci return PTR_ERR(old_xattr); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci simple_xattr_free(old_xattr); 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int kernfs_vfs_xattr_get(const struct xattr_handler *handler, 32262306a36Sopenharmony_ci struct dentry *unused, struct inode *inode, 32362306a36Sopenharmony_ci const char *suffix, void *value, size_t size) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci const char *name = xattr_full_name(handler, suffix); 32662306a36Sopenharmony_ci struct kernfs_node *kn = inode->i_private; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci return kernfs_xattr_get(kn, name, value, size); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int kernfs_vfs_xattr_set(const struct xattr_handler *handler, 33262306a36Sopenharmony_ci struct mnt_idmap *idmap, 33362306a36Sopenharmony_ci struct dentry *unused, struct inode *inode, 33462306a36Sopenharmony_ci const char *suffix, const void *value, 33562306a36Sopenharmony_ci size_t size, int flags) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci const char *name = xattr_full_name(handler, suffix); 33862306a36Sopenharmony_ci struct kernfs_node *kn = inode->i_private; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return kernfs_xattr_set(kn, name, value, size, flags); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int kernfs_vfs_user_xattr_add(struct kernfs_node *kn, 34462306a36Sopenharmony_ci const char *full_name, 34562306a36Sopenharmony_ci struct simple_xattrs *xattrs, 34662306a36Sopenharmony_ci const void *value, size_t size, int flags) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci atomic_t *sz = &kn->iattr->user_xattr_size; 34962306a36Sopenharmony_ci atomic_t *nr = &kn->iattr->nr_user_xattrs; 35062306a36Sopenharmony_ci struct simple_xattr *old_xattr; 35162306a36Sopenharmony_ci int ret; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (atomic_inc_return(nr) > KERNFS_MAX_USER_XATTRS) { 35462306a36Sopenharmony_ci ret = -ENOSPC; 35562306a36Sopenharmony_ci goto dec_count_out; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (atomic_add_return(size, sz) > KERNFS_USER_XATTR_SIZE_LIMIT) { 35962306a36Sopenharmony_ci ret = -ENOSPC; 36062306a36Sopenharmony_ci goto dec_size_out; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci old_xattr = simple_xattr_set(xattrs, full_name, value, size, flags); 36462306a36Sopenharmony_ci if (!old_xattr) 36562306a36Sopenharmony_ci return 0; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (IS_ERR(old_xattr)) { 36862306a36Sopenharmony_ci ret = PTR_ERR(old_xattr); 36962306a36Sopenharmony_ci goto dec_size_out; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci ret = 0; 37362306a36Sopenharmony_ci size = old_xattr->size; 37462306a36Sopenharmony_ci simple_xattr_free(old_xattr); 37562306a36Sopenharmony_cidec_size_out: 37662306a36Sopenharmony_ci atomic_sub(size, sz); 37762306a36Sopenharmony_cidec_count_out: 37862306a36Sopenharmony_ci atomic_dec(nr); 37962306a36Sopenharmony_ci return ret; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int kernfs_vfs_user_xattr_rm(struct kernfs_node *kn, 38362306a36Sopenharmony_ci const char *full_name, 38462306a36Sopenharmony_ci struct simple_xattrs *xattrs, 38562306a36Sopenharmony_ci const void *value, size_t size, int flags) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci atomic_t *sz = &kn->iattr->user_xattr_size; 38862306a36Sopenharmony_ci atomic_t *nr = &kn->iattr->nr_user_xattrs; 38962306a36Sopenharmony_ci struct simple_xattr *old_xattr; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci old_xattr = simple_xattr_set(xattrs, full_name, value, size, flags); 39262306a36Sopenharmony_ci if (!old_xattr) 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (IS_ERR(old_xattr)) 39662306a36Sopenharmony_ci return PTR_ERR(old_xattr); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci atomic_sub(old_xattr->size, sz); 39962306a36Sopenharmony_ci atomic_dec(nr); 40062306a36Sopenharmony_ci simple_xattr_free(old_xattr); 40162306a36Sopenharmony_ci return 0; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int kernfs_vfs_user_xattr_set(const struct xattr_handler *handler, 40562306a36Sopenharmony_ci struct mnt_idmap *idmap, 40662306a36Sopenharmony_ci struct dentry *unused, struct inode *inode, 40762306a36Sopenharmony_ci const char *suffix, const void *value, 40862306a36Sopenharmony_ci size_t size, int flags) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci const char *full_name = xattr_full_name(handler, suffix); 41162306a36Sopenharmony_ci struct kernfs_node *kn = inode->i_private; 41262306a36Sopenharmony_ci struct kernfs_iattrs *attrs; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (!(kernfs_root(kn)->flags & KERNFS_ROOT_SUPPORT_USER_XATTR)) 41562306a36Sopenharmony_ci return -EOPNOTSUPP; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci attrs = kernfs_iattrs(kn); 41862306a36Sopenharmony_ci if (!attrs) 41962306a36Sopenharmony_ci return -ENOMEM; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (value) 42262306a36Sopenharmony_ci return kernfs_vfs_user_xattr_add(kn, full_name, &attrs->xattrs, 42362306a36Sopenharmony_ci value, size, flags); 42462306a36Sopenharmony_ci else 42562306a36Sopenharmony_ci return kernfs_vfs_user_xattr_rm(kn, full_name, &attrs->xattrs, 42662306a36Sopenharmony_ci value, size, flags); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic const struct xattr_handler kernfs_trusted_xattr_handler = { 43162306a36Sopenharmony_ci .prefix = XATTR_TRUSTED_PREFIX, 43262306a36Sopenharmony_ci .get = kernfs_vfs_xattr_get, 43362306a36Sopenharmony_ci .set = kernfs_vfs_xattr_set, 43462306a36Sopenharmony_ci}; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic const struct xattr_handler kernfs_security_xattr_handler = { 43762306a36Sopenharmony_ci .prefix = XATTR_SECURITY_PREFIX, 43862306a36Sopenharmony_ci .get = kernfs_vfs_xattr_get, 43962306a36Sopenharmony_ci .set = kernfs_vfs_xattr_set, 44062306a36Sopenharmony_ci}; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic const struct xattr_handler kernfs_user_xattr_handler = { 44362306a36Sopenharmony_ci .prefix = XATTR_USER_PREFIX, 44462306a36Sopenharmony_ci .get = kernfs_vfs_xattr_get, 44562306a36Sopenharmony_ci .set = kernfs_vfs_user_xattr_set, 44662306a36Sopenharmony_ci}; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ciconst struct xattr_handler *kernfs_xattr_handlers[] = { 44962306a36Sopenharmony_ci &kernfs_trusted_xattr_handler, 45062306a36Sopenharmony_ci &kernfs_security_xattr_handler, 45162306a36Sopenharmony_ci &kernfs_user_xattr_handler, 45262306a36Sopenharmony_ci NULL 45362306a36Sopenharmony_ci}; 454