Commit eceae1e7 authored by Linus Torvalds's avatar Linus Torvalds

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
...@@ -45,7 +45,7 @@ static void configfs_d_iput(struct dentry * dentry, ...@@ -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 * Set sd->s_dentry to null only when this dentry is the one
* that is going to be killed. Otherwise configfs_d_iput may * 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. * NULL even it's still in use.
*/ */
if (sd->s_dentry == dentry) if (sd->s_dentry == dentry)
...@@ -417,44 +417,16 @@ static void configfs_remove_dir(struct config_item * item) ...@@ -417,44 +417,16 @@ static void configfs_remove_dir(struct config_item * item)
dput(dentry); 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, static struct dentry * configfs_lookup(struct inode *dir,
struct dentry *dentry, struct dentry *dentry,
unsigned int flags) unsigned int flags)
{ {
struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata; struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
struct configfs_dirent * sd; struct configfs_dirent * sd;
int found = 0; struct inode *inode = NULL;
int err;
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
/* /*
* Fake invisibility if dir belongs to a group/default groups hierarchy * Fake invisibility if dir belongs to a group/default groups hierarchy
...@@ -464,36 +436,39 @@ static struct dentry * configfs_lookup(struct inode *dir, ...@@ -464,36 +436,39 @@ static struct dentry * configfs_lookup(struct inode *dir,
* not complete their initialization, since the dentries of the * not complete their initialization, since the dentries of the
* attributes won't be instantiated. * attributes won't be instantiated.
*/ */
err = -ENOENT;
if (!configfs_dirent_is_ready(parent_sd)) 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) { list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
if (sd->s_type & CONFIGFS_NOT_PINNED) { if ((sd->s_type & CONFIGFS_NOT_PINNED) &&
const unsigned char * name = configfs_get_name(sd); !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)) dentry->d_fsdata = configfs_get(sd);
continue; sd->s_dentry = dentry;
spin_unlock(&configfs_dirent_lock);
found = 1; inode = configfs_create(dentry, mode);
err = configfs_attach_attr(sd, dentry); if (IS_ERR(inode)) {
break; 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;
}
goto done;
} }
} }
spin_unlock(&configfs_dirent_lock);
if (!found) { done:
/* d_add(dentry, inode);
* If it doesn't exist and it isn't a NOT_PINNED item, return NULL;
* it must be negative.
*/
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
d_add(dentry, NULL);
return NULL;
}
out:
return ERR_PTR(err);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment