Re: WTF is d_add_ci() doing with negative dentries?

From: Al Viro
Date: Sun Oct 12 2014 - 22:15:16 EST


On Mon, Oct 13, 2014 at 12:56:11AM +0100, Anton Altaparmakov wrote:

> I am just wondering whether there might be error conditions in which we might end up with a (perhaps invalid) negative dentry in memory which could be found here? Probably not a problem especially now that d_invalidate() cannot fail any more.

Huh? Failing d_invalidate() on _negative_ dentry is flat-out impossible;
it would be dropped just fine, and we wouldn't have found it in the first
place. Check what it used to do all way back to 2.2.0:
if (dentry->d_count) {
if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
return -EBUSY;
}

So unless you care about 2.1.something (2.0 didn't have dcache at all),
this scenario isn't possible.

In any case, d_add_ci() users that might have negative dentries become
positive cannot afford hashed negative dentries at all - at the very
least they need to treat them as invalid in ->d_revalidate() in such
situations. Exactly because having a hashed valid negative dentry for
FuBaR after e.g. mkdir fubar will really hurt - mkdir won't have any way
to know that old dentry was there; there was no variant of fubar in directory
prior to that mkdir (FuBaR _was_ negative) and there's nothing to suggest
looking for it. So it won't be noticed and it'll bloody well stay negative
and hashed. I.e. stat FuBaR; mkdir fubar; stat FuBaR will have the second
stat find dentry still hashed and valid negative.

You can get away with that if you store something like timestamp[1] of
the parent directory in those negative dentries and check that in
->d_revalidate(). But that will work just fine, since d_add_ci() is
serialized by ->i_mutex held on parent and whatever it was that added your
"exact spelling" into directory has made all preexisting negative dentries
invalid...

[1] for arbitrary values of time - e.g.
on positive lookup set ->d_time to 0
on negative lookup set ->d_time to that of parent dentry
on mkdir set ->d_time to 0
on unlink, rmdir and rename victim copy ->d_time from parent dentry
on any directory modification bump its ->d_time
on d_revalidate of negative dentry compare ->d_time with that of parent
dentry and declare invalid on mismatch
will do just fine.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/