]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
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:49:11 +0000 (08:49 +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 8beda999e1346e8917bc3b624f33fed22e710d7b..c187d892e656db5c4054c6d629a454e5a969de91 100644 (file)
@@ -1083,7 +1083,8 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                goto out;
 
        status = nfsd4_clone_file_range(src, clone->cl_src_pos,
-                       dst, clone->cl_dst_pos, clone->cl_count);
+                       dst, clone->cl_dst_pos, clone->cl_count,
+                       EX_ISSYNC(cstate->current_fh.fh_export));
 
        fput(dst);
        fput(src);
index c85783e536d595de5816584b3dadac4a73fc4b83..18ffb590f008289091a4cdfb8c9cf17df44f77a2 100644 (file)
@@ -552,7 +552,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;
 
@@ -561,6 +561,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 db351247892d05155e9cc2d2517229b071e807a1..02b0a140af8cc920b072c5477fa07ad47b8f8cdd 100644 (file)
@@ -58,7 +58,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,