- * remove own list functionality from hash
- * use hlist_head, hlist_node in hash
* Request a new review
* Process the comments from the review
* Move into mainline proper
hash->elements = 0;
for (i = 0 ; i < hash->size; i++)
- hash->table[i] = NULL;
+ INIT_HLIST_HEAD(&hash->table[i]);
}
/* free only the hashtable and the hash itself. */
void *hash_remove_bucket(struct hashtable_t *hash, struct hash_it_t *hash_it_t)
{
void *data_save;
+ struct element_t *bucket;
- data_save = hash_it_t->bucket->data;
+ bucket = hlist_entry(hash_it_t->walk, struct element_t, hlist);
+ data_save = bucket->data;
- if (hash_it_t->prev_bucket != NULL)
- hash_it_t->prev_bucket->next = hash_it_t->bucket->next;
- else if (hash_it_t->first_bucket != NULL)
- (*hash_it_t->first_bucket) = hash_it_t->bucket->next;
-
- kfree(hash_it_t->bucket);
+ hlist_del(hash_it_t->walk);
+ kfree(bucket);
hash->elements--;
return data_save;
#ifndef _NET_BATMAN_ADV_HASH_H_
#define _NET_BATMAN_ADV_HASH_H_
+#include <linux/list.h>
+
#define HASHIT(name) struct hash_it_t name = { \
- .index = -1, .bucket = NULL, \
- .prev_bucket = NULL, \
- .first_bucket = NULL }
+ .index = 0, .walk = NULL, \
+ .safe = NULL}
/* callback to a compare function. should
* compare 2 element datas for their keys,
struct element_t {
void *data; /* pointer to the data */
- struct element_t *next; /* overflow bucket pointer */
+ struct hlist_node hlist; /* bucket list pointer */
};
struct hash_it_t {
- int index;
- struct element_t *bucket;
- struct element_t *prev_bucket;
- struct element_t **first_bucket;
+ size_t index;
+ struct hlist_node *walk;
+ struct hlist_node *safe;
};
struct hashtable_t {
- struct element_t **table; /* the hashtable itself, with the buckets */
+ struct hlist_head *table; /* the hashtable itself, with the buckets */
int elements; /* number of elements registered */
int size; /* size of hashtable */
};
static inline void hash_delete(struct hashtable_t *hash,
hashdata_free_cb free_cb, void *arg)
{
- struct element_t *bucket, *last_bucket;
+ struct hlist_head *head;
+ struct hlist_node *walk, *safe;
+ struct element_t *bucket;
int i;
for (i = 0; i < hash->size; i++) {
- bucket = hash->table[i];
+ head = &hash->table[i];
- while (bucket != NULL) {
+ hlist_for_each_safe(walk, safe, head) {
+ bucket = hlist_entry(walk, struct element_t, hlist);
if (free_cb != NULL)
free_cb(bucket->data, arg);
- last_bucket = bucket;
- bucket = bucket->next;
- kfree(last_bucket);
+ hlist_del(walk);
+ kfree(bucket);
}
}
hashdata_choose_cb choose, void *data)
{
int index;
- struct element_t *bucket, *prev_bucket = NULL;
+ struct hlist_head *head;
+ struct hlist_node *walk, *safe;
+ struct element_t *bucket;
if (!hash)
return -1;
index = choose(data, hash->size);
- bucket = hash->table[index];
+ head = &hash->table[index];
- while (bucket != NULL) {
+ hlist_for_each_safe(walk, safe, head) {
+ bucket = hlist_entry(walk, struct element_t, hlist);
if (compare(bucket->data, data))
return -1;
-
- prev_bucket = bucket;
- bucket = bucket->next;
}
- /* found the tail of the list, add new element */
+ /* no duplicate found in list, add new element */
bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC);
if (bucket == NULL)
return -1;
bucket->data = data;
- bucket->next = NULL;
-
- /* and link it */
- if (prev_bucket == NULL)
- hash->table[index] = bucket;
- else
- prev_bucket->next = bucket;
+ hlist_add_head(&bucket->hlist, head);
hash->elements++;
return 0;
hashdata_choose_cb choose, void *data)
{
struct hash_it_t hash_it_t;
+ struct element_t *bucket;
+ struct hlist_head *head;
hash_it_t.index = choose(data, hash->size);
- hash_it_t.bucket = hash->table[hash_it_t.index];
- hash_it_t.prev_bucket = NULL;
-
- while (hash_it_t.bucket != NULL) {
- if (compare(hash_it_t.bucket->data, data)) {
- hash_it_t.first_bucket =
- (hash_it_t.bucket ==
- hash->table[hash_it_t.index] ?
- &hash->table[hash_it_t.index] : NULL);
- return hash_remove_bucket(hash, &hash_it_t);
- }
+ head = &hash->table[hash_it_t.index];
- hash_it_t.prev_bucket = hash_it_t.bucket;
- hash_it_t.bucket = hash_it_t.bucket->next;
+ hlist_for_each(hash_it_t.walk, head) {
+ bucket = hlist_entry(hash_it_t.walk, struct element_t, hlist);
+ if (compare(bucket->data, data))
+ return hash_remove_bucket(hash, &hash_it_t);
}
return NULL;
hashdata_choose_cb choose, void *keydata)
{
int index;
+ struct hlist_head *head;
+ struct hlist_node *walk;
struct element_t *bucket;
if (!hash)
return NULL;
index = choose(keydata , hash->size);
- bucket = hash->table[index];
+ head = &hash->table[index];
- while (bucket != NULL) {
+ hlist_for_each(walk, head) {
+ bucket = hlist_entry(walk, struct element_t, hlist);
if (compare(bucket->data, keydata))
return bucket->data;
-
- bucket = bucket->next;
}
return NULL;
/* resize the hash, returns the pointer to the new hash or NULL on
* error. removes the old hash on success */
static inline struct hashtable_t *hash_resize(struct hashtable_t *hash,
- hashdata_compare_cb compare,
hashdata_choose_cb choose,
int size)
{
struct hashtable_t *new_hash;
+ struct hlist_head *head, *new_head;
+ struct hlist_node *walk, *safe;
struct element_t *bucket;
- int i;
+ int i, new_index;
/* initialize a new hash with the new size */
new_hash = hash_new(size);
/* copy the elements */
for (i = 0; i < hash->size; i++) {
- bucket = hash->table[i];
+ head = &hash->table[i];
+
+ hlist_for_each_safe(walk, safe, head) {
+ bucket = hlist_entry(walk, struct element_t, hlist);
- while (bucket != NULL) {
- hash_add(new_hash, compare, choose, bucket->data);
- bucket = bucket->next;
+ new_index = choose(bucket->data, size);
+ new_head = &new_hash->table[new_index];
+
+ hlist_del(walk);
+ hlist_add_head(walk, new_head);
}
}
- /* remove hash and eventual overflow buckets but not the content
- * itself. */
- hash_delete(hash, NULL, NULL);
+ hash_destroy(hash);
return new_hash;
}
if (!iter)
return NULL;
- /* sanity checks first (if our bucket got deleted in the last
- * iteration): */
- if (iter->bucket != NULL) {
- if (iter->first_bucket != NULL) {
- /* we're on the first element and it got removed after
- * the last iteration. */
- if ((*iter->first_bucket) != iter->bucket) {
- /* there are still other elements in the list */
- if ((*iter->first_bucket) != NULL) {
- iter->prev_bucket = NULL;
- iter->bucket = (*iter->first_bucket);
- iter->first_bucket =
- &hash->table[iter->index];
- return iter;
- } else {
- iter->bucket = NULL;
- }
- }
- } else if (iter->prev_bucket != NULL) {
- /*
- * we're not on the first element, and the bucket got
- * removed after the last iteration. the last bucket's
- * next pointer is not pointing to our actual bucket
- * anymore. select the next.
- */
- if (iter->prev_bucket->next != iter->bucket)
- iter->bucket = iter->prev_bucket;
- }
- }
+ iter->walk = iter->safe;
- /* now as we are sane, select the next one if there is some */
- if (iter->bucket != NULL) {
- if (iter->bucket->next != NULL) {
- iter->prev_bucket = iter->bucket;
- iter->bucket = iter->bucket->next;
- iter->first_bucket = NULL;
- return iter;
- }
- }
+ /* we search for the next head with list entries */
+ if (!iter->walk) {
+ while (iter->index < hash->size) {
+ if (hlist_empty(&hash->table[iter->index]))
+ iter->index++;
+ else {
+ iter->walk = hash->table[iter->index].first;
- /* if not returned yet, we've reached the last one on the index and have
- * to search forward */
- iter->index++;
- /* go through the entries of the hash table */
- while (iter->index < hash->size) {
- if ((hash->table[iter->index]) != NULL) {
- iter->prev_bucket = NULL;
- iter->bucket = hash->table[iter->index];
- iter->first_bucket = &hash->table[iter->index];
- return iter;
- } else {
- iter->index++;
+ /* search next time */
+ ++iter->index;
+ break;
+ }
}
}
- /* nothing to iterate over anymore */
- return NULL;
+ /* return iter when we found bucket otherwise null */
+ if (!iter->walk)
+ return NULL;
+
+ iter->safe = iter->walk->next;
+ return iter;
}
#endif /* _NET_BATMAN_ADV_HASH_H_ */
goto free_bcast_own_sum;
if (bat_priv->orig_hash->elements * 4 > bat_priv->orig_hash->size) {
- swaphash = hash_resize(bat_priv->orig_hash, compare_orig,
- choose_orig,
+ swaphash = hash_resize(bat_priv->orig_hash, choose_orig,
bat_priv->orig_hash->size * 2);
if (!swaphash)
static void _purge_orig(struct bat_priv *bat_priv)
{
HASHIT(hashit);
+ struct element_t *bucket;
struct orig_node *orig_node;
unsigned long flags;
/* for all origins... */
while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ orig_node = bucket->data;
if (purge_orig_node(bat_priv, orig_node)) {
hash_remove_bucket(bat_priv->orig_hash, &hashit);
int orig_seq_print_text(struct seq_file *seq, void *offset)
{
HASHIT(hashit);
+ struct element_t *bucket;
struct net_device *net_dev = (struct net_device *)seq->private;
struct bat_priv *bat_priv = netdev_priv(net_dev);
struct orig_node *orig_node;
spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
while (hash_iterate(bat_priv->orig_hash, &hashit)) {
-
- orig_node = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ orig_node = bucket->data;
if (!orig_node->router)
continue;
struct orig_node *orig_node;
unsigned long flags;
HASHIT(hashit);
+ struct element_t *bucket;
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
* if_num */
spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ orig_node = bucket->data;
if (orig_node_add_if(orig_node, max_if_num) == -1)
goto err;
struct orig_node *orig_node;
unsigned long flags;
HASHIT(hashit);
+ struct element_t *bucket;
int ret;
/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ orig_node = bucket->data;
ret = orig_node_del_if(orig_node, max_if_num,
batman_if->if_num);
{
struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
HASHIT(hashit);
+ struct element_t *bucket;
struct orig_node *orig_node;
TYPE_OF_WORD *word;
unsigned long flags;
spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ orig_node = bucket->data;
word = &(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]);
bit_get_packet(bat_priv, word, 1, 0);
if (bat_priv->hna_local_hash->elements * 4 >
bat_priv->hna_local_hash->size) {
- swaphash = hash_resize(bat_priv->hna_local_hash, compare_orig,
- choose_orig,
+ swaphash = hash_resize(bat_priv->hna_local_hash, choose_orig,
bat_priv->hna_local_hash->size * 2);
if (!swaphash)
unsigned char *buff, int buff_len)
{
struct hna_local_entry *hna_local_entry;
+ struct element_t *bucket;
HASHIT(hashit);
int i = 0;
unsigned long flags;
if (buff_len < (i + 1) * ETH_ALEN)
break;
- hna_local_entry = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ hna_local_entry = bucket->data;
memcpy(buff + (i * ETH_ALEN), hna_local_entry->addr, ETH_ALEN);
i++;
struct hna_local_entry *hna_local_entry;
HASHIT(hashit);
HASHIT(hashit_count);
+ struct element_t *bucket;
unsigned long flags;
size_t buf_size, pos;
char *buff;
pos = 0;
while (hash_iterate(bat_priv->hna_local_hash, &hashit)) {
- hna_local_entry = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ hna_local_entry = bucket->data;
pos += snprintf(buff + pos, 22, " * %pM\n",
hna_local_entry->addr);
container_of(delayed_work, struct bat_priv, hna_work);
struct hna_local_entry *hna_local_entry;
HASHIT(hashit);
+ struct element_t *bucket;
unsigned long flags;
unsigned long timeout;
spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
while (hash_iterate(bat_priv->hna_local_hash, &hashit)) {
- hna_local_entry = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ hna_local_entry = bucket->data;
timeout = hna_local_entry->last_seen + LOCAL_HNA_TIMEOUT * HZ;
if (bat_priv->hna_global_hash->elements * 4 >
bat_priv->hna_global_hash->size) {
- swaphash = hash_resize(bat_priv->hna_global_hash, compare_orig,
- choose_orig,
+ swaphash = hash_resize(bat_priv->hna_global_hash, choose_orig,
bat_priv->hna_global_hash->size * 2);
if (!swaphash)
struct hna_global_entry *hna_global_entry;
HASHIT(hashit);
HASHIT(hashit_count);
+ struct element_t *bucket;
unsigned long flags;
size_t buf_size, pos;
char *buff;
pos = 0;
while (hash_iterate(bat_priv->hna_global_hash, &hashit)) {
- hna_global_entry = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ hna_global_entry = bucket->data;
pos += snprintf(buff + pos, 44,
" * %pM via %pM\n", hna_global_entry->addr,
{
HASHIT(hashit);
HASHIT(hashit_count);
+ struct element_t *bucket;
struct vis_info *info;
struct vis_packet *packet;
struct vis_info_entry *entries;
/* Estimate length */
spin_lock_irqsave(&bat_priv->vis_hash_lock, flags);
while (hash_iterate(bat_priv->vis_hash, &hashit_count)) {
- info = hashit_count.bucket->data;
+ bucket = hlist_entry(hashit_count.walk, struct element_t,
+ hlist);
+ info = bucket->data;
packet = (struct vis_packet *)info->skb_packet->data;
entries = (struct vis_info_entry *)
((char *)packet + sizeof(struct vis_packet));
buff_pos = 0;
while (hash_iterate(bat_priv->vis_hash, &hashit)) {
- info = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ info = bucket->data;
packet = (struct vis_packet *)info->skb_packet->data;
entries = (struct vis_info_entry *)
((char *)packet + sizeof(struct vis_packet));
struct vis_info *info)
{
HASHIT(hashit);
+ struct element_t *bucket;
struct orig_node *orig_node;
struct vis_packet *packet;
int best_tq = -1;
packet = (struct vis_packet *)info->skb_packet->data;
while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ orig_node = bucket->data;
if ((orig_node) && (orig_node->router) &&
(orig_node->flags & VIS_SERVER) &&
(orig_node->router->tq_avg > best_tq)) {
{
HASHIT(hashit_local);
HASHIT(hashit_global);
+ struct element_t *bucket;
struct orig_node *orig_node;
struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info;
struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data;
}
while (hash_iterate(bat_priv->orig_hash, &hashit_global)) {
- orig_node = hashit_global.bucket->data;
+ bucket = hlist_entry(hashit_global.walk, struct element_t,
+ hlist);
+ orig_node = bucket->data;
if (!orig_node->router)
continue;
spin_lock_irqsave(&bat_priv->hna_lhash_lock, flags);
while (hash_iterate(bat_priv->hna_local_hash, &hashit_local)) {
- hna_local_entry = hashit_local.bucket->data;
+ bucket = hlist_entry(hashit_local.walk, struct element_t,
+ hlist);
+ hna_local_entry = bucket->data;
entry = (struct vis_info_entry *)skb_put(info->skb_packet,
sizeof(*entry));
memset(entry->src, 0, ETH_ALEN);
static void purge_vis_packets(struct bat_priv *bat_priv)
{
HASHIT(hashit);
+ struct element_t *bucket;
struct vis_info *info;
while (hash_iterate(bat_priv->vis_hash, &hashit)) {
- info = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ info = bucket->data;
/* never purge own data. */
if (info == bat_priv->my_vis_info)
struct vis_info *info)
{
HASHIT(hashit);
+ struct element_t *bucket;
struct orig_node *orig_node;
struct vis_packet *packet;
struct sk_buff *skb;
/* send to all routers in range. */
while (hash_iterate(bat_priv->orig_hash, &hashit)) {
- orig_node = hashit.bucket->data;
+ bucket = hlist_entry(hashit.walk, struct element_t, hlist);
+ orig_node = bucket->data;
/* if it's a vis server and reachable, send it. */
if ((!orig_node) || (!orig_node->router))