[PATCH 4/4] NFSD: Add support for dynamic slot changes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux