aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2014-02-13 10:54:28 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2014-10-09 02:38:54 -0400
commitbafc9b754f752ea798c39f9b099a228fd56604e0 (patch)
tree73116f40eebcf348d3f35ae0350576e5955c7422 /fs
parent3ccb354d641d910309b916b9c856e2a82ced7237 (diff)
vfs: More precise tests in d_invalidate
The current comments in d_invalidate about what and why it is doing what it is doing are wildly off-base. Which is not surprising as the comments date back to last minute bug fix of the 2.2 kernel. The big fat lie of a comment said: If it's a directory, we can't drop it for fear of somebody re-populating it with children (even though dropping it would make it unreachable from that root, we still might repopulate it if it was a working directory or similar). [AV] What we really need to avoid is multiple dentry aliases of the same directory inode; on all filesystems that have ->d_revalidate() we either declare all positive dentries always valid (and thus never fed to d_invalidate()) or use d_materialise_unique() and/or d_splice_alias(), which take care of alias prevention. The current rules are: - To prevent mount point leaks dentries that are mount points or that have childrent that are mount points may not be be unhashed. - All dentries may be unhashed. - Directories may be rehashed with d_materialise_unique check_submounts_and_drop implements this already for well maintained remote filesystems so implement the current rules in d_invalidate by just calling check_submounts_and_drop. The one difference between d_invalidate and check_submounts_and_drop is that d_invalidate must respect it when a d_revalidate method has earlier called d_drop so preserve the d_unhashed check in d_invalidate. Reviewed-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c38
1 files changed, 4 insertions, 34 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 1f8e6acb0ea4..8150e4e9e88b 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -650,9 +650,8 @@ EXPORT_SYMBOL(dput);
650 * @dentry: dentry to invalidate 650 * @dentry: dentry to invalidate
651 * 651 *
652 * Try to invalidate the dentry if it turns out to be 652 * Try to invalidate the dentry if it turns out to be
653 * possible. If there are other dentries that can be 653 * possible. If there are reasons not to delete it
654 * reached through this one we can't delete it and we 654 * return -EBUSY. On success return 0.
655 * return -EBUSY. On success we return 0.
656 * 655 *
657 * no dcache lock. 656 * no dcache lock.
658 */ 657 */
@@ -667,38 +666,9 @@ int d_invalidate(struct dentry * dentry)
667 spin_unlock(&dentry->d_lock); 666 spin_unlock(&dentry->d_lock);
668 return 0; 667 return 0;
669 } 668 }
670 /*
671 * Check whether to do a partial shrink_dcache
672 * to get rid of unused child entries.
673 */
674 if (!list_empty(&dentry->d_subdirs)) {
675 spin_unlock(&dentry->d_lock);
676 shrink_dcache_parent(dentry);
677 spin_lock(&dentry->d_lock);
678 }
679
680 /*
681 * Somebody else still using it?
682 *
683 * If it's a directory, we can't drop it
684 * for fear of somebody re-populating it
685 * with children (even though dropping it
686 * would make it unreachable from the root,
687 * we might still populate it if it was a
688 * working directory or similar).
689 * We also need to leave mountpoints alone,
690 * directory or not.
691 */
692 if (dentry->d_lockref.count > 1 && dentry->d_inode) {
693 if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) {
694 spin_unlock(&dentry->d_lock);
695 return -EBUSY;
696 }
697 }
698
699 __d_drop(dentry);
700 spin_unlock(&dentry->d_lock); 669 spin_unlock(&dentry->d_lock);
701 return 0; 670
671 return check_submounts_and_drop(dentry);
702} 672}
703EXPORT_SYMBOL(d_invalidate); 673EXPORT_SYMBOL(d_invalidate);
704 674