brintos

brintos / linux-shallow public Read only

0
0
Text · 6.0 KiB · dcc22f5 Raw
244 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * inode.c - basic inode and dentry operations.4 *5 * Based on sysfs:6 * 	sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel7 *8 * configfs Copyright (C) 2005 Oracle.  All rights reserved.9 *10 * Please see Documentation/filesystems/configfs.rst for more11 * information.12 */13 14#undef DEBUG15 16#include <linux/pagemap.h>17#include <linux/namei.h>18#include <linux/backing-dev.h>19#include <linux/capability.h>20#include <linux/sched.h>21#include <linux/lockdep.h>22#include <linux/slab.h>23 24#include <linux/configfs.h>25#include "configfs_internal.h"26 27#ifdef CONFIG_LOCKDEP28static struct lock_class_key default_group_class[MAX_LOCK_DEPTH];29#endif30 31static const struct inode_operations configfs_inode_operations ={32	.setattr	= configfs_setattr,33};34 35int configfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,36		     struct iattr *iattr)37{38	struct inode * inode = d_inode(dentry);39	struct configfs_dirent * sd = dentry->d_fsdata;40	struct iattr * sd_iattr;41	unsigned int ia_valid = iattr->ia_valid;42	int error;43 44	if (!sd)45		return -EINVAL;46 47	sd_iattr = sd->s_iattr;48	if (!sd_iattr) {49		/* setting attributes for the first time, allocate now */50		sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);51		if (!sd_iattr)52			return -ENOMEM;53		/* assign default attributes */54		sd_iattr->ia_mode = sd->s_mode;55		sd_iattr->ia_uid = GLOBAL_ROOT_UID;56		sd_iattr->ia_gid = GLOBAL_ROOT_GID;57		sd_iattr->ia_atime = sd_iattr->ia_mtime =58			sd_iattr->ia_ctime = current_time(inode);59		sd->s_iattr = sd_iattr;60	}61	/* attributes were changed atleast once in past */62 63	error = simple_setattr(idmap, dentry, iattr);64	if (error)65		return error;66 67	if (ia_valid & ATTR_UID)68		sd_iattr->ia_uid = iattr->ia_uid;69	if (ia_valid & ATTR_GID)70		sd_iattr->ia_gid = iattr->ia_gid;71	if (ia_valid & ATTR_ATIME)72		sd_iattr->ia_atime = iattr->ia_atime;73	if (ia_valid & ATTR_MTIME)74		sd_iattr->ia_mtime = iattr->ia_mtime;75	if (ia_valid & ATTR_CTIME)76		sd_iattr->ia_ctime = iattr->ia_ctime;77	if (ia_valid & ATTR_MODE) {78		umode_t mode = iattr->ia_mode;79 80		if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))81			mode &= ~S_ISGID;82		sd_iattr->ia_mode = sd->s_mode = mode;83	}84 85	return error;86}87 88static inline void set_default_inode_attr(struct inode * inode, umode_t mode)89{90	inode->i_mode = mode;91	simple_inode_init_ts(inode);92}93 94static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)95{96	inode->i_mode = iattr->ia_mode;97	inode->i_uid = iattr->ia_uid;98	inode->i_gid = iattr->ia_gid;99	inode_set_atime_to_ts(inode, iattr->ia_atime);100	inode_set_mtime_to_ts(inode, iattr->ia_mtime);101	inode_set_ctime_to_ts(inode, iattr->ia_ctime);102}103 104struct inode *configfs_new_inode(umode_t mode, struct configfs_dirent *sd,105				 struct super_block *s)106{107	struct inode * inode = new_inode(s);108	if (inode) {109		inode->i_ino = get_next_ino();110		inode->i_mapping->a_ops = &ram_aops;111		inode->i_op = &configfs_inode_operations;112 113		if (sd->s_iattr) {114			/* sysfs_dirent has non-default attributes115			 * get them for the new inode from persistent copy116			 * in sysfs_dirent117			 */118			set_inode_attr(inode, sd->s_iattr);119		} else120			set_default_inode_attr(inode, mode);121	}122	return inode;123}124 125#ifdef CONFIG_LOCKDEP126 127static void configfs_set_inode_lock_class(struct configfs_dirent *sd,128					  struct inode *inode)129{130	int depth = sd->s_depth;131 132	if (depth > 0) {133		if (depth <= ARRAY_SIZE(default_group_class)) {134			lockdep_set_class(&inode->i_rwsem,135					  &default_group_class[depth - 1]);136		} else {137			/*138			 * In practice the maximum level of locking depth is139			 * already reached. Just inform about possible reasons.140			 */141			pr_info("Too many levels of inodes for the locking correctness validator.\n");142			pr_info("Spurious warnings may appear.\n");143		}144	}145}146 147#else /* CONFIG_LOCKDEP */148 149static void configfs_set_inode_lock_class(struct configfs_dirent *sd,150					  struct inode *inode)151{152}153 154#endif /* CONFIG_LOCKDEP */155 156struct inode *configfs_create(struct dentry *dentry, umode_t mode)157{158	struct inode *inode = NULL;159	struct configfs_dirent *sd;160	struct inode *p_inode;161 162	if (!dentry)163		return ERR_PTR(-ENOENT);164 165	if (d_really_is_positive(dentry))166		return ERR_PTR(-EEXIST);167 168	sd = dentry->d_fsdata;169	inode = configfs_new_inode(mode, sd, dentry->d_sb);170	if (!inode)171		return ERR_PTR(-ENOMEM);172 173	p_inode = d_inode(dentry->d_parent);174	inode_set_mtime_to_ts(p_inode, inode_set_ctime_current(p_inode));175	configfs_set_inode_lock_class(sd, inode);176	return inode;177}178 179/*180 * Get the name for corresponding element represented by the given configfs_dirent181 */182const unsigned char * configfs_get_name(struct configfs_dirent *sd)183{184	struct configfs_attribute *attr;185 186	BUG_ON(!sd || !sd->s_element);187 188	/* These always have a dentry, so use that */189	if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK))190		return sd->s_dentry->d_name.name;191 192	if (sd->s_type & (CONFIGFS_ITEM_ATTR | CONFIGFS_ITEM_BIN_ATTR)) {193		attr = sd->s_element;194		return attr->ca_name;195	}196	return NULL;197}198 199 200/*201 * Unhashes the dentry corresponding to given configfs_dirent202 * Called with parent inode's i_mutex held.203 */204void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent)205{206	struct dentry * dentry = sd->s_dentry;207 208	if (dentry) {209		spin_lock(&dentry->d_lock);210		if (simple_positive(dentry)) {211			dget_dlock(dentry);212			__d_drop(dentry);213			spin_unlock(&dentry->d_lock);214			simple_unlink(d_inode(parent), dentry);215		} else216			spin_unlock(&dentry->d_lock);217	}218}219 220void configfs_hash_and_remove(struct dentry * dir, const char * name)221{222	struct configfs_dirent * sd;223	struct configfs_dirent * parent_sd = dir->d_fsdata;224 225	if (d_really_is_negative(dir))226		/* no inode means this hasn't been made visible yet */227		return;228 229	inode_lock(d_inode(dir));230	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {231		if (!sd->s_element)232			continue;233		if (!strcmp(configfs_get_name(sd), name)) {234			spin_lock(&configfs_dirent_lock);235			list_del_init(&sd->s_sibling);236			spin_unlock(&configfs_dirent_lock);237			configfs_drop_dentry(sd, dir);238			configfs_put(sd);239			break;240		}241	}242	inode_unlock(d_inode(dir));243}244