From patchwork Fri Dec 3 16:29:01 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Adamson X-Patchwork-Id: 378511 X-Patchwork-Delegate: Trond.Myklebust@netapp.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oB3GSto2022272 for ; Fri, 3 Dec 2010 16:28:55 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753176Ab0LCQ2m (ORCPT ); Fri, 3 Dec 2010 11:28:42 -0500 Received: from mx2.netapp.com ([216.240.18.37]:21165 "EHLO mx2.netapp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753170Ab0LCQ2l (ORCPT ); Fri, 3 Dec 2010 11:28:41 -0500 X-IronPort-AV: E=Sophos;i="4.59,294,1288594800"; d="scan'208";a="490560537" Received: from smtp1.corp.netapp.com ([10.57.156.124]) by mx2-out.netapp.com with ESMTP; 03 Dec 2010 08:28:40 -0800 Received: from localhost.localdomain (tuchfeld-lxp.hq.netapp.com [10.58.58.163] (may be forged)) by smtp1.corp.netapp.com (8.13.1/8.13.1/NTAP-1.6) with ESMTP id oB3GSdj2009787; Fri, 3 Dec 2010 08:28:39 -0800 (PST) From: andros@netapp.com To: trond.myklebust@netapp.com Cc: linux-nfs@vger.kernel.org, Andy Adamson Subject: [PATCH 1/1] NFS add session back channel draining Date: Fri, 3 Dec 2010 11:29:01 -0500 Message-Id: <1291393741-2851-1-git-send-email-andros@netapp.com> X-Mailer: git-send-email 1.6.6 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Fri, 03 Dec 2010 16:28:55 +0000 (UTC) diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index aa62342..bcad3c1 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -251,6 +251,12 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, if (clp == NULL) goto out; + /* state manager is resetting the session */ + if (test_bit(NFS4_SESSION_DRAINING, &clp->cl_session->session_state)) { + status = NFS4ERR_DELAY; + goto err_putclient; + } + status = validate_seqid(&clp->cl_session->bc_slot_table, args); if (status) goto err_putclient; diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 85cbb8f..d21f17c 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -596,6 +596,22 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) return htonl(NFS_OK); } +static void nfs4_callback_free_slot(struct nfs4_session *session) +{ + struct nfs4_slot_table *tbl = &session->bc_slot_table; + + spin_lock(&tbl->slot_tbl_lock); + /* + * Let the state manager know callback processing done. + * A single slot, so highest used slotid is either 0 or -1 + */ + tbl->highest_used_slotid--; + nfs4_check_drain_bc_complete(session); + spin_unlock(&tbl->slot_tbl_lock); + dprintk("%s highest_used_slotid %d\n", __func__, + tbl->highest_used_slotid); +} + #else /* CONFIG_NFS_V4_1 */ static __be32 @@ -604,6 +620,9 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) return htonl(NFS4ERR_MINOR_VERS_MISMATCH); } +static void nfs4_callback_free_slot(struct nfs4_session *session) +{ +} #endif /* CONFIG_NFS_V4_1 */ static __be32 diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index f65602c..0b5d99e 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -281,6 +281,7 @@ extern int _nfs4_call_sync_session(struct nfs_server *server, struct nfs4_sequence_res *res, int cache_reply); +void nfs4_check_drain_bc_complete(struct nfs4_session *ses); /* * Determine the device name as a string */ diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a241957..c244000 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -355,9 +355,9 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot) } /* - * Signal state manager thread if session is drained + * Signal state manager thread if session fore channel is drained */ -static void nfs41_check_drain_session_complete(struct nfs4_session *ses) +static void nfs4_check_drain_fc_complete(struct nfs4_session *ses) { struct rpc_task *task; @@ -371,8 +371,20 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses) if (ses->fc_slot_table.highest_used_slotid != -1) return; - dprintk("%s COMPLETE: Session Drained\n", __func__); - complete(&ses->complete); + dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__); + complete(&ses->fc_slot_table.complete); +} + +/* + * Signal state manager thread if session back channel is drained + */ +void nfs4_check_drain_bc_complete(struct nfs4_session *ses) +{ + if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) || + ses->bc_slot_table.highest_used_slotid != -1) + return; + dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__); + complete(&ses->bc_slot_table.complete); } static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) @@ -389,7 +401,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) spin_lock(&tbl->slot_tbl_lock); nfs4_free_slot(tbl, res->sr_slot); - nfs41_check_drain_session_complete(res->sr_session); + nfs4_check_drain_fc_complete(res->sr_session); spin_unlock(&tbl->slot_tbl_lock); res->sr_slot = NULL; } @@ -4772,17 +4784,17 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) if (!session) return NULL; - init_completion(&session->complete); - tbl = &session->fc_slot_table; tbl->highest_used_slotid = -1; spin_lock_init(&tbl->slot_tbl_lock); rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); + init_completion(&tbl->complete); tbl = &session->bc_slot_table; tbl->highest_used_slotid = -1; spin_lock_init(&tbl->slot_tbl_lock); rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); + init_completion(&tbl->complete); session->session_state = 1<cl_session; @@ -170,16 +175,32 @@ static int nfs4_begin_drain_session(struct nfs_client *clp) { struct nfs4_session *ses = clp->cl_session; struct nfs4_slot_table *tbl = &ses->fc_slot_table; + int ret = 0; - spin_lock(&tbl->slot_tbl_lock); set_bit(NFS4_SESSION_DRAINING, &ses->session_state); + /* back channel */ + tbl = &ses->bc_slot_table; + spin_lock(&tbl->slot_tbl_lock); if (tbl->highest_used_slotid != -1) { - INIT_COMPLETION(ses->complete); + INIT_COMPLETION(tbl->complete); spin_unlock(&tbl->slot_tbl_lock); - return wait_for_completion_interruptible(&ses->complete); + ret = wait_for_completion_interruptible(&tbl->complete); + if (ret) + goto out; + goto forechannel; } spin_unlock(&tbl->slot_tbl_lock); - return 0; +forechannel: + /* fore channel */ + spin_lock(&tbl->slot_tbl_lock); + if (tbl->highest_used_slotid != -1) { + INIT_COMPLETION(tbl->complete); + spin_unlock(&tbl->slot_tbl_lock); + return wait_for_completion_interruptible(&tbl->complete); + } + spin_unlock(&tbl->slot_tbl_lock); +out: + return ret; } int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 1eaa054..e93ada0 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -197,6 +197,7 @@ struct nfs4_slot_table { * op for dynamic resizing */ int target_max_slots; /* Set by CB_RECALL_SLOT as * the new max_slots */ + struct completion complete; }; static inline int slot_idx(struct nfs4_slot_table *tbl, struct nfs4_slot *sp) @@ -213,7 +214,6 @@ struct nfs4_session { unsigned long session_state; u32 hash_alg; u32 ssv_len; - struct completion complete; /* The fore and back channel */ struct nfs4_channel_attrs fc_attrs;