Commit de82e210 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Zheng Zengkai
Browse files

configfs: fold configfs_attach_attr into configfs_lookup

mainline inclusion
from mainline-v5.15-rc1
commit d07f132a
category: bugfix
bugzilla: 187567, https://gitee.com/openeuler/kernel/issues/I5PK1G
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/fs/configfs/dir.c?h=v6.0-rc3&id=d07f132a225c013e59aa77f514ad9211ecab82ee



--------------------------------

This makes it more clear what gets added to the dcache and prepares
for an additional locking fix.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarZhihao Cheng <chengzhihao1@huawei.com>
Reviewed-by: default avatarZhang Yi <yi.zhang@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent 5d28738d
Loading
Loading
Loading
Loading
+24 −49
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@ static void configfs_d_iput(struct dentry * dentry,
		/*
		 * Set sd->s_dentry to null only when this dentry is the one
		 * that is going to be killed.  Otherwise configfs_d_iput may
		 * run just after configfs_attach_attr and set sd->s_dentry to
		 * run just after configfs_lookup and set sd->s_dentry to
		 * NULL even it's still in use.
		 */
		if (sd->s_dentry == dentry)
@@ -426,44 +426,13 @@ static void configfs_remove_dir(struct config_item * item)
	dput(dentry);
}


/* attaches attribute's configfs_dirent to the dentry corresponding to the
 * attribute file
 */
static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * dentry)
{
	struct configfs_attribute * attr = sd->s_element;
	struct inode *inode;

	spin_lock(&configfs_dirent_lock);
	dentry->d_fsdata = configfs_get(sd);
	sd->s_dentry = dentry;
	spin_unlock(&configfs_dirent_lock);

	inode = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG);
	if (IS_ERR(inode)) {
		configfs_put(sd);
		return PTR_ERR(inode);
	}
	if (sd->s_type & CONFIGFS_ITEM_BIN_ATTR) {
		inode->i_size = 0;
		inode->i_fop = &configfs_bin_file_operations;
	} else {
		inode->i_size = PAGE_SIZE;
		inode->i_fop = &configfs_file_operations;
	}
	d_add(dentry, inode);
	return 0;
}

static struct dentry * configfs_lookup(struct inode *dir,
				       struct dentry *dentry,
				       unsigned int flags)
{
	struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
	struct configfs_dirent * sd;
	int found = 0;
	int err;
	struct inode *inode = NULL;

	if (dentry->d_name.len > NAME_MAX)
		return ERR_PTR(-ENAMETOOLONG);
@@ -480,30 +449,36 @@ static struct dentry * configfs_lookup(struct inode *dir,
		return ERR_PTR(-ENOENT);

	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
		if (sd->s_type & CONFIGFS_NOT_PINNED) {
			const unsigned char * name = configfs_get_name(sd);
		if ((sd->s_type & CONFIGFS_NOT_PINNED) &&
		    !strcmp(configfs_get_name(sd), dentry->d_name.name)) {
			struct configfs_attribute *attr = sd->s_element;
			umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG;

			if (strcmp(name, dentry->d_name.name))
				continue;
			spin_lock(&configfs_dirent_lock);
			dentry->d_fsdata = configfs_get(sd);
			sd->s_dentry = dentry;
			spin_unlock(&configfs_dirent_lock);

			found = 1;
			err = configfs_attach_attr(sd, dentry);
			inode = configfs_create(dentry, mode);
			if (IS_ERR(inode)) {
				configfs_put(sd);
				return ERR_CAST(inode);
			}
			if (sd->s_type & CONFIGFS_ITEM_BIN_ATTR) {
				inode->i_size = 0;
				inode->i_fop = &configfs_bin_file_operations;
			} else {
				inode->i_size = PAGE_SIZE;
				inode->i_fop = &configfs_file_operations;
			}
			break;
		}
	}

	if (!found) {
		/*
		 * If it doesn't exist and it isn't a NOT_PINNED item,
		 * it must be negative.
		 */
		d_add(dentry, NULL);
	d_add(dentry, inode);
	return NULL;
}

	return ERR_PTR(err);
}

/*
 * Only subdirectories count here.  Files (CONFIGFS_NOT_PINNED) are
 * attributes and are removed by rmdir().  We recurse, setting