From bafc9b754f752ea798c39f9b099a228fd56604e0 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 13 Feb 2014 07:54:28 -0800 Subject: 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 Signed-off-by: "Eric W. Biederman" Signed-off-by: Al Viro diff --git a/fs/dcache.c b/fs/dcache.c index 1f8e6ac..8150e4e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -650,9 +650,8 @@ EXPORT_SYMBOL(dput); * @dentry: dentry to invalidate * * Try to invalidate the dentry if it turns out to be - * possible. If there are other dentries that can be - * reached through this one we can't delete it and we - * return -EBUSY. On success we return 0. + * possible. If there are reasons not to delete it + * return -EBUSY. On success return 0. * * no dcache lock. */ @@ -667,38 +666,9 @@ int d_invalidate(struct dentry * dentry) spin_unlock(&dentry->d_lock); return 0; } - /* - * Check whether to do a partial shrink_dcache - * to get rid of unused child entries. - */ - if (!list_empty(&dentry->d_subdirs)) { - spin_unlock(&dentry->d_lock); - shrink_dcache_parent(dentry); - spin_lock(&dentry->d_lock); - } - - /* - * Somebody else still using it? - * - * 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 the root, - * we might still populate it if it was a - * working directory or similar). - * We also need to leave mountpoints alone, - * directory or not. - */ - if (dentry->d_lockref.count > 1 && dentry->d_inode) { - if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) { - spin_unlock(&dentry->d_lock); - return -EBUSY; - } - } - - __d_drop(dentry); spin_unlock(&dentry->d_lock); - return 0; + + return check_submounts_and_drop(dentry); } EXPORT_SYMBOL(d_invalidate); -- cgit v0.10.2