Index: sys/fs/nfsserver/nfs_nfsdport.c =================================================================== --- sys/fs/nfsserver/nfs_nfsdport.c +++ sys/fs/nfsserver/nfs_nfsdport.c @@ -2169,39 +2169,64 @@ } } } - 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->nd_cred, p, 1); + if (r == 0) { + r = nfsvno_getattr(nvp, nvap, + nd->nd_cred, p, 1); + } + + /* + * For a ZFS snapshot, there is a + * pseudo mount that does not set + * v_mountedhere, so it needs to + * be detected via a different + * mount structure. + */ if (r == 0 && is_zfs == 1 && nfsrv_enable_crossmntpt != 0 && (nd->nd_flag & ND_NFSV4) != 0 && nvp->v_type == VDIR && vp->v_mount != nvp->v_mount) { - /* - * For a ZFS snapshot, there is a - * pseudo mount that does not set - * v_mountedhere, so it needs to - * be detected via a different - * mount structure. - */ - at_root = 1; - if (new_mp == mp) - new_mp = nvp->v_mount; + at_root = 1; + 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. + */ + if (r != 0) { + if ((nd->nd_flag & ND_NFSV3) != 0) { + vput(nvp); + nvp = NULL; + goto invalid; + } if (!NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR)) { - if (nvp != NULL) - vput(nvp); + vput(nvp); + nvp = NULL; if (needs_unbusy != 0) vfs_unbusy(new_mp); nd->nd_repstat = r; @@ -2272,6 +2297,7 @@ if (dirlen <= cnt) entrycnt++; } +invalid: cpos += dp->d_reclen; dp = (struct dirent *)cpos; cookiep++;