Re: dcache: remove trylock loops (was Re: [BUG] lock_parent() breakage when used from shrink_dentry_list())
From: NeilBrown
Date: Mon Mar 12 2018 - 21:13:09 EST
On Mon, Mar 12 2018, Al Viro wrote:
> On Mon, Mar 12, 2018 at 07:13:51PM +0000, Al Viro wrote:
>
>> There's an unpleasant area around the ->s_root vs. NFS. There's
>> code that makes assumptions about ->s_root that are simply not true
>> for NFS. Is path_connected() correct wrt NFS multiple imports from
>> the same server? Ditto for mnt_already_visible() (that one might
>> be mitigated at the moment, but probably won't last). Eric, am
>> I missing something subtle in there?
>
> BTW, another thing spotted while trying to document the stuff:
> Neil's "VFS: don't keep disconnected dentries on d_anon" has a subtle
> side effect I hadn't spotted when applying. Namely, for
> DCACHE_DISCONNECTED non-directory IS_ROOT dentries we now have
> d_unhashed() true. That makes d_find_alias() logics around
> discon_alias dead code:
> if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
> if (IS_ROOT(alias) &&
> (alias->d_flags & DCACHE_DISCONNECTED)) {
> discon_alias = alias;
> } else {
> __dget_dlock(alias);
> spin_unlock(&alias->d_lock);
> return alias;
> }
> }
I agree that this code is now more complex than needed.
>
> Directory case is a red herring - we'll end up picking one and only
> alias, whether it's IS_ROOT/disconnected or not. For non-directories,
> though, IS_ROOT and disconnected implies d_unhashed() now, so we might
> as well turn that into
> if directory
> return d_find_any_alias
> else
> return the first hashed alias
Yes, this looks like a good simplification.
>
> Does any of the d_find_alias() callers want those dentries? That is,
> non-directories from d_obtain_alias() still not attached to a parent;
> note that exportfs_decode_fh() is *not* one of such places - we don't
> use d_find_alias() there at all. If there's no such caller, we can
> bloody well just drop the discon_alias logics and be done with that;
> if there is, that commit has introduced a bug. I might have missed
> a part of threads related to that patch, so my apologies if it had
> been discussed.
>
> Neil, what's the situation there? A lot of those callers clearly treat
> the "only disconnected IS_ROOT alias exist" same as "no aliases at all";
> it looks like the change might have been the right thing, but it sure
> as hell shouldn't be an undocumented side effect...
Many of the callers really want a name, which these disconnected
dentries didn't have, so the new code is more correct in those cases.
d_find_alias() is documented as returning a hashed dentry (for
non-directories) and I suspect most people would be surprised to find
that a disconnected dentry with no name was considered to be "hashed",
so I think the patch could be seen as fixing the documentation.
Of the three users that you didn't classify as "clearly" not wanting the
disconnected dentries:
> * ceph invalidate_aliases()
This wants to ensure the dentries are discarded on final dput(). This
is already the case for disconnected dentries, so it doesn't need to be
told about them. Code is correct.
> * cap_inode_getsecurity()
If this gets invoked when the nfsd server calls vfs_getxattr() on a
disconnected dentry, it will return -EINVAL. This looks like a
potential bug.
nfsd only calls vfs_getxattr() in nfsd4_is_junction() so this bug would
not affect many use cases.
I think cap_inode_getsecurity() should really be calling
d_find_any_alias().
> * selinux inode_doinit_with_dentry() (two call sites, very alike)
I'm less sure about this one, but I think it probably wants
d_find_any_alias() as well. Like cap_inode_getsecurity() it only wants
a dentry so that it can pass something to __vfs_getxattr(),
and that only wants a dentry so it can pass something to ->get.
Possibly we should rename d_find_alias() to d_find_hashed_alias() so that
people need to make a conscious choice between d_find_hashed_alias() and
d_find_any_alias() ??
Thanks,
NeilBrown
Attachment:
signature.asc
Description: PGP signature