svn commit: r350337 - in projects/nfsv42/sys/fs: nfs nfsclient nfsserver
Rick Macklem
rmacklem at FreeBSD.org
Fri Jul 26 00:27:49 UTC 2019
Author: rmacklem
Date: Fri Jul 26 00:27:47 2019
New Revision: 350337
URL: https://svnweb.freebsd.org/changeset/base/350337
Log:
Add support for Copy (the intra-server case) to the NFSv4.2 client and server.
The NFSv4.2 server now has a method for VOP_COPY_FILE_RANGE() that will do
the Copy intra-server operation on an NFSv4.2 server. If this operation fails
with EACCES, it will be retried with the other credentials, since an NFS
RPC only takes one set of credentials.
If the operation fails due to lack of support (or both attempts fail with
EACCES), then it falls back on vn_generic_copy_file_range() using read/write.
The NFSv4.2 server uses vn_generic_copy_file_range() to perform the Copy
operation.
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/nfsclient/nfsmount.h
projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c
projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c
projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsubs.c
Modified: projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c
==============================================================================
--- projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c Thu Jul 25 22:23:34 2019 (r350336)
+++ projects/nfsv42/sys/fs/nfs/nfs_commonsubs.c Fri Jul 26 00:27:47 2019 (r350337)
@@ -168,7 +168,7 @@ struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */
{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */
{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Allocate */
- { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy */
+ { 2, 1, 1, 0, LK_SHARED, 1, 0 }, /* Copy */
{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Copy Notify */
{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Deallocate */
{ 0, 1, 0, 1, LK_SHARED, 1, 0 }, /* IO Advise */
@@ -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, 1, 0, 0, 0, 0, 0, 0 };
/* local functions */
static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
@@ -282,6 +282,7 @@ static struct {
{ NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
{ NFSV4OP_IOADVISE, 1, "Advise", 6, },
{ NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
+ { NFSV4OP_SAVEFH, 5, "Copy", 4, },
};
/*
@@ -290,7 +291,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, 1, 0, 0, 0, 0, 0, 0, 0
};
/*
Modified: projects/nfsv42/sys/fs/nfs/nfs_var.h
==============================================================================
--- projects/nfsv42/sys/fs/nfs/nfs_var.h Thu Jul 25 22:23:34 2019 (r350336)
+++ projects/nfsv42/sys/fs/nfs/nfs_var.h Fri Jul 26 00:27:47 2019 (r350337)
@@ -279,6 +279,8 @@ int nfsrvd_teststateid(struct nfsrv_descript *, int,
vnode_t, struct nfsexstuff *);
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_notsupp(struct nfsrv_descript *, int,
vnode_t, struct nfsexstuff *);
@@ -535,6 +537,9 @@ int nfscl_findlayoutforio(struct nfscllayout *, uint64
void nfscl_freenfsclds(struct nfsclds *);
int nfsrpc_allocate(vnode_t, off_t, off_t, struct nfsvattr *, int *,
struct ucred *, NFSPROC_T *, void *);
+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 *);
/* 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 Thu Jul 25 22:23:34 2019 (r350336)
+++ projects/nfsv42/sys/fs/nfs/nfsport.h Fri Jul 26 00:27:47 2019 (r350337)
@@ -396,11 +396,12 @@
/* Additional procedures for NFSv4.2. */
#define NFSPROC_IOADVISE 56
#define NFSPROC_ALLOCATE 57
+#define NFSPROC_COPY 58
/*
* Must be defined as one higher than the last NFSv4.2 Proc# above.
*/
-#define NFSV42_NPROCS 58
+#define NFSV42_NPROCS 59
#endif /* NFS_V3NPROCS */
@@ -429,7 +430,7 @@ struct nfsstatsv1 {
uint64_t readlink_bios;
uint64_t biocache_readdirs;
uint64_t readdir_bios;
- uint64_t rpccnt[NFSV42_NPROCS + 11];
+ uint64_t rpccnt[NFSV42_NPROCS + 10];
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 Thu Jul 25 22:23:34 2019 (r350336)
+++ projects/nfsv42/sys/fs/nfs/nfsproto.h Fri Jul 26 00:27:47 2019 (r350337)
@@ -215,6 +215,18 @@
#define NFSERR_RETURNCONFLICT 10086
#define NFSERR_DELEGREVOKED 10087
+/* NFSv4.2 specific errors. */
+#define NFSERR_PARTNERNOTSUPP 10088
+#define NFSERR_PARTNERNOAUTH 10089
+#define NFSERR_UNIONNOTSUPP 10090
+#define NFSERR_OFFLOADDENIED 10091
+#define NFSERR_WRONGLFS 10092
+#define NFSERR_BADLABEL 10093
+#define NFSERR_OFFLOADNOREQS 10094
+
+/* Maximum value of all the NFS error values. */
+#define NFSERR_MAXERRVAL NFSERR_OFFLOADNOREQS
+
#define NFSERR_STALEWRITEVERF 30001 /* Fake return for nfs_commit() */
#define NFSERR_DONTREPLY 30003 /* Don't process request */
#define NFSERR_RETVOID 30004 /* Return void, not error */
@@ -368,11 +380,12 @@
/* Additional procedures for NFSv4.2. */
#define NFSPROC_IOADVISE 56
#define NFSPROC_ALLOCATE 57
+#define NFSPROC_COPY 58
/*
* Must be defined as one higher than the last NFSv4.2 Proc# above.
*/
-#define NFSV42_NPROCS 58
+#define NFSV42_NPROCS 59
#endif /* NFS_V3NPROCS */
Modified: projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c
==============================================================================
--- projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c Thu Jul 25 22:23:34 2019 (r350336)
+++ projects/nfsv42/sys/fs/nfsclient/nfs_clrpcops.c Fri Jul 26 00:27:47 2019 (r350337)
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include "opt_inet6.h"
#include <fs/nfs/nfsport.h>
+#include <fs/nfsclient/nfs.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
@@ -212,6 +213,9 @@ static int nfsrpc_layoutget(struct nfsmount *, uint8_t
static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *,
int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **,
struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_T *);
+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 *);
int nfs_pnfsio(task_fn_t *, void *);
@@ -7946,5 +7950,194 @@ out:
*islockedp = 1;
}
return (laystat);
+}
+
+/*
+ * nfs copy_file_range operation.
+ */
+APPLESTATIC int
+nfsrpc_copy_file_range(vnode_t invp, off_t *inoffp, vnode_t outvp,
+ off_t *outoffp, size_t *lenp, unsigned int flags, int *inattrflagp,
+ struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap,
+ struct ucred *cred, bool consecutive, bool *must_commitp)
+{
+ int commit, error, expireret = 0, retrycnt;
+ u_int32_t clidrev = 0;
+ struct nfsmount *nmp = VFSTONFS(vnode_mount(invp));
+ struct nfsfh *innfhp = NULL, *outnfhp = NULL;
+ nfsv4stateid_t instateid, outstateid;
+ void *inlckp, *outlckp;
+
+ if (nmp->nm_clp != NULL)
+ clidrev = nmp->nm_clp->nfsc_clientidrev;
+ innfhp = VTONFS(invp)->n_fhp;
+ outnfhp = VTONFS(outvp)->n_fhp;
+ retrycnt = 0;
+ do {
+ /* Get both stateids. */
+ inlckp = NULL;
+ nfscl_getstateid(invp, innfhp->nfh_fh, innfhp->nfh_len,
+ NFSV4OPEN_ACCESSREAD, 0, NULL, curthread, &instateid,
+ &inlckp);
+ outlckp = NULL;
+ nfscl_getstateid(outvp, outnfhp->nfh_fh, outnfhp->nfh_len,
+ NFSV4OPEN_ACCESSWRITE, 0, NULL, curthread, &outstateid,
+ &outlckp);
+
+ error = nfsrpc_copyrpc(invp, *inoffp, outvp, *outoffp, lenp,
+ &instateid, &outstateid, innap, inattrflagp, outnap,
+ outattrflagp, consecutive, &commit, cred, curthread);
+ if (error == 0) {
+ if (commit != NFSWRITE_FILESYNC)
+ *must_commitp = true;
+ *inoffp += *lenp;
+ *outoffp += *lenp;
+ } else if (error == NFSERR_STALESTATEID)
+ nfscl_initiate_recovery(nmp->nm_clp);
+ if (inlckp != NULL)
+ nfscl_lockderef(inlckp);
+ if (outlckp != NULL)
+ nfscl_lockderef(outlckp);
+ 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_cfr");
+ } 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_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 == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
+ error == NFSERR_STALEDONTRECOVER))
+ error = EIO;
+ return (error);
+}
+
+/*
+ * The copy RPC.
+ */
+static int
+nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff,
+ size_t *lenp, nfsv4stateid_t *instateidp, nfsv4stateid_t *outstateidp,
+ struct nfsvattr *innap, int *inattrflagp, struct nfsvattr *outnap,
+ int *outattrflagp, bool consecutive, int *commitp, struct ucred *cred,
+ NFSPROC_T *p)
+{
+ uint32_t *tl;
+ int error;
+ struct nfsrv_descript nfsd;
+ struct nfsrv_descript *nd = &nfsd;
+ struct nfsmount *nmp;
+ nfsattrbit_t attrbits;
+ uint64_t len;
+
+ nmp = VFSTONFS(outvp->v_mount);
+ *inattrflagp = *outattrflagp = 0;
+ *commitp = NFSWRITE_UNSTABLE;
+ len = *lenp;
+ *lenp = 0;
+ NFSCL_REQSTART(nd, NFSPROC_COPY, invp);
+ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV4OP_GETATTR);
+ NFSGETATTR_ATTRBIT(&attrbits);
+ nfsrv_putattrbit(nd, &attrbits);
+ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV4OP_PUTFH);
+ nfsm_fhtom(nd, VTONFS(outvp)->n_fhp->nfh_fh,
+ VTONFS(outvp)->n_fhp->nfh_len, 0);
+ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV4OP_COPY);
+ nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID);
+ nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID);
+ NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + 4 * NFSX_UNSIGNED);
+ txdr_hyper(inoff, tl); tl += 2;
+ txdr_hyper(outoff, tl); tl += 2;
+ txdr_hyper(len, tl); tl += 2;
+ if (consecutive)
+ *tl++ = newnfs_true;
+ else
+ *tl++ = newnfs_false;
+ *tl++ = newnfs_true;
+ *tl++ = 0;
+ *tl = txdr_unsigned(NFSV4OP_GETATTR);
+ NFSWRITEGETATTR_ATTRBIT(&attrbits);
+ nfsrv_putattrbit(nd, &attrbits);
+ error = nfscl_request(nd, invp, p, cred, NULL);
+ if (error != 0)
+ return (error);
+ if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
+ /* Get the input file's attributes. */
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ if (*(tl + 1) == 0) {
+ error = nfsm_loadattr(nd, innap);
+ if (error != 0)
+ goto nfsmout;
+ *inattrflagp = 1;
+ } else
+ nd->nd_flag |= ND_NOMOREDATA;
+ }
+ /* Skip over return stat for PutFH. */
+ if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ if (*++tl != 0)
+ nd->nd_flag |= ND_NOMOREDATA;
+ }
+ /* Skip over return stat for Copy. */
+ if ((nd->nd_flag & ND_NOMOREDATA) == 0)
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ if (nd->nd_repstat == 0) {
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ if (*tl != 0) {
+ /* There should be no callback ids. */
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ }
+ NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED +
+ NFSX_VERF);
+ len = fxdr_hyper(tl); tl += 2;
+ *commitp = fxdr_unsigned(int, *tl++);
+ NFSLOCKMNT(nmp);
+ if (!NFSHASWRITEVERF(nmp)) {
+ NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
+ NFSSETWRITEVERF(nmp);
+ }
+ NFSUNLOCKMNT(nmp);
+ tl += (NFSX_VERF / NFSX_UNSIGNED);
+ if (nd->nd_repstat == 0 && *++tl != newnfs_true)
+ /* Must be a synchronous copy. */
+ nd->nd_repstat = NFSERR_NOTSUPP;
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ error = nfsm_loadattr(nd, outnap);
+ if (error == 0)
+ *outattrflagp = NFS_LATTR_NOSHRINK;
+ if (nd->nd_repstat == 0)
+ *lenp = len;
+ } else if (nd->nd_repstat == NFSERR_OFFLOADNOREQS) {
+ /*
+ * For the case where consecutive is not supported, but
+ * synchronous is supported, we can try consecutive == false
+ * by returning this error. Otherwise, return NFSERR_NOTSUPP,
+ * since Copy cannot be done.
+ */
+ if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ if (!consecutive || *++tl == newnfs_false)
+ nd->nd_repstat = NFSERR_NOTSUPP;
+ } else
+ nd->nd_repstat = NFSERR_BADXDR;
+ }
+ if (error == 0)
+ 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 Thu Jul 25 22:23:34 2019 (r350336)
+++ projects/nfsv42/sys/fs/nfsclient/nfs_clvnops.c Fri Jul 26 00:27:47 2019 (r350337)
@@ -144,6 +144,7 @@ static vop_getacl_t nfs_getacl;
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;
/*
* Global vfs data structures for nfs
@@ -183,6 +184,7 @@ static struct vop_vector newnfs_vnodeops_nosig = {
.vop_setacl = nfs_setacl,
.vop_advise = nfs_advise,
.vop_allocate = nfs_allocate,
+ .vop_copy_file_range = nfs_copy_file_range,
};
static int
@@ -3509,6 +3511,162 @@ nfs_allocate(struct vop_allocate_args *ap)
}
if (error != 0)
error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
+ return (error);
+}
+
+/*
+ * nfs copy_file_range call
+ */
+static int
+nfs_copy_file_range(struct vop_copy_file_range_args *ap)
+{
+ struct vnode *invp = ap->a_invp;
+ struct vnode *outvp = ap->a_outvp;
+ struct mount *mp;
+ struct nfsvattr innfsva, outnfsva;
+ struct uio io;
+ struct nfsmount *nmp;
+ size_t len, len2;
+ int error, inattrflag, outattrflag, ret;
+ off_t inoff, outoff;
+ bool consecutive, must_commit, tryoutcred;
+
+ nmp = VFSTONFS(invp->v_mount);
+ mtx_lock(&nmp->nm_mtx);
+ if (!NFSHASNFSV4(nmp) || nmp->nm_minorvers < NFSV42_MINORVERSION ||
+ (nmp->nm_privflag & NFSMNTP_NOCOPY) != 0) {
+ mtx_unlock(&nmp->nm_mtx);
+ error = vn_generic_copy_file_range(ap->a_invp, ap->a_inoffp,
+ ap->a_outvp, ap->a_outoffp, ap->a_lenp, ap->a_flags,
+ ap->a_incred, ap->a_outcred, ap->a_fsizetd);
+ return (error);
+ }
+ mtx_unlock(&nmp->nm_mtx);
+
+ /* Lock both vnodes, avoiding risk of deadlock. */
+ do {
+ mp = NULL;
+ error = vn_start_write(outvp, &mp, V_WAIT);
+ if (error == 0) {
+ error = vn_lock(outvp, LK_EXCLUSIVE);
+ if (error == 0) {
+ error = vn_lock(invp, LK_SHARED | LK_NOWAIT);
+ if (error == 0)
+ break;
+ VOP_UNLOCK(outvp, 0);
+ if (mp != NULL)
+ vn_finished_write(mp);
+ mp = NULL;
+ error = vn_lock(invp, LK_SHARED);
+ if (error == 0)
+ VOP_UNLOCK(invp, 0);
+ }
+ }
+ if (mp != NULL)
+ vn_finished_write(mp);
+ } while (error == 0);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Do the vn_rlimit_fsize() check. Should this be above the VOP layer?
+ */
+ io.uio_offset = *ap->a_outoffp;
+ io.uio_resid = *ap->a_lenp;
+ error = vn_rlimit_fsize(outvp, &io, ap->a_fsizetd);
+ /* Do the actual NFSv4.2 RPC. */
+ len = *ap->a_lenp;
+ mtx_lock(&nmp->nm_mtx);
+ if ((nmp->nm_privflag & NFSMNTP_NOCONSECUTIVE) == 0)
+ consecutive = true;
+ else
+ consecutive = false;
+ mtx_unlock(&nmp->nm_mtx);
+ inoff = *ap->a_inoffp;
+ outoff = *ap->a_outoffp;
+ tryoutcred = true;
+ while (len > 0 && error == 0) {
+ inattrflag = outattrflag = 0;
+ must_commit = false;
+ len2 = len;
+ if (tryoutcred)
+ error = nfsrpc_copy_file_range(invp, ap->a_inoffp,
+ outvp, ap->a_outoffp, &len2, ap->a_flags,
+ &inattrflag, &innfsva, &outattrflag, &outnfsva,
+ ap->a_outcred, consecutive, &must_commit);
+ else
+ error = nfsrpc_copy_file_range(invp, ap->a_inoffp,
+ outvp, ap->a_outoffp, &len2, ap->a_flags,
+ &inattrflag, &innfsva, &outattrflag, &outnfsva,
+ ap->a_incred, consecutive, &must_commit);
+ if (inattrflag != 0) {
+ ret = nfscl_loadattrcache(&invp, &innfsva, NULL, NULL,
+ 0, 1);
+ if (error == 0 && ret != 0)
+ error = ret;
+ }
+ if (outattrflag != 0) {
+ ret = nfscl_loadattrcache(&outvp, &outnfsva, NULL, NULL,
+ 1, 1);
+ if (error == 0 && ret != 0)
+ error = ret;
+ }
+ if (error == 0) {
+ if (consecutive == false) {
+ if (len2 == len) {
+ mtx_lock(&nmp->nm_mtx);
+ nmp->nm_privflag |=
+ NFSMNTP_NOCONSECUTIVE;
+ mtx_unlock(&nmp->nm_mtx);
+ } else
+ error = NFSERR_OFFLOADNOREQS;
+ }
+ len -= len2;
+ } else if (error == NFSERR_OFFLOADNOREQS && consecutive) {
+ /*
+ * Try consecutive == false, which is ok only if all
+ * bytes are copied.
+ */
+ consecutive = false;
+ error = 0;
+ } else if (error == NFSERR_ACCES && tryoutcred) {
+ /* Try again with incred. */
+ tryoutcred = false;
+ error = 0;
+ }
+ }
+ if (must_commit && error == 0)
+ error = ncl_commit(outvp, outoff, *ap->a_lenp, ap->a_outcred,
+ curthread);
+ VOP_UNLOCK(invp, 0);
+ VOP_UNLOCK(outvp, 0);
+ if (mp != NULL)
+ vn_finished_write(mp);
+ if (error == NFSERR_NOTSUPP || error == NFSERR_OFFLOADNOREQS ||
+ error == NFSERR_ACCES) {
+ /*
+ * Unlike the NFSv4.2 Copy, vn_generic_copy_file_range() can
+ * use a_incred for the read and a_outcred for the write, so
+ * try this for NFSERR_ACCES failures for the Copy.
+ * For NFSERR_NOTSUPP and NFSERR_OFFLOADNOREQS, the Copy can
+ * never succeed, so disable it.
+ */
+ if (error != NFSERR_ACCES) {
+ /* Can never do Copy on this mount. */
+ mtx_lock(&nmp->nm_mtx);
+ nmp->nm_privflag |= NFSMNTP_NOCOPY;
+ mtx_unlock(&nmp->nm_mtx);
+ }
+ *ap->a_inoffp = inoff;
+ *ap->a_outoffp = outoff;
+ error = vn_generic_copy_file_range(ap->a_invp, ap->a_inoffp,
+ ap->a_outvp, ap->a_outoffp, ap->a_lenp, ap->a_flags,
+ ap->a_incred, ap->a_outcred, ap->a_fsizetd);
+ } else if (error != 0)
+ *ap->a_lenp = 0;
+
+ if (error != 0)
+ error = nfscl_maperr(curthread, error, (uid_t)0, (gid_t)0);
return (error);
}
Modified: projects/nfsv42/sys/fs/nfsclient/nfsmount.h
==============================================================================
--- projects/nfsv42/sys/fs/nfsclient/nfsmount.h Thu Jul 25 22:23:34 2019 (r350336)
+++ projects/nfsv42/sys/fs/nfsclient/nfsmount.h Fri Jul 26 00:27:47 2019 (r350337)
@@ -106,6 +106,8 @@ struct nfsmount {
#define NFSMNTP_FORCEDISM 0x00000001
#define NFSMNTP_CANCELRPCS 0x00000002
#define NFSMNTP_IOADVISETHRUMDS 0x00000004
+#define NFSMNTP_NOCOPY 0x00000008
+#define NFSMNTP_NOCONSECUTIVE 0x00000010
#define NFSMNT_DIRPATH(m) (&((m)->nm_name[(m)->nm_krbnamelen + 1]))
#define NFSMNT_SRVKRBNAME(m) \
Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c Thu Jul 25 22:23:34 2019 (r350336)
+++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdserv.c Fri Jul 26 00:27:47 2019 (r350337)
@@ -74,6 +74,9 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nf
extern int nfsrv_doflexfile;
SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
&nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
+static int nfsrv_maxcopyrange = 10 * 1024 * 1024;
+SYSCTL_INT(_vfs_nfsd, OID_AUTO, maxcopyrange, CTLFLAG_RW,
+ &nfsrv_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
/*
* This list defines the GSS mechanisms supported.
@@ -5179,6 +5182,214 @@ nfsrvd_allocate(struct nfsrv_descript *nd, __unused in
return (0);
nfsmout:
vput(vp);
+ NFSEXITCODE2(error, nd);
+ return (error);
+}
+
+/*
+ * nfs copy service
+ */
+APPLESTATIC int
+nfsrvd_copy_file_range(struct nfsrv_descript *nd, int isdgram,
+ vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
+{
+ uint32_t *tl;
+ struct nfsvattr at;
+ int cnt, error = 0, ret;
+ off_t inoff, outoff;
+ uint64_t len;
+ size_t xfer;
+ struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
+ struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
+ nfsquad_t clientid;
+ nfsv4stateid_t stateid;
+ nfsattrbit_t attrbits;
+ void *rl_rcookie, *rl_wcookie;
+
+ rl_rcookie = rl_wcookie = NULL;
+ if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
+ nd->nd_repstat = NFSERR_WRONGSEC;
+ goto nfsmout;
+ }
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
+ 3 * NFSX_UNSIGNED);
+ instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
+ inlop->lo_flags = NFSLCK_READ;
+ 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++);
+ 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)
+ clientid.qval = nd->nd_clientid.qval;
+ instp->ls_stateid.other[2] = *tl++;
+ outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
+ outlop->lo_flags = NFSLCK_WRITE;
+ 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.other[0] = *tl++;
+ outstp->ls_stateid.other[1] = *tl++;
+ outstp->ls_stateid.other[2] = *tl++;
+ inoff = fxdr_hyper(tl); tl += 2;
+ inlop->lo_first = inoff;
+ outoff = fxdr_hyper(tl); tl += 2;
+ outlop->lo_first = outoff;
+ len = fxdr_hyper(tl); tl += 2;
+ if (len == 0) {
+ /* len == 0 means to EOF. */
+ inlop->lo_end = OFF_MAX;
+ outlop->lo_end = OFF_MAX;
+ } else {
+ inlop->lo_end = inlop->lo_first + len;
+ outlop->lo_end = outlop->lo_first + len;
+ }
+
+ /* Only supports synchronous Copy. */
+ if (*++tl != newnfs_true) {
+ nd->nd_repstat = NFSERR_OFFLOADNOREQS;
+ NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ *tl++ = newnfs_true;
+ *tl = newnfs_true;
+ goto nfsmout;
+ }
+ cnt = fxdr_unsigned(int, *++tl);
+ if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
+ nd->nd_repstat = NFSERR_NOTSUPP;
+ if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
+ inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
+ inlop->lo_end < inlop->lo_first || outlop->lo_end <
+ outlop->lo_first))
+ nd->nd_repstat = NFSERR_INVAL;
+
+ if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG)
+ nd->nd_repstat = NFSERR_WRONGTYPE;
+
+ /* Check permissions for the input file. */
+ NFSZERO_ATTRBIT(&attrbits);
+ NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
+ ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
+ if (nd->nd_repstat == 0)
+ nd->nd_repstat = ret;
+ 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)
+ nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
+ clientid, &stateid, exp, nd, curthread);
+ NFSVOPUNLOCK(vp, 0);
+ if (nd->nd_repstat != 0)
+ goto out;
+
+ error = NFSVOPLOCK(tovp, LK_SHARED);
+ if (error != 0)
+ goto out;
+ if (vnode_vtype(tovp) != VREG)
+ nd->nd_repstat = NFSERR_WRONGTYPE;
+
+ /* For the output file, we only need the Owner attribute. */
+ ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
+ if (nd->nd_repstat == 0)
+ nd->nd_repstat = ret;
+ if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
+ NFSVNO_EXSTRICTACCESS(exp)))
+ nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
+ curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
+ NULL);
+ if (nd->nd_repstat == 0)
+ nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
+ clientid, &stateid, toexp, nd, curthread);
+ NFSVOPUNLOCK(tovp, 0);
+
+ /* Range lock the byte ranges for both invp and outvp. */
+ if (nd->nd_repstat == 0) {
+ for (;;) {
+ if (len == 0) {
+ rl_wcookie = vn_rangelock_wlock(tovp, outoff,
+ OFF_MAX);
+ rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
+ OFF_MAX);
+ } else {
+ rl_wcookie = vn_rangelock_wlock(tovp, outoff,
+ outoff + len);
+ rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
+ inoff + len);
+ }
+ if (rl_rcookie != NULL)
+ break;
+ vn_rangelock_unlock(tovp, rl_wcookie);
+ if (len == 0)
+ rl_rcookie = vn_rangelock_rlock(vp, inoff,
+ OFF_MAX);
+ else
+ rl_rcookie = vn_rangelock_rlock(vp, inoff,
+ inoff + len);
+ vn_rangelock_unlock(vp, rl_rcookie);
+ }
+
+ /*
+ * If len == 0, set it based on invp's size. Since it is range
+ * locked, it should not change in size.
+ */
+ if (len == 0) {
+ error = NFSVOPLOCK(vp, LK_SHARED);
+ if (error == 0) {
+ ret = nfsvno_getattr(vp, &at, nd, curthread, 1,
+ NULL);
+ /* If offset past EOF, just leave len == 0. */
+ if (ret == 0 && at.na_size > inoff)
+ len = at.na_size - inoff;
+ NFSVOPUNLOCK(vp, 0);
+ if (ret != 0 && nd->nd_repstat == 0)
+ nd->nd_repstat = ret;
+ } else if (nd->nd_repstat == 0)
+ nd->nd_repstat = error;
+ }
+ }
+
+ /*
+ * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange.
+ * This limit is applied to ensure that the RPC replies in a
+ * reasonable time.
+ */
+ if (len > nfsrv_maxcopyrange)
+ xfer = nfsrv_maxcopyrange;
+ else
+ xfer = len;
+ nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff, &xfer, 0,
+ nd->nd_cred, nd->nd_cred, NULL);
+ if (nd->nd_repstat == 0)
+ len = xfer;
+
+ /* Unlock the ranges. */
+ if (rl_rcookie != NULL)
+ vn_rangelock_unlock(vp, rl_rcookie);
+ if (rl_wcookie != NULL)
+ vn_rangelock_unlock(tovp, rl_wcookie);
+
+ if (nd->nd_repstat == 0) {
+ NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
+ NFSX_VERF);
+ *tl++ = txdr_unsigned(0); /* No callback ids. */
+ txdr_hyper(len, tl); tl += 2;
+ *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
+ *tl++ = txdr_unsigned(nfsboottime.tv_sec);
+ *tl++ = txdr_unsigned(nfsboottime.tv_usec);
+ *tl++ = newnfs_true;
+ *tl = newnfs_true;
+ }
+out:
+ vrele(vp);
+ vrele(tovp);
+ NFSEXITCODE2(error, nd);
+ return (error);
+nfsmout:
+ vput(vp);
+ vrele(tovp);
NFSEXITCODE2(error, nd);
return (error);
}
Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c
==============================================================================
--- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c Thu Jul 25 22:23:34 2019 (r350336)
+++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsocket.c Fri Jul 26 00:27:47 2019 (r350337)
@@ -197,9 +197,9 @@ int (*nfsrv4_ops0[NFSV42_NOPS])(struct nfsrv_descript
nfsrvd_destroyclientid,
nfsrvd_reclaimcomplete,
nfsrvd_allocate,
+ (int (*)(struct nfsrv_descript *, int, vnode_t , struct nfsexstuff *))0,
nfsrvd_notsupp,
nfsrvd_notsupp,
- nfsrvd_notsupp,
nfsrvd_ioadvise,
nfsrvd_layouterror,
nfsrvd_layoutstats,
@@ -349,7 +349,7 @@ int (*nfsrv4_ops2[NFSV42_NOPS])(struct nfsrv_descript
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
- (int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
+ nfsrvd_copy_file_range,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , struct nfsexstuff *, struct nfsexstuff *))0,
Modified: projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsubs.c
==============================================================================
--- projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsubs.c Thu Jul 25 22:23:34 2019 (r350336)
+++ projects/nfsv42/sys/fs/nfsserver/nfs_nfsdsubs.c Fri Jul 26 00:27:47 2019 (r350337)
@@ -1544,7 +1544,7 @@ nfsrv_isannfserr(u_int32_t errval)
if (errval == NFSERR_OK)
return (errval);
- if (errval >= NFSERR_BADHANDLE && errval <= NFSERR_DELEGREVOKED)
+ if (errval >= NFSERR_BADHANDLE && errval <= NFSERR_MAXERRVAL)
return (errval);
if (errval > 0 && errval <= NFSERR_REMOTE)
return (nfsrv_v2errmap[errval - 1]);
More information about the svn-src-projects
mailing list