Commit 962faa265c06f9bb4d4ec6d836fb71376557ad6d
Committed by
Greg Kroah-Hartman
1 parent
2888d04f7a
Exists in
smarc-ti-linux-3.14.y
and in
1 other branch
debugfs: leave freeing a symlink body until inode eviction
commit 0db59e59299f0b67450c5db21f7f316c8fb04e84 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>
Showing 1 changed file with 17 additions and 17 deletions Side-by-side Diff
fs/debugfs/inode.c
... | ... | @@ -245,10 +245,19 @@ |
245 | 245 | return 0; |
246 | 246 | } |
247 | 247 | |
248 | +static void debugfs_evict_inode(struct inode *inode) | |
249 | +{ | |
250 | + truncate_inode_pages(&inode->i_data, 0); | |
251 | + clear_inode(inode); | |
252 | + if (S_ISLNK(inode->i_mode)) | |
253 | + kfree(inode->i_private); | |
254 | +} | |
255 | + | |
248 | 256 | static const struct super_operations debugfs_super_operations = { |
249 | 257 | .statfs = simple_statfs, |
250 | 258 | .remount_fs = debugfs_remount, |
251 | 259 | .show_options = debugfs_show_options, |
260 | + .evict_inode = debugfs_evict_inode, | |
252 | 261 | }; |
253 | 262 | |
254 | 263 | static int debug_fill_super(struct super_block *sb, void *data, int silent) |
... | ... | @@ -465,23 +474,14 @@ |
465 | 474 | int ret = 0; |
466 | 475 | |
467 | 476 | if (debugfs_positive(dentry)) { |
468 | - if (dentry->d_inode) { | |
469 | - dget(dentry); | |
470 | - switch (dentry->d_inode->i_mode & S_IFMT) { | |
471 | - case S_IFDIR: | |
472 | - ret = simple_rmdir(parent->d_inode, dentry); | |
473 | - break; | |
474 | - case S_IFLNK: | |
475 | - kfree(dentry->d_inode->i_private); | |
476 | - /* fall through */ | |
477 | - default: | |
478 | - simple_unlink(parent->d_inode, dentry); | |
479 | - break; | |
480 | - } | |
481 | - if (!ret) | |
482 | - d_delete(dentry); | |
483 | - dput(dentry); | |
484 | - } | |
477 | + dget(dentry); | |
478 | + if (S_ISDIR(dentry->d_inode->i_mode)) | |
479 | + ret = simple_rmdir(parent->d_inode, dentry); | |
480 | + else | |
481 | + simple_unlink(parent->d_inode, dentry); | |
482 | + if (!ret) | |
483 | + d_delete(dentry); | |
484 | + dput(dentry); | |
485 | 485 | } |
486 | 486 | return ret; |
487 | 487 | } |