2017-11-19 17:05:11 +03:00
/* SPDX-License-Identifier: GPL-2.0 */
2020-01-01 02:00:01 +03:00
/* Copyright (C) 2006-2020 B.A.T.M.A.N. contributors:
2010-12-13 14:19:28 +03:00
*
* Simon Wunderlich , Marek Lindner
*/
# ifndef _NET_BATMAN_ADV_HASH_H_
# define _NET_BATMAN_ADV_HASH_H_
2015-04-17 20:40:28 +03:00
# include "main.h"
2018-10-31 00:01:25 +03:00
# include <linux/atomic.h>
2015-04-17 20:40:28 +03:00
# include <linux/compiler.h>
2010-12-13 14:19:28 +03:00
# include <linux/list.h>
2019-05-24 21:11:17 +03:00
# include <linux/lockdep.h>
2015-04-17 20:40:28 +03:00
# include <linux/rculist.h>
# include <linux/spinlock.h>
# include <linux/stddef.h>
# include <linux/types.h>
2012-05-12 04:09:43 +04:00
/* callback to a compare function. should compare 2 element datas for their
2015-09-15 20:00:48 +03:00
* keys
*
2016-02-22 23:02:39 +03:00
* Return : true if same and false if not same
2012-05-12 04:09:43 +04:00
*/
2016-02-22 23:02:39 +03:00
typedef bool ( * batadv_hashdata_compare_cb ) ( const struct hlist_node * ,
const void * ) ;
2010-12-13 14:19:28 +03:00
2015-09-15 20:00:48 +03:00
/* the hashfunction
*
* Return : an index based on the key in the data of the first argument and the
* size the second
2012-05-12 04:09:43 +04:00
*/
2015-05-26 19:34:26 +03:00
typedef u32 ( * batadv_hashdata_choose_cb ) ( const void * , u32 ) ;
2012-06-06 00:31:28 +04:00
typedef void ( * batadv_hashdata_free_cb ) ( struct hlist_node * , void * ) ;
2010-12-13 14:19:28 +03:00
2017-12-02 21:51:50 +03:00
/**
* struct batadv_hashtable - Wrapper of simple hlist based hashtable
*/
2012-06-06 00:31:28 +04:00
struct batadv_hashtable {
2017-12-02 21:51:50 +03:00
/** @table: the hashtable itself with the buckets */
struct hlist_head * table ;
/** @list_locks: spinlock for each hash list entry */
spinlock_t * list_locks ;
/** @size: size of hashtable */
u32 size ;
2018-10-31 00:01:25 +03:00
/** @generation: current (generation) sequence number */
atomic_t generation ;
2010-12-13 14:19:28 +03:00
} ;
/* allocates and clears the hash */
2015-05-26 19:34:26 +03:00
struct batadv_hashtable * batadv_hash_new ( u32 size ) ;
2010-12-13 14:19:28 +03:00
2012-03-29 14:38:20 +04:00
/* set class key for all locks */
2012-06-06 00:31:28 +04:00
void batadv_hash_set_lock_class ( struct batadv_hashtable * hash ,
2012-03-29 14:38:20 +04:00
struct lock_class_key * key ) ;
2010-12-13 14:19:28 +03:00
/* free only the hashtable and the hash itself. */
2012-06-06 00:31:28 +04:00
void batadv_hash_destroy ( struct batadv_hashtable * hash ) ;
2010-12-13 14:19:28 +03:00
2012-07-10 14:55:09 +04:00
/**
2017-12-02 21:51:47 +03:00
* batadv_hash_add ( ) - adds data to the hashtable
2011-07-10 02:36:36 +04:00
* @ hash : storage hash table
* @ compare : callback to determine if 2 hash elements are identical
* @ choose : callback calculating the hash index
* @ data : data passed to the aforementioned callbacks as argument
* @ data_node : to be added element
*
2015-09-15 20:00:48 +03:00
* Return : 0 on success , 1 if the element already is in the hash
2011-07-10 02:36:36 +04:00
* and - 1 on error .
*/
2012-06-06 00:31:28 +04:00
static inline int batadv_hash_add ( struct batadv_hashtable * hash ,
batadv_hashdata_compare_cb compare ,
batadv_hashdata_choose_cb choose ,
2012-05-12 15:48:55 +04:00
const void * data ,
struct hlist_node * data_node )
2010-12-13 14:19:28 +03:00
{
2015-05-26 19:34:26 +03:00
u32 index ;
2011-10-05 19:05:25 +04:00
int ret = - 1 ;
2010-12-13 14:19:28 +03:00
struct hlist_head * head ;
2011-02-18 15:28:09 +03:00
struct hlist_node * node ;
2011-01-19 23:01:40 +03:00
spinlock_t * list_lock ; /* spinlock to protect write access */
2010-12-13 14:19:28 +03:00
if ( ! hash )
2011-07-10 02:36:36 +04:00
goto out ;
2010-12-13 14:19:28 +03:00
index = choose ( data , hash - > size ) ;
head = & hash - > table [ index ] ;
2011-01-19 23:01:40 +03:00
list_lock = & hash - > list_locks [ index ] ;
2010-12-13 14:19:28 +03:00
2012-05-09 00:31:57 +04:00
spin_lock_bh ( list_lock ) ;
hlist_for_each ( node , head ) {
2011-02-18 15:28:09 +03:00
if ( ! compare ( node , data ) )
continue ;
2011-07-10 02:36:36 +04:00
ret = 1 ;
2012-05-09 00:31:57 +04:00
goto unlock ;
2010-12-13 14:19:28 +03:00
}
/* no duplicate found in list, add new element */
2011-02-18 15:28:09 +03:00
hlist_add_head_rcu ( data_node , head ) ;
2018-10-31 00:01:25 +03:00
atomic_inc ( & hash - > generation ) ;
2010-12-13 14:19:28 +03:00
2011-07-10 02:36:36 +04:00
ret = 0 ;
2011-01-19 23:01:40 +03:00
2012-05-09 00:31:57 +04:00
unlock :
spin_unlock_bh ( list_lock ) ;
2011-07-10 02:36:36 +04:00
out :
return ret ;
2010-12-13 14:19:28 +03:00
}
2017-12-02 21:51:52 +03:00
/**
* batadv_hash_remove ( ) - Removes data from hash , if found
* @ hash : hash table
* @ compare : callback to determine if 2 hash elements are identical
* @ choose : callback calculating the hash index
* @ data : data passed to the aforementioned callbacks as argument
*
* ata could be the structure you use with just the key filled , we just need
* the key for comparing .
2015-09-15 20:00:48 +03:00
*
* Return : returns pointer do data on success , so you can remove the used
* structure yourself , or NULL on error
2012-05-12 04:09:43 +04:00
*/
2012-06-06 00:31:28 +04:00
static inline void * batadv_hash_remove ( struct batadv_hashtable * hash ,
batadv_hashdata_compare_cb compare ,
batadv_hashdata_choose_cb choose ,
void * data )
2010-12-13 14:19:28 +03:00
{
2015-05-26 19:34:26 +03:00
u32 index ;
2011-02-18 15:28:09 +03:00
struct hlist_node * node ;
2010-12-13 14:19:28 +03:00
struct hlist_head * head ;
2011-01-19 23:01:40 +03:00
void * data_save = NULL ;
2010-12-13 14:19:28 +03:00
index = choose ( data , hash - > size ) ;
head = & hash - > table [ index ] ;
2011-01-19 23:01:40 +03:00
spin_lock_bh ( & hash - > list_locks [ index ] ) ;
2011-02-18 15:28:09 +03:00
hlist_for_each ( node , head ) {
if ( ! compare ( node , data ) )
continue ;
data_save = node ;
hlist_del_rcu ( node ) ;
2018-10-31 00:01:25 +03:00
atomic_inc ( & hash - > generation ) ;
2011-02-18 15:28:09 +03:00
break ;
2010-12-13 14:19:28 +03:00
}
2011-01-19 23:01:40 +03:00
spin_unlock_bh ( & hash - > list_locks [ index ] ) ;
2010-12-13 14:19:28 +03:00
2011-01-19 23:01:40 +03:00
return data_save ;
2010-12-13 14:19:28 +03:00
}
# endif /* _NET_BATMAN_ADV_HASH_H_ */