[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