aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--include/linux/nfs_fs_sb.h2
6 files changed, 86 insertions, 16 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;
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 1eaa054a2c7d..e93ada0565fc 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -197,6 +197,7 @@ struct nfs4_slot_table {
197 * op for dynamic resizing */ 197 * op for dynamic resizing */
198 int target_max_slots; /* Set by CB_RECALL_SLOT as 198 int target_max_slots; /* Set by CB_RECALL_SLOT as
199 * the new max_slots */ 199 * the new max_slots */
200 struct completion complete;
200}; 201};
201 202
202static inline int slot_idx(struct nfs4_slot_table *tbl, struct nfs4_slot *sp) 203static inline int slot_idx(struct nfs4_slot_table *tbl, struct nfs4_slot *sp)
@@ -213,7 +214,6 @@ struct nfs4_session {
213 unsigned long session_state; 214 unsigned long session_state;
214 u32 hash_alg; 215 u32 hash_alg;
215 u32 ssv_len; 216 u32 ssv_len;
216 struct completion complete;
217 217
218 /* The fore and back channel */ 218 /* The fore and back channel */
219 struct nfs4_channel_attrs fc_attrs; 219 struct nfs4_channel_attrs fc_attrs;