18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * A hash table (hashtab) maintains associations between 48c2ecf20Sopenharmony_ci * key values and datum values. The type of the key values 58c2ecf20Sopenharmony_ci * and the type of the datum values is arbitrary. The 68c2ecf20Sopenharmony_ci * functions for hash computation and key comparison are 78c2ecf20Sopenharmony_ci * provided by the creator of the table. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Author : Stephen Smalley, <sds@tycho.nsa.gov> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#ifndef _SS_HASHTAB_H_ 128c2ecf20Sopenharmony_ci#define _SS_HASHTAB_H_ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/types.h> 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/sched.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define HASHTAB_MAX_NODES U32_MAX 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct hashtab_key_params { 218c2ecf20Sopenharmony_ci u32 (*hash)(const void *key); /* hash function */ 228c2ecf20Sopenharmony_ci int (*cmp)(const void *key1, const void *key2); 238c2ecf20Sopenharmony_ci /* key comparison function */ 248c2ecf20Sopenharmony_ci}; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct hashtab_node { 278c2ecf20Sopenharmony_ci void *key; 288c2ecf20Sopenharmony_ci void *datum; 298c2ecf20Sopenharmony_ci struct hashtab_node *next; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct hashtab { 338c2ecf20Sopenharmony_ci struct hashtab_node **htable; /* hash table */ 348c2ecf20Sopenharmony_ci u32 size; /* number of slots in hash table */ 358c2ecf20Sopenharmony_ci u32 nel; /* number of elements in hash table */ 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct hashtab_info { 398c2ecf20Sopenharmony_ci u32 slots_used; 408c2ecf20Sopenharmony_ci u32 max_chain_len; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* 448c2ecf20Sopenharmony_ci * Initializes a new hash table with the specified characteristics. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * Returns -ENOMEM if insufficient space is available or 0 otherwise. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ciint hashtab_init(struct hashtab *h, u32 nel_hint); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciint __hashtab_insert(struct hashtab *h, struct hashtab_node **dst, 518c2ecf20Sopenharmony_ci void *key, void *datum); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * Inserts the specified (key, datum) pair into the specified hash table. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * Returns -ENOMEM on memory allocation error, 578c2ecf20Sopenharmony_ci * -EEXIST if there is already an entry with the same key, 588c2ecf20Sopenharmony_ci * -EINVAL for general errors or 598c2ecf20Sopenharmony_ci 0 otherwise. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_cistatic inline int hashtab_insert(struct hashtab *h, void *key, void *datum, 628c2ecf20Sopenharmony_ci struct hashtab_key_params key_params) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci u32 hvalue; 658c2ecf20Sopenharmony_ci struct hashtab_node *prev, *cur; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci cond_resched(); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (!h->size || h->nel == HASHTAB_MAX_NODES) 708c2ecf20Sopenharmony_ci return -EINVAL; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci hvalue = key_params.hash(key) & (h->size - 1); 738c2ecf20Sopenharmony_ci prev = NULL; 748c2ecf20Sopenharmony_ci cur = h->htable[hvalue]; 758c2ecf20Sopenharmony_ci while (cur) { 768c2ecf20Sopenharmony_ci int cmp = key_params.cmp(key, cur->key); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (cmp == 0) 798c2ecf20Sopenharmony_ci return -EEXIST; 808c2ecf20Sopenharmony_ci if (cmp < 0) 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci prev = cur; 838c2ecf20Sopenharmony_ci cur = cur->next; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return __hashtab_insert(h, prev ? &prev->next : &h->htable[hvalue], 878c2ecf20Sopenharmony_ci key, datum); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* 918c2ecf20Sopenharmony_ci * Searches for the entry with the specified key in the hash table. 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * Returns NULL if no entry has the specified key or 948c2ecf20Sopenharmony_ci * the datum of the entry otherwise. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_cistatic inline void *hashtab_search(struct hashtab *h, const void *key, 978c2ecf20Sopenharmony_ci struct hashtab_key_params key_params) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci u32 hvalue; 1008c2ecf20Sopenharmony_ci struct hashtab_node *cur; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (!h->size) 1038c2ecf20Sopenharmony_ci return NULL; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci hvalue = key_params.hash(key) & (h->size - 1); 1068c2ecf20Sopenharmony_ci cur = h->htable[hvalue]; 1078c2ecf20Sopenharmony_ci while (cur) { 1088c2ecf20Sopenharmony_ci int cmp = key_params.cmp(key, cur->key); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (cmp == 0) 1118c2ecf20Sopenharmony_ci return cur->datum; 1128c2ecf20Sopenharmony_ci if (cmp < 0) 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci cur = cur->next; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci return NULL; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * Destroys the specified hash table. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_civoid hashtab_destroy(struct hashtab *h); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* 1258c2ecf20Sopenharmony_ci * Applies the specified apply function to (key,datum,args) 1268c2ecf20Sopenharmony_ci * for each entry in the specified hash table. 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * The order in which the function is applied to the entries 1298c2ecf20Sopenharmony_ci * is dependent upon the internal structure of the hash table. 1308c2ecf20Sopenharmony_ci * 1318c2ecf20Sopenharmony_ci * If apply returns a non-zero status, then hashtab_map will cease 1328c2ecf20Sopenharmony_ci * iterating through the hash table and will propagate the error 1338c2ecf20Sopenharmony_ci * return to its caller. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ciint hashtab_map(struct hashtab *h, 1368c2ecf20Sopenharmony_ci int (*apply)(void *k, void *d, void *args), 1378c2ecf20Sopenharmony_ci void *args); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ciint hashtab_duplicate(struct hashtab *new, struct hashtab *orig, 1408c2ecf20Sopenharmony_ci int (*copy)(struct hashtab_node *new, 1418c2ecf20Sopenharmony_ci struct hashtab_node *orig, void *args), 1428c2ecf20Sopenharmony_ci int (*destroy)(void *k, void *d, void *args), 1438c2ecf20Sopenharmony_ci void *args); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/* Fill info with some hash table statistics */ 1468c2ecf20Sopenharmony_civoid hashtab_stat(struct hashtab *h, struct hashtab_info *info); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#endif /* _SS_HASHTAB_H */ 149