svn commit: r346794 - in projects/nfsv42/sys/fs: nfs nfsclient nfsserver
Rick Macklem
rmacklem at FreeBSD.org
Sat Apr 27 20:22:34 UTC 2019
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,
More information about the svn-src-projects
mailing list