@@ -704,15 +704,6 @@ gen_sessionid(struct nfsd4_session *ses)
*/
#define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44)
-static void
-free_session_slots(struct nfsd4_session *ses)
-{
- int i;
-
- for (i = 0; i < ses->se_fchannel.maxreqs; i++)
- kfree(ses->se_slots[i]);
-}
-
/*
* We don't actually need to cache the rpc and session headers, so we
* can allocate a little less for each slot:
@@ -758,29 +749,127 @@ static void nfsd4_put_drc_mem(int slotsize, int num)
spin_unlock(&nfsd_drc_lock);
}
-static struct nfsd4_session *__alloc_session(int slotsize, int numslots)
+static void nfsd4_free_slot(struct nfsd4_slot *slot)
{
- struct nfsd4_session *new;
- int mem, i;
+ kfree(slot);
+}
+
+static struct nfsd4_slot *nfsd4_new_slot(size_t slotsize, gfp_t gfp_mask)
+{
+ return kzalloc(sizeof(struct nfsd4_slot) + slotsize, gfp_mask);
+}
+
+static struct nfsd4_slot *nfsd4_find_slot_locked(const struct nfsd4_slot_table *tbl,
+ u32 slotid)
+{
+ struct nfsd4_slot *slot;
+
+ list_for_each_entry(slot, &tbl->slt_head, sl_list) {
+ if (slot->sl_slotid == slotid)
+ return slot;
+ }
+ return NULL;
+}
+
+static struct nfsd4_slot *nfsd4_find_slot(struct nfsd4_slot_table *tbl,
+ u32 slotid)
+{
+ struct nfsd4_slot *slot;
+
+ spin_lock(&tbl->slt_lock);
+ slot = nfsd4_find_slot_locked(tbl, slotid);
+ spin_unlock(&tbl->slt_lock);
+ return slot;
+}
+
+static struct nfsd4_slot *nfsd4_find_last_slot_locked(const struct nfsd4_slot_table *tbl)
+{
+ if (list_empty(&tbl->slt_head))
+ return NULL;
+ return list_entry(tbl->slt_head.prev, struct nfsd4_slot, sl_list);
+}
+
+static bool nfsd4_grow_slot_table_locked(struct nfsd4_slot_table *tbl,
+ u32 slotid, gfp_t gfp_mask)
+{
+ struct nfsd4_slot *slot = NULL;
+ struct nfsd4_slot *prev;
+ u32 next_slotid;
+
+ for (;;) {
+ prev = nfsd4_find_last_slot_locked(tbl);
+ if (prev != NULL) {
+ if (prev->sl_slotid >= slotid)
+ break;
+ next_slotid = prev->sl_slotid + 1;
+ } else
+ next_slotid = 0;
+ if (slot != NULL){
+ slot->sl_slotid = next_slotid;
+ list_add_tail(&slot->sl_list, &tbl->slt_head);
+ }
+ spin_unlock(&tbl->slt_lock);
+ slot = nfsd4_new_slot(tbl->slt_slotsize, gfp_mask);
+ spin_lock(&tbl->slt_lock);
+ if (slot == NULL)
+ return false;
+ }
+ nfsd4_free_slot(slot);
+ return true;
+}
+
+static bool nfsd4_grow_slot_table(struct nfsd4_slot_table *tbl,
+ u32 slotid, gfp_t gfp_mask)
+{
+ bool ret;
+
+ spin_lock(&tbl->slt_lock);
+ ret = nfsd4_grow_slot_table_locked(tbl, slotid, gfp_mask);
+ spin_unlock(&tbl->slt_lock);
+ return ret;
+}
+
+static void nfsd4_truncate_slot_table_locked(struct nfsd4_slot_table *tbl,
+ u32 slotid)
+{
+ struct nfsd4_slot *slot;
+
+ for (;;) {
+ slot = nfsd4_find_last_slot_locked(tbl);
+ if (slot == NULL || slot->sl_slotid < slotid)
+ break;
+ list_del(&slot->sl_list);
+ nfsd4_free_slot(slot);
+ }
+}
+
+static void nfsd4_free_slot_table(struct nfsd4_slot_table *tbl)
+{
+ spin_lock(&tbl->slt_lock);
+ nfsd4_truncate_slot_table_locked(tbl, 0);
+ spin_unlock(&tbl->slt_lock);
+}
+
+static void nfsd4_init_slot_table(struct nfsd4_slot_table *tbl, size_t slotsize)
+{
+ INIT_LIST_HEAD(&tbl->slt_head);
+ spin_lock_init(&tbl->slt_lock);
+ tbl->slt_slotsize = slotsize;
+}
- BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
- + sizeof(struct nfsd4_session) > PAGE_SIZE);
- mem = numslots * sizeof(struct nfsd4_slot *);
+static struct nfsd4_session *__alloc_session(size_t slotsize, u32 highest_slotid)
+{
+ struct nfsd4_session *new;
- new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
if (!new)
return NULL;
+ nfsd4_init_slot_table(&new->se_slots, slotsize);
/* allocate each struct nfsd4_slot and data cache in one piece */
- for (i = 0; i < numslots; i++) {
- mem = sizeof(struct nfsd4_slot) + slotsize;
- new->se_slots[i] = kzalloc(mem, GFP_KERNEL);
- if (!new->se_slots[i])
- goto out_free;
- }
- return new;
-out_free:
- while (i--)
- kfree(new->se_slots[i]);
+ if (nfsd4_grow_slot_table(&new->se_slots, highest_slotid, GFP_KERNEL))
+ return new;
+
+ nfsd4_free_slot_table(&new->se_slots);
kfree(new);
return NULL;
}
@@ -899,7 +988,7 @@ static void nfsd4_del_conns(struct nfsd4_session *s)
static void __free_session(struct nfsd4_session *ses)
{
nfsd4_put_drc_mem(slot_bytes(&ses->se_fchannel), ses->se_fchannel.maxreqs);
- free_session_slots(ses);
+ nfsd4_free_slot_table(&ses->se_slots);
kfree(ses);
}
@@ -936,7 +1025,7 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan)
if (numslots < 1)
return NULL;
- new = __alloc_session(slotsize, numslots);
+ new = __alloc_session(slotsize, numslots - 1);
if (!new) {
nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
return NULL;
@@ -2032,11 +2121,11 @@ nfsd4_sequence(struct svc_rqst *rqstp,
if (nfsd4_request_too_big(rqstp, session))
goto out;
+ /* Note: nfsd4_find_slot checks the validity of seq->slotid */
status = nfserr_badslot;
- if (seq->slotid >= session->se_fchannel.maxreqs)
+ slot = nfsd4_find_slot(&session->se_slots, seq->slotid);
+ if (slot == NULL)
goto out;
-
- slot = session->se_slots[seq->slotid];
dprintk("%s: slotid %d\n", __func__, seq->slotid);
/* We do not negotiate the number of slots yet, so set the
@@ -128,6 +128,8 @@ static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s)
(NFSD_CACHE_SIZE_SLOTS_PER_SESSION * NFSD_SLOT_CACHE_SIZE)
struct nfsd4_slot {
+ struct list_head sl_list;
+ u32 sl_slotid;
u32 sl_seqid;
__be32 sl_status;
u32 sl_datalen;
@@ -139,6 +141,12 @@ struct nfsd4_slot {
char sl_data[];
};
+struct nfsd4_slot_table {
+ struct list_head slt_head;
+ spinlock_t slt_lock;
+ size_t slt_slotsize;
+};
+
struct nfsd4_channel_attrs {
u32 headerpadsz;
u32 maxreq_sz;
@@ -195,7 +203,7 @@ struct nfsd4_session {
struct list_head se_conns;
u32 se_cb_prog;
u32 se_cb_seq_nr;
- struct nfsd4_slot *se_slots[]; /* forward channel slots */
+ struct nfsd4_slot_table se_slots;
};
extern void nfsd4_put_session(struct nfsd4_session *ses);
In preparation for the dynamic slot table allocation, convert the nfsd slot table to a linked list model. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> --- fs/nfsd/nfs4state.c | 151 +++++++++++++++++++++++++++++++++++++++++----------- fs/nfsd/state.h | 10 +++- 2 files changed, 129 insertions(+), 32 deletions(-)