diff options
-rw-r--r-- | fs/nfs/callback.h | 3 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 7 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 35 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 26 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 29 | ||||
-rw-r--r-- | include/linux/nfs_fs_sb.h | 2 |
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 | ||
141 | extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses); | ||
142 | extern void nfs4_cb_take_slot(struct nfs_client *clp); | ||
141 | #endif /* CONFIG_NFS_V4_1 */ | 143 | #endif /* CONFIG_NFS_V4_1 */ |
142 | 144 | ||
143 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, | 145 | extern __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); |
146 | extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, | 148 | extern __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 |
150 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); | 151 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); |
151 | extern void nfs_callback_down(int minorversion); | 152 | extern 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 | ||
278 | out: | 285 | out: |
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 | ||
599 | static 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 | |||
613 | static 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 */ | ||
620 | void 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 | ||
601 | static __be32 | 632 | static __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 | ||
638 | static 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 | ||
609 | static __be32 | 643 | static __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 | */ |
361 | static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | 361 | static 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 | */ | ||
382 | void 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 | ||
379 | static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) | 391 | static 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 | */ | ||
145 | static void nfs4_end_drain_session(struct nfs_client *clp) | 150 | static 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 | ||
168 | static int nfs4_begin_drain_session(struct nfs_client *clp) | 173 | static 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 | ||
185 | static 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 | |||
184 | int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | 199 | int 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 | ||
202 | static inline int slot_idx(struct nfs4_slot_table *tbl, struct nfs4_slot *sp) | 203 | static 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; |