mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 10:00:17 +00:00
debugfs: leave freeing a symlink body until inode eviction
commit 0db59e5929 upstream.
As it is, we have debugfs_remove() racing with symlink traversals.
Supply ->evict_inode() and do freeing there - inode will remain
pinned until we are done with the symlink body.
And rip the idiocy with checking if dentry is positive right after
we'd verified debugfs_positive(), which is a stronger check...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
17a75de122
commit
ea149d39ea
@@ -246,10 +246,19 @@ static int debugfs_show_options(struct seq_file *m, struct dentry *root)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void debugfs_evict_inode(struct inode *inode)
|
||||||
|
{
|
||||||
|
truncate_inode_pages_final(&inode->i_data);
|
||||||
|
clear_inode(inode);
|
||||||
|
if (S_ISLNK(inode->i_mode))
|
||||||
|
kfree(inode->i_private);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct super_operations debugfs_super_operations = {
|
static const struct super_operations debugfs_super_operations = {
|
||||||
.statfs = simple_statfs,
|
.statfs = simple_statfs,
|
||||||
.remount_fs = debugfs_remount,
|
.remount_fs = debugfs_remount,
|
||||||
.show_options = debugfs_show_options,
|
.show_options = debugfs_show_options,
|
||||||
|
.evict_inode = debugfs_evict_inode,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int debug_fill_super(struct super_block *sb, void *data, int silent)
|
static int debug_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
@@ -466,23 +475,14 @@ static int __debugfs_remove(struct dentry *dentry, struct dentry *parent)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (debugfs_positive(dentry)) {
|
if (debugfs_positive(dentry)) {
|
||||||
if (dentry->d_inode) {
|
dget(dentry);
|
||||||
dget(dentry);
|
if (S_ISDIR(dentry->d_inode->i_mode))
|
||||||
switch (dentry->d_inode->i_mode & S_IFMT) {
|
ret = simple_rmdir(parent->d_inode, dentry);
|
||||||
case S_IFDIR:
|
else
|
||||||
ret = simple_rmdir(parent->d_inode, dentry);
|
simple_unlink(parent->d_inode, dentry);
|
||||||
break;
|
if (!ret)
|
||||||
case S_IFLNK:
|
d_delete(dentry);
|
||||||
kfree(dentry->d_inode->i_private);
|
dput(dentry);
|
||||||
/* fall through */
|
|
||||||
default:
|
|
||||||
simple_unlink(parent->d_inode, dentry);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!ret)
|
|
||||||
d_delete(dentry);
|
|
||||||
dput(dentry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user