diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-11-29 17:27:47 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-12-05 18:30:52 -0500 |
commit | b75ad4cda5a6cd3431b1c65c2739c5ebd2c4b9da (patch) | |
tree | 6ba6dd80fc8e118067ca70bd67345864835fe98a | |
parent | 62ae082d883d167cdaa7895cf2972d85e178228a (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.c | 12 | ||||
-rw-r--r-- | fs/nfs/nfs4session.c | 59 | ||||
-rw-r--r-- | fs/nfs/nfs4session.h | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 6 |
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)) { | 412 | out_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(); |
1466 | out_no_action: | 1467 | out_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 | ||
1470 | static void nfs4_open_done(struct rpc_task *task, void *calldata) | 1472 | static 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 | ||
220 | static 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 | |||
238 | static 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 | |||
246 | bool 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 | |||
254 | static 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 | |||
266 | void 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 */ |
221 | static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl, | 275 | static 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 | ||
237 | void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, | 290 | void 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 | ||
97 | bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl, | ||
98 | struct nfs4_slot *slot); | ||
99 | void 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 | } |