summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trondmy@gmail.com>2020-01-06 13:40:33 -0500
committerJ. Bruce Fields <bfields@redhat.com>2020-01-22 16:25:41 -0500
commit1b28d756b2eaee03e838390465754e431389e483 (patch)
tree4363f1d9b488d526342a7b4a8418aff4926c030c
parentb66ae6dd0c30c750cbc5c633dea08712203abc03 (diff)
downloadlinux-1b28d756b2eaee03e838390465754e431389e483.tar.bz2
nfsd: Ensure exclusion between CLONE and WRITE errors
Ensure that we can distinguish between synchronous CLONE and WRITE errors, and that we can assign them correctly. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/vfs.c25
1 files changed, 18 insertions, 7 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 7950f2ea1d95..126149b06463 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -536,22 +536,33 @@ __be32 nfsd4_clone_file_range(struct nfsd_file *nf_src, u64 src_pos,
struct file *src = nf_src->nf_file;
struct file *dst = nf_dst->nf_file;
loff_t cloned;
+ __be32 ret = 0;
+ down_write(&nf_dst->nf_rwsem);
cloned = vfs_clone_file_range(src, src_pos, dst, dst_pos, count, 0);
- if (cloned < 0)
- return nfserrno(cloned);
- if (count && cloned != count)
- return nfserrno(-EINVAL);
+ if (cloned < 0) {
+ ret = nfserrno(cloned);
+ goto out_err;
+ }
+ if (count && cloned != count) {
+ ret = nfserrno(-EINVAL);
+ goto out_err;
+ }
if (sync) {
loff_t dst_end = count ? dst_pos + count - 1 : LLONG_MAX;
int status = vfs_fsync_range(dst, dst_pos, dst_end, 0);
if (!status)
status = commit_inode_metadata(file_inode(src));
- if (status < 0)
- return nfserrno(status);
+ if (status < 0) {
+ nfsd_reset_boot_verifier(net_generic(nf_dst->nf_net,
+ nfsd_net_id));
+ ret = nfserrno(status);
+ }
}
- return 0;
+out_err:
+ up_write(&nf_dst->nf_rwsem);
+ return ret;
}
ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,