From 8eee52af27b96047894bd18649102a0d2de3c3bb Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 4 Jun 2015 13:51:13 -0400 Subject: [PATCH 1/6] NFSv4: nfs4_handle_delegation_recall_error should ignore EAGAIN EAGAIN is a valid return code from nfs4_open_recover(), and should be handled by nfs4_handle_delegation_recall_error by simply passing it through. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 55e1e3af23a3..d25de2ab12fb 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1684,6 +1684,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct "%d.\n", __func__, err); case 0: case -ENOENT: + case -EAGAIN: case -ESTALE: break; case -NFS4ERR_BADSESSION: From e937ee714b2df638275a61a99e0d033682f764d2 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Tue, 2 Jun 2015 18:58:46 +0800 Subject: [PATCH 2/6] nfs: Only update callback sequnce id when CB_SEQUENCE success When testing pnfs layout, nfsd got error NFS4ERR_SEQ_MISORDERED. It is caused by nfs return NFS4ERR_DELAY before validate_seqid(), don't update the sequnce id, but nfsd updates the sequnce id !!! According to RFC5661 20.9.3, " If CB_SEQUENCE returns an error, then the state of the slot (sequence ID, cached reply) MUST NOT change. " Signed-off-by: Kinglong Mee Signed-off-by: Trond Myklebust --- fs/nfs/callback_proc.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 197806fb87ff..7e9653aae5d8 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -327,10 +327,8 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) dprintk("%s slot table seqid: %u\n", __func__, slot->seq_nr); /* Normal */ - if (likely(args->csa_sequenceid == slot->seq_nr + 1)) { - slot->seq_nr++; + if (likely(args->csa_sequenceid == slot->seq_nr + 1)) goto out_ok; - } /* Replay */ if (args->csa_sequenceid == slot->seq_nr) { @@ -418,6 +416,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, struct cb_process_state *cps) { struct nfs4_slot_table *tbl; + struct nfs4_slot *slot; struct nfs_client *clp; int i; __be32 status = htonl(NFS4ERR_BADSESSION); @@ -429,7 +428,9 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, if (!(clp->cl_session->flags & SESSION4_BACK_CHAN)) goto out; + tbl = &clp->cl_session->bc_slot_table; + slot = tbl->slots + args->csa_slotid; spin_lock(&tbl->slot_tbl_lock); /* state manager is resetting the session */ @@ -444,7 +445,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, goto out; } - status = validate_seqid(&clp->cl_session->bc_slot_table, args); + status = validate_seqid(tbl, args); spin_unlock(&tbl->slot_tbl_lock); if (status) goto out; @@ -468,6 +469,13 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; + /* + * RFC5661 20.9.3 + * If CB_SEQUENCE returns an error, then the state of the slot + * (sequence ID, cached reply) MUST NOT change. + */ + slot->seq_nr++; + out: cps->clp = clp; /* put in nfs4_callback_compound */ for (i = 0; i < args->csa_nrclists; i++) From 0579c8d2084adf932f09fe7edb5ee9328795d89f Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Tue, 2 Jun 2015 18:59:01 +0800 Subject: [PATCH 3/6] nfs: Initialize cb_sequenceres information before validate_seqid() For a cb_layoutrecall replay, nfsd got CB_SEQUENCE status of zero, but all informations of cb_sequenceres are zero too !!! validate_seqid() return NFS4ERR_RETRY_UNCACHED_REP for a replay, and skip the initlize cb_sequenceres. Signed-off-by: Kinglong Mee Signed-off-by: Trond Myklebust --- fs/nfs/callback_proc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 7e9653aae5d8..17a5c571a006 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -445,6 +445,13 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, goto out; } + memcpy(&res->csr_sessionid, &args->csa_sessionid, + sizeof(res->csr_sessionid)); + res->csr_sequenceid = args->csa_sequenceid; + res->csr_slotid = args->csa_slotid; + res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; + res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; + status = validate_seqid(tbl, args); spin_unlock(&tbl->slot_tbl_lock); if (status) @@ -462,13 +469,6 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, goto out; } - memcpy(&res->csr_sessionid, &args->csa_sessionid, - sizeof(res->csr_sessionid)); - res->csr_sequenceid = args->csa_sequenceid; - res->csr_slotid = args->csa_slotid; - res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; - res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; - /* * RFC5661 20.9.3 * If CB_SEQUENCE returns an error, then the state of the slot From 4e54ab8d8c744f977ba13404342aeb260e353330 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 11 Jun 2015 21:13:58 -0400 Subject: [PATCH 4/6] NFS: Ensure that we update the sequence id under the slot table lock Fix a callback slot table regression. Fixes: e937ee714b2d ("nfs: Only update callback sequnce id when CB_SEQUENCE success") Cc: Kinglong Mee Signed-off-by: Trond Myklebust --- fs/nfs/callback_proc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 17a5c571a006..29e3c1b011b7 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -435,14 +435,13 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, spin_lock(&tbl->slot_tbl_lock); /* state manager is resetting the session */ if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) { - spin_unlock(&tbl->slot_tbl_lock); status = htonl(NFS4ERR_DELAY); /* Return NFS4ERR_BADSESSION if we're draining the session * in order to reset it. */ if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) status = htonl(NFS4ERR_BADSESSION); - goto out; + goto out_unlock; } memcpy(&res->csr_sessionid, &args->csa_sessionid, @@ -453,9 +452,8 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; status = validate_seqid(tbl, args); - spin_unlock(&tbl->slot_tbl_lock); if (status) - goto out; + goto out_unlock; cps->slotid = args->csa_slotid; @@ -466,7 +464,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, */ if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) { status = htonl(NFS4ERR_DELAY); - goto out; + goto out_unlock; } /* @@ -475,6 +473,8 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, * (sequence ID, cached reply) MUST NOT change. */ slot->seq_nr++; +out_unlock: + spin_unlock(&tbl->slot_tbl_lock); out: cps->clp = clp; /* put in nfs4_callback_compound */ From 1ca018d28d96d07788474abf66a5f3e9594841f5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 17 Jun 2015 19:41:51 -0400 Subject: [PATCH 5/6] pNFS: Fix a memory leak when attempted pnfs fails pnfs_do_write() expects the call to pnfs_write_through_mds() to free the pgio header and to release the layout segment before exiting. The problem is that nfs_pgio_data_destroy() doesn't actually do this; it only frees the memory allocated by nfs_generic_pgio(). Ditto for pnfs_do_read()... Fix in both cases is to add a call to hdr->release(hdr). Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust --- fs/nfs/pnfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 230606243be6..219ee6a3f1b3 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1865,6 +1865,7 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, mirror->pg_recoalesce = 1; } nfs_pgio_data_destroy(hdr); + hdr->release(hdr); } static enum pnfs_try_status @@ -1979,6 +1980,7 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc, mirror->pg_recoalesce = 1; } nfs_pgio_data_destroy(hdr); + hdr->release(hdr); } /* From c70701131f7a8edea91fc49d11796d342cff7c62 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 17 Jun 2015 19:56:22 -0400 Subject: [PATCH 6/6] NFS: Ensure we set NFS_CONTEXT_RESEND_WRITES when requeuing writes If a write attempt fails, and the write is queued up for resending to the server, as opposed to being dropped, then we need to set the appropriate flag so that nfs_file_fsync() does the right thing. Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust --- fs/nfs/pnfs.c | 1 + fs/nfs/write.c | 1 + 2 files changed, 2 insertions(+) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 219ee6a3f1b3..d47c188682b1 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1821,6 +1821,7 @@ int pnfs_write_done_resend_to_mds(struct nfs_pgio_header *hdr) /* Resend all requests through the MDS */ nfs_pageio_init_write(&pgio, hdr->inode, FLUSH_STABLE, true, hdr->completion_ops); + set_bit(NFS_CONTEXT_RESEND_WRITES, &hdr->args.context->flags); return nfs_pageio_resend(&pgio, hdr); } EXPORT_SYMBOL_GPL(pnfs_write_done_resend_to_mds); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index dfc19f1575a1..daf355642845 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1289,6 +1289,7 @@ static void nfs_initiate_write(struct nfs_pgio_header *hdr, static void nfs_redirty_request(struct nfs_page *req) { nfs_mark_request_dirty(req); + set_bit(NFS_CONTEXT_RESEND_WRITES, &req->wb_context->flags); nfs_unlock_request(req); nfs_end_page_writeback(req); nfs_release_request(req);