summaryrefslogtreecommitdiff
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
authorTrond Myklebust <trondmy@gmail.com>2020-01-06 13:40:30 -0500
committerJ. Bruce Fields <bfields@redhat.com>2020-01-22 16:25:40 -0500
commit5011af4c698a95b4dc4e374b1ce3acd122a9170f (patch)
tree963befb8ca298ac85242f9916fc808de07c33420 /fs/nfsd/vfs.c
parent16f8f894108270fd99667f06bae6ebcdd0f4e4bf (diff)
nfsd: Fix stable writes
Strictly speaking, a stable write error needs to reflect the write + the commit of that write (and only that write). To ensure that we don't pick up the write errors from other writebacks, add a rw_semaphore to provide exclusion. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r--fs/nfsd/vfs.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index e1ffefab2552..4652854f3dd5 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -982,7 +982,18 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
flags |= RWF_SYNC;
iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt);
- host_err = vfs_iter_write(file, &iter, &pos, flags);
+ if (flags & RWF_SYNC) {
+ down_write(&nf->nf_rwsem);
+ host_err = vfs_iter_write(file, &iter, &pos, flags);
+ if (host_err < 0)
+ nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp),
+ nfsd_net_id));
+ up_write(&nf->nf_rwsem);
+ } else {
+ down_read(&nf->nf_rwsem);
+ host_err = vfs_iter_write(file, &iter, &pos, flags);
+ up_read(&nf->nf_rwsem);
+ }
if (host_err < 0)
goto out_nfserr;
*cnt = host_err;
@@ -1097,8 +1108,10 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (err)
goto out;
if (EX_ISSYNC(fhp->fh_export)) {
- int err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
+ int err2;
+ down_write(&nf->nf_rwsem);
+ err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
switch (err2) {
case 0:
break;
@@ -1110,6 +1123,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
nfsd_reset_boot_verifier(net_generic(nf->nf_net,
nfsd_net_id));
}
+ up_write(&nf->nf_rwsem);
}
nfsd_file_put(nf);