diff options
| author | Rick Macklem <rmacklem@FreeBSD.org> | 2022-04-30 20:49:23 +0000 |
|---|---|---|
| committer | Rick Macklem <rmacklem@FreeBSD.org> | 2022-04-30 20:49:23 +0000 |
| commit | 5218d82c81f987223054671b9821d39f08d87599 (patch) | |
| tree | 1bc31e50e82dc6201c9de6f188febe8cc99281ef /sys/fs | |
| parent | 13cf4313043655ce2562bf2fb9b8af554db184d2 (diff) | |
Diffstat (limited to 'sys/fs')
| -rw-r--r-- | sys/fs/nfs/nfs_var.h | 2 | ||||
| -rw-r--r-- | sys/fs/nfsclient/nfs.h | 2 | ||||
| -rw-r--r-- | sys/fs/nfsclient/nfs_clbio.c | 26 | ||||
| -rw-r--r-- | sys/fs/nfsclient/nfs_clrpcops.c | 67 | ||||
| -rw-r--r-- | sys/fs/nfsclient/nfs_clvnops.c | 6 |
5 files changed, 78 insertions, 25 deletions
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 3a2a27890d7b..c4dc2451523e 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -471,7 +471,7 @@ int nfsrpc_readlink(vnode_t, struct uio *, struct ucred *, int nfsrpc_read(vnode_t, struct uio *, struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); int nfsrpc_write(vnode_t, struct uio *, int *, int *, - struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *, int); + struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, int, int); int nfsrpc_mknod(vnode_t, char *, int, struct vattr *, u_int32_t, enum vtype, struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, int *, void *); diff --git a/sys/fs/nfsclient/nfs.h b/sys/fs/nfsclient/nfs.h index ce1747a2ab6b..94faeb381ac0 100644 --- a/sys/fs/nfsclient/nfs.h +++ b/sys/fs/nfsclient/nfs.h @@ -107,7 +107,7 @@ void ncl_nodeunlock(struct nfsnode *); int ncl_getattrcache(struct vnode *, struct vattr *); int ncl_readrpc(struct vnode *, struct uio *, struct ucred *); int ncl_writerpc(struct vnode *, struct uio *, struct ucred *, int *, int *, - int); + int, int); int ncl_readlinkrpc(struct vnode *, struct uio *, struct ucred *); int ncl_readdirrpc(struct vnode *, struct uio *, struct ucred *, struct thread *); diff --git a/sys/fs/nfsclient/nfs_clbio.c b/sys/fs/nfsclient/nfs_clbio.c index 081aff6c0e7c..c89d6796ea00 100644 --- a/sys/fs/nfsclient/nfs_clbio.c +++ b/sys/fs/nfsclient/nfs_clbio.c @@ -793,7 +793,7 @@ do_sync: */ must_commit = 2; error = ncl_writerpc(vp, &uio, cred, &iomode, - &must_commit, 0); + &must_commit, 0, ioflag); KASSERT((must_commit == 2), ("ncl_directio_write: Updated write verifier")); if (error) @@ -986,11 +986,21 @@ ncl_write(struct vop_write_args *ap) * get the append lock. */ if (ioflag & IO_APPEND) { - np->n_attrstamp = 0; - KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); - error = VOP_GETATTR(vp, &vattr, cred); - if (error) - return (error); + /* + * For NFSv4, the AppendWrite will Verify the size against + * the file's size on the server. If not the same, the + * write will then be retried, using the file size returned + * by the AppendWrite. However, for NFSv2 and NFSv3, the + * size must be acquired here via a Getattr RPC. + * The AppendWrite is not done for a pNFS mount. + */ + if (!NFSHASNFSV4(nmp) || NFSHASPNFS(nmp)) { + np->n_attrstamp = 0; + KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); + error = VOP_GETATTR(vp, &vattr, cred); + if (error) + return (error); + } NFSLOCKNODE(np); uio->uio_offset = np->n_size; NFSUNLOCKNODE(np); @@ -1633,7 +1643,7 @@ ncl_doio_directwrite(struct buf *bp) * verifier on the mount point. */ must_commit = 2; - ncl_writerpc(bp->b_vp, uiop, bp->b_wcred, &iomode, &must_commit, 0); + ncl_writerpc(bp->b_vp, uiop, bp->b_wcred, &iomode, &must_commit, 0, 0); KASSERT((must_commit == 2), ("ncl_doio_directwrite: Updated write" " verifier")); if (iomode != NFSWRITE_FILESYNC) @@ -1818,7 +1828,7 @@ ncl_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td, iomode = NFSWRITE_FILESYNC; error = ncl_writerpc(vp, uiop, cr, &iomode, &must_commit, - called_from_strategy); + called_from_strategy, 0); /* * When setting B_NEEDCOMMIT also set B_CLUSTEROK to try diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 48cd6467c78f..9d19114ab07c 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -134,7 +134,7 @@ static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *); static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *, struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, - void *); + int); static int nfsrpc_deallocaterpc(vnode_t, off_t, off_t, nfsv4stateid_t *, struct nfsvattr *, int *, struct ucred *, NFSPROC_T *); static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *, @@ -1849,7 +1849,7 @@ nfsmout: int nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, - void *stuff, int called_from_strategy) + int called_from_strategy, int ioflag) { int error, expireret = 0, retrycnt, nostateid; u_int32_t clidrev = 0; @@ -1893,7 +1893,7 @@ nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, error = 0; else error = nfsrpc_writerpc(vp, uiop, iomode, must_commit, - newcred, &stateid, p, nap, attrflagp, stuff); + newcred, &stateid, p, nap, attrflagp, ioflag); if (error == NFSERR_STALESTATEID) nfscl_initiate_recovery(nmp->nm_clp); if (lckp != NULL) @@ -1928,18 +1928,19 @@ nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, static int nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp, - NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) + NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, int ioflag) { u_int32_t *tl; struct nfsmount *nmp = VFSTONFS(vp->v_mount); struct nfsnode *np = VTONFS(vp); - int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC; - int wccflag = 0, wsize; + int error = 0, len, rlen, commit, committed = NFSWRITE_FILESYNC; + int wccflag = 0; int32_t backup; - struct nfsrv_descript nfsd; - struct nfsrv_descript *nd = &nfsd; + struct nfsrv_descript *nd; nfsattrbit_t attrbits; - off_t tmp_off; + uint64_t tmp_off; + ssize_t tsiz, wsize; + bool do_append; KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); *attrflagp = 0; @@ -1951,14 +1952,31 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, return (EFBIG); } wsize = nmp->nm_wsize; + do_append = false; + if ((ioflag & IO_APPEND) != 0 && NFSHASNFSV4(nmp) && !NFSHASPNFS(nmp)) + do_append = true; NFSUNLOCKMNT(nmp); + nd = malloc(sizeof(*nd), M_TEMP, M_WAITOK); nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */ nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */ while (tsiz > 0) { *attrflagp = 0; len = (tsiz > wsize) ? wsize : tsiz; - NFSCL_REQSTART(nd, NFSPROC_WRITE, vp); + if (do_append) + NFSCL_REQSTART(nd, NFSPROC_APPENDWRITE, vp); + else + NFSCL_REQSTART(nd, NFSPROC_WRITE, vp); if (nd->nd_flag & ND_NFSV4) { + if (do_append) { + NFSZERO_ATTRBIT(&attrbits); + NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE); + nfsrv_putattrbit(nd, &attrbits); + NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED + + NFSX_HYPER); + *tl++ = txdr_unsigned(NFSX_HYPER); + txdr_hyper(uiop->uio_offset, tl); tl += 2; + *tl = txdr_unsigned(NFSV4OP_WRITE); + } nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED); txdr_hyper(uiop->uio_offset, tl); @@ -2018,8 +2036,10 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, (void) nfsrv_putattrbit(nd, &attrbits); } error = nfscl_request(nd, vp, p, cred); - if (error) + if (error) { + free(nd, M_TEMP); return (error); + } if (nd->nd_repstat) { /* * In case the rpc gets retried, roll @@ -2034,11 +2054,33 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, } if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { error = nfscl_wcc_data(nd, vp, nap, attrflagp, - &wccflag, NULL); + &wccflag, &tmp_off); if (error) goto nfsmout; } + if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == + (ND_NFSV4 | ND_NOMOREDATA) && + nd->nd_repstat == NFSERR_NOTSAME && do_append) { + /* + * Verify of the file's size failed, so redo the + * write using the file's size as returned in + * the wcc attributes. + */ + if (tmp_off + tsiz <= nmp->nm_maxfilesize) { + do_append = false; + uiop->uio_offset = tmp_off; + m_freem(nd->nd_mrep); + nd->nd_mrep = NULL; + continue; + } else + nd->nd_repstat = EFBIG; + } if (!nd->nd_repstat) { + if (do_append) { + /* Strip off the Write reply status. */ + do_append = false; + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + } if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); @@ -2103,6 +2145,7 @@ nfsmout: *iomode = committed; if (nd->nd_repstat && !error) error = nd->nd_repstat; + free(nd, M_TEMP); return (error); } diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 4d549909f80a..3bc65f5136f4 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -1622,7 +1622,7 @@ ncl_readrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred) */ int ncl_writerpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, - int *iomode, int *must_commit, int called_from_strategy) + int *iomode, int *must_commit, int called_from_strategy, int ioflag) { struct nfsvattr nfsva; int error, attrflag, ret; @@ -1637,8 +1637,8 @@ ncl_writerpc(struct vnode *vp, struct uio *uiop, struct ucred *cred, NFSCL_DEBUG(4, "writerpc: aft doiods=%d\n", error); if (error != 0) error = nfsrpc_write(vp, uiop, iomode, must_commit, cred, - uiop->uio_td, &nfsva, &attrflag, NULL, - called_from_strategy); + uiop->uio_td, &nfsva, &attrflag, called_from_strategy, + ioflag); if (attrflag) { if (VTONFS(vp)->n_flag & ND_NFSV4) ret = nfscl_loadattrcache(&vp, &nfsva, NULL, 1, 1); |
