#include <linux/mm.h>
#include <asm/pgtable.h>
-/**
- * struct tbl - hash table
- * @n_buckets: number of buckets (a power of 2 between %TBL_L1_SIZE and
- * %TBL_MAX_BUCKETS)
- * @buckets: pointer to @n_buckets/%TBL_L1_SIZE pointers to %TBL_L1_SIZE pointers
- * to buckets
- * @rcu: RCU callback structure
- * @obj_destructor: Called on each element when the table is destroyed.
- *
- * The @buckets array is logically an array of pointers to buckets. It is
- * broken into two levels to avoid the need to kmalloc() any object larger than
- * a single page or to use vmalloc(). @buckets is always nonnull, as is each
- * @buckets[i], but each @buckets[i][j] is nonnull only if the specified hash
- * bucket is nonempty (for 0 <= i < @n_buckets/%TBL_L1_SIZE, 0 <= j <
- * %TBL_L1_SIZE).
- */
-struct tbl {
- struct rcu_head rcu;
- unsigned int n_buckets;
- struct tbl_bucket ***buckets;
- unsigned int count;
- void (*obj_destructor)(struct tbl_node *);
-};
-
/**
* struct tbl_bucket - single bucket within a hash table
* @rcu: RCU callback structure
for (i = 0; i < n_buckets >> TBL_L1_BITS; i++) {
l1[i] = (struct tbl_bucket **)get_zeroed_page(GFP_KERNEL);
if (!l1[i]) {
- free_buckets(l1, i << TBL_L1_BITS, 0);
+ free_buckets(l1, i << TBL_L1_BITS, NULL);
return NULL;
}
}
call_rcu(&table->rcu, destroy_table_rcu);
}
-static struct tbl_bucket **find_bucket(struct tbl *table, u32 hash)
+static struct tbl_bucket __rcu **find_bucket(struct tbl *table, u32 hash)
{
unsigned int l1 = (hash & (table->n_buckets - 1)) >> TBL_L1_SHIFT;
unsigned int l2 = hash & ((1 << TBL_L2_BITS) - 1);
int i;
for (i = 0; i < bucket->n_objs; i++) {
- struct tbl_node *obj = rcu_dereference(bucket->objs[i]);
+ struct tbl_node *obj = bucket->objs[i];
if (obj->hash == hash && likely(cmp(obj, target)))
return i;
}
struct tbl_node *tbl_lookup(struct tbl *table, void *target, u32 hash,
int (*cmp)(const struct tbl_node *, void *))
{
- struct tbl_bucket **bucketp = find_bucket(table, hash);
+ struct tbl_bucket __rcu **bucketp = find_bucket(table, hash);
struct tbl_bucket *bucket = rcu_dereference(*bucketp);
int index;
{
unsigned int i, j, k;
for (i = 0; i < table->n_buckets >> TBL_L1_BITS; i++) {
- struct tbl_bucket **l2 = table->buckets[i];
+ struct tbl_bucket __rcu **l2 = table->buckets[i];
for (j = 0; j < TBL_L1_SIZE; j++) {
struct tbl_bucket *bucket = rcu_dereference(l2[j]);
if (!bucket)
*/
int tbl_insert(struct tbl *table, struct tbl_node *target, u32 hash)
{
- struct tbl_bucket **oldp = find_bucket(table, hash);
- struct tbl_bucket *old = *rcu_dereference(oldp);
+ struct tbl_bucket __rcu **oldp = find_bucket(table, hash);
+ struct tbl_bucket *old = rcu_dereference(*oldp);
unsigned int n = old ? old->n_objs : 0;
struct tbl_bucket *new = bucket_alloc(n + 1);
*/
int tbl_remove(struct tbl *table, struct tbl_node *target)
{
- struct tbl_bucket **oldp = find_bucket(table, target->hash);
- struct tbl_bucket *old = *rcu_dereference(oldp);
+ struct tbl_bucket __rcu **oldp = find_bucket(table, target->hash);
+ struct tbl_bucket *old = rcu_dereference(*oldp);
unsigned int n = old->n_objs;
struct tbl_bucket *new;