From owner-svn-src-projects@freebsd.org Mon Aug 12 05:25:42 2019 Return-Path: Delivered-To: svn-src-projects@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id CE655CE098 for ; Mon, 12 Aug 2019 05:25:42 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 466PSk5ZB3z3LqP; Mon, 12 Aug 2019 05:25:42 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 9C17621BDB; Mon, 12 Aug 2019 05:25:42 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x7C5Pg8f076304; Mon, 12 Aug 2019 05:25:42 GMT (envelope-from rmacklem@FreeBSD.org) Received: (from rmacklem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x7C5PeB9076296; Mon, 12 Aug 2019 05:25:40 GMT (envelope-from rmacklem@FreeBSD.org) Message-Id: <201908120525.x7C5PeB9076296@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: rmacklem set sender to rmacklem@FreeBSD.org using -f From: Rick Macklem Date: Mon, 12 Aug 2019 05:25:40 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r350884 - in projects/nfsv42/sys/fs: nfs nfsclient nfsserver X-SVN-Group: projects X-SVN-Commit-Author: rmacklem X-SVN-Commit-Paths: in projects/nfsv42/sys/fs: nfs nfsclient nfsserver X-SVN-Commit-Revision: 350884 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Aug 2019 05:25:42 -0000 Author: rmacklem Date: Mon Aug 12 05:25:40 2019 New Revision: 350884 URL: https://svnweb.freebsd.org/changeset/base/350884 Log: Add support for the Seek operation to the NFSv4.2 client and server. Modified: projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c projects/nfsv42/sys/fs/nfs/nfs_var.h projects/nfsv42/sys/fs/nfs/nfsport.h projects/nfsv42/sys/fs/nfs/nfsproto.h projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c Modified: projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c ============================================================================== --- projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c Mon Aug 12 03:03:56 2019 (r350883) +++ projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c Mon Aug 12 05:25:40 2019 (r350884) @@ -177,7 +177,7 @@ struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = { { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Cancel */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Offload Status */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Read Plus */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Seek */ + { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Seek */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Write Same */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Clone */ }; @@ -206,7 +206,7 @@ static struct nfsrv_lughash *nfsgroupnamehash; */ static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }; /* local functions */ static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); @@ -283,6 +283,7 @@ static struct { { NFSV4OP_IOADVISE, 1, "Advise", 6, }, { NFSV4OP_ALLOCATE, 2, "Allocate", 8, }, { NFSV4OP_SAVEFH, 5, "Copy", 4, }, + { NFSV4OP_SEEK, 2, "Seek", 4, }, }; /* @@ -291,7 +292,7 @@ static struct { static int nfs_bigrequest[NFSV42_NPROCS] = { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; /* Modified: projects/nfsv42/sys/fs/nfs/nfs_var.h ============================================================================== --- projects/nfsv42/sys/fs/nfs/nfs_var.h Mon Aug 12 03:03:56 2019 (r350883) +++ projects/nfsv42/sys/fs/nfs/nfs_var.h Mon Aug 12 05:25:40 2019 (r350884) @@ -281,6 +281,8 @@ int nfsrvd_allocate(struct nfsrv_descript *, int, vnode_t, struct nfsexstuff *); int nfsrvd_copy_file_range(struct nfsrv_descript *, int, vnode_t, vnode_t, struct nfsexstuff *, struct nfsexstuff *); +int nfsrvd_seek(struct nfsrv_descript *, int, + vnode_t, struct nfsexstuff *); int nfsrvd_notsupp(struct nfsrv_descript *, int, vnode_t, struct nfsexstuff *); @@ -540,6 +542,8 @@ int nfsrpc_allocate(vnode_t, off_t, off_t, struct nfsv int nfsrpc_copy_file_range(vnode_t, off_t *, vnode_t, off_t *, size_t *, unsigned int, int *, struct nfsvattr *, int *, struct nfsvattr *, struct ucred *, bool, bool *); +int nfsrpc_seek(vnode_t, off_t *, bool *, int, struct ucred *, + struct nfsvattr *, int *); /* nfs_clstate.c */ int nfscl_open(vnode_t, u_int8_t *, int, u_int32_t, int, Modified: projects/nfsv42/sys/fs/nfs/nfsport.h ============================================================================== --- projects/nfsv42/sys/fs/nfs/nfsport.h Mon Aug 12 03:03:56 2019 (r350883) +++ projects/nfsv42/sys/fs/nfs/nfsport.h Mon Aug 12 05:25:40 2019 (r350884) @@ -397,11 +397,12 @@ #define NFSPROC_IOADVISE 56 #define NFSPROC_ALLOCATE 57 #define NFSPROC_COPY 58 +#define NFSPROC_SEEK 59 /* * Must be defined as one higher than the last NFSv4.2 Proc# above. */ -#define NFSV42_NPROCS 59 +#define NFSV42_NPROCS 60 #endif /* NFS_V3NPROCS */ @@ -430,7 +431,7 @@ struct nfsstatsv1 { uint64_t readlink_bios; uint64_t biocache_readdirs; uint64_t readdir_bios; - uint64_t rpccnt[NFSV42_NPROCS + 10]; + uint64_t rpccnt[NFSV42_NPROCS + 9]; uint64_t rpcretries; uint64_t srvrpccnt[NFSV42_NOPS + NFSV4OP_FAKENOPS]; uint64_t srvrpc_errs; Modified: projects/nfsv42/sys/fs/nfs/nfsproto.h ============================================================================== --- projects/nfsv42/sys/fs/nfs/nfsproto.h Mon Aug 12 03:03:56 2019 (r350883) +++ projects/nfsv42/sys/fs/nfs/nfsproto.h Mon Aug 12 05:25:40 2019 (r350884) @@ -381,11 +381,12 @@ #define NFSPROC_IOADVISE 56 #define NFSPROC_ALLOCATE 57 #define NFSPROC_COPY 58 +#define NFSPROC_SEEK 59 /* * Must be defined as one higher than the last NFSv4.2 Proc# above. */ -#define NFSV42_NPROCS 59 +#define NFSV42_NPROCS 60 #endif /* NFS_V3NPROCS */ @@ -1477,5 +1478,9 @@ typedef struct nfsv4stateid nfsv4stateid_t; #define NFSV4LAYOUTRET_FILE 1 #define NFSV4LAYOUTRET_FSID 2 #define NFSV4LAYOUTRET_ALL 3 + +/* Seek Contents. */ +#define NFSV4CONTENT_DATA 0 +#define NFSV4CONTENT_HOLE 1 #endif /* _NFS_NFSPROTO_H_ */ Modified: projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c ============================================================================== --- projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c Mon Aug 12 03:03:56 2019 (r350883) +++ projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c Mon Aug 12 05:25:40 2019 (r350884) @@ -216,6 +216,8 @@ static int nfsrpc_layoutgetres(struct nfsmount *, vnod static int nfsrpc_copyrpc(vnode_t, off_t, vnode_t, off_t, size_t *, nfsv4stateid_t *, nfsv4stateid_t *, struct nfsvattr *, int *, struct nfsvattr *, int *, bool, int *, struct ucred *, NFSPROC_T *); +static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *, + int, struct nfsvattr *, int *, struct ucred *); int nfs_pnfsio(task_fn_t *, void *); @@ -8139,6 +8141,100 @@ nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outv } if (error == 0) error = nd->nd_repstat; +nfsmout: + mbuf_freem(nd->nd_mrep); + return (error); +} + +/* + * Seek operation. + */ +APPLESTATIC int +nfsrpc_seek(vnode_t vp, off_t *offp, bool *eofp, int content, + struct ucred *cred, struct nfsvattr *nap, int *attrflagp) +{ + int error, expireret = 0, retrycnt; + u_int32_t clidrev = 0; + struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); + struct nfsnode *np = VTONFS(vp); + struct nfsfh *nfhp = NULL; + nfsv4stateid_t stateid; + void *lckp; + + if (nmp->nm_clp != NULL) + clidrev = nmp->nm_clp->nfsc_clientidrev; + nfhp = np->n_fhp; + retrycnt = 0; + do { + lckp = NULL; + nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, + NFSV4OPEN_ACCESSREAD, 0, cred, curthread, &stateid, &lckp); + error = nfsrpc_seekrpc(vp, offp, &stateid, eofp, content, + nap, attrflagp, cred); + if (error == NFSERR_STALESTATEID) + nfscl_initiate_recovery(nmp->nm_clp); + if (lckp != NULL) + nfscl_lockderef(lckp); + if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || + error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || + error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { + (void) nfs_catnap(PZERO, error, "nfs_seek"); + } else if ((error == NFSERR_EXPIRED || + error == NFSERR_BADSTATEID) && clidrev != 0) { + expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, + curthread); + } + retrycnt++; + } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || + error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || + error == NFSERR_BADSESSION || + (error == NFSERR_OLDSTATEID && retrycnt < 20) || + ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && + expireret == 0 && clidrev != 0 && retrycnt < 4) || + (error == NFSERR_OPENMODE && retrycnt < 4)); + if (error && retrycnt >= 4) + error = EIO; + return (error); +} + +/* + * The seek RPC. + */ +static int +nfsrpc_seekrpc(vnode_t vp, off_t *offp, nfsv4stateid_t *stateidp, bool *eofp, + int content, struct nfsvattr *nap, int *attrflagp, struct ucred *cred) +{ + uint32_t *tl; + int error; + struct nfsrv_descript nfsd; + struct nfsrv_descript *nd = &nfsd; + nfsattrbit_t attrbits; + + *attrflagp = 0; + NFSCL_REQSTART(nd, NFSPROC_SEEK, vp); + nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); + NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); + txdr_hyper(*offp, tl); tl += 2; + *tl++ = txdr_unsigned(content); + *tl = txdr_unsigned(NFSV4OP_GETATTR); + NFSGETATTR_ATTRBIT(&attrbits); + nfsrv_putattrbit(nd, &attrbits); + error = nfscl_request(nd, vp, curthread, cred, NULL); + if (error != 0) + return (error); + if (nd->nd_repstat == 0) { + NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_HYPER); + if (*tl++ == newnfs_true) + *eofp = true; + else + *eofp = false; + *offp = fxdr_hyper(tl); + /* Just skip over Getattr op status. */ + error = nfsm_loadattr(nd, nap); + if (error == 0) + *attrflagp = 1; + } + error = nd->nd_repstat; nfsmout: mbuf_freem(nd->nd_mrep); return (error); Modified: projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c ============================================================================== --- projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c Mon Aug 12 03:03:56 2019 (r350883) +++ projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c Mon Aug 12 05:25:40 2019 (r350884) @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -145,6 +146,7 @@ static vop_setacl_t nfs_setacl; static vop_advise_t nfs_advise; static vop_allocate_t nfs_allocate; static vop_copy_file_range_t nfs_copy_file_range; +static vop_ioctl_t nfs_ioctl; /* * Global vfs data structures for nfs @@ -185,6 +187,7 @@ static struct vop_vector newnfs_vnodeops_nosig = { .vop_advise = nfs_advise, .vop_allocate = nfs_allocate, .vop_copy_file_range = nfs_copy_file_range, + .vop_ioctl = nfs_ioctl, }; static int @@ -3678,6 +3681,67 @@ nfs_copy_file_range(struct vop_copy_file_range_args *a if (error != 0) error = nfscl_maperr(curthread, error, (uid_t)0, (gid_t)0); + return (error); +} + +/* + * nfs ioctl call + */ +static int +nfs_ioctl(struct vop_ioctl_args *ap) +{ + struct vnode *vp = ap->a_vp; + struct nfsvattr nfsva; + struct nfsmount *nmp; + int attrflag, content, error, ret; + bool eof; + + if (vp->v_type != VREG) + return (ENOTTY); + nmp = VFSTONFS(vp->v_mount); + if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION) { +#ifdef notyet + error = vop_stdioctl(ap); +#else + error = ENOTTY; +#endif + return (error); + } + + error = vn_lock(vp, LK_SHARED); + if (error != 0) + return (EBADF); + + /* Do the actual NFSv4.2 RPC. */ + switch (ap->a_command) { + case FIOSEEKDATA: + content = NFSV4CONTENT_DATA; + break; + case FIOSEEKHOLE: + content = NFSV4CONTENT_HOLE; + break; + default: + return (ENOTTY); + } + attrflag = 0; + if (*((off_t *)ap->a_data) >= VTONFS(vp)->n_size) + error = ENXIO; + else { + error = nfsrpc_seek(vp, (off_t *)ap->a_data, &eof, content, + ap->a_cred, &nfsva, &attrflag); + /* If at eof for FIOSEEKDATA, return ENXIO. */ + if (eof && error == 0 && content == NFSV4CONTENT_DATA) + error = ENXIO; + } + if (attrflag != 0) { + ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); + if (error == 0 && ret != 0) + error = ret; + } + NFSVOPUNLOCK(vp, 0); + + if (error != 0) + error = ENXIO; return (error); } Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c ============================================================================== --- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c Mon Aug 12 03:03:56 2019 (r350883) +++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c Mon Aug 12 05:25:40 2019 (r350884) @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); #ifndef APPLEKEXT #include +#include /* Global vars */ extern u_int32_t newnfs_false, newnfs_true; @@ -5190,7 +5191,7 @@ nfsmout: * nfs copy service */ APPLESTATIC int -nfsrvd_copy_file_range(struct nfsrv_descript *nd, int isdgram, +nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram, vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) { uint32_t *tl; @@ -5226,7 +5227,7 @@ nfsrvd_copy_file_range(struct nfsrv_descript *nd, int instp->ls_ownerlen = 0; instp->ls_op = NULL; instp->ls_uid = nd->nd_cred->cr_uid; - instp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); + instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); clientid.lval[0] = instp->ls_stateid.other[0] = *tl++; clientid.lval[1] = instp->ls_stateid.other[1] = *tl++; if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) @@ -5237,7 +5238,7 @@ nfsrvd_copy_file_range(struct nfsrv_descript *nd, int outstp->ls_ownerlen = 0; outstp->ls_op = NULL; outstp->ls_uid = nd->nd_cred->cr_uid; - outstp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); + outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); outstp->ls_stateid.other[0] = *tl++; outstp->ls_stateid.other[1] = *tl++; outstp->ls_stateid.other[2] = *tl++; @@ -5398,6 +5399,98 @@ out: nfsmout: vput(vp); vrele(tovp); + NFSEXITCODE2(error, nd); + return (error); +} + +/* + * nfs seek service + */ +APPLESTATIC int +nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram, + vnode_t vp, struct nfsexstuff *exp) +{ + uint32_t *tl; + struct nfsvattr at; + int content, error = 0; + off_t off; + u_long cmd; + nfsattrbit_t attrbits; + + if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { + nd->nd_repstat = NFSERR_WRONGSEC; + goto nfsmout; + } + if (nfsrv_devidcnt > 0) { + nd->nd_repstat = NFSERR_NOTSUPP; + goto nfsmout; + } + NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED); + /* Ignore the stateid for now. */ + tl += (NFSX_STATEID / NFSX_UNSIGNED); + off = fxdr_hyper(tl); tl += 2; + content = fxdr_unsigned(int, *tl); + if (content == NFSV4CONTENT_DATA) + cmd = FIOSEEKDATA; + else if (content == NFSV4CONTENT_HOLE) + cmd = FIOSEEKHOLE; + else + nd->nd_repstat = NFSERR_BADXDR; + if (nd->nd_repstat == 0 && (nd->nd_flag & ND_DSSERVER) != 0) + nd->nd_repstat = NFSERR_NOTSUPP; + if (nd->nd_repstat == 0 && vnode_vtype(vp) == VDIR) + nd->nd_repstat = NFSERR_ISDIR; + if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) + nd->nd_repstat = NFSERR_WRONGTYPE; + if (nd->nd_repstat == 0 && off < 0) + nd->nd_repstat = NFSERR_NXIO; + if (nd->nd_repstat == 0) { + /* Check permissions for the input file. */ + NFSZERO_ATTRBIT(&attrbits); + NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); + NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE); + nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1, + &attrbits); + } + if (nd->nd_repstat == 0 && off > at.na_size) + nd->nd_repstat = NFSERR_NXIO; + if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || + NFSVNO_EXSTRICTACCESS(exp))) + nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, + curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, + NULL); + if (nd->nd_repstat != 0) + goto nfsmout; + + if (off < at.na_size) { + NFSVOPUNLOCK(vp, 0); + nd->nd_repstat = VOP_IOCTL(vp, cmd, &off, 0, nd->nd_cred, + curthread); + vrele(vp); + if (nd->nd_repstat == ENOTTY || nd->nd_repstat == ENXIO) { + /* + * For FIOSEEKHOLE, find the "virtual hole" at EOF. + * For FIOSEEKDATA, just return the offset in the + * request unless the error is ENXIO. + */ + if (cmd == FIOSEEKHOLE || error == ENXIO) + off = at.na_size; + nd->nd_repstat = 0; + } + } else + vput(vp); + if (nd->nd_repstat == 0) { + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); + if (off == at.na_size) + *tl++ = newnfs_true; + else + *tl++ = newnfs_false; + txdr_hyper(off, tl); + } + NFSEXITCODE2(error, nd); + return (error); +nfsmout: + vput(vp); NFSEXITCODE2(error, nd); return (error); } Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c ============================================================================== --- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c Mon Aug 12 03:03:56 2019 (r350883) +++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c Mon Aug 12 05:25:40 2019 (r350884) @@ -206,7 +206,7 @@ int (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript nfsrvd_notsupp, nfsrvd_notsupp, nfsrvd_notsupp, - nfsrvd_notsupp, + nfsrvd_seek, nfsrvd_notsupp, nfsrvd_notsupp, };