Commit db32c774 authored by Al Viro's avatar Al Viro Committed by Greg Kroah-Hartman

debugfs: leave freeing a symlink body until inode eviction

commit 0db59e59 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: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d91c5de5
...@@ -245,10 +245,19 @@ static int debugfs_show_options(struct seq_file *m, struct dentry *root) ...@@ -245,10 +245,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(&inode->i_data, 0);
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)
...@@ -465,23 +474,14 @@ static int __debugfs_remove(struct dentry *dentry, struct dentry *parent) ...@@ -465,23 +474,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;
} }
......
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