Date: Sat, 27 Apr 2019 20:22:31 +0000 (UTC) From: Rick Macklem <rmacklem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r346794 - in projects/nfsv42/sys/fs: nfs nfsclient nfsserver Message-ID: <201904272022.x3RKMVVg075211@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rmacklem Date: Sat Apr 27 20:22:31 2019 New Revision: 346794 URL: https://svnweb.freebsd.org/changeset/base/346794 Log: Add some support for the posix_fallocate(2) syscall to the NFSv42 client/server. Also, update the NFSv42 vop_advise to call vop_stdvopadvise() to handle buffer cache updates in the client. 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 Sat Apr 27 19:48:15 2019 (r346793) +++ projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c Sat Apr 27 20:22:31 2019 (r346794) @@ -166,7 +166,7 @@ struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = { { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */ { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */ - { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Allocate */ + { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Allocate */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy Notify */ { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Deallocate */ @@ -205,7 +205,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, 1, 0, 0, 0, 0, 0 }; /* local functions */ static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); @@ -281,6 +281,7 @@ static struct { { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, }, { NFSV4OP_OPEN, 8, "CreateLayGet", 12, }, { NFSV4OP_IOADVISE, 1, "Advise", 6, }, + { NFSV4OP_ALLOCATE, 2, "Allocate", 8, }, }; /* @@ -289,7 +290,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, 1, 0, 0, 0, 0, 0, 0 }; /* Modified: projects/nfsv42/sys/fs/nfs/nfs_var.h ============================================================================== --- projects/nfsv42/sys/fs/nfs/nfs_var.h Sat Apr 27 19:48:15 2019 (r346793) +++ projects/nfsv42/sys/fs/nfs/nfs_var.h Sat Apr 27 20:22:31 2019 (r346794) @@ -543,6 +543,8 @@ int nfscl_doiods(vnode_t, struct uio *, int *, int *, int nfscl_findlayoutforio(struct nfscllayout *, uint64_t, uint32_t, struct nfsclflayout **); void nfscl_freenfsclds(struct nfsclds *); +int nfsrpc_allocate(vnode_t, off_t, off_t, struct nfsvattr *, int *, + struct ucred *, NFSPROC_T *, void *); /* 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 Sat Apr 27 19:48:15 2019 (r346793) +++ projects/nfsv42/sys/fs/nfs/nfsport.h Sat Apr 27 20:22:31 2019 (r346794) @@ -395,11 +395,12 @@ /* Additional procedures for NFSv4.2. */ #define NFSPROC_IOADVISE 56 +#define NFSPROC_ALLOCATE 57 /* * Must be defined as one higher than the last NFSv4.2 Proc# above. */ -#define NFSV42_NPROCS 57 +#define NFSV42_NPROCS 58 #endif /* NFS_V3NPROCS */ @@ -428,7 +429,7 @@ struct nfsstatsv1 { uint64_t readlink_bios; uint64_t biocache_readdirs; uint64_t readdir_bios; - uint64_t rpccnt[NFSV42_NPROCS + 12]; + uint64_t rpccnt[NFSV42_NPROCS + 11]; 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 Sat Apr 27 19:48:15 2019 (r346793) +++ projects/nfsv42/sys/fs/nfs/nfsproto.h Sat Apr 27 20:22:31 2019 (r346794) @@ -367,11 +367,12 @@ /* Additional procedures for NFSv4.2. */ #define NFSPROC_IOADVISE 56 +#define NFSPROC_ALLOCATE 57 /* * Must be defined as one higher than the last NFSv4.2 Proc# above. */ -#define NFSV42_NPROCS 57 +#define NFSV42_NPROCS 58 #endif /* NFS_V3NPROCS */ Modified: projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c ============================================================================== --- projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c Sat Apr 27 19:48:15 2019 (r346793) +++ projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c Sat Apr 27 20:22:31 2019 (r346794) @@ -182,6 +182,8 @@ static int nfsio_adviseds(vnode_t, uint64_t, int, int, static int nfsrpc_adviseds(vnode_t, uint64_t, int, int, struct nfsclds *, struct nfsfh *, int, int, struct ucred *, NFSPROC_T *); #endif +static int nfsrpc_allocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *, + struct nfsvattr *, int *, struct ucred *, NFSPROC_T *, void *); static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t, uint64_t, uint64_t, nfsv4stateid_t *, int, int, int); static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *, @@ -6838,6 +6840,118 @@ nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, i return (error); } #endif /* notyet */ + +/* + * Do the Allocate operation, retrying for recovery. + */ +APPLESTATIC int +nfsrpc_allocate(vnode_t vp, off_t off, off_t len, struct nfsvattr *nap, + int *attrflagp, struct ucred *cred, NFSPROC_T *p, void *stuff) +{ + int error, expireret = 0, retrycnt, nostateid; + uint32_t clidrev = 0; + struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); + struct nfsfh *nfhp = NULL; + nfsv4stateid_t stateid; + off_t tmp_off; + void *lckp; + + if (len < 0) + return (EINVAL); + if (len == 0) + return (0); + tmp_off = off + len; + NFSLOCKMNT(nmp); + if (tmp_off > nmp->nm_maxfilesize || tmp_off < off) { + NFSUNLOCKMNT(nmp); + return (EFBIG); + } + if (nmp->nm_clp != NULL) + clidrev = nmp->nm_clp->nfsc_clientidrev; + NFSUNLOCKMNT(nmp); + nfhp = VTONFS(vp)->n_fhp; + retrycnt = 0; + do { + lckp = NULL; + nostateid = 0; + nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, + NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp); + if (stateid.other[0] == 0 && stateid.other[1] == 0 && + stateid.other[2] == 0) { + nostateid = 1; + NFSCL_DEBUG(1, "stateid0 in allocate\n"); + } + + /* + * Not finding a stateid should probably never happen, + * but just return an error for this case. + */ + if (nostateid != 0) + error = EIO; + else + error = nfsrpc_allocaterpc(vp, off, len, &stateid, + nap, attrflagp, cred, p, stuff); + 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_allocate"); + } else if ((error == NFSERR_EXPIRED || + error == NFSERR_BADSTATEID) && clidrev != 0) { + expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); + } + retrycnt++; + } while (error == NFSERR_GRACE || error == NFSERR_DELAY || + error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || + error == NFSERR_STALEDONTRECOVER || + (error == NFSERR_OLDSTATEID && retrycnt < 20) || + ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && + expireret == 0 && clidrev != 0 && retrycnt < 4)); + if (error != 0 && retrycnt >= 4) + error = EIO; + return (error); +} + +/* + * The allocate RPC. + */ +static int +nfsrpc_allocaterpc(vnode_t vp, off_t off, off_t len, nfsv4stateid_t *stateidp, + struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p, + void *stuff) +{ + uint32_t *tl; + int error; + struct nfsrv_descript nfsd; + struct nfsrv_descript *nd = &nfsd; + nfsattrbit_t attrbits; + + *attrflagp = 0; + NFSCL_REQSTART(nd, NFSPROC_ALLOCATE, vp); + nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); + NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); + txdr_hyper(off, tl); tl += 2; + txdr_hyper(len, tl); tl += 2; + *tl = txdr_unsigned(NFSV4OP_GETATTR); + NFSGETATTR_ATTRBIT(&attrbits); + nfsrv_putattrbit(nd, &attrbits); + error = nfscl_request(nd, vp, p, cred, stuff); + if (error != 0) + return (error); + if (nd->nd_repstat == 0) { + NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + error = nfsm_loadattr(nd, nap); + if (error == 0) + *attrflagp = NFS_LATTR_NOSHRINK; + } else + error = nd->nd_repstat; +nfsmout: + mbuf_freem(nd->nd_mrep); + return (error); +} /* * Set up the XDR arguments for the LayoutGet operation. Modified: projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c ============================================================================== --- projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c Sat Apr 27 19:48:15 2019 (r346793) +++ projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c Sat Apr 27 20:22:31 2019 (r346794) @@ -144,6 +144,7 @@ static vop_getacl_t nfs_getacl; static vop_setacl_t nfs_setacl; static vop_set_text_t nfs_set_text; static vop_advise_t nfs_advise; +static vop_allocate_t nfs_allocate; /* * Global vfs data structures for nfs @@ -183,6 +184,7 @@ static struct vop_vector newnfs_vnodeops_nosig = { .vop_setacl = nfs_setacl, .vop_set_text = nfs_set_text, .vop_advise = nfs_advise, + .vop_allocate = nfs_allocate, }; static int @@ -3458,7 +3460,14 @@ nfs_advise(struct vop_advise_args *ap) struct thread *td = curthread; struct nfsmount *nmp; uint64_t len; + int error; + /* + * First do vop_stdadvise() to handle the buffer cache. + */ + error = vop_stdadvise(ap); + if (error != 0) + return (error); if (ap->a_start < 0 || ap->a_end < 0) return (0); if (ap->a_end == OFF_MAX) @@ -3468,12 +3477,56 @@ nfs_advise(struct vop_advise_args *ap) else len = ap->a_end - ap->a_start + 1; nmp = VFSTONFS(ap->a_vp->v_mount); - if (NFSHASPNFS(nmp) && (nmp->nm_privflag & NFSMNTP_IOADVISETHRUMDS) == - 0) + if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION || + (NFSHASPNFS(nmp) && (nmp->nm_privflag & NFSMNTP_IOADVISETHRUMDS) == + 0)) return (0); nfsrpc_advise(ap->a_vp, ap->a_start, len, ap->a_advice, td->td_ucred, td); return (0); +} + +/* + * nfs allocate call + */ +static int +nfs_allocate(struct vop_allocate_args *ap) +{ + struct vnode *vp = ap->a_vp; + struct thread *td = curthread; + struct nfsvattr nfsva; + struct nfsmount *nmp; + int attrflag, error, ret; + + attrflag = 0; + nmp = VFSTONFS(vp->v_mount); + if (NFSHASNFSV4(nmp) && nmp->nm_minorvers >= NFSV42_MINORVERSION) { +printf("at alloc\n"); + error = nfsrpc_allocate(vp, *ap->a_offset, *ap->a_len, &nfsva, + &attrflag, td->td_ucred, td, NULL); +printf("aft alloc=%d\n", error); + if (error == 0) { + *ap->a_offset += *ap->a_len; + *ap->a_len = 0; + } + } else + error = EIO; + /* + * If the NFS server cannot perform the Allocate operation, just call + * vop_stdallocate() to perform it. + */ + if (error != 0) + error = vop_stdallocate(ap); +printf("aft stdalloc=%d af=%d\n", error, attrflag); + if (attrflag != 0) { + ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); + if (error == 0 && ret != 0) + error = ret; + } + if (error != 0) + error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); +printf("eo alloc=%d\n", error); + return (error); } /* Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c ============================================================================== --- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c Sat Apr 27 19:48:15 2019 (r346793) +++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c Sat Apr 27 20:22:31 2019 (r346794) @@ -4993,6 +4993,93 @@ nfsmout: } /* + * nfs allocate service + */ +APPLESTATIC int +nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram, + vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) +{ + uint32_t *tl; + struct nfsvattr forat; + int error = 0, forat_ret = 1, trycnt; + off_t off, len; + struct nfsstate st, *stp = &st; + struct nfslock lo, *lop = &lo; + nfsv4stateid_t stateid; + nfsquad_t clientid; + nfsattrbit_t attrbits; + + NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); + stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); + lop->lo_flags = NFSLCK_WRITE; + stp->ls_ownerlen = 0; + stp->ls_op = NULL; + stp->ls_uid = nd->nd_cred->cr_uid; + stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); + clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; + clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; + if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { + if ((nd->nd_flag & ND_NFSV41) != 0) + clientid.qval = nd->nd_clientid.qval; + else if (nd->nd_clientid.qval != clientid.qval) + printf("EEK2 multiple clids\n"); + } else { + if ((nd->nd_flag & ND_NFSV41) != 0) + printf("EEK! no clientid from session\n"); + nd->nd_flag |= ND_IMPLIEDCLID; + nd->nd_clientid.qval = clientid.qval; + } + stp->ls_stateid.other[2] = *tl++; + /* + * Don't allow this to be done for a DS. + */ + if ((nd->nd_flag & ND_DSSERVER) != 0) + nd->nd_repstat = NFSERR_NOTSUPP; + off = fxdr_hyper(tl); tl += 2; + lop->lo_first = off; + len = fxdr_hyper(tl); + lop->lo_end = off + len; + /* + * Paranoia, just in case it wraps around, which shouldn't + * ever happen anyhow. + */ + if (nd->nd_repstat == 0 && lop->lo_end < lop->lo_first) + nd->nd_repstat = NFSERR_INVAL; + + if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) + nd->nd_repstat = NFSERR_WRONGTYPE; + NFSZERO_ATTRBIT(&attrbits); + NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); + forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits); + if (nd->nd_repstat == 0) + nd->nd_repstat = forat_ret; + if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || + NFSVNO_EXSTRICTACCESS(exp))) + nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, + NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); + if (nd->nd_repstat == 0) + nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, + &stateid, exp, nd, p); + + /* + * Do the actual VOP_ALLOCATE(), looping a reasonable number of + * times to achieve completion. + */ + trycnt = 0; + while (nd->nd_repstat == 0 && len > 0 && trycnt++ < 20) + nd->nd_repstat = VOP_ALLOCATE(vp, &off, &len); + if (nd->nd_repstat == 0 && len > 0) + nd->nd_repstat = NFSERR_IO; + vput(vp); + NFSEXITCODE2(0, nd); + return (0); +nfsmout: + vput(vp); + NFSEXITCODE2(error, nd); + return (error); +} + +/* * nfsv4 service not supported */ APPLESTATIC int Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c ============================================================================== --- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c Sat Apr 27 19:48:15 2019 (r346793) +++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c Sat Apr 27 20:22:31 2019 (r346794) @@ -198,7 +198,7 @@ int (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript nfsrvd_notsupp, nfsrvd_destroyclientid, nfsrvd_reclaimcomplete, - nfsrvd_notsupp, + nfsrvd_allocate, nfsrvd_notsupp, nfsrvd_notsupp, nfsrvd_notsupp,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904272022.x3RKMVVg075211>