162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * inode.c - basic inode and dentry operations. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Based on sysfs: 662306a36Sopenharmony_ci * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * configfs Copyright (C) 2005 Oracle. All rights reserved. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Please see Documentation/filesystems/configfs.rst for more 1162306a36Sopenharmony_ci * information. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#undef DEBUG 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/pagemap.h> 1762306a36Sopenharmony_ci#include <linux/namei.h> 1862306a36Sopenharmony_ci#include <linux/backing-dev.h> 1962306a36Sopenharmony_ci#include <linux/capability.h> 2062306a36Sopenharmony_ci#include <linux/sched.h> 2162306a36Sopenharmony_ci#include <linux/lockdep.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/configfs.h> 2562306a36Sopenharmony_ci#include "configfs_internal.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#ifdef CONFIG_LOCKDEP 2862306a36Sopenharmony_cistatic struct lock_class_key default_group_class[MAX_LOCK_DEPTH]; 2962306a36Sopenharmony_ci#endif 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const struct inode_operations configfs_inode_operations ={ 3262306a36Sopenharmony_ci .setattr = configfs_setattr, 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciint configfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 3662306a36Sopenharmony_ci struct iattr *iattr) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct inode * inode = d_inode(dentry); 3962306a36Sopenharmony_ci struct configfs_dirent * sd = dentry->d_fsdata; 4062306a36Sopenharmony_ci struct iattr * sd_iattr; 4162306a36Sopenharmony_ci unsigned int ia_valid = iattr->ia_valid; 4262306a36Sopenharmony_ci int error; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (!sd) 4562306a36Sopenharmony_ci return -EINVAL; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci sd_iattr = sd->s_iattr; 4862306a36Sopenharmony_ci if (!sd_iattr) { 4962306a36Sopenharmony_ci /* setting attributes for the first time, allocate now */ 5062306a36Sopenharmony_ci sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); 5162306a36Sopenharmony_ci if (!sd_iattr) 5262306a36Sopenharmony_ci return -ENOMEM; 5362306a36Sopenharmony_ci /* assign default attributes */ 5462306a36Sopenharmony_ci sd_iattr->ia_mode = sd->s_mode; 5562306a36Sopenharmony_ci sd_iattr->ia_uid = GLOBAL_ROOT_UID; 5662306a36Sopenharmony_ci sd_iattr->ia_gid = GLOBAL_ROOT_GID; 5762306a36Sopenharmony_ci sd_iattr->ia_atime = sd_iattr->ia_mtime = 5862306a36Sopenharmony_ci sd_iattr->ia_ctime = current_time(inode); 5962306a36Sopenharmony_ci sd->s_iattr = sd_iattr; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci /* attributes were changed atleast once in past */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci error = simple_setattr(idmap, dentry, iattr); 6462306a36Sopenharmony_ci if (error) 6562306a36Sopenharmony_ci return error; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (ia_valid & ATTR_UID) 6862306a36Sopenharmony_ci sd_iattr->ia_uid = iattr->ia_uid; 6962306a36Sopenharmony_ci if (ia_valid & ATTR_GID) 7062306a36Sopenharmony_ci sd_iattr->ia_gid = iattr->ia_gid; 7162306a36Sopenharmony_ci if (ia_valid & ATTR_ATIME) 7262306a36Sopenharmony_ci sd_iattr->ia_atime = iattr->ia_atime; 7362306a36Sopenharmony_ci if (ia_valid & ATTR_MTIME) 7462306a36Sopenharmony_ci sd_iattr->ia_mtime = iattr->ia_mtime; 7562306a36Sopenharmony_ci if (ia_valid & ATTR_CTIME) 7662306a36Sopenharmony_ci sd_iattr->ia_ctime = iattr->ia_ctime; 7762306a36Sopenharmony_ci if (ia_valid & ATTR_MODE) { 7862306a36Sopenharmony_ci umode_t mode = iattr->ia_mode; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) 8162306a36Sopenharmony_ci mode &= ~S_ISGID; 8262306a36Sopenharmony_ci sd_iattr->ia_mode = sd->s_mode = mode; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return error; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic inline void set_default_inode_attr(struct inode * inode, umode_t mode) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci inode->i_mode = mode; 9162306a36Sopenharmony_ci inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic inline void set_inode_attr(struct inode * inode, struct iattr * iattr) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci inode->i_mode = iattr->ia_mode; 9762306a36Sopenharmony_ci inode->i_uid = iattr->ia_uid; 9862306a36Sopenharmony_ci inode->i_gid = iattr->ia_gid; 9962306a36Sopenharmony_ci inode->i_atime = iattr->ia_atime; 10062306a36Sopenharmony_ci inode->i_mtime = iattr->ia_mtime; 10162306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, iattr->ia_ctime); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistruct inode *configfs_new_inode(umode_t mode, struct configfs_dirent *sd, 10562306a36Sopenharmony_ci struct super_block *s) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct inode * inode = new_inode(s); 10862306a36Sopenharmony_ci if (inode) { 10962306a36Sopenharmony_ci inode->i_ino = get_next_ino(); 11062306a36Sopenharmony_ci inode->i_mapping->a_ops = &ram_aops; 11162306a36Sopenharmony_ci inode->i_op = &configfs_inode_operations; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (sd->s_iattr) { 11462306a36Sopenharmony_ci /* sysfs_dirent has non-default attributes 11562306a36Sopenharmony_ci * get them for the new inode from persistent copy 11662306a36Sopenharmony_ci * in sysfs_dirent 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci set_inode_attr(inode, sd->s_iattr); 11962306a36Sopenharmony_ci } else 12062306a36Sopenharmony_ci set_default_inode_attr(inode, mode); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci return inode; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#ifdef CONFIG_LOCKDEP 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic void configfs_set_inode_lock_class(struct configfs_dirent *sd, 12862306a36Sopenharmony_ci struct inode *inode) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci int depth = sd->s_depth; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (depth > 0) { 13362306a36Sopenharmony_ci if (depth <= ARRAY_SIZE(default_group_class)) { 13462306a36Sopenharmony_ci lockdep_set_class(&inode->i_rwsem, 13562306a36Sopenharmony_ci &default_group_class[depth - 1]); 13662306a36Sopenharmony_ci } else { 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * In practice the maximum level of locking depth is 13962306a36Sopenharmony_ci * already reached. Just inform about possible reasons. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci pr_info("Too many levels of inodes for the locking correctness validator.\n"); 14262306a36Sopenharmony_ci pr_info("Spurious warnings may appear.\n"); 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#else /* CONFIG_LOCKDEP */ 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic void configfs_set_inode_lock_class(struct configfs_dirent *sd, 15062306a36Sopenharmony_ci struct inode *inode) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#endif /* CONFIG_LOCKDEP */ 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistruct inode *configfs_create(struct dentry *dentry, umode_t mode) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct inode *inode = NULL; 15962306a36Sopenharmony_ci struct configfs_dirent *sd; 16062306a36Sopenharmony_ci struct inode *p_inode; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (!dentry) 16362306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (d_really_is_positive(dentry)) 16662306a36Sopenharmony_ci return ERR_PTR(-EEXIST); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci sd = dentry->d_fsdata; 16962306a36Sopenharmony_ci inode = configfs_new_inode(mode, sd, dentry->d_sb); 17062306a36Sopenharmony_ci if (!inode) 17162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci p_inode = d_inode(dentry->d_parent); 17462306a36Sopenharmony_ci p_inode->i_mtime = inode_set_ctime_current(p_inode); 17562306a36Sopenharmony_ci configfs_set_inode_lock_class(sd, inode); 17662306a36Sopenharmony_ci return inode; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* 18062306a36Sopenharmony_ci * Get the name for corresponding element represented by the given configfs_dirent 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ciconst unsigned char * configfs_get_name(struct configfs_dirent *sd) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct configfs_attribute *attr; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci BUG_ON(!sd || !sd->s_element); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* These always have a dentry, so use that */ 18962306a36Sopenharmony_ci if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK)) 19062306a36Sopenharmony_ci return sd->s_dentry->d_name.name; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (sd->s_type & (CONFIGFS_ITEM_ATTR | CONFIGFS_ITEM_BIN_ATTR)) { 19362306a36Sopenharmony_ci attr = sd->s_element; 19462306a36Sopenharmony_ci return attr->ca_name; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci return NULL; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* 20162306a36Sopenharmony_ci * Unhashes the dentry corresponding to given configfs_dirent 20262306a36Sopenharmony_ci * Called with parent inode's i_mutex held. 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_civoid configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct dentry * dentry = sd->s_dentry; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (dentry) { 20962306a36Sopenharmony_ci spin_lock(&dentry->d_lock); 21062306a36Sopenharmony_ci if (simple_positive(dentry)) { 21162306a36Sopenharmony_ci dget_dlock(dentry); 21262306a36Sopenharmony_ci __d_drop(dentry); 21362306a36Sopenharmony_ci spin_unlock(&dentry->d_lock); 21462306a36Sopenharmony_ci simple_unlink(d_inode(parent), dentry); 21562306a36Sopenharmony_ci } else 21662306a36Sopenharmony_ci spin_unlock(&dentry->d_lock); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_civoid configfs_hash_and_remove(struct dentry * dir, const char * name) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct configfs_dirent * sd; 22362306a36Sopenharmony_ci struct configfs_dirent * parent_sd = dir->d_fsdata; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (d_really_is_negative(dir)) 22662306a36Sopenharmony_ci /* no inode means this hasn't been made visible yet */ 22762306a36Sopenharmony_ci return; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci inode_lock(d_inode(dir)); 23062306a36Sopenharmony_ci list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { 23162306a36Sopenharmony_ci if (!sd->s_element) 23262306a36Sopenharmony_ci continue; 23362306a36Sopenharmony_ci if (!strcmp(configfs_get_name(sd), name)) { 23462306a36Sopenharmony_ci spin_lock(&configfs_dirent_lock); 23562306a36Sopenharmony_ci list_del_init(&sd->s_sibling); 23662306a36Sopenharmony_ci spin_unlock(&configfs_dirent_lock); 23762306a36Sopenharmony_ci configfs_drop_dentry(sd, dir); 23862306a36Sopenharmony_ci configfs_put(sd); 23962306a36Sopenharmony_ci break; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci inode_unlock(d_inode(dir)); 24362306a36Sopenharmony_ci} 244