162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (C) B.A.T.M.A.N. contributors:
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Simon Wunderlich, Marek Lindner
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "hash.h"
862306a36Sopenharmony_ci#include "main.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/gfp.h>
1162306a36Sopenharmony_ci#include <linux/lockdep.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/* clears the hash */
1562306a36Sopenharmony_cistatic void batadv_hash_init(struct batadv_hashtable *hash)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	u32 i;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	for (i = 0; i < hash->size; i++) {
2062306a36Sopenharmony_ci		INIT_HLIST_HEAD(&hash->table[i]);
2162306a36Sopenharmony_ci		spin_lock_init(&hash->list_locks[i]);
2262306a36Sopenharmony_ci	}
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	atomic_set(&hash->generation, 0);
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/**
2862306a36Sopenharmony_ci * batadv_hash_destroy() - Free only the hashtable and the hash itself
2962306a36Sopenharmony_ci * @hash: hash object to destroy
3062306a36Sopenharmony_ci */
3162306a36Sopenharmony_civoid batadv_hash_destroy(struct batadv_hashtable *hash)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	kfree(hash->list_locks);
3462306a36Sopenharmony_ci	kfree(hash->table);
3562306a36Sopenharmony_ci	kfree(hash);
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/**
3962306a36Sopenharmony_ci * batadv_hash_new() - Allocates and clears the hashtable
4062306a36Sopenharmony_ci * @size: number of hash buckets to allocate
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci * Return: newly allocated hashtable, NULL on errors
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_cistruct batadv_hashtable *batadv_hash_new(u32 size)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct batadv_hashtable *hash;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	hash = kmalloc(sizeof(*hash), GFP_ATOMIC);
4962306a36Sopenharmony_ci	if (!hash)
5062306a36Sopenharmony_ci		return NULL;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	hash->table = kmalloc_array(size, sizeof(*hash->table), GFP_ATOMIC);
5362306a36Sopenharmony_ci	if (!hash->table)
5462306a36Sopenharmony_ci		goto free_hash;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	hash->list_locks = kmalloc_array(size, sizeof(*hash->list_locks),
5762306a36Sopenharmony_ci					 GFP_ATOMIC);
5862306a36Sopenharmony_ci	if (!hash->list_locks)
5962306a36Sopenharmony_ci		goto free_table;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	hash->size = size;
6262306a36Sopenharmony_ci	batadv_hash_init(hash);
6362306a36Sopenharmony_ci	return hash;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cifree_table:
6662306a36Sopenharmony_ci	kfree(hash->table);
6762306a36Sopenharmony_cifree_hash:
6862306a36Sopenharmony_ci	kfree(hash);
6962306a36Sopenharmony_ci	return NULL;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/**
7362306a36Sopenharmony_ci * batadv_hash_set_lock_class() - Set specific lockdep class for hash spinlocks
7462306a36Sopenharmony_ci * @hash: hash object to modify
7562306a36Sopenharmony_ci * @key: lockdep class key address
7662306a36Sopenharmony_ci */
7762306a36Sopenharmony_civoid batadv_hash_set_lock_class(struct batadv_hashtable *hash,
7862306a36Sopenharmony_ci				struct lock_class_key *key)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	u32 i;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	for (i = 0; i < hash->size; i++)
8362306a36Sopenharmony_ci		lockdep_set_class(&hash->list_locks[i], key);
8462306a36Sopenharmony_ci}
85