diff options
author | ps <ps@FreeBSD.org> | 2004-12-01 06:51:07 +0000 |
---|---|---|
committer | ps <ps@FreeBSD.org> | 2004-12-01 06:51:07 +0000 |
commit | 36019877652c79fb03325c5c3033e24a7f02da6f (patch) | |
tree | b5f91d4db0f16d3dcd4c6380310895ec555d8828 /sys/nfsclient/nfs_vnops.c | |
parent | 531cb416aedb221d9b2ae727002a2893350f73da (diff) | |
download | FreeBSD-src-36019877652c79fb03325c5c3033e24a7f02da6f.zip FreeBSD-src-36019877652c79fb03325c5c3033e24a7f02da6f.tar.gz |
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
Diffstat (limited to 'sys/nfsclient/nfs_vnops.c')
-rw-r--r-- | sys/nfsclient/nfs_vnops.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c index 50edb58..2d2b7f2 100644 --- a/sys/nfsclient/nfs_vnops.c +++ b/sys/nfsclient/nfs_vnops.c @@ -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)) { |