2016-01-01 02:01:03 +03:00
/* Copyright (C) 2006-2016 B.A.T.M.A.N. contributors:
2010-12-13 14:19:28 +03:00
*
* Simon Wunderlich , Marek Lindner
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2013-11-03 23:40:48 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2010-12-13 14:19:28 +03:00
*/
# ifndef _NET_BATMAN_ADV_HASH_H_
# define _NET_BATMAN_ADV_HASH_H_
2015-04-17 20:40:28 +03:00
# include "main.h"
# include <linux/compiler.h>
2010-12-13 14:19:28 +03:00
# include <linux/list.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>
struct lock_class_key ;
2010-12-13 14:19:28 +03:00
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
2012-06-06 00:31:28 +04:00
struct batadv_hashtable {
2011-01-19 23:01:40 +03:00
struct hlist_head * table ; /* the hashtable itself with the buckets */
spinlock_t * list_locks ; /* spinlock for each hash list entry */
2015-05-26 19:34:26 +03:00
u32 size ; /* size of hashtable */
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
/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
* called to remove the elements inside of the hash . if you don ' t remove the
2012-05-12 04:09:43 +04:00
* elements , memory might be leaked .
*/
2012-06-06 00:31:28 +04:00
static inline void batadv_hash_delete ( struct batadv_hashtable * hash ,
batadv_hashdata_free_cb free_cb ,
void * arg )
2010-12-13 14:19:28 +03:00
{
struct hlist_head * head ;
2011-02-18 15:28:09 +03:00
struct hlist_node * node , * node_tmp ;
2011-01-19 23:01:40 +03:00
spinlock_t * list_lock ; /* spinlock to protect write access */
2015-05-26 19:34:26 +03:00
u32 i ;
2010-12-13 14:19:28 +03:00
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-01-19 23:01:40 +03:00
list_lock = & hash - > list_locks [ i ] ;
2010-12-13 14:19:28 +03:00
2011-01-19 23:01:40 +03:00
spin_lock_bh ( list_lock ) ;
2011-02-18 15:28:09 +03:00
hlist_for_each_safe ( node , node_tmp , head ) {
hlist_del_rcu ( node ) ;
2010-12-13 14:19:28 +03:00
2011-02-18 15:28:09 +03:00
if ( free_cb )
free_cb ( node , arg ) ;
2010-12-13 14:19:28 +03:00
}
2011-01-19 23:01:40 +03:00
spin_unlock_bh ( list_lock ) ;
2010-12-13 14:19:28 +03:00
}
2012-05-12 04:09:32 +04:00
batadv_hash_destroy ( hash ) ;
2010-12-13 14:19:28 +03:00
}
2012-07-10 14:55:09 +04: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 ) ;
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
}
2015-09-15 20:00:48 +03:00
/* removes data from hash, if found. data could be the structure you use with
* just the key filled , we just need the key for comparing .
*
* 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 ) ;
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_ */