From: Benny Halevy <bhalevy@xxxxxxxxxxx> Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx> [pnfsd: alloc_sid should kmalloc a object not a pointer] Signed-off-by: Bian Naimeng <biannm@xxxxxxxxxxxxxx> Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxx> Signed-off-by: Benny Halevy <bhalevy@xxxxxxxxxxxxxxx> --- fs/nfsd/nfs4pnfsd.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/nfsd/pnfsd.h | 2 + 2 files changed, 122 insertions(+) diff --git a/fs/nfsd/nfs4pnfsd.c b/fs/nfsd/nfs4pnfsd.c index cb28207..9a7cbc9 100644 --- a/fs/nfsd/nfs4pnfsd.c +++ b/fs/nfsd/nfs4pnfsd.c @@ -25,3 +25,123 @@ #define NFSDDBG_FACILITY NFSDDBG_PNFS +static DEFINE_SPINLOCK(layout_lock); + +/* hash table for nfsd4_pnfs_deviceid.sbid */ +#define SBID_HASH_BITS 8 +#define SBID_HASH_SIZE (1 << SBID_HASH_BITS) +#define SBID_HASH_MASK (SBID_HASH_SIZE - 1) + +struct sbid_tracker { + u64 id; + struct super_block *sb; + struct list_head hash; +}; + +static u64 current_sbid; +static struct list_head sbid_hashtbl[SBID_HASH_SIZE]; + +static unsigned long +sbid_hashval(struct super_block *sb) +{ + return hash_ptr(sb, SBID_HASH_BITS); +} + +static struct sbid_tracker * +alloc_sbid(void) +{ + return kmalloc(sizeof(struct sbid_tracker), GFP_KERNEL); +} + +static void +destroy_sbid(struct sbid_tracker *sbid) +{ + spin_lock(&layout_lock); + list_del(&sbid->hash); + spin_unlock(&layout_lock); + kfree(sbid); +} + +void +nfsd4_free_pnfs_slabs(void) +{ + int i; + struct sbid_tracker *sbid; + + for (i = 0; i < SBID_HASH_SIZE; i++) { + while (!list_empty(&sbid_hashtbl[i])) { + sbid = list_first_entry(&sbid_hashtbl[i], + struct sbid_tracker, + hash); + destroy_sbid(sbid); + } + } +} + +int +nfsd4_init_pnfs_slabs(void) +{ + int i; + + for (i = 0; i < SBID_HASH_SIZE; i++) + INIT_LIST_HEAD(&sbid_hashtbl[i]); + + return 0; +} + +static u64 +alloc_init_sbid(struct super_block *sb) +{ + struct sbid_tracker *sbid; + struct sbid_tracker *new = alloc_sbid(); + unsigned long hash_idx = sbid_hashval(sb); + u64 id = 0; + + if (likely(new)) { + spin_lock(&layout_lock); + id = ++current_sbid; + new->id = (id << SBID_HASH_BITS) | (hash_idx & SBID_HASH_MASK); + id = new->id; + BUG_ON(id == 0); + new->sb = sb; + + list_for_each_entry (sbid, &sbid_hashtbl[hash_idx], hash) + if (sbid->sb == sb) { + kfree(new); + id = sbid->id; + spin_unlock(&layout_lock); + return id; + } + list_add(&new->hash, &sbid_hashtbl[hash_idx]); + spin_unlock(&layout_lock); + } + return id; +} + +static u64 +find_create_sbid(struct super_block *sb) +{ + struct sbid_tracker *sbid; + unsigned long hash_idx = sbid_hashval(sb); + int pos = 0; + u64 id = 0; + + spin_lock(&layout_lock); + list_for_each_entry (sbid, &sbid_hashtbl[hash_idx], hash) { + pos++; + if (sbid->sb != sb) + continue; + if (pos > 1) { + list_del(&sbid->hash); + list_add(&sbid->hash, &sbid_hashtbl[hash_idx]); + } + id = sbid->id; + break; + } + spin_unlock(&layout_lock); + + if (!id) + id = alloc_init_sbid(sb); + + return id; +} diff --git a/fs/nfsd/pnfsd.h b/fs/nfsd/pnfsd.h index 7c46791..29ea2e7 100644 --- a/fs/nfsd/pnfsd.h +++ b/fs/nfsd/pnfsd.h @@ -36,4 +36,6 @@ #include <linux/nfsd/nfsd4_pnfs.h> +#include "xdr4.h" + #endif /* LINUX_NFSD_PNFSD_H */ -- 1.8.3.1 -- 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