diff options
Diffstat (limited to 'sys/fs/nfsclient/nfs_clrpcops.c')
-rw-r--r-- | sys/fs/nfsclient/nfs_clrpcops.c | 237 |
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); |