18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*- 38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0: 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * inode.c - basic inode and dentry operations. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on sysfs: 88c2ecf20Sopenharmony_ci * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * configfs Copyright (C) 2005 Oracle. All rights reserved. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Please see Documentation/filesystems/configfs.rst for more 138c2ecf20Sopenharmony_ci * information. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#undef DEBUG 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 198c2ecf20Sopenharmony_ci#include <linux/namei.h> 208c2ecf20Sopenharmony_ci#include <linux/backing-dev.h> 218c2ecf20Sopenharmony_ci#include <linux/capability.h> 228c2ecf20Sopenharmony_ci#include <linux/sched.h> 238c2ecf20Sopenharmony_ci#include <linux/lockdep.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/configfs.h> 278c2ecf20Sopenharmony_ci#include "configfs_internal.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#ifdef CONFIG_LOCKDEP 308c2ecf20Sopenharmony_cistatic struct lock_class_key default_group_class[MAX_LOCK_DEPTH]; 318c2ecf20Sopenharmony_ci#endif 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic const struct address_space_operations configfs_aops = { 348c2ecf20Sopenharmony_ci .readpage = simple_readpage, 358c2ecf20Sopenharmony_ci .write_begin = simple_write_begin, 368c2ecf20Sopenharmony_ci .write_end = simple_write_end, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const struct inode_operations configfs_inode_operations ={ 408c2ecf20Sopenharmony_ci .setattr = configfs_setattr, 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciint configfs_setattr(struct dentry * dentry, struct iattr * iattr) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct inode * inode = d_inode(dentry); 468c2ecf20Sopenharmony_ci struct configfs_dirent * sd = dentry->d_fsdata; 478c2ecf20Sopenharmony_ci struct iattr * sd_iattr; 488c2ecf20Sopenharmony_ci unsigned int ia_valid = iattr->ia_valid; 498c2ecf20Sopenharmony_ci int error; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (!sd) 528c2ecf20Sopenharmony_ci return -EINVAL; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci sd_iattr = sd->s_iattr; 558c2ecf20Sopenharmony_ci if (!sd_iattr) { 568c2ecf20Sopenharmony_ci /* setting attributes for the first time, allocate now */ 578c2ecf20Sopenharmony_ci sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); 588c2ecf20Sopenharmony_ci if (!sd_iattr) 598c2ecf20Sopenharmony_ci return -ENOMEM; 608c2ecf20Sopenharmony_ci /* assign default attributes */ 618c2ecf20Sopenharmony_ci sd_iattr->ia_mode = sd->s_mode; 628c2ecf20Sopenharmony_ci sd_iattr->ia_uid = GLOBAL_ROOT_UID; 638c2ecf20Sopenharmony_ci sd_iattr->ia_gid = GLOBAL_ROOT_GID; 648c2ecf20Sopenharmony_ci sd_iattr->ia_atime = sd_iattr->ia_mtime = 658c2ecf20Sopenharmony_ci sd_iattr->ia_ctime = current_time(inode); 668c2ecf20Sopenharmony_ci sd->s_iattr = sd_iattr; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci /* attributes were changed atleast once in past */ 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci error = simple_setattr(dentry, iattr); 718c2ecf20Sopenharmony_ci if (error) 728c2ecf20Sopenharmony_ci return error; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (ia_valid & ATTR_UID) 758c2ecf20Sopenharmony_ci sd_iattr->ia_uid = iattr->ia_uid; 768c2ecf20Sopenharmony_ci if (ia_valid & ATTR_GID) 778c2ecf20Sopenharmony_ci sd_iattr->ia_gid = iattr->ia_gid; 788c2ecf20Sopenharmony_ci if (ia_valid & ATTR_ATIME) 798c2ecf20Sopenharmony_ci sd_iattr->ia_atime = iattr->ia_atime; 808c2ecf20Sopenharmony_ci if (ia_valid & ATTR_MTIME) 818c2ecf20Sopenharmony_ci sd_iattr->ia_mtime = iattr->ia_mtime; 828c2ecf20Sopenharmony_ci if (ia_valid & ATTR_CTIME) 838c2ecf20Sopenharmony_ci sd_iattr->ia_ctime = iattr->ia_ctime; 848c2ecf20Sopenharmony_ci if (ia_valid & ATTR_MODE) { 858c2ecf20Sopenharmony_ci umode_t mode = iattr->ia_mode; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) 888c2ecf20Sopenharmony_ci mode &= ~S_ISGID; 898c2ecf20Sopenharmony_ci sd_iattr->ia_mode = sd->s_mode = mode; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return error; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic inline void set_default_inode_attr(struct inode * inode, umode_t mode) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci inode->i_mode = mode; 988c2ecf20Sopenharmony_ci inode->i_atime = inode->i_mtime = 998c2ecf20Sopenharmony_ci inode->i_ctime = current_time(inode); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic inline void set_inode_attr(struct inode * inode, struct iattr * iattr) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci inode->i_mode = iattr->ia_mode; 1058c2ecf20Sopenharmony_ci inode->i_uid = iattr->ia_uid; 1068c2ecf20Sopenharmony_ci inode->i_gid = iattr->ia_gid; 1078c2ecf20Sopenharmony_ci inode->i_atime = iattr->ia_atime; 1088c2ecf20Sopenharmony_ci inode->i_mtime = iattr->ia_mtime; 1098c2ecf20Sopenharmony_ci inode->i_ctime = iattr->ia_ctime; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistruct inode *configfs_new_inode(umode_t mode, struct configfs_dirent *sd, 1138c2ecf20Sopenharmony_ci struct super_block *s) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct inode * inode = new_inode(s); 1168c2ecf20Sopenharmony_ci if (inode) { 1178c2ecf20Sopenharmony_ci inode->i_ino = get_next_ino(); 1188c2ecf20Sopenharmony_ci inode->i_mapping->a_ops = &configfs_aops; 1198c2ecf20Sopenharmony_ci inode->i_op = &configfs_inode_operations; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (sd->s_iattr) { 1228c2ecf20Sopenharmony_ci /* sysfs_dirent has non-default attributes 1238c2ecf20Sopenharmony_ci * get them for the new inode from persistent copy 1248c2ecf20Sopenharmony_ci * in sysfs_dirent 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci set_inode_attr(inode, sd->s_iattr); 1278c2ecf20Sopenharmony_ci } else 1288c2ecf20Sopenharmony_ci set_default_inode_attr(inode, mode); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci return inode; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#ifdef CONFIG_LOCKDEP 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic void configfs_set_inode_lock_class(struct configfs_dirent *sd, 1368c2ecf20Sopenharmony_ci struct inode *inode) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci int depth = sd->s_depth; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (depth > 0) { 1418c2ecf20Sopenharmony_ci if (depth <= ARRAY_SIZE(default_group_class)) { 1428c2ecf20Sopenharmony_ci lockdep_set_class(&inode->i_rwsem, 1438c2ecf20Sopenharmony_ci &default_group_class[depth - 1]); 1448c2ecf20Sopenharmony_ci } else { 1458c2ecf20Sopenharmony_ci /* 1468c2ecf20Sopenharmony_ci * In practice the maximum level of locking depth is 1478c2ecf20Sopenharmony_ci * already reached. Just inform about possible reasons. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci pr_info("Too many levels of inodes for the locking correctness validator.\n"); 1508c2ecf20Sopenharmony_ci pr_info("Spurious warnings may appear.\n"); 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#else /* CONFIG_LOCKDEP */ 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void configfs_set_inode_lock_class(struct configfs_dirent *sd, 1588c2ecf20Sopenharmony_ci struct inode *inode) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#endif /* CONFIG_LOCKDEP */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistruct inode *configfs_create(struct dentry *dentry, umode_t mode) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct inode *inode = NULL; 1678c2ecf20Sopenharmony_ci struct configfs_dirent *sd; 1688c2ecf20Sopenharmony_ci struct inode *p_inode; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (!dentry) 1718c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (d_really_is_positive(dentry)) 1748c2ecf20Sopenharmony_ci return ERR_PTR(-EEXIST); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci sd = dentry->d_fsdata; 1778c2ecf20Sopenharmony_ci inode = configfs_new_inode(mode, sd, dentry->d_sb); 1788c2ecf20Sopenharmony_ci if (!inode) 1798c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci p_inode = d_inode(dentry->d_parent); 1828c2ecf20Sopenharmony_ci p_inode->i_mtime = p_inode->i_ctime = current_time(p_inode); 1838c2ecf20Sopenharmony_ci configfs_set_inode_lock_class(sd, inode); 1848c2ecf20Sopenharmony_ci return inode; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* 1888c2ecf20Sopenharmony_ci * Get the name for corresponding element represented by the given configfs_dirent 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ciconst unsigned char * configfs_get_name(struct configfs_dirent *sd) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct configfs_attribute *attr; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci BUG_ON(!sd || !sd->s_element); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* These always have a dentry, so use that */ 1978c2ecf20Sopenharmony_ci if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK)) 1988c2ecf20Sopenharmony_ci return sd->s_dentry->d_name.name; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (sd->s_type & (CONFIGFS_ITEM_ATTR | CONFIGFS_ITEM_BIN_ATTR)) { 2018c2ecf20Sopenharmony_ci attr = sd->s_element; 2028c2ecf20Sopenharmony_ci return attr->ca_name; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci return NULL; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/* 2098c2ecf20Sopenharmony_ci * Unhashes the dentry corresponding to given configfs_dirent 2108c2ecf20Sopenharmony_ci * Called with parent inode's i_mutex held. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_civoid configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct dentry * dentry = sd->s_dentry; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (dentry) { 2178c2ecf20Sopenharmony_ci spin_lock(&dentry->d_lock); 2188c2ecf20Sopenharmony_ci if (simple_positive(dentry)) { 2198c2ecf20Sopenharmony_ci dget_dlock(dentry); 2208c2ecf20Sopenharmony_ci __d_drop(dentry); 2218c2ecf20Sopenharmony_ci spin_unlock(&dentry->d_lock); 2228c2ecf20Sopenharmony_ci simple_unlink(d_inode(parent), dentry); 2238c2ecf20Sopenharmony_ci } else 2248c2ecf20Sopenharmony_ci spin_unlock(&dentry->d_lock); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_civoid configfs_hash_and_remove(struct dentry * dir, const char * name) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct configfs_dirent * sd; 2318c2ecf20Sopenharmony_ci struct configfs_dirent * parent_sd = dir->d_fsdata; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (d_really_is_negative(dir)) 2348c2ecf20Sopenharmony_ci /* no inode means this hasn't been made visible yet */ 2358c2ecf20Sopenharmony_ci return; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci inode_lock(d_inode(dir)); 2388c2ecf20Sopenharmony_ci list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { 2398c2ecf20Sopenharmony_ci if (!sd->s_element) 2408c2ecf20Sopenharmony_ci continue; 2418c2ecf20Sopenharmony_ci if (!strcmp(configfs_get_name(sd), name)) { 2428c2ecf20Sopenharmony_ci spin_lock(&configfs_dirent_lock); 2438c2ecf20Sopenharmony_ci list_del_init(&sd->s_sibling); 2448c2ecf20Sopenharmony_ci spin_unlock(&configfs_dirent_lock); 2458c2ecf20Sopenharmony_ci configfs_drop_dentry(sd, dir); 2468c2ecf20Sopenharmony_ci configfs_put(sd); 2478c2ecf20Sopenharmony_ci break; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci inode_unlock(d_inode(dir)); 2518c2ecf20Sopenharmony_ci} 252