xref: /linux/net/batman-adv/hash.c (revision c36461825469a9ceee2346a2e89286c522525da7)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) B.A.T.M.A.N. contributors:
3  *
4  * Simon Wunderlich, Marek Lindner
5  */
6 
7 #include "hash.h"
8 #include "main.h"
9 
10 #include <linux/gfp.h>
11 #include <linux/lockdep.h>
12 #include <linux/slab.h>
13 
14 /**
15  * batadv_hash_init() - clear all buckets of a hashtable
16  * @hash: hashtable to clear
17  */
18 static void batadv_hash_init(struct batadv_hashtable *hash)
19 {
20 	u32 i;
21 
22 	for (i = 0; i < hash->size; i++) {
23 		INIT_HLIST_HEAD(&hash->table[i]);
24 		spin_lock_init(&hash->list_locks[i]);
25 	}
26 
27 	atomic_set(&hash->generation, 0);
28 }
29 
30 /**
31  * batadv_hash_destroy() - Free only the hashtable and the hash itself
32  * @hash: hash object to destroy
33  */
34 void batadv_hash_destroy(struct batadv_hashtable *hash)
35 {
36 	kfree(hash->list_locks);
37 	kfree(hash->table);
38 	kfree(hash);
39 }
40 
41 /**
42  * batadv_hash_new() - Allocates and clears the hashtable
43  * @size: number of hash buckets to allocate
44  *
45  * Return: newly allocated hashtable, NULL on errors
46  */
47 struct batadv_hashtable *batadv_hash_new(u32 size)
48 {
49 	struct batadv_hashtable *hash;
50 
51 	hash = kmalloc_obj(*hash, GFP_ATOMIC);
52 	if (!hash)
53 		return NULL;
54 
55 	hash->table = kmalloc_objs(*hash->table, size, GFP_ATOMIC);
56 	if (!hash->table)
57 		goto free_hash;
58 
59 	hash->list_locks = kmalloc_objs(*hash->list_locks, size, GFP_ATOMIC);
60 	if (!hash->list_locks)
61 		goto free_table;
62 
63 	hash->size = size;
64 	batadv_hash_init(hash);
65 	return hash;
66 
67 free_table:
68 	kfree(hash->table);
69 free_hash:
70 	kfree(hash);
71 	return NULL;
72 }
73 
74 /**
75  * batadv_hash_set_lock_class() - Set specific lockdep class for hash spinlocks
76  * @hash: hash object to modify
77  * @key: lockdep class key address
78  */
79 void batadv_hash_set_lock_class(struct batadv_hashtable *hash,
80 				struct lock_class_key *key)
81 {
82 	u32 i;
83 
84 	for (i = 0; i < hash->size; i++)
85 		lockdep_set_class(&hash->list_locks[i], key);
86 }
87