17db7d9f3SSven Eckelmann // SPDX-License-Identifier: GPL-2.0
2*cfa55c6dSSven Eckelmann /* Copyright (C) B.A.T.M.A.N. contributors:
3c6c8fea2SSven Eckelmann *
4c6c8fea2SSven Eckelmann * Simon Wunderlich, Marek Lindner
5c6c8fea2SSven Eckelmann */
6c6c8fea2SSven Eckelmann
7c6c8fea2SSven Eckelmann #include "hash.h"
81e2c2a4fSSven Eckelmann #include "main.h"
91e2c2a4fSSven Eckelmann
10b92b94acSSven Eckelmann #include <linux/gfp.h>
111e2c2a4fSSven Eckelmann #include <linux/lockdep.h>
121e2c2a4fSSven Eckelmann #include <linux/slab.h>
13c6c8fea2SSven Eckelmann
14c6c8fea2SSven Eckelmann /* clears the hash */
batadv_hash_init(struct batadv_hashtable * hash)155bf74e9cSSven Eckelmann static void batadv_hash_init(struct batadv_hashtable *hash)
16c6c8fea2SSven Eckelmann {
176b5e971aSSven Eckelmann u32 i;
18c6c8fea2SSven Eckelmann
19fb778ea1SMarek Lindner for (i = 0; i < hash->size; i++) {
20c6c8fea2SSven Eckelmann INIT_HLIST_HEAD(&hash->table[i]);
21fb778ea1SMarek Lindner spin_lock_init(&hash->list_locks[i]);
22fb778ea1SMarek Lindner }
2305abd7bcSSven Eckelmann
2405abd7bcSSven Eckelmann atomic_set(&hash->generation, 0);
25c6c8fea2SSven Eckelmann }
26c6c8fea2SSven Eckelmann
27ff15c27cSSven Eckelmann /**
28ff15c27cSSven Eckelmann * batadv_hash_destroy() - Free only the hashtable and the hash itself
29ff15c27cSSven Eckelmann * @hash: hash object to destroy
30ff15c27cSSven Eckelmann */
batadv_hash_destroy(struct batadv_hashtable * hash)315bf74e9cSSven Eckelmann void batadv_hash_destroy(struct batadv_hashtable *hash)
32c6c8fea2SSven Eckelmann {
33fb778ea1SMarek Lindner kfree(hash->list_locks);
34c6c8fea2SSven Eckelmann kfree(hash->table);
35c6c8fea2SSven Eckelmann kfree(hash);
36c6c8fea2SSven Eckelmann }
37c6c8fea2SSven Eckelmann
38ff15c27cSSven Eckelmann /**
39ff15c27cSSven Eckelmann * batadv_hash_new() - Allocates and clears the hashtable
40ff15c27cSSven Eckelmann * @size: number of hash buckets to allocate
41ff15c27cSSven Eckelmann *
42ff15c27cSSven Eckelmann * Return: newly allocated hashtable, NULL on errors
43ff15c27cSSven Eckelmann */
batadv_hash_new(u32 size)446b5e971aSSven Eckelmann struct batadv_hashtable *batadv_hash_new(u32 size)
45c6c8fea2SSven Eckelmann {
465bf74e9cSSven Eckelmann struct batadv_hashtable *hash;
47c6c8fea2SSven Eckelmann
48704509b8SSven Eckelmann hash = kmalloc(sizeof(*hash), GFP_ATOMIC);
49c6c8fea2SSven Eckelmann if (!hash)
50c6c8fea2SSven Eckelmann return NULL;
51c6c8fea2SSven Eckelmann
520185dda6SAntonio Quartulli hash->table = kmalloc_array(size, sizeof(*hash->table), GFP_ATOMIC);
53fb778ea1SMarek Lindner if (!hash->table)
54fb778ea1SMarek Lindner goto free_hash;
55c6c8fea2SSven Eckelmann
560185dda6SAntonio Quartulli hash->list_locks = kmalloc_array(size, sizeof(*hash->list_locks),
57704509b8SSven Eckelmann GFP_ATOMIC);
58fb778ea1SMarek Lindner if (!hash->list_locks)
59fb778ea1SMarek Lindner goto free_table;
60fb778ea1SMarek Lindner
61fb778ea1SMarek Lindner hash->size = size;
627f9f02cbSSven Eckelmann batadv_hash_init(hash);
63fb778ea1SMarek Lindner return hash;
64fb778ea1SMarek Lindner
65fb778ea1SMarek Lindner free_table:
66fb778ea1SMarek Lindner kfree(hash->table);
67fb778ea1SMarek Lindner free_hash:
68c6c8fea2SSven Eckelmann kfree(hash);
69c6c8fea2SSven Eckelmann return NULL;
70c6c8fea2SSven Eckelmann }
715d52dad2SSven Eckelmann
72ff15c27cSSven Eckelmann /**
73ff15c27cSSven Eckelmann * batadv_hash_set_lock_class() - Set specific lockdep class for hash spinlocks
74ff15c27cSSven Eckelmann * @hash: hash object to modify
75ff15c27cSSven Eckelmann * @key: lockdep class key address
76ff15c27cSSven Eckelmann */
batadv_hash_set_lock_class(struct batadv_hashtable * hash,struct lock_class_key * key)775bf74e9cSSven Eckelmann void batadv_hash_set_lock_class(struct batadv_hashtable *hash,
785d52dad2SSven Eckelmann struct lock_class_key *key)
795d52dad2SSven Eckelmann {
806b5e971aSSven Eckelmann u32 i;
815d52dad2SSven Eckelmann
825d52dad2SSven Eckelmann for (i = 0; i < hash->size; i++)
835d52dad2SSven Eckelmann lockdep_set_class(&hash->list_locks[i], key);
845d52dad2SSven Eckelmann }
85