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