The algorithm chosen for growing/shrinking the dynamic slot table size is as follows: If the client is sending a sa_highest_slotid value that is greater than or equal to the our server target_highest_slotid, then multiply the value of the latter by 5/4. If, on the other hand, the sa_highest_slotid value is smaller than our target_highest_slotid, then try adjusting the latter to half its current value, or to the value of sa_highest_slotid+1, whichever is larger. Signed-off-by: Trond Myklebust <Trond.Myklebust@xxxxxxxxxx> --- fs/nfsd/nfs4state.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++---- fs/nfsd/state.h | 2 ++ 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index a1208cc..88d0de9 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -807,6 +807,7 @@ static bool nfsd4_grow_slot_table_locked(struct nfsd4_slot_table *tbl, if (slot != NULL){ if (!nfsd4_get_drc_mem(tbl)) break; + slot->sl_generation = tbl->slt_generation - 1; slot->sl_slotid = next_slotid; list_add_tail(&slot->sl_list, &tbl->slt_head); } @@ -853,6 +854,30 @@ static void nfsd4_free_slot_table(struct nfsd4_slot_table *tbl) spin_unlock(&tbl->slt_lock); } +static void nfsd4_fc_set_highest_slotid_locked(struct nfsd4_session *session, + struct nfsd4_slot_table *tbl, + u32 target_highest_slotid, + u32 highest_slotid) +{ + /* Lower limit for target_highest_slotid is negotiated limit */ + target_highest_slotid = max(target_highest_slotid, + session->se_fchannel.maxreqs - 1); + /* Lower limit for highest_slotid is target_highest_slotid */ + highest_slotid = max(highest_slotid, target_highest_slotid); + + if (target_highest_slotid == tbl->slt_target_highest_slotid && + highest_slotid == tbl->slt_highest_slotid) + return; + + if (!nfsd4_grow_slot_table_locked(tbl, highest_slotid, GFP_KERNEL)) + return; + + tbl->slt_target_highest_slotid = target_highest_slotid; + tbl->slt_highest_slotid = highest_slotid; + tbl->slt_generation++; + nfsd4_truncate_slot_table_locked(tbl, tbl->slt_highest_slotid); +} + static void nfsd4_init_slot_table(struct nfsd4_slot_table *tbl, size_t slotsize, u32 highest_slotid) { @@ -2039,6 +2064,45 @@ out: return status; } +static void nfsd4_sequence_adjust_slot_table(struct nfsd4_session *session, + struct nfsd4_slot *slot, u32 sa_highest_slotid, + struct nfsd4_sequence *res) +{ + struct nfsd4_slot_table *tbl = &session->se_slots; + u32 next_target; + u32 next_highest; + + spin_lock(&tbl->slt_lock); + /* + * If this slot hasn't seen our previous values, then don't trust + * that the client has seen them. Don't adjust the slot table yet. + */ + if (slot->sl_generation != tbl->slt_generation) + goto out; + + next_target = tbl->slt_target_highest_slotid; + + /* Is the client bumping against our current window limits? */ + if (sa_highest_slotid >= tbl->slt_target_highest_slotid) { + /* Yes! Grow the window size by 1/4 */ + next_target += 1 + (tbl->slt_target_highest_slotid >> 2); + next_highest = next_target; + } else { + /* No! Try to shrink the window size by 1/2 */ + next_target >>= 1; + if (sa_highest_slotid + 1 > next_target) + next_target = sa_highest_slotid + 1; + next_highest = tbl->slt_target_highest_slotid; + } + nfsd4_fc_set_highest_slotid_locked(session, tbl, + next_target, next_highest); +out: + slot->sl_generation = tbl->slt_generation; + res->highest_slotid = tbl->slt_highest_slotid; + res->target_highest_slotid = tbl->slt_target_highest_slotid; + spin_unlock(&tbl->slt_lock); +} + static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) { struct nfsd4_conn *c; @@ -2159,11 +2223,9 @@ nfsd4_sequence(struct svc_rqst *rqstp, else slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; - /* Retrieve new target/highest slotid values */ - spin_lock(&session->se_slots.slt_lock); - seq->target_highest_slotid = session->se_slots.slt_target_highest_slotid; - seq->highest_slotid = session->se_slots.slt_highest_slotid; - spin_unlock(&session->se_slots.slt_lock); + /* Adjust slot table, and retrieve new target/highest slotid values */ + nfsd4_sequence_adjust_slot_table(session, slot, + seq->highest_slotid, seq); cstate->slot = slot; cstate->session = session; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 7a0d8e4..c2f897f 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -129,6 +129,7 @@ static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s) struct nfsd4_slot { struct list_head sl_list; + unsigned long sl_generation; u32 sl_slotid; u32 sl_seqid; __be32 sl_status; @@ -146,6 +147,7 @@ struct nfsd4_slot_table { spinlock_t slt_lock; size_t slt_slotsize; unsigned long slt_memused; + unsigned long slt_generation; u32 slt_target_highest_slotid; u32 slt_highest_slotid; }; -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html