[pnfs] [PATCH 4/4] nfs41: use a sorted free list for sessions slots

Benny Halevy bhalevy at panasas.com
Fri Mar 14 07:13:38 EDT 2008


Also,
* Maintain highest_slotid correctly.
* sleep for a free slot only if failed to allocate one.

Signed-off-by: Benny Halevy <bhalevy at panasas.com>
---
 fs/nfs/nfs4proc.c            |  104 +++++++++++++++++++++++++++---------------
 include/linux/nfs4_session.h |    9 +--
 2 files changed, 70 insertions(+), 43 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 0203afe..d0e9c5a 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -210,6 +210,43 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
 }
 
 #if defined(CONFIG_NFS_V4_1)
+
+static inline void __free_slot_sorted(struct nfs4_slot_table *tbl,
+				      struct nfs4_slot *slot)
+{
+	int slot_nr = slot->slot_nr;
+	struct nfs4_slot *sp;
+
+	list_for_each_entry (sp, &tbl->free_slots, entry)
+		if (slot_nr < sp->slot_nr) {
+			list_add_tail(&slot->entry, &sp->entry);
+			return;
+		}
+	list_add_tail(&slot->entry, &tbl->free_slots);
+}
+
+static inline void __nfs41_free_slot(struct nfs4_slot_table *tbl,
+				     struct nfs4_slot *slot)
+{
+	int slot_nr;
+	struct nfs4_slot *sp;
+
+	spin_lock(&tbl->slot_tbl_lock);
+	__free_slot_sorted(tbl, slot);
+	slot_nr = slot->slot_nr;
+	if (slot_nr == tbl->highest_slotid) {
+		slot_nr--;
+		list_for_each_entry_reverse(sp, &tbl->free_slots, entry) {
+			if (sp->slot_nr != slot_nr)
+				break;
+			slot_nr--;
+		}
+		tbl->highest_slotid = slot_nr;
+	}
+	spin_unlock(&tbl->slot_tbl_lock);
+	rpc_wake_up_next(&tbl->slot_tbl_waitq);
+}
+
 /* For pNFS filelayout data servers:
  * the nfs_client is NULL - to signal no lease update.
  * session is the data server.
@@ -235,7 +272,7 @@ static int nfs41_sequence_done(struct nfs_client *clp,
 	slot = res->sr_slot;
 	if (slot == NULL) {
 		dprintk("%s: no slot: status %d\n", __func__, status);
-		goto out;	/* session recovery probably failed */
+		goto ret;	/* session recovery probably failed */
 	}
 
 	switch (status) {
@@ -267,12 +304,7 @@ static int nfs41_sequence_done(struct nfs_client *clp,
 		spin_unlock(&clp->cl_lock);
 	}
 no_update:
-	/* Clear the 'busy' bit on the slot that was used */
-	smp_mb__before_clear_bit();
-	clear_bit(NFS4_SLOT_BUSY, &slot->flags);
-	smp_mb__after_clear_bit();
-out:
-	rpc_wake_up_next(&tbl->slot_tbl_waitq);
+	__nfs41_free_slot(tbl, slot);
 ret:
 	return status;
 }
@@ -299,31 +331,28 @@ static int nfs4_sequence_done(struct nfs_server *server,
 	return ret;
 }
 
-static struct nfs4_slot *__nfs4_find_slot(struct nfs4_slot_table *tbl)
+static inline struct nfs4_slot *nfs4_find_slot(struct nfs4_slot_table *tbl,
+					       struct rpc_task *task,
+					       struct nfs41_sequence_args *args)
 {
-	int i;
+	int slot_nr;
 	struct nfs4_slot *slot;
 
-	for (i = 0; i < tbl->max_slots; ++i) {
-		slot = &tbl->slots[i];
-		if (!test_bit(NFS4_SLOT_BUSY, &slot->flags)) {
-			set_bit(NFS4_SLOT_BUSY, &slot->flags);
-			return slot;
-		}
-	}
-
-	return NULL;
-}
-
-static struct nfs4_slot *nfs4_find_slot(struct nfs4_slot_table *tbl,
-					struct rpc_task *task)
-{
-	struct nfs4_slot *slot;
-
-	rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL, NULL);
-
 	spin_lock(&tbl->slot_tbl_lock);
-	slot = __nfs4_find_slot(tbl);
+	if (likely(!list_empty(&tbl->free_slots))) {
+		slot = list_first_entry(&tbl->free_slots, struct nfs4_slot,
+					entry);
+		list_del(&slot->entry);
+		slot_nr = slot->slot_nr;
+		if (tbl->highest_slotid < slot_nr)
+			tbl->highest_slotid = slot_nr;
+		args->sa_slotid = slot_nr;
+		args->sa_seqid = slot->seq_nr;
+		args->sa_max_slotid = tbl->highest_slotid;
+	} else {
+		slot = NULL;
+		rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL, NULL);
+	}
 	spin_unlock(&tbl->slot_tbl_lock);
 
 	return slot;
@@ -338,21 +367,21 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
 	struct nfs4_slot *slot;
 	struct nfs4_slot_table *tbl;
 
+	dprintk("--> %s\n", __func__);
 	tbl = &session->fore_channel.slot_table;
-	slot = nfs4_find_slot(tbl, task);
+	slot = nfs4_find_slot(tbl, task, args);
 
-	if (!slot)
+	if (!slot) {
+		dprintk("<-- %s: no free slots\n", __func__);
 		return -EAGAIN;
+	}
 
 	memcpy(args->sa_sessionid.data, session->sess_id,
 	       NFS4_MAX_SESSIONID_LEN);
-	args->sa_slotid = slot->slot_nr;
-	args->sa_seqid = slot->seq_nr;
 	args->sa_cache_this = cache_reply;
 
-	spin_lock(&tbl->slot_tbl_lock);
-	args->sa_max_slotid = tbl->max_slots;
-	spin_unlock(&tbl->slot_tbl_lock);
+	dprintk("<-- %s slot=%p slotid=%d seqid=%d\n", __func__,
+		slot, args->sa_slotid, slot->seq_nr);
 
 	res->sr_slot = slot;
 	res->sr_renewal_time = jiffies;
@@ -4541,11 +4570,11 @@ int nfs4_init_slot_table(struct nfs4_channel *channel)
 	dprintk("%s: slots=%p max_slots=%d\n", __func__, 
 		tbl->slots, tbl->max_slots);
 
-	for (i = 0; i < channel->chan_attrs.max_reqs; ++i) {
+	for (i = 0; i < channel->chan_attrs.max_reqs - 1; ++i) {
 		slot = &tbl->slots[i];
 		slot->slot_nr = i;
 		slot->seq_nr = 1;
-		slot->flags = 0;
+		list_add_tail(&slot->entry, &tbl->free_slots);
 	}
 
 out:
@@ -4573,6 +4602,7 @@ static int nfs4_init_channel(struct nfs4_channel *channel)
 	tbl = &channel->slot_table;
 
 	spin_lock_init(&tbl->slot_tbl_lock);
+	INIT_LIST_HEAD(&tbl->free_slots);
 	rpc_init_wait_queue(&tbl->slot_tbl_waitq, "Slot table");
 
 	return 0;
diff --git a/include/linux/nfs4_session.h b/include/linux/nfs4_session.h
index 8ef8d6d..542d099 100644
--- a/include/linux/nfs4_session.h
+++ b/include/linux/nfs4_session.h
@@ -7,11 +7,6 @@
 #include <linux/smp_lock.h>
 #include <linux/sunrpc/sched.h>
 
-/* The flags for the nfs4_slot struct */
-#define NFS4_SLOT_BUSY		0X0	/* Slot in use */
-#define NFS4_SLOT_RECLAIMED	0x1	/* Slot has been reclaimed by
-					   the server */
-
 struct nfs4_channel_attrs {
 	u32			headerpadsz;
 	u32			max_rqst_sz;
@@ -25,14 +20,16 @@ struct nfs4_channel_attrs {
 struct nfs4_slot {
 	u32		 	slot_nr;
 	u32		 	seq_nr;
-	unsigned long		flags;
+	struct list_head 	entry;
 };
 
 struct nfs4_slot_table {
 	struct nfs4_slot 	*slots;
 	spinlock_t		slot_tbl_lock;
+	struct list_head 	free_slots;
 	struct rpc_wait_queue	slot_tbl_waitq;
 	int			max_slots;
+	int			highest_slotid;
 };
 
 struct nfs4_channel {
-- 
1.5.3.3



More information about the pNFS mailing list