#include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/rhashtable.h> #include <linux/sched.h>
MODULE_LICENSE("GPL");
struct kvpair { u64 key; u64 value; };
struct hash_entry { struct rhash_head node; struct kvpair kv; };
void hash_entry_free(void *ptr, void *arg) { kfree(ptr); }
u32 hashfn(const void *data, u32 len, u32 seed) { return jhash(data, len, seed); }
u32 hash_entry_hashfn(const void *data, u32 len, u32 seed) { struct hash_entry *entry = (struct hash_entry *)data; return jhash(&entry->kv.key, sizeof(entry->kv.key), seed); }
int key_entry_cmp(struct rhashtable_compare_arg *arg, const void *obj) { struct hash_entry *entry = (struct hash_entry *)obj; return *(u64 *)arg->key - entry->kv.key; }
static int __init start_init(void) { u64 i; struct hash_entry *entry; struct rhashtable_params param = { .key_len = sizeof(u64), .head_offset = offsetof(struct hash_entry, node), .hashfn = hashfn, .obj_hashfn = hash_entry_hashfn, .obj_cmpfn = key_entry_cmp, .automatic_shrinking = true, }; struct rhashtable rht; int ret = rhashtable_init(&rht, ¶m); printk("rhashtable_init returns %d\n", ret); if (ret < 0) return ret; for (i = 0; i < (1 << 20); ++i) { entry = kzalloc(sizeof(struct hash_entry), GFP_KERNEL); if (entry == NULL) { printk("kzalloc returns NULL\n"); goto err_exit; } entry->kv.key = i; entry->kv.value = i * i; while (1) { ret = rhashtable_insert_fast(&rht, &entry->node, param); if (ret != -EBUSY) break; schedule(); } if (ret < 0) { kfree(entry); printk("rhashtable_insert_fast returns %d\n", ret); goto err_exit; } ret = rhashtable_lookup_insert_key(&rht, &i, &entry->node, param); BUG_ON(ret != -EEXIST); } for (i = 0; i < (1 << 20); ++i) { entry = rhashtable_lookup_fast(&rht, &i, param); if (entry == NULL) { printk("rhashtable_lookup_fast returns NULL\n"); goto err_exit; } if (entry->kv.value != i * i) { printk("%llu %llu\n", i, entry->kv.value); goto err_exit; }
rcu_read_lock(); entry = rhashtable_lookup(&rht, &i, param); if (entry == NULL) { printk("rhashtable_lookup returns NULL\n"); goto err_exit; } if (entry->kv.value != (u64)i * i) { printk("%llu %llu\n", i, entry->kv.value); goto err_exit; } rcu_read_unlock(); } err_exit: rhashtable_free_and_destroy(&rht, hash_entry_free, NULL); return 0; }
static void __exit end_exit(void) { }
module_init(start_init) module_exit(end_exit)
|