Commit 0db59e59299f0b67450c5db21f7f316c8fb04e84
1 parent
dca111782c
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
debugfs: leave freeing a symlink body until inode eviction
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... Cc: stable@vger.kernel.org Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 1 changed file with 17 additions and 17 deletions Side-by-side Diff
fs/debugfs/inode.c
... | ... | @@ -169,10 +169,19 @@ |
169 | 169 | return 0; |
170 | 170 | } |
171 | 171 | |
172 | +static void debugfs_evict_inode(struct inode *inode) | |
173 | +{ | |
174 | + truncate_inode_pages_final(&inode->i_data); | |
175 | + clear_inode(inode); | |
176 | + if (S_ISLNK(inode->i_mode)) | |
177 | + kfree(inode->i_private); | |
178 | +} | |
179 | + | |
172 | 180 | static const struct super_operations debugfs_super_operations = { |
173 | 181 | .statfs = simple_statfs, |
174 | 182 | .remount_fs = debugfs_remount, |
175 | 183 | .show_options = debugfs_show_options, |
184 | + .evict_inode = debugfs_evict_inode, | |
176 | 185 | }; |
177 | 186 | |
178 | 187 | static struct vfsmount *debugfs_automount(struct path *path) |
... | ... | @@ -511,23 +520,14 @@ |
511 | 520 | int ret = 0; |
512 | 521 | |
513 | 522 | if (debugfs_positive(dentry)) { |
514 | - if (dentry->d_inode) { | |
515 | - dget(dentry); | |
516 | - switch (dentry->d_inode->i_mode & S_IFMT) { | |
517 | - case S_IFDIR: | |
518 | - ret = simple_rmdir(parent->d_inode, dentry); | |
519 | - break; | |
520 | - case S_IFLNK: | |
521 | - kfree(dentry->d_inode->i_private); | |
522 | - /* fall through */ | |
523 | - default: | |
524 | - simple_unlink(parent->d_inode, dentry); | |
525 | - break; | |
526 | - } | |
527 | - if (!ret) | |
528 | - d_delete(dentry); | |
529 | - dput(dentry); | |
530 | - } | |
523 | + dget(dentry); | |
524 | + if (S_ISDIR(dentry->d_inode->i_mode)) | |
525 | + ret = simple_rmdir(parent->d_inode, dentry); | |
526 | + else | |
527 | + simple_unlink(parent->d_inode, dentry); | |
528 | + if (!ret) | |
529 | + d_delete(dentry); | |
530 | + dput(dentry); | |
531 | 531 | } |
532 | 532 | return ret; |
533 | 533 | } |