summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2011-04-17 02:44:51 +0000
committerrmacklem <rmacklem@FreeBSD.org>2011-04-17 02:44:51 +0000
commit38b3fd21a2339767935db059b819816e64cc9430 (patch)
tree06e816454ccc115045bdb6d7bf54df69a1917b4f
parentd77942ccd46b9d83e6034e871a4c714b3ab64614 (diff)
downloadFreeBSD-src-38b3fd21a2339767935db059b819816e64cc9430.zip
FreeBSD-src-38b3fd21a2339767935db059b819816e64cc9430.tar.gz
Fix readdirplus in the experimental NFS client so that it
skips over ".." to avoid a LOR race with nfs_lookup(). This fix is analagous to r138256 in the regular NFS client. MFC after: 2 weeks
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index bb4f4ba..6e4c046 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -2942,7 +2942,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
nfsquad_t cookie, ncookie;
int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
- int unlocknewvp = 0;
+ int isdotdot = 0, unlocknewvp = 0;
long dotfileid, dotdotfileid = 0, fileno = 0;
char *cp;
nfsattrbit_t attrbits, dattrbits;
@@ -3192,6 +3192,11 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
*cp = '\0';
cp += tlen; /* points to cookie storage */
tl2 = (u_int32_t *)cp;
+ if (len == 2 && cnp->cn_nameptr[0] == '.' &&
+ cnp->cn_nameptr[1] == '.')
+ isdotdot = 1;
+ else
+ isdotdot = 0;
uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
@@ -3269,6 +3274,22 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
unlocknewvp = 0;
FREE((caddr_t)nfhp, M_NFSFH);
np = dnp;
+ } else if (isdotdot != 0) {
+ /*
+ * Skip doing a nfscl_nget() call for "..".
+ * There's a race between acquiring the nfs
+ * node here and lookups that look for the
+ * directory being read (in the parent).
+ * It would try to get a 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.
+ * If the directory is unlocked/relocked,
+ * then there is a LOR with the buflock
+ * vp is relocked.
+ */
+ free(nfhp, M_NFSFH);
} else {
error = nfscl_nget(vnode_mount(vp), vp,
nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
OpenPOWER on IntegriCloud