aboutsummaryrefslogtreecommitdiff
path: root/sys/fs/nfsclient/nfs_clrpcops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfsclient/nfs_clrpcops.c')
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c237
1 files changed, 219 insertions, 18 deletions
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 920fcf7b8c61..4ec621de2eff 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -225,6 +225,9 @@ static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_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 *);
+static int nfsrpc_clonerpc(vnode_t, off_t, vnode_t, off_t, size_t *, bool,
+ nfsv4stateid_t *, nfsv4stateid_t *, struct nfsvattr *, int *,
+ struct nfsvattr *, int *, struct ucred *, NFSPROC_T *);
static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *,
int, struct nfsvattr *, int *, struct ucred *);
static struct mbuf *nfsm_split(struct mbuf *, uint64_t);
@@ -696,7 +699,7 @@ nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
("nfsrpc_openrpc: Getattr repstat"));
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
- NULL, NULL, NULL, NULL, p, cred);
+ NULL, NULL, NULL, NULL, NULL, p, cred);
if (error)
goto nfsmout;
}
@@ -1355,7 +1358,7 @@ nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
if ((nd->nd_flag & ND_NFSV4) != 0)
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL);
else
error = nfsm_loadattr(nd, nap);
} else
@@ -3597,7 +3600,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
nfsva.na_mntonfileno = UINT64_MAX;
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
- NULL, NULL, NULL, NULL, p, cred);
+ NULL, NULL, NULL, NULL, NULL, p, cred);
if (error) {
dotdotfileid = dotfileid;
} else if (gotmnton) {
@@ -3847,7 +3850,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
nfsva.na_mntonfileno = UINT64_MAX;
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
- NULL, NULL, &rderr, NULL, p, cred);
+ NULL, NULL, &rderr, NULL, NULL, p, cred);
if (error)
goto nfsmout;
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
@@ -4072,7 +4075,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
nfsva.na_mntonfileno = UINT64_MAX;
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
- NULL, NULL, NULL, NULL, p, cred);
+ NULL, NULL, NULL, NULL, NULL, p, cred);
if (error) {
dotdotfileid = dotfileid;
} else if (gotmnton) {
@@ -4346,7 +4349,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
nfsva.na_mntonfileno = 0xffffffff;
error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
- NULL, NULL, &rderr, NULL, p, cred);
+ NULL, NULL, &rderr, NULL, NULL, p, cred);
if (error)
goto nfsmout;
}
@@ -4981,8 +4984,8 @@ nfsmout:
*/
int
nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
- uint32_t *leasep, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap,
- int *attrflagp)
+ uint32_t *leasep, uint32_t *cloneblksizep, struct ucred *cred, NFSPROC_T *p,
+ struct nfsvattr *nap, int *attrflagp)
{
u_int32_t *tl = NULL;
struct nfsrv_descript nfsd, *nd = &nfsd;
@@ -4991,6 +4994,8 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
int error;
*attrflagp = 0;
+ if (cloneblksizep != NULL)
+ *cloneblksizep = 0;
nmp = VFSTONFS(vp->v_mount);
if (NFSHASNFSV4(nmp)) {
/*
@@ -5009,7 +5014,7 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
if (nd->nd_repstat == 0) {
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
NULL, NULL, sbp, fsp, NULL, 0, NULL, leasep, NULL,
- NULL, p, cred);
+ NULL, cloneblksizep, p, cred);
if (!error) {
nmp->nm_fsid[0] = nap->na_filesid[0];
nmp->nm_fsid[1] = nap->na_filesid[1];
@@ -5063,7 +5068,8 @@ nfsmout:
*/
int
nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, bool *has_namedattrp,
- struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
+ uint32_t *clone_blksizep, struct ucred *cred, NFSPROC_T *p,
+ struct nfsvattr *nap, int *attrflagp)
{
struct nfsrv_descript nfsd, *nd = &nfsd;
struct nfsmount *nmp;
@@ -5074,6 +5080,7 @@ nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, bool *has_namedattrp,
*has_namedattrp = false;
*attrflagp = 0;
+ *clone_blksizep = 0;
nmp = VFSTONFS(vp->v_mount);
if (NFSHASNFSV4(nmp)) {
np = VTONFS(vp);
@@ -5100,7 +5107,7 @@ nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, bool *has_namedattrp,
if (nd->nd_repstat == 0) {
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL,
- has_namedattrp, p, cred);
+ has_namedattrp, clone_blksizep, p, cred);
if (!error)
*attrflagp = 1;
} else {
@@ -5395,7 +5402,8 @@ nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp)
return (error);
if (!nd->nd_repstat)
error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
- NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, NULL, p, cred);
+ NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, NULL, NULL, p,
+ cred);
else
error = nd->nd_repstat;
m_freem(nd->nd_mrep);
@@ -5437,7 +5445,7 @@ nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
(void) nfsv4_fillattr(nd, vp->v_mount, vp, aclp, NULL, NULL, 0,
&attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL, false, false,
- false);
+ false, 0);
error = nfscl_request(nd, vp, p, cred);
if (error)
return (error);
@@ -8496,7 +8504,7 @@ nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
if (*++tl == 0) {
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
- NULL, NULL, NULL, NULL, p, cred);
+ NULL, NULL, NULL, NULL, NULL, p, cred);
if (error != 0)
goto nfsmout;
if (ndp != NULL) {
@@ -9168,6 +9176,199 @@ nfsmout:
}
/*
+ * nfs clone operation.
+ */
+int
+nfsrpc_clone(vnode_t invp, off_t *inoffp, vnode_t outvp,
+ off_t *outoffp, size_t *lenp, bool toeof, int *inattrflagp,
+ struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap,
+ struct ucred *cred)
+{
+ int error, expireret = 0, retrycnt;
+ uint32_t clidrev = 0;
+ struct nfsmount *nmp = VFSTONFS(invp->v_mount);
+ 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_clonerpc(invp, *inoffp, outvp, *outoffp, lenp,
+ toeof, &instateid, &outstateid, innap, inattrflagp, outnap,
+ outattrflagp, cred, curthread);
+ if (error == 0) {
+ *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 || (!NFSHASINT(nmp) &&
+ error == NFSERR_BADSTATEID)) && clidrev != 0) {
+ expireret = nfscl_hasexpired(nmp->nm_clp, clidrev,
+ curthread);
+ } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) {
+ error = EIO;
+ }
+ 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 clone RPC.
+ */
+static int
+nfsrpc_clonerpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff,
+ size_t *lenp, bool toeof, nfsv4stateid_t *instateidp,
+ nfsv4stateid_t *outstateidp, struct nfsvattr *innap, int *inattrflagp,
+ struct nfsvattr *outnap, int *outattrflagp, struct ucred *cred,
+ NFSPROC_T *p)
+{
+ uint32_t *tl, *opcntp;
+ int error;
+ struct nfsrv_descript nfsd;
+ struct nfsrv_descript *nd = &nfsd;
+ struct nfsmount *nmp;
+ nfsattrbit_t attrbits;
+ struct vattr va;
+ uint64_t len;
+
+ nmp = VFSTONFS(invp->v_mount);
+ *inattrflagp = *outattrflagp = 0;
+ len = *lenp;
+ if (len == 0)
+ return (0);
+ if (toeof)
+ len = 0;
+ nfscl_reqstart(nd, NFSPROC_CLONE, nmp, VTONFS(invp)->n_fhp->nfh_fh,
+ VTONFS(invp)->n_fhp->nfh_len, &opcntp, NULL, 0, 0, cred);
+ /*
+ * First do a Setattr of atime to the server's clock
+ * time. The FreeBSD "collective" was of the opinion
+ * that setting atime was necessary for this syscall.
+ * Do the Setattr before the Clone, so that it can be
+ * handled well if the server replies NFSERR_DELAY to
+ * the Setattr operation.
+ */
+ if ((nmp->nm_mountp->mnt_flag & MNT_NOATIME) == 0) {
+ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV4OP_SETATTR);
+ nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID);
+ VATTR_NULL(&va);
+ va.va_atime.tv_sec = va.va_atime.tv_nsec = 0;
+ va.va_vaflags = VA_UTIMES_NULL;
+ nfscl_fillsattr(nd, &va, invp, 0, 0);
+ /* Bump opcnt from 7 to 8. */
+ *opcntp = txdr_unsigned(8);
+ }
+
+ /* Now Getattr the invp attributes. */
+ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV4OP_GETATTR);
+ NFSGETATTR_ATTRBIT(&attrbits);
+ nfsrv_putattrbit(nd, &attrbits);
+
+ /* Set outvp. */
+ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV4OP_PUTFH);
+ (void)nfsm_fhtom(nmp, nd, VTONFS(outvp)->n_fhp->nfh_fh,
+ VTONFS(outvp)->n_fhp->nfh_len, 0);
+
+ /* Do the Clone. */
+ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+ *tl = txdr_unsigned(NFSV4OP_CLONE);
+ nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID);
+ nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID);
+ NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + NFSX_UNSIGNED);
+ txdr_hyper(inoff, tl); tl += 2;
+ txdr_hyper(outoff, tl); tl += 2;
+ txdr_hyper(len, tl); tl += 2;
+
+ /* Get the outvp attributes. */
+ *tl = txdr_unsigned(NFSV4OP_GETATTR);
+ NFSWRITEGETATTR_ATTRBIT(&attrbits);
+ nfsrv_putattrbit(nd, &attrbits);
+
+ error = nfscl_request(nd, invp, p, cred);
+ if (error != 0)
+ return (error);
+ /* Skip over the Setattr reply. */
+ if ((nd->nd_flag & ND_NOMOREDATA) == 0 &&
+ (nmp->nm_mountp->mnt_flag & MNT_NOATIME) == 0) {
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ if (*(tl + 1) == 0) {
+ error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
+ if (error != 0)
+ goto nfsmout;
+ } else
+ nd->nd_flag |= ND_NOMOREDATA;
+ }
+ 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 Clone. */
+ 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 *, 2 * NFSX_UNSIGNED);
+ error = nfsm_loadattr(nd, outnap);
+ if (error == 0)
+ *outattrflagp = NFS_LATTR_NOSHRINK;
+ } else {
+ *lenp = 0;
+ }
+ if (error == 0)
+ error = nd->nd_repstat;
+nfsmout:
+ m_freem(nd->nd_mrep);
+ return (error);
+}
+
+/*
* Seek operation.
*/
int
@@ -9724,13 +9925,13 @@ nfscl_statfs(struct vnode *vp, struct ucred *cred, NFSPROC_T *td)
struct nfsstatfs sb;
struct mount *mp;
struct nfsmount *nmp;
- uint32_t lease;
+ uint32_t clone_blksize, lease;
int attrflag, error;
mp = vp->v_mount;
nmp = VFSTONFS(mp);
- error = nfsrpc_statfs(vp, &sb, &fs, &lease, cred, td, &nfsva,
- &attrflag);
+ error = nfsrpc_statfs(vp, &sb, &fs, &lease, &clone_blksize, cred, td,
+ &nfsva, &attrflag);
if (attrflag != 0)
(void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1);
if (error == 0) {
@@ -9739,7 +9940,7 @@ nfscl_statfs(struct vnode *vp, struct ucred *cred, NFSPROC_T *td)
nmp->nm_clp->nfsc_renew = NFSCL_RENEW(lease);
NFSUNLOCKCLSTATE();
mtx_lock(&nmp->nm_mtx);
- nfscl_loadfsinfo(nmp, &fs);
+ nfscl_loadfsinfo(nmp, &fs, clone_blksize);
nfscl_loadsbinfo(nmp, &sb, &mp->mnt_stat);
mp->mnt_stat.f_iosize = newnfs_iosize(nmp);
mtx_unlock(&nmp->nm_mtx);