Index: sys/fs/nfsserver/nfs_nfsdport.c =================================================================== --- sys/fs/nfsserver/nfs_nfsdport.c +++ sys/fs/nfsserver/nfs_nfsdport.c @@ -2169,39 +2169,57 @@ } } } - 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; + } + + 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 bheavior is controlled by + * RDATTRERROR. + */ + if (r != 0) { + if ((nd->nd_flag & ND_NFSV3) != 0) + goto invalid; if (!NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR)) { - if (nvp != NULL) - vput(nvp); + vput(nvp); if (needs_unbusy != 0) vfs_unbusy(new_mp); nd->nd_repstat = r; @@ -2225,27 +2243,21 @@ nfsrv_postopattr(nd, 0, nvap); dirlen += nfsm_fhtom(nd,(u_int8_t *)&nfh,0,1); dirlen += (5*NFSX_UNSIGNED+NFSX_V3POSTOPATTR); - if (nvp != NULL) - vput(nvp); + vput(nvp); } else { NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); *tl++ = newnfs_true; *tl++ = 0; *tl = txdr_unsigned(*cookiep); dirlen += nfsm_strtom(nd, dp->d_name, nlen); - if (nvp != NULL) { - supports_nfsv4acls = - nfs_supportsnfsv4acls(nvp); - NFSVOPUNLOCK(nvp, 0); - } else - supports_nfsv4acls = 0; + supports_nfsv4acls = nfs_supportsnfsv4acls(nvp); + NFSVOPUNLOCK(nvp, 0); if (refp != NULL) { dirlen += nfsrv_putreferralattr(nd, &savbits, refp, 0, &nd->nd_repstat); if (nd->nd_repstat) { - if (nvp != NULL) - vrele(nvp); + vrele(nvp); if (needs_unbusy != 0) vfs_unbusy(new_mp); break; @@ -2263,8 +2275,7 @@ supports_nfsv4acls, at_root, mounted_on_fileno); } - if (nvp != NULL) - vrele(nvp); + vrele(nvp); dirlen += (3 * NFSX_UNSIGNED); } if (needs_unbusy != 0) @@ -2272,6 +2283,7 @@ if (dirlen <= cnt) entrycnt++; } +invalid: cpos += dp->d_reclen; dp = (struct dirent *)cpos; cookiep++;