aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-11-29 17:27:47 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-12-05 18:30:52 -0500
commitb75ad4cda5a6cd3431b1c65c2739c5ebd2c4b9da (patch)
tree6ba6dd80fc8e118067ca70bd67345864835fe98a
parent62ae082d883d167cdaa7895cf2972d85e178228a (diff)
NFSv4.1: Ensure smooth handover of slots from one task to the next waiting
Currently, we see a lot of bouncing for the value of highest_used_slotid due to the fact that slots are getting freed, instead of getting instantly transmitted to the next waiting task. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/nfs4proc.c12
-rw-r--r--fs/nfs/nfs4session.c59
-rw-r--r--fs/nfs/nfs4session.h4
-rw-r--r--fs/nfs/nfs4state.c6
4 files changed, 69 insertions, 12 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 99d99a5a3f61..992233561dbd 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -401,14 +401,15 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
401 if (tbl->highest_used_slotid > tbl->target_highest_slotid) 401 if (tbl->highest_used_slotid > tbl->target_highest_slotid)
402 send_new_highest_used_slotid = true; 402 send_new_highest_used_slotid = true;
403 403
404 if (nfs41_wake_and_assign_slot(tbl, res->sr_slot)) {
405 send_new_highest_used_slotid = false;
406 goto out_unlock;
407 }
404 nfs4_free_slot(tbl, res->sr_slot); 408 nfs4_free_slot(tbl, res->sr_slot);
405 409
406 if (tbl->highest_used_slotid != NFS4_NO_SLOT) 410 if (tbl->highest_used_slotid != NFS4_NO_SLOT)
407 send_new_highest_used_slotid = false; 411 send_new_highest_used_slotid = false;
408 if (!nfs4_session_draining(session)) { 412out_unlock:
409 if (rpc_wake_up_next(&tbl->slot_tbl_waitq) != NULL)
410 send_new_highest_used_slotid = false;
411 }
412 spin_unlock(&tbl->slot_tbl_lock); 413 spin_unlock(&tbl->slot_tbl_lock);
413 res->sr_slot = NULL; 414 res->sr_slot = NULL;
414 if (send_new_highest_used_slotid) 415 if (send_new_highest_used_slotid)
@@ -1465,6 +1466,7 @@ unlock_no_action:
1465 rcu_read_unlock(); 1466 rcu_read_unlock();
1466out_no_action: 1467out_no_action:
1467 task->tk_action = NULL; 1468 task->tk_action = NULL;
1469 nfs4_sequence_done(task, &data->o_res.seq_res);
1468} 1470}
1469 1471
1470static void nfs4_open_done(struct rpc_task *task, void *calldata) 1472static void nfs4_open_done(struct rpc_task *task, void *calldata)
@@ -2135,6 +2137,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
2135 if (!call_close) { 2137 if (!call_close) {
2136 /* Note: exit _without_ calling nfs4_close_done */ 2138 /* Note: exit _without_ calling nfs4_close_done */
2137 task->tk_action = NULL; 2139 task->tk_action = NULL;
2140 nfs4_sequence_done(task, &calldata->res.seq_res);
2138 goto out; 2141 goto out;
2139 } 2142 }
2140 2143
@@ -4384,6 +4387,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
4384 if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) { 4387 if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
4385 /* Note: exit _without_ running nfs4_locku_done */ 4388 /* Note: exit _without_ running nfs4_locku_done */
4386 task->tk_action = NULL; 4389 task->tk_action = NULL;
4390 nfs4_sequence_done(task, &calldata->res.seq_res);
4387 return; 4391 return;
4388 } 4392 }
4389 calldata->timestamp = jiffies; 4393 calldata->timestamp = jiffies;
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c
index 701170293ceb..066cfa101b41 100644
--- a/fs/nfs/nfs4session.c
+++ b/fs/nfs/nfs4session.c
@@ -217,11 +217,65 @@ static void nfs4_destroy_slot_tables(struct nfs4_session *session)
217 nfs4_shrink_slot_table(&session->bc_slot_table, 0); 217 nfs4_shrink_slot_table(&session->bc_slot_table, 0);
218} 218}
219 219
220static bool nfs41_assign_slot(struct rpc_task *task, void *pslot)
221{
222 struct nfs4_sequence_args *args = task->tk_msg.rpc_argp;
223 struct nfs4_sequence_res *res = task->tk_msg.rpc_resp;
224 struct nfs4_slot *slot = pslot;
225 struct nfs4_slot_table *tbl = slot->table;
226
227 if (nfs4_session_draining(tbl->session) && !args->sa_privileged)
228 return false;
229 slot->renewal_time = jiffies;
230 slot->generation = tbl->generation;
231 args->sa_slot = slot;
232 res->sr_slot = slot;
233 res->sr_status_flags = 0;
234 res->sr_status = 1;
235 return true;
236}
237
238static bool __nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
239 struct nfs4_slot *slot)
240{
241 if (rpc_wake_up_first(&tbl->slot_tbl_waitq, nfs41_assign_slot, slot))
242 return true;
243 return false;
244}
245
246bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
247 struct nfs4_slot *slot)
248{
249 if (slot->slot_nr > tbl->max_slotid)
250 return false;
251 return __nfs41_wake_and_assign_slot(tbl, slot);
252}
253
254static bool nfs41_try_wake_next_slot_table_entry(struct nfs4_slot_table *tbl)
255{
256 struct nfs4_slot *slot = nfs4_alloc_slot(tbl);
257 if (!IS_ERR(slot)) {
258 bool ret = __nfs41_wake_and_assign_slot(tbl, slot);
259 if (ret)
260 return ret;
261 nfs4_free_slot(tbl, slot);
262 }
263 return false;
264}
265
266void nfs41_wake_slot_table(struct nfs4_slot_table *tbl)
267{
268 for (;;) {
269 if (!nfs41_try_wake_next_slot_table_entry(tbl))
270 break;
271 }
272}
273
220/* Update the client's idea of target_highest_slotid */ 274/* Update the client's idea of target_highest_slotid */
221static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, 275static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl,
222 u32 target_highest_slotid) 276 u32 target_highest_slotid)
223{ 277{
224 unsigned int max_slotid, i; 278 unsigned int max_slotid;
225 279
226 if (tbl->target_highest_slotid == target_highest_slotid) 280 if (tbl->target_highest_slotid == target_highest_slotid)
227 return; 281 return;
@@ -229,9 +283,8 @@ static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl,
229 tbl->generation++; 283 tbl->generation++;
230 284
231 max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, tbl->target_highest_slotid); 285 max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, tbl->target_highest_slotid);
232 for (i = tbl->max_slotid + 1; i <= max_slotid; i++)
233 rpc_wake_up_next(&tbl->slot_tbl_waitq);
234 tbl->max_slotid = max_slotid; 286 tbl->max_slotid = max_slotid;
287 nfs41_wake_slot_table(tbl);
235} 288}
236 289
237void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, 290void nfs41_set_target_slotid(struct nfs4_slot_table *tbl,
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h
index bdd14a60722b..7db739370164 100644
--- a/fs/nfs/nfs4session.h
+++ b/fs/nfs/nfs4session.h
@@ -94,6 +94,10 @@ static inline bool nfs4_session_draining(struct nfs4_session *session)
94 return !!test_bit(NFS4_SESSION_DRAINING, &session->session_state); 94 return !!test_bit(NFS4_SESSION_DRAINING, &session->session_state);
95} 95}
96 96
97bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
98 struct nfs4_slot *slot);
99void nfs41_wake_slot_table(struct nfs4_slot_table *tbl);
100
97/* 101/*
98 * Determine if sessions are in use. 102 * Determine if sessions are in use.
99 */ 103 */
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 7d73df5a05d1..78e90a80fc3a 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -255,17 +255,13 @@ static void nfs4_end_drain_session(struct nfs_client *clp)
255{ 255{
256 struct nfs4_session *ses = clp->cl_session; 256 struct nfs4_session *ses = clp->cl_session;
257 struct nfs4_slot_table *tbl; 257 struct nfs4_slot_table *tbl;
258 unsigned int i;
259 258
260 if (ses == NULL) 259 if (ses == NULL)
261 return; 260 return;
262 tbl = &ses->fc_slot_table; 261 tbl = &ses->fc_slot_table;
263 if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { 262 if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
264 spin_lock(&tbl->slot_tbl_lock); 263 spin_lock(&tbl->slot_tbl_lock);
265 for (i = 0; i <= tbl->max_slotid; i++) { 264 nfs41_wake_slot_table(tbl);
266 if (rpc_wake_up_next(&tbl->slot_tbl_waitq) == NULL)
267 break;
268 }
269 spin_unlock(&tbl->slot_tbl_lock); 265 spin_unlock(&tbl->slot_tbl_lock);
270 } 266 }
271} 267}