linux/net/batman-adv/hash.h
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2006-2011 B.A.T.M.A.N. contributors:
   3 *
   4 * Simon Wunderlich, Marek Lindner
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of version 2 of the GNU General Public
   8 * License as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13 * General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  18 * 02110-1301, USA
  19 *
  20 */
  21
  22#ifndef _NET_BATMAN_ADV_HASH_H_
  23#define _NET_BATMAN_ADV_HASH_H_
  24
  25#include <linux/list.h>
  26
  27/* callback to a compare function.  should
  28 * compare 2 element datas for their keys,
  29 * return 0 if same and not 0 if not
  30 * same */
  31typedef int (*hashdata_compare_cb)(const struct hlist_node *, const void *);
  32
  33/* the hashfunction, should return an index
  34 * based on the key in the data of the first
  35 * argument and the size the second */
  36typedef uint32_t (*hashdata_choose_cb)(const void *, uint32_t);
  37typedef void (*hashdata_free_cb)(struct hlist_node *, void *);
  38
  39struct hashtable_t {
  40        struct hlist_head *table;   /* the hashtable itself with the buckets */
  41        spinlock_t *list_locks;     /* spinlock for each hash list entry */
  42        uint32_t size;              /* size of hashtable */
  43};
  44
  45/* allocates and clears the hash */
  46struct hashtable_t *hash_new(uint32_t size);
  47
  48/* free only the hashtable and the hash itself. */
  49void hash_destroy(struct hashtable_t *hash);
  50
  51/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
  52 * called to remove the elements inside of the hash.  if you don't remove the
  53 * elements, memory might be leaked. */
  54static inline void hash_delete(struct hashtable_t *hash,
  55                               hashdata_free_cb free_cb, void *arg)
  56{
  57        struct hlist_head *head;
  58        struct hlist_node *node, *node_tmp;
  59        spinlock_t *list_lock; /* spinlock to protect write access */
  60        uint32_t i;
  61
  62        for (i = 0; i < hash->size; i++) {
  63                head = &hash->table[i];
  64                list_lock = &hash->list_locks[i];
  65
  66                spin_lock_bh(list_lock);
  67                hlist_for_each_safe(node, node_tmp, head) {
  68                        hlist_del_rcu(node);
  69
  70                        if (free_cb)
  71                                free_cb(node, arg);
  72                }
  73                spin_unlock_bh(list_lock);
  74        }
  75
  76        hash_destroy(hash);
  77}
  78
  79/**
  80 *      hash_add - adds data to the hashtable
  81 *      @hash: storage hash table
  82 *      @compare: callback to determine if 2 hash elements are identical
  83 *      @choose: callback calculating the hash index
  84 *      @data: data passed to the aforementioned callbacks as argument
  85 *      @data_node: to be added element
  86 *
  87 *      Returns 0 on success, 1 if the element already is in the hash
  88 *      and -1 on error.
  89 */
  90
  91static inline int hash_add(struct hashtable_t *hash,
  92                           hashdata_compare_cb compare,
  93                           hashdata_choose_cb choose,
  94                           const void *data, struct hlist_node *data_node)
  95{
  96        uint32_t index;
  97        int ret = -1;
  98        struct hlist_head *head;
  99        struct hlist_node *node;
 100        spinlock_t *list_lock; /* spinlock to protect write access */
 101
 102        if (!hash)
 103                goto out;
 104
 105        index = choose(data, hash->size);
 106        head = &hash->table[index];
 107        list_lock = &hash->list_locks[index];
 108
 109        rcu_read_lock();
 110        __hlist_for_each_rcu(node, head) {
 111                if (!compare(node, data))
 112                        continue;
 113
 114                ret = 1;
 115                goto err_unlock;
 116        }
 117        rcu_read_unlock();
 118
 119        /* no duplicate found in list, add new element */
 120        spin_lock_bh(list_lock);
 121        hlist_add_head_rcu(data_node, head);
 122        spin_unlock_bh(list_lock);
 123
 124        ret = 0;
 125        goto out;
 126
 127err_unlock:
 128        rcu_read_unlock();
 129out:
 130        return ret;
 131}
 132
 133/* removes data from hash, if found. returns pointer do data on success, so you
 134 * can remove the used structure yourself, or NULL on error .  data could be the
 135 * structure you use with just the key filled, we just need the key for
 136 * comparing. */
 137static inline void *hash_remove(struct hashtable_t *hash,
 138                                hashdata_compare_cb compare,
 139                                hashdata_choose_cb choose, void *data)
 140{
 141        uint32_t index;
 142        struct hlist_node *node;
 143        struct hlist_head *head;
 144        void *data_save = NULL;
 145
 146        index = choose(data, hash->size);
 147        head = &hash->table[index];
 148
 149        spin_lock_bh(&hash->list_locks[index]);
 150        hlist_for_each(node, head) {
 151                if (!compare(node, data))
 152                        continue;
 153
 154                data_save = node;
 155                hlist_del_rcu(node);
 156                break;
 157        }
 158        spin_unlock_bh(&hash->list_locks[index]);
 159
 160        return data_save;
 161}
 162
 163#endif /* _NET_BATMAN_ADV_HASH_H_ */
 164
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.