Commit 962faa265c06f9bb4d4ec6d836fb71376557ad6d

Authored by Al Viro
Committed by Greg Kroah-Hartman
1 parent 2888d04f7a

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

... ... @@ -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 }