Fix for a race between lookup and readdirplus, that causes

a deadlock (with NFS exclusive vnode locks enabled). Lookup
grabs the parent's lock and wants to lock child. Readdirplus
locks the child and wants to lock parent (for loading the attrs
for ".."). The fix is to not load the attrs for ".." in
readdirplus.

Submitted by:	Mohan Srinivasan mohans at yahoo-inc dot com
Reviewed by:	rwatson
This commit is contained in:
Paul Saab 2004-12-01 06:51:07 +00:00
parent 3e9c9e432a
commit cd15125084
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=138256

View File

@ -2272,6 +2272,34 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred)
nfsm_adv(NFSX_V3FATTR);
tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
doit = fxdr_unsigned(int, *tl);
/*
* Skip loading the attrs for "..". There's a
* race between loading the attrs here and
* lookups that look for the directory currently
* being read (in the parent). We try to acquire
* the exclusive lock on ".." here, owning the
* lock on the directory being read. Lookup will
* hold the lock on ".." and try to acquire the
* lock on the directory being read.
*
* There are other ways of fixing this, one would
* be to do a trylock on the ".." vnode and skip
* loading the attrs on ".." if it happens to be
* locked by another process. But skipping the
* attrload on ".." seems the easiest option.
*/
if (strcmp(dp->d_name, "..") == 0) {
doit = 0;
/*
* We've already skipped over the attrs,
* skip over the filehandle. And store d_type
* as VDIR.
*/
tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
i = fxdr_unsigned(int, *tl);
nfsm_adv(nfsm_rndup(i));
dp->d_type = IFTODT(VTTOIF(VDIR));
}
if (doit) {
nfsm_getfh(fhp, fhsize, 1);
if (NFS_CMPFH(dnp, fhp, fhsize)) {