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:34:10 +0000 (16:34 -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 040a50fd9bf307d9e2bdd25643a3db9f73dcb64e..29f00da8a0b7f030338da3eb97841f29e311696d 100644 (file)
@@ -245,10 +245,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 602767850b36015a546eafb9005282d05d0369fb..1f60ab2535eed9240f0005a1df2d93c09454a0e2 100644 (file)
@@ -2338,6 +2338,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;
 
@@ -2350,7 +2351,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 ab07db0f07cde00a7763224f633c054ac26b95d1..7c0ff1a3b5914a5505a83663dc56e1ccc34c320c 100644 (file)
@@ -4316,11 +4316,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 82af4809b869a63851ce8d49f4e0d982bdc6305c..8b37e7f8e789f9be96612089977142365553f7b1 100644 (file)
@@ -31,12 +31,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 f5170bc839aa2ff455d6f3f456f08e5a52f1b288..913eb37c249bbad0986408bd48341bcd9f702adc 100644 (file)
@@ -1837,6 +1837,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;
@@ -1864,7 +1865,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);