mirror of https://github.com/torvalds/linux.git
functionfs: switch to simple_remove_by_name()
No need to return dentry from ffs_sb_create_file() or keep it around afterwards. To avoid subtle issues with getting to ffs from epfiles in ffs_epfiles_destroy(), pass the superblock as explicit argument. Callers have it anyway. Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
e5bf5ee266
commit
c7747fafab
|
|
@ -160,8 +160,6 @@ struct ffs_epfile {
|
||||||
struct ffs_data *ffs;
|
struct ffs_data *ffs;
|
||||||
struct ffs_ep *ep; /* P: ffs->eps_lock */
|
struct ffs_ep *ep; /* P: ffs->eps_lock */
|
||||||
|
|
||||||
struct dentry *dentry;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Buffer for holding data from partial reads which may happen since
|
* Buffer for holding data from partial reads which may happen since
|
||||||
* we’re rounding user read requests to a multiple of a max packet size.
|
* we’re rounding user read requests to a multiple of a max packet size.
|
||||||
|
|
@ -271,11 +269,11 @@ struct ffs_desc_helper {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
|
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
|
||||||
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
|
static void ffs_epfiles_destroy(struct super_block *sb,
|
||||||
|
struct ffs_epfile *epfiles, unsigned count);
|
||||||
|
|
||||||
static struct dentry *
|
static int ffs_sb_create_file(struct super_block *sb, const char *name,
|
||||||
ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
|
void *data, const struct file_operations *fops);
|
||||||
const struct file_operations *fops);
|
|
||||||
|
|
||||||
/* Devices management *******************************************************/
|
/* Devices management *******************************************************/
|
||||||
|
|
||||||
|
|
@ -1894,9 +1892,8 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create "regular" file */
|
/* Create "regular" file */
|
||||||
static struct dentry *ffs_sb_create_file(struct super_block *sb,
|
static int ffs_sb_create_file(struct super_block *sb, const char *name,
|
||||||
const char *name, void *data,
|
void *data, const struct file_operations *fops)
|
||||||
const struct file_operations *fops)
|
|
||||||
{
|
{
|
||||||
struct ffs_data *ffs = sb->s_fs_info;
|
struct ffs_data *ffs = sb->s_fs_info;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
|
@ -1904,16 +1901,16 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb,
|
||||||
|
|
||||||
dentry = d_alloc_name(sb->s_root, name);
|
dentry = d_alloc_name(sb->s_root, name);
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
return NULL;
|
return -ENOMEM;
|
||||||
|
|
||||||
inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
|
inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
|
||||||
if (!inode) {
|
if (!inode) {
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
return NULL;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
d_add(dentry, inode);
|
d_add(dentry, inode);
|
||||||
return dentry;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Super block */
|
/* Super block */
|
||||||
|
|
@ -1956,10 +1953,7 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* EP0 file */
|
/* EP0 file */
|
||||||
if (!ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations))
|
return ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations);
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -2196,7 +2190,7 @@ static void ffs_data_closed(struct ffs_data *ffs)
|
||||||
flags);
|
flags);
|
||||||
|
|
||||||
if (epfiles)
|
if (epfiles)
|
||||||
ffs_epfiles_destroy(epfiles,
|
ffs_epfiles_destroy(ffs->sb, epfiles,
|
||||||
ffs->eps_count);
|
ffs->eps_count);
|
||||||
|
|
||||||
if (ffs->setup_state == FFS_SETUP_PENDING)
|
if (ffs->setup_state == FFS_SETUP_PENDING)
|
||||||
|
|
@ -2255,7 +2249,7 @@ static void ffs_data_clear(struct ffs_data *ffs)
|
||||||
* copy of epfile will save us from use-after-free.
|
* copy of epfile will save us from use-after-free.
|
||||||
*/
|
*/
|
||||||
if (epfiles) {
|
if (epfiles) {
|
||||||
ffs_epfiles_destroy(epfiles, ffs->eps_count);
|
ffs_epfiles_destroy(ffs->sb, epfiles, ffs->eps_count);
|
||||||
ffs->epfiles = NULL;
|
ffs->epfiles = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2352,6 +2346,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
|
||||||
{
|
{
|
||||||
struct ffs_epfile *epfile, *epfiles;
|
struct ffs_epfile *epfile, *epfiles;
|
||||||
unsigned i, count;
|
unsigned i, count;
|
||||||
|
int err;
|
||||||
|
|
||||||
count = ffs->eps_count;
|
count = ffs->eps_count;
|
||||||
epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
|
epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
|
||||||
|
|
@ -2368,12 +2363,11 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
|
||||||
sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
|
sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
|
||||||
else
|
else
|
||||||
sprintf(epfile->name, "ep%u", i);
|
sprintf(epfile->name, "ep%u", i);
|
||||||
epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
|
err = ffs_sb_create_file(ffs->sb, epfile->name,
|
||||||
epfile,
|
epfile, &ffs_epfile_operations);
|
||||||
&ffs_epfile_operations);
|
if (err) {
|
||||||
if (!epfile->dentry) {
|
ffs_epfiles_destroy(ffs->sb, epfiles, i - 1);
|
||||||
ffs_epfiles_destroy(epfiles, i - 1);
|
return err;
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2386,16 +2380,15 @@ static void clear_one(struct dentry *dentry)
|
||||||
smp_store_release(&dentry->d_inode->i_private, NULL);
|
smp_store_release(&dentry->d_inode->i_private, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
|
static void ffs_epfiles_destroy(struct super_block *sb,
|
||||||
|
struct ffs_epfile *epfiles, unsigned count)
|
||||||
{
|
{
|
||||||
struct ffs_epfile *epfile = epfiles;
|
struct ffs_epfile *epfile = epfiles;
|
||||||
|
struct dentry *root = sb->s_root;
|
||||||
|
|
||||||
for (; count; --count, ++epfile) {
|
for (; count; --count, ++epfile) {
|
||||||
BUG_ON(mutex_is_locked(&epfile->mutex));
|
BUG_ON(mutex_is_locked(&epfile->mutex));
|
||||||
if (epfile->dentry) {
|
simple_remove_by_name(root, epfile->name, clear_one);
|
||||||
simple_recursive_removal(epfile->dentry, clear_one);
|
|
||||||
epfile->dentry = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(epfiles);
|
kfree(epfiles);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue