summaryrefslogtreecommitdiffstats
path: root/sys/nfsclient
diff options
context:
space:
mode:
authorps <ps@FreeBSD.org>2004-12-01 06:51:07 +0000
committerps <ps@FreeBSD.org>2004-12-01 06:51:07 +0000
commit36019877652c79fb03325c5c3033e24a7f02da6f (patch)
treeb5f91d4db0f16d3dcd4c6380310895ec555d8828 /sys/nfsclient
parent531cb416aedb221d9b2ae727002a2893350f73da (diff)
downloadFreeBSD-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')
-rw-r--r--sys/nfsclient/nfs_vnops.c28
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)) {
OpenPOWER on IntegriCloud