]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.19.2/debugfs-leave-freeing-a-symlink-body-until-inode-eviction.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.19.2 / debugfs-leave-freeing-a-symlink-body-until-inode-eviction.patch
1 From 0db59e59299f0b67450c5db21f7f316c8fb04e84 Mon Sep 17 00:00:00 2001
2 From: Al Viro <viro@zeniv.linux.org.uk>
3 Date: Sat, 21 Feb 2015 22:05:11 -0500
4 Subject: debugfs: leave freeing a symlink body until inode eviction
5
6 From: Al Viro <viro@zeniv.linux.org.uk>
7
8 commit 0db59e59299f0b67450c5db21f7f316c8fb04e84 upstream.
9
10 As it is, we have debugfs_remove() racing with symlink traversals.
11 Supply ->evict_inode() and do freeing there - inode will remain
12 pinned until we are done with the symlink body.
13
14 And rip the idiocy with checking if dentry is positive right after
15 we'd verified debugfs_positive(), which is a stronger check...
16
17 Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
18 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
19
20 ---
21 fs/debugfs/inode.c | 34 +++++++++++++++++-----------------
22 1 file changed, 17 insertions(+), 17 deletions(-)
23
24 --- a/fs/debugfs/inode.c
25 +++ b/fs/debugfs/inode.c
26 @@ -246,10 +246,19 @@ static int debugfs_show_options(struct s
27 return 0;
28 }
29
30 +static void debugfs_evict_inode(struct inode *inode)
31 +{
32 + truncate_inode_pages_final(&inode->i_data);
33 + clear_inode(inode);
34 + if (S_ISLNK(inode->i_mode))
35 + kfree(inode->i_private);
36 +}
37 +
38 static const struct super_operations debugfs_super_operations = {
39 .statfs = simple_statfs,
40 .remount_fs = debugfs_remount,
41 .show_options = debugfs_show_options,
42 + .evict_inode = debugfs_evict_inode,
43 };
44
45 static int debug_fill_super(struct super_block *sb, void *data, int silent)
46 @@ -466,23 +475,14 @@ static int __debugfs_remove(struct dentr
47 int ret = 0;
48
49 if (debugfs_positive(dentry)) {
50 - if (dentry->d_inode) {
51 - dget(dentry);
52 - switch (dentry->d_inode->i_mode & S_IFMT) {
53 - case S_IFDIR:
54 - ret = simple_rmdir(parent->d_inode, dentry);
55 - break;
56 - case S_IFLNK:
57 - kfree(dentry->d_inode->i_private);
58 - /* fall through */
59 - default:
60 - simple_unlink(parent->d_inode, dentry);
61 - break;
62 - }
63 - if (!ret)
64 - d_delete(dentry);
65 - dput(dentry);
66 - }
67 + dget(dentry);
68 + if (S_ISDIR(dentry->d_inode->i_mode))
69 + ret = simple_rmdir(parent->d_inode, dentry);
70 + else
71 + simple_unlink(parent->d_inode, dentry);
72 + if (!ret)
73 + d_delete(dentry);
74 + dput(dentry);
75 }
76 return ret;
77 }