nfsd: Ensure CLONE persists data and metadata changes to the target file
authorTrond Myklebust <trondmy@gmail.com>
Wed, 27 Nov 2019 22:05:51 +0000 (17:05 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 13 Dec 2019 07:42:51 +0000 (08:42 +0100)
commit a25e3726b32c746c0098125d4c7463bb84df72bb upstream.

The NFSv4.2 CLONE operation has implicit persistence requirements on the
target file, since there is no protocol requirement that the client issue
a separate operation to persist data.
For that reason, we should call vfs_fsync_range() on the destination file
after a successful call to vfs_clone_file_range().

Fixes: ffa0160a1039 ("nfsd: implement the NFSv4.2 CLONE operation")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Cc: stable@vger.kernel.org # v4.5+
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/nfsd/nfs4proc.c
fs/nfsd/vfs.c
fs/nfsd/vfs.h

index 4e3e77b..38c0aed 100644 (file)
@@ -1077,7 +1077,8 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                goto out;
 
        status = nfsd4_clone_file_range(src->nf_file, clone->cl_src_pos,
-                       dst->nf_file, clone->cl_dst_pos, clone->cl_count);
+                       dst->nf_file, clone->cl_dst_pos, clone->cl_count,
+                       EX_ISSYNC(cstate->current_fh.fh_export));
 
        nfsd_file_put(dst);
        nfsd_file_put(src);
index bd0a385..cf423fe 100644 (file)
@@ -525,7 +525,7 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
 #endif
 
 __be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst,
-               u64 dst_pos, u64 count)
+               u64 dst_pos, u64 count, bool sync)
 {
        loff_t cloned;
 
@@ -534,6 +534,12 @@ __be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst,
                return nfserrno(cloned);
        if (count && cloned != count)
                return nfserrno(-EINVAL);
+       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 < 0)
+                       return nfserrno(status);
+       }
        return 0;
 }
 
index a13fd9d..cc110a1 100644 (file)
@@ -56,7 +56,7 @@ __be32          nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
 __be32         nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
                                    struct file *, loff_t, loff_t, int);
 __be32         nfsd4_clone_file_range(struct file *, u64, struct file *,
-                       u64, u64);
+                                      u64, u64, bool);
 #endif /* CONFIG_NFSD_V4 */
 __be32         nfsd_create_locked(struct svc_rqst *, struct svc_fh *,
                                char *name, int len, struct iattr *attrs,