aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorAndy Adamson <andros@netapp.com>2011-01-05 21:04:34 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2011-01-06 14:46:25 -0500
commit42acd021824578fa0eeb6eb58d457c23ec5dc9c0 (patch)
tree7affe8e1108373906eefcea00498df088b6dfccb /fs/nfs
parentece0de633c4d9106c39ea9f0db1638c42ead2541 (diff)
NFS add session back channel draining
Currently session draining only drains the fore channel. The back channel processing must also be drained. Use the back channel highest_slot_used to indicate that a callback is being processed by the callback thread. Move the session complete to be per channel. When the session is draininig, wait for any current back channel processing to complete and stop all new back channel processing by returning NFS4ERR_DELAY to the back channel client. Drain the back channel, then the fore channel. Signed-off-by: Andy Adamson <andros@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/callback.h3
-rw-r--r--fs/nfs/callback_proc.c7
-rw-r--r--fs/nfs/callback_xdr.c35
-rw-r--r--fs/nfs/nfs4proc.c26
-rw-r--r--fs/nfs/nfs4state.c29
5 files changed, 85 insertions, 15 deletions
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index 25e8802a51d1..b678e3e15bd9 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -138,6 +138,8 @@ extern __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args,
138 void *dummy, 138 void *dummy,
139 struct cb_process_state *cps); 139 struct cb_process_state *cps);
140 140
141extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
142extern void nfs4_cb_take_slot(struct nfs_client *clp);
141#endif /* CONFIG_NFS_V4_1 */ 143#endif /* CONFIG_NFS_V4_1 */
142 144
143extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, 145extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
@@ -145,7 +147,6 @@ extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
145 struct cb_process_state *cps); 147 struct cb_process_state *cps);
146extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, 148extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
147 struct cb_process_state *cps); 149 struct cb_process_state *cps);
148
149#ifdef CONFIG_NFS_V4 150#ifdef CONFIG_NFS_V4
150extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); 151extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt);
151extern void nfs_callback_down(int minorversion); 152extern void nfs_callback_down(int minorversion);
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index b70e46da16fc..c1bead2f3e04 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -253,6 +253,12 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
253 if (clp == NULL) 253 if (clp == NULL)
254 goto out; 254 goto out;
255 255
256 /* state manager is resetting the session */
257 if (test_bit(NFS4_SESSION_DRAINING, &clp->cl_session->session_state)) {
258 status = NFS4ERR_DELAY;
259 goto out;
260 }
261
256 status = validate_seqid(&clp->cl_session->bc_slot_table, args); 262 status = validate_seqid(&clp->cl_session->bc_slot_table, args);
257 if (status) 263 if (status)
258 goto out; 264 goto out;
@@ -273,6 +279,7 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
273 res->csr_slotid = args->csa_slotid; 279 res->csr_slotid = args->csa_slotid;
274 res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; 280 res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
275 res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; 281 res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
282 nfs4_cb_take_slot(clp);
276 cps->clp = clp; /* put in nfs4_callback_compound */ 283 cps->clp = clp; /* put in nfs4_callback_compound */
277 284
278out: 285out:
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index dbd0d649805c..7a2d6c5864ca 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -596,6 +596,37 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
596 return htonl(NFS_OK); 596 return htonl(NFS_OK);
597} 597}
598 598
599static void nfs4_callback_free_slot(struct nfs4_session *session)
600{
601 struct nfs4_slot_table *tbl = &session->bc_slot_table;
602
603 spin_lock(&tbl->slot_tbl_lock);
604 /*
605 * Let the state manager know callback processing done.
606 * A single slot, so highest used slotid is either 0 or -1
607 */
608 tbl->highest_used_slotid--;
609 nfs4_check_drain_bc_complete(session);
610 spin_unlock(&tbl->slot_tbl_lock);
611}
612
613static void nfs4_cb_free_slot(struct nfs_client *clp)
614{
615 if (clp && clp->cl_session)
616 nfs4_callback_free_slot(clp->cl_session);
617}
618
619/* A single slot, so highest used slotid is either 0 or -1 */
620void nfs4_cb_take_slot(struct nfs_client *clp)
621{
622 struct nfs4_slot_table *tbl = &clp->cl_session->bc_slot_table;
623
624 spin_lock(&tbl->slot_tbl_lock);
625 tbl->highest_used_slotid++;
626 BUG_ON(tbl->highest_used_slotid != 0);
627 spin_unlock(&tbl->slot_tbl_lock);
628}
629
599#else /* CONFIG_NFS_V4_1 */ 630#else /* CONFIG_NFS_V4_1 */
600 631
601static __be32 632static __be32
@@ -604,6 +635,9 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
604 return htonl(NFS4ERR_MINOR_VERS_MISMATCH); 635 return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
605} 636}
606 637
638static void nfs4_cb_free_slot(struct nfs_client *clp)
639{
640}
607#endif /* CONFIG_NFS_V4_1 */ 641#endif /* CONFIG_NFS_V4_1 */
608 642
609static __be32 643static __be32
@@ -724,6 +758,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
724 758
725 *hdr_res.status = status; 759 *hdr_res.status = status;
726 *hdr_res.nops = htonl(nops); 760 *hdr_res.nops = htonl(nops);
761 nfs4_cb_free_slot(cps.clp);
727 nfs_put_client(cps.clp); 762 nfs_put_client(cps.clp);
728 dprintk("%s: done, status = %u\n", __func__, ntohl(status)); 763 dprintk("%s: done, status = %u\n", __func__, ntohl(status));
729 return rpc_success; 764 return rpc_success;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index e165c53db08f..18a4d5a9a4e9 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -356,9 +356,9 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot)
356} 356}
357 357
358/* 358/*
359 * Signal state manager thread if session is drained 359 * Signal state manager thread if session fore channel is drained
360 */ 360 */
361static void nfs41_check_drain_session_complete(struct nfs4_session *ses) 361static void nfs4_check_drain_fc_complete(struct nfs4_session *ses)
362{ 362{
363 struct rpc_task *task; 363 struct rpc_task *task;
364 364
@@ -372,8 +372,20 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses)
372 if (ses->fc_slot_table.highest_used_slotid != -1) 372 if (ses->fc_slot_table.highest_used_slotid != -1)
373 return; 373 return;
374 374
375 dprintk("%s COMPLETE: Session Drained\n", __func__); 375 dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__);
376 complete(&ses->complete); 376 complete(&ses->fc_slot_table.complete);
377}
378
379/*
380 * Signal state manager thread if session back channel is drained
381 */
382void nfs4_check_drain_bc_complete(struct nfs4_session *ses)
383{
384 if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) ||
385 ses->bc_slot_table.highest_used_slotid != -1)
386 return;
387 dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__);
388 complete(&ses->bc_slot_table.complete);
377} 389}
378 390
379static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) 391static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
@@ -390,7 +402,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
390 402
391 spin_lock(&tbl->slot_tbl_lock); 403 spin_lock(&tbl->slot_tbl_lock);
392 nfs4_free_slot(tbl, res->sr_slot); 404 nfs4_free_slot(tbl, res->sr_slot);
393 nfs41_check_drain_session_complete(res->sr_session); 405 nfs4_check_drain_fc_complete(res->sr_session);
394 spin_unlock(&tbl->slot_tbl_lock); 406 spin_unlock(&tbl->slot_tbl_lock);
395 res->sr_slot = NULL; 407 res->sr_slot = NULL;
396} 408}
@@ -4777,17 +4789,17 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
4777 if (!session) 4789 if (!session)
4778 return NULL; 4790 return NULL;
4779 4791
4780 init_completion(&session->complete);
4781
4782 tbl = &session->fc_slot_table; 4792 tbl = &session->fc_slot_table;
4783 tbl->highest_used_slotid = -1; 4793 tbl->highest_used_slotid = -1;
4784 spin_lock_init(&tbl->slot_tbl_lock); 4794 spin_lock_init(&tbl->slot_tbl_lock);
4785 rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); 4795 rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
4796 init_completion(&tbl->complete);
4786 4797
4787 tbl = &session->bc_slot_table; 4798 tbl = &session->bc_slot_table;
4788 tbl->highest_used_slotid = -1; 4799 tbl->highest_used_slotid = -1;
4789 spin_lock_init(&tbl->slot_tbl_lock); 4800 spin_lock_init(&tbl->slot_tbl_lock);
4790 rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); 4801 rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
4802 init_completion(&tbl->complete);
4791 4803
4792 session->session_state = 1<<NFS4_SESSION_INITING; 4804 session->session_state = 1<<NFS4_SESSION_INITING;
4793 4805
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 485e95e8fd62..6891dedd80f1 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -142,6 +142,11 @@ static int nfs41_setup_state_renewal(struct nfs_client *clp)
142 return status; 142 return status;
143} 143}
144 144
145/*
146 * Back channel returns NFS4ERR_DELAY for new requests when
147 * NFS4_SESSION_DRAINING is set so there is no work to be done when draining
148 * is ended.
149 */
145static void nfs4_end_drain_session(struct nfs_client *clp) 150static void nfs4_end_drain_session(struct nfs_client *clp)
146{ 151{
147 struct nfs4_session *ses = clp->cl_session; 152 struct nfs4_session *ses = clp->cl_session;
@@ -165,22 +170,32 @@ static void nfs4_end_drain_session(struct nfs_client *clp)
165 } 170 }
166} 171}
167 172
168static int nfs4_begin_drain_session(struct nfs_client *clp) 173static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl)
169{ 174{
170 struct nfs4_session *ses = clp->cl_session;
171 struct nfs4_slot_table *tbl = &ses->fc_slot_table;
172
173 spin_lock(&tbl->slot_tbl_lock); 175 spin_lock(&tbl->slot_tbl_lock);
174 set_bit(NFS4_SESSION_DRAINING, &ses->session_state);
175 if (tbl->highest_used_slotid != -1) { 176 if (tbl->highest_used_slotid != -1) {
176 INIT_COMPLETION(ses->complete); 177 INIT_COMPLETION(tbl->complete);
177 spin_unlock(&tbl->slot_tbl_lock); 178 spin_unlock(&tbl->slot_tbl_lock);
178 return wait_for_completion_interruptible(&ses->complete); 179 return wait_for_completion_interruptible(&tbl->complete);
179 } 180 }
180 spin_unlock(&tbl->slot_tbl_lock); 181 spin_unlock(&tbl->slot_tbl_lock);
181 return 0; 182 return 0;
182} 183}
183 184
185static int nfs4_begin_drain_session(struct nfs_client *clp)
186{
187 struct nfs4_session *ses = clp->cl_session;
188 int ret = 0;
189
190 set_bit(NFS4_SESSION_DRAINING, &ses->session_state);
191 /* back channel */
192 ret = nfs4_wait_on_slot_tbl(&ses->bc_slot_table);
193 if (ret)
194 return ret;
195 /* fore channel */
196 return nfs4_wait_on_slot_tbl(&ses->fc_slot_table);
197}
198
184int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) 199int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
185{ 200{
186 int status; 201 int status;