diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2014-02-13 10:54:28 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-10-09 02:38:54 -0400 |
commit | bafc9b754f752ea798c39f9b099a228fd56604e0 (patch) | |
tree | 73116f40eebcf348d3f35ae0350576e5955c7422 /fs/dcache.c | |
parent | 3ccb354d641d910309b916b9c856e2a82ced7237 (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/dcache.c')
-rw-r--r-- | fs/dcache.c | 38 |
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 | } |
703 | EXPORT_SYMBOL(d_invalidate); | 673 | EXPORT_SYMBOL(d_invalidate); |
704 | 674 | ||