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