Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bafc9b75 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by Al Viro
Browse files

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: default avatarMiklos Szeredi <miklos@szeredi.hu>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 3ccb354d
Loading
Loading
Loading
Loading
+4 −34
Original line number Original line Diff line number Diff line
@@ -650,9 +650,8 @@ EXPORT_SYMBOL(dput);
 * @dentry: dentry to invalidate
 * @dentry: dentry to invalidate
 *
 *
 * Try to invalidate the dentry if it turns out to be
 * Try to invalidate the dentry if it turns out to be
 * possible. If there are other dentries that can be
 * possible. If there are reasons not to delete it
 * reached through this one we can't delete it and we
 * return -EBUSY. On success return 0.
 * return -EBUSY. On success we return 0.
 *
 *
 * no dcache lock.
 * no dcache lock.
 */
 */
@@ -667,38 +666,9 @@ int d_invalidate(struct dentry * dentry)
		spin_unlock(&dentry->d_lock);
		spin_unlock(&dentry->d_lock);
		return 0;
		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);
	spin_unlock(&dentry->d_lock);
		shrink_dcache_parent(dentry);
		spin_lock(&dentry->d_lock);
	}


	/*
	return check_submounts_and_drop(dentry);
	 * 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;
}
}
EXPORT_SYMBOL(d_invalidate);
EXPORT_SYMBOL(d_invalidate);