Code to initialize and destroy the slot table. Uses bitmap-based allocation. Signed-off-by: Andy Adamson<andros@xxxxxxxxxx> Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx> --- fs/nfs/nfs4proc.c | 88 ++++++++++++++++++++++++++++++++++++++++++ include/linux/nfs4_session.h | 17 ++++++++ 2 files changed, 105 insertions(+), 0 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d0b6ca1..08e7129 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3683,6 +3683,92 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, } #ifdef CONFIG_NFS_V4_1 +/* + * Initialize slot table + * + * Note: the "used" bitmap points to _used_slots id max_slots <= BITS_PER_LONG. + * Otherwise, we dynamically allocate enough ulongs to hold max_slots bits. + */ +static int nfs4_init_slot_table(struct nfs4_channel *channel) +{ + struct nfs4_slot_table *tbl = &channel->slot_table; + int i, max_slots = channel->chan_attrs.max_reqs; + struct nfs4_slot *slot; + unsigned long *used; + int ret = -ENOMEM; + + dprintk("--> %s: max_reqs=%u\n", __func__, + channel->chan_attrs.max_reqs); + slot = kzalloc(max_slots * sizeof(struct nfs4_slot), GFP_ATOMIC); + if (!slot) + goto out; + for (i = 0; i < max_slots; ++i) + slot[i].seq_nr = 1; + + if (max_slots <= BITS_PER_LONG) + used = &tbl->_used_slots; /* use word in tbl */ + else { + /* allocate enough unsigned longs for max_slots bits */ + used = kzalloc(sizeof(unsigned long) * + DIV_ROUND_UP(max_slots, BITS_PER_LONG), + GFP_ATOMIC); + if (!used) + goto out_free; + } + ret = 0; + + spin_lock(&tbl->slot_tbl_lock); + if (tbl->slots != NULL) { + spin_unlock(&tbl->slot_tbl_lock); + dprintk("%s: slot table already initialized. tbl=%p slots=%p\n", + __func__, tbl, tbl->slots); + WARN_ON(1); + goto out_free; + } + tbl->max_slots = max_slots; + tbl->slots = slot; + tbl->used_slots = used; + tbl->lowest_free_slotid = 0; /* first slot is free */ + tbl->highest_used_slotid = -1; /* no slot is currently used */ + spin_unlock(&tbl->slot_tbl_lock); + dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, + tbl, tbl->slots, tbl->max_slots); +out: + dprintk("<-- %s: return %d\n", __func__, ret); + return ret; +out_free: + kfree(slot); + if (used != &tbl->_used_slots) + kfree(used); + goto out; +} + +/* Destroy the slot table */ +static void nfs4_destroy_slot_table(struct nfs4_channel *channel) +{ + if (channel->slot_table.slots == NULL) + return; + kfree(channel->slot_table.slots); + channel->slot_table.slots = NULL; + /* Was the "used" bitmap dynamically allocated? */ + if (channel->slot_table.used_slots != &channel->slot_table._used_slots) + kfree(channel->slot_table.used_slots); + + return; +} + +static int nfs4_init_channel(struct nfs4_channel *channel) +{ + struct nfs4_slot_table *tbl; + + tbl = &channel->slot_table; + + spin_lock_init(&tbl->slot_tbl_lock); + rpc_init_wait_queue(&tbl->slot_tbl_waitq, "Slot table"); + + return 0; +} + struct nfs4_session *nfs4_alloc_session(void) { struct nfs4_session *session; @@ -3693,6 +3779,7 @@ struct nfs4_session *nfs4_alloc_session(void) atomic_set(&session->ref_count, 1); + nfs4_init_channel(&session->fore_channel); return session; } @@ -3706,6 +3793,7 @@ void nfs4_put_session(struct nfs4_session **session) { dprintk("--> nfs4_put_session()\n"); if (atomic_dec_and_test(&((*session)->ref_count))) { + nfs4_destroy_slot_table(&((*session)->fore_channel)); nfs4_free_session(*session); *session = NULL; } diff --git a/include/linux/nfs4_session.h b/include/linux/nfs4_session.h index 36c0f94..d534269 100644 --- a/include/linux/nfs4_session.h +++ b/include/linux/nfs4_session.h @@ -17,9 +17,26 @@ struct nfs4_channel_attrs { u32 rdma_attrs; }; +struct nfs4_slot { + u32 seq_nr; +}; + +struct nfs4_slot_table { + struct nfs4_slot *slots; /* seqid per slot */ + unsigned long *used_slots; /* used/unused bitmap */ + unsigned long _used_slots; /* used when max_slots fits */ + spinlock_t slot_tbl_lock; + struct rpc_wait_queue slot_tbl_waitq; /* allocators may wait here */ + int max_slots; /* # slots in table */ + int lowest_free_slotid; /* lower bound hint */ + int highest_used_slotid; /* sent to server on each SEQ. + * op for dynamic resizing */ +}; + struct nfs4_channel { struct nfs4_channel_attrs chan_attrs; struct rpc_clnt *rpc_client; + struct nfs4_slot_table slot_table; }; /* -- 1.6.0.2 -- 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