Commit eceae1e7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'configfs-5.15' of git://git.infradead.org/users/hch/configfs

Pull configfs updates from Christoph Hellwig:

 - fix a race in configfs_lookup (Sishuai Gong)

 - minor cleanups (me)

* tag 'configfs-5.15' of git://git.infradead.org/users/hch/configfs:
  configfs: fix a race in configfs_lookup()
  configfs: fold configfs_attach_attr into configfs_lookup
  configfs: simplify the configfs_dirent_is_ready
  configfs: return -ENAMETOOLONG earlier in configfs_lookup
parents 265113f7 c42dd069
Loading
Loading
Loading
Loading
+31 −56
Original line number Diff line number Diff line
@@ -45,7 +45,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)
@@ -417,44 +417,16 @@ 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);

	/*
	 * Fake invisibility if dir belongs to a group/default groups hierarchy
@@ -464,36 +436,39 @@ static struct dentry * configfs_lookup(struct inode *dir,
	 * not complete their initialization, since the dentries of the
	 * attributes won't be instantiated.
	 */
	err = -ENOENT;
	if (!configfs_dirent_is_ready(parent_sd))
		goto out;
		return ERR_PTR(-ENOENT);

	spin_lock(&configfs_dirent_lock);
	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;
			dentry->d_fsdata = configfs_get(sd);
			sd->s_dentry = dentry;
			spin_unlock(&configfs_dirent_lock);

			found = 1;
			err = configfs_attach_attr(sd, dentry);
			break;
			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;
			}

	if (!found) {
		/*
		 * If it doesn't exist and it isn't a NOT_PINNED item,
		 * it must be negative.
		 */
		if (dentry->d_name.len > NAME_MAX)
			return ERR_PTR(-ENAMETOOLONG);
		d_add(dentry, NULL);
		return NULL;
			goto done;
		}

out:
	return ERR_PTR(err);
	}
	spin_unlock(&configfs_dirent_lock);
done:
	d_add(dentry, inode);
	return NULL;
}

/*