]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/commit
The UFS dirhash code was attempting to update shared state in the dirhash
authorjhb <jhb@FreeBSD.org>
Mon, 7 Mar 2011 18:33:29 +0000 (18:33 +0000)
committerjhb <jhb@FreeBSD.org>
Mon, 7 Mar 2011 18:33:29 +0000 (18:33 +0000)
commitd219d97f454003c4e7350f050bf3d0c8ff260f93
treecd6583066747fff48480b70439487fa48265d874
parente3510dd42989db62dc2fe826d0984d464b4bf598
The UFS dirhash code was attempting to update shared state in the dirhash
from multiple threads while holding a shared lock during a lookup operation.
This could result in incorrect ENOENT failures which could then be
permanently stored in the name cache.

Specifically, the dirhash code optimizes the case that a single thread is
walking a directory sequentially opening (or stat'ing) each file.  It uses
state in the dirhash structure to determine if a given lookup is using the
optimization.  If the optimization fails, it disables it and restarts the
lookup.  The problem arises when two threads both attempt the optimization
and fail.  The first thread will restart the loop, but the second thread
will incorrectly think that it did not try the optimization and will only
examine a subset of the directory entires in its hash chain.  As a result,
it may fail to find its directory entry and incorrectly fail with ENOENT.

To make this safe for use with shared locks, simplify the state stored in
the dirhash and move some of the state (the part that determines if the
current thread is trying the optimization) into a local variable.  One
result is that we will now try the optimization more often.  We still
update the value under the shared lock, but it is a single atomic store
similar to i_diroff that is stored in UFS directory i-nodes for the
non-dirhash lookup.

Reviewed by: kib
MFC after: 1 week
sys/ufs/ufs/dirhash.h
sys/ufs/ufs/ufs_dirhash.c