aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndriy Gapon <avg@FreeBSD.org>2018-10-22 15:33:05 +0000
committerAndriy Gapon <avg@FreeBSD.org>2018-10-22 15:33:05 +0000
commitca8f3d1ca2db70399a8b0f7bada026a73e8a491f (patch)
treefee1e8bd8e32318a6baa309e95f02ce3e7a29d4f
parent43e08d07c5c6f36b96d5139b99d1283870d66d5c (diff)
downloadsrc-ca8f3d1ca2db70399a8b0f7bada026a73e8a491f.tar.gz
src-ca8f3d1ca2db70399a8b0f7bada026a73e8a491f.zip
nfsrvd_readdirplus: for some errors, do not fail the entire request
Instead, a failing entry is skipped. This change consist of two logical changes. A failure to vget or lookup an entry is considered to be a result of a concurrent removal, which is the only reasonable explanation given that the filesystem is busied. So, the entry would be silently skipped. In the case of a failure to get attributes of an entry for an NFSv3 request, the entry would be silently skipped. There can be legitimate reasons for the failure, but NFSv3 does not provide any means to report the error, so we have two options: either fail the whole request or ignore the failed entry. Traditionally, the old NFS server used the latter option, so the code is reverted to it. Making the whole directory unreadable because of a single entry seems to be unpractical. Additionally, some bits of code are slightly re-arranged to account for the new control flow and to honor style(9). Reviewed by: rmacklem Sponsored by: Panzura Differential Revision: https://reviews.freebsd.org/D15424
Notes
Notes: svn path=/head/; revision=339595
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c41
1 files changed, 31 insertions, 10 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index d0296a101c73..72c5051c69fb 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -2416,10 +2416,22 @@ again:
}
}
}
- if (!r) {
- if (refp == NULL &&
- ((nd->nd_flag & ND_NFSV3) ||
- NFSNONZERO_ATTRBIT(&attrbits))) {
+
+ /*
+ * If we failed to look up the entry, then it
+ * has become invalid, most likely removed.
+ */
+ if (r != 0) {
+ if (needs_unbusy)
+ vfs_unbusy(new_mp);
+ goto invalid;
+ }
+ KASSERT(refp != NULL || nvp != NULL,
+ ("%s: undetected lookup error", __func__));
+
+ if (refp == NULL &&
+ ((nd->nd_flag & ND_NFSV3) ||
+ NFSNONZERO_ATTRBIT(&attrbits))) {
r = nfsvno_getfh(nvp, &nfh, p);
if (!r)
r = nfsvno_getattr(nvp, nvap, nd, p,
@@ -2440,17 +2452,25 @@ again:
if (new_mp == mp)
new_mp = nvp->v_mount;
}
- }
- } else {
- nvp = NULL;
}
- if (r) {
+
+ /*
+ * If we failed to get attributes of the entry,
+ * then just skip it for NFSv3 (the traditional
+ * behavior in the old NFS server).
+ * For NFSv4 the behavior is controlled by
+ * RDATTRERROR: we either ignore the error or
+ * fail the request.
+ * Note that RDATTRERROR is never set for NFSv3.
+ */
+ if (r != 0) {
if (!NFSISSET_ATTRBIT(&attrbits,
NFSATTRBIT_RDATTRERROR)) {
- if (nvp != NULL)
- vput(nvp);
+ vput(nvp);
if (needs_unbusy != 0)
vfs_unbusy(new_mp);
+ if ((nd->nd_flag & ND_NFSV3))
+ goto invalid;
nd->nd_repstat = r;
break;
}
@@ -2519,6 +2539,7 @@ again:
if (dirlen <= cnt)
entrycnt++;
}
+invalid:
cpos += dp->d_reclen;
dp = (struct dirent *)cpos;
cookiep++;