]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
NFS/pnfs: Fix pnfs_generic_prepare_to_resend_writes()
authorTrond Myklebust <trondmy@gmail.com>
Mon, 6 Jan 2020 20:25:04 +0000 (15:25 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 14 Feb 2020 21:33:24 +0000 (16:33 -0500)
commit 221203ce6406273cf00e5c6397257d986c003ee6 upstream.

Instead of making assumptions about the commit verifier contents, change
the commit code to ensure we always check that the verifier was set
by the XDR code.

Fixes: f54bcf2ecee9 ("pnfs: Prepare for flexfiles by pulling out common code")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/nfs/direct.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4xdr.c
fs/nfs/pnfs_nfs.c
fs/nfs/write.c

index 29b70337dcd9fd14a9217195a6787b3bb377aba4..c61bd3fc723ee2ce295d7eea6aeb00e148986736 100644 (file)
@@ -261,10 +261,10 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
                                         data->ds_commit_index);
 
        /* verifier not set so always fail */
-       if (verfp->committed < 0)
+       if (verfp->committed < 0 || data->res.verf->committed <= NFS_UNSTABLE)
                return 1;
 
-       return nfs_direct_cmp_verf(verfp, &data->verf);
+       return nfs_direct_cmp_verf(verfp, data->res.verf);
 }
 
 /**
index 64e4fa33d89f0e347155db74507862ec6f09fcc8..9956453aa6ffc8cd498cd6fbe8b4139959207eae 100644 (file)
@@ -2380,6 +2380,7 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
                                   void *data)
 {
        struct nfs_commitres *result = data;
+       struct nfs_writeverf *verf = result->verf;
        enum nfs_stat status;
        int error;
 
@@ -2392,7 +2393,9 @@ static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
        result->op_status = status;
        if (status != NFS3_OK)
                goto out_status;
-       error = decode_writeverf3(xdr, &result->verf->verifier);
+       error = decode_writeverf3(xdr, &verf->verifier);
+       if (!error)
+               verf->committed = NFS_FILE_SYNC;
 out:
        return error;
 out_status:
index 1c0227c78a7bc4a9b0f57549c94e297deb1b9875..c4cf0192d7bb8c0896fd0aed70b5a03c041ed074 100644 (file)
@@ -4439,11 +4439,14 @@ static int decode_write_verifier(struct xdr_stream *xdr, struct nfs_write_verifi
 
 static int decode_commit(struct xdr_stream *xdr, struct nfs_commitres *res)
 {
+       struct nfs_writeverf *verf = res->verf;
        int status;
 
        status = decode_op_hdr(xdr, OP_COMMIT);
        if (!status)
-               status = decode_write_verifier(xdr, &res->verf->verifier);
+               status = decode_write_verifier(xdr, &verf->verifier);
+       if (!status)
+               verf->committed = NFS_FILE_SYNC;
        return status;
 }
 
index d5e4d3cd8c7f15762ef11de727a2fbcdb10c3f7a..acfb52bc0007dcf401be1f82ad6d1f9acc6c7f23 100644 (file)
@@ -30,12 +30,11 @@ EXPORT_SYMBOL_GPL(pnfs_generic_rw_release);
 /* Fake up some data that will cause nfs_commit_release to retry the writes. */
 void pnfs_generic_prepare_to_resend_writes(struct nfs_commit_data *data)
 {
-       struct nfs_page *first = nfs_list_entry(data->pages.next);
+       struct nfs_writeverf *verf = data->res.verf;
 
        data->task.tk_status = 0;
-       memcpy(&data->verf.verifier, &first->wb_verf,
-              sizeof(data->verf.verifier));
-       data->verf.verifier.data[0]++; /* ensure verifier mismatch */
+       memset(&verf->verifier, 0, sizeof(verf->verifier));
+       verf->committed = NFS_UNSTABLE;
 }
 EXPORT_SYMBOL_GPL(pnfs_generic_prepare_to_resend_writes);
 
index e8152781814dda96706fe2caed335a24455fb75e..ce1da8cbac0038ba41b014f2f2bd0c126b15a6bc 100644 (file)
@@ -1814,6 +1814,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
 
 static void nfs_commit_release_pages(struct nfs_commit_data *data)
 {
+       const struct nfs_writeverf *verf = data->res.verf;
        struct nfs_page *req;
        int status = data->task.tk_status;
        struct nfs_commit_info cinfo;
@@ -1840,7 +1841,8 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
 
                /* Okay, COMMIT succeeded, apparently. Check the verifier
                 * returned by the server against all stored verfs. */
-               if (!nfs_write_verifier_cmp(&req->wb_verf, &data->verf.verifier)) {
+               if (verf->committed > NFS_UNSTABLE &&
+                   !nfs_write_verifier_cmp(&req->wb_verf, &verf->verifier)) {
                        /* We have a match */
                        if (req->wb_page)
                                nfs_inode_remove_request(req);