aboutsummaryrefslogtreecommitdiff
path: root/sys/fs
diff options
context:
space:
mode:
authorRick Macklem <rmacklem@FreeBSD.org>2022-04-30 20:49:23 +0000
committerRick Macklem <rmacklem@FreeBSD.org>2022-04-30 20:49:23 +0000
commit5218d82c81f987223054671b9821d39f08d87599 (patch)
tree1bc31e50e82dc6201c9de6f188febe8cc99281ef /sys/fs
parent13cf4313043655ce2562bf2fb9b8af554db184d2 (diff)
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/nfs/nfs_var.h2
-rw-r--r--sys/fs/nfsclient/nfs.h2
-rw-r--r--sys/fs/nfsclient/nfs_clbio.c26
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c67
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c6
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);