@@ -62,7 +62,14 @@ static bool htab_lru_map_delete_node(void *arg, struct bpf_lru_node *node);
6262
6363static bool htab_is_lru (const struct bpf_htab * htab )
6464{
65- return htab -> map .map_type == BPF_MAP_TYPE_LRU_HASH ;
65+ return htab -> map .map_type == BPF_MAP_TYPE_LRU_HASH ||
66+ htab -> map .map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ;
67+ }
68+
69+ static bool htab_is_percpu (const struct bpf_htab * htab )
70+ {
71+ return htab -> map .map_type == BPF_MAP_TYPE_PERCPU_HASH ||
72+ htab -> map .map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ;
6673}
6774
6875static inline void htab_elem_set_ptr (struct htab_elem * l , u32 key_size ,
@@ -85,7 +92,7 @@ static void htab_free_elems(struct bpf_htab *htab)
8592{
8693 int i ;
8794
88- if (htab -> map . map_type != BPF_MAP_TYPE_PERCPU_HASH )
95+ if (! htab_is_percpu ( htab ) )
8996 goto free_elems ;
9097
9198 for (i = 0 ; i < htab -> map .max_entries ; i ++ ) {
@@ -122,7 +129,7 @@ static int prealloc_init(struct bpf_htab *htab)
122129 if (!htab -> elems )
123130 return - ENOMEM ;
124131
125- if (htab -> map . map_type != BPF_MAP_TYPE_PERCPU_HASH )
132+ if (! htab_is_percpu ( htab ) )
126133 goto skip_percpu_elems ;
127134
128135 for (i = 0 ; i < htab -> map .max_entries ; i ++ ) {
@@ -195,8 +202,10 @@ static int alloc_extra_elems(struct bpf_htab *htab)
195202/* Called from syscall */
196203static struct bpf_map * htab_map_alloc (union bpf_attr * attr )
197204{
198- bool percpu = attr -> map_type == BPF_MAP_TYPE_PERCPU_HASH ;
199- bool lru = attr -> map_type == BPF_MAP_TYPE_LRU_HASH ;
205+ bool percpu = (attr -> map_type == BPF_MAP_TYPE_PERCPU_HASH ||
206+ attr -> map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH );
207+ bool lru = (attr -> map_type == BPF_MAP_TYPE_LRU_HASH ||
208+ attr -> map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH );
200209 /* percpu_lru means each cpu has its own LRU list.
201210 * it is different from BPF_MAP_TYPE_PERCPU_HASH where
202211 * the map's value itself is percpu. percpu_lru has
@@ -823,12 +832,84 @@ static int __htab_percpu_map_update_elem(struct bpf_map *map, void *key,
823832 return ret ;
824833}
825834
835+ static int __htab_lru_percpu_map_update_elem (struct bpf_map * map , void * key ,
836+ void * value , u64 map_flags ,
837+ bool onallcpus )
838+ {
839+ struct bpf_htab * htab = container_of (map , struct bpf_htab , map );
840+ struct htab_elem * l_new = NULL , * l_old ;
841+ struct hlist_head * head ;
842+ unsigned long flags ;
843+ struct bucket * b ;
844+ u32 key_size , hash ;
845+ int ret ;
846+
847+ if (unlikely (map_flags > BPF_EXIST ))
848+ /* unknown flags */
849+ return - EINVAL ;
850+
851+ WARN_ON_ONCE (!rcu_read_lock_held ());
852+
853+ key_size = map -> key_size ;
854+
855+ hash = htab_map_hash (key , key_size );
856+
857+ b = __select_bucket (htab , hash );
858+ head = & b -> head ;
859+
860+ /* For LRU, we need to alloc before taking bucket's
861+ * spinlock because LRU's elem alloc may need
862+ * to remove older elem from htab and this removal
863+ * operation will need a bucket lock.
864+ */
865+ if (map_flags != BPF_EXIST ) {
866+ l_new = prealloc_lru_pop (htab , key , hash );
867+ if (!l_new )
868+ return - ENOMEM ;
869+ }
870+
871+ /* bpf_map_update_elem() can be called in_irq() */
872+ raw_spin_lock_irqsave (& b -> lock , flags );
873+
874+ l_old = lookup_elem_raw (head , hash , key , key_size );
875+
876+ ret = check_flags (htab , l_old , map_flags );
877+ if (ret )
878+ goto err ;
879+
880+ if (l_old ) {
881+ bpf_lru_node_set_ref (& l_old -> lru_node );
882+
883+ /* per-cpu hash map can update value in-place */
884+ pcpu_copy_value (htab , htab_elem_get_ptr (l_old , key_size ),
885+ value , onallcpus );
886+ } else {
887+ pcpu_copy_value (htab , htab_elem_get_ptr (l_new , key_size ),
888+ value , onallcpus );
889+ hlist_add_head_rcu (& l_new -> hash_node , head );
890+ l_new = NULL ;
891+ }
892+ ret = 0 ;
893+ err :
894+ raw_spin_unlock_irqrestore (& b -> lock , flags );
895+ if (l_new )
896+ bpf_lru_push_free (& htab -> lru , & l_new -> lru_node );
897+ return ret ;
898+ }
899+
826900static int htab_percpu_map_update_elem (struct bpf_map * map , void * key ,
827901 void * value , u64 map_flags )
828902{
829903 return __htab_percpu_map_update_elem (map , key , value , map_flags , false);
830904}
831905
906+ static int htab_lru_percpu_map_update_elem (struct bpf_map * map , void * key ,
907+ void * value , u64 map_flags )
908+ {
909+ return __htab_lru_percpu_map_update_elem (map , key , value , map_flags ,
910+ false);
911+ }
912+
832913/* Called from syscall or from eBPF program */
833914static int htab_map_delete_elem (struct bpf_map * map , void * key )
834915{
@@ -976,8 +1057,21 @@ static void *htab_percpu_map_lookup_elem(struct bpf_map *map, void *key)
9761057 return NULL ;
9771058}
9781059
1060+ static void * htab_lru_percpu_map_lookup_elem (struct bpf_map * map , void * key )
1061+ {
1062+ struct htab_elem * l = __htab_map_lookup_elem (map , key );
1063+
1064+ if (l ) {
1065+ bpf_lru_node_set_ref (& l -> lru_node );
1066+ return this_cpu_ptr (htab_elem_get_ptr (l , map -> key_size ));
1067+ }
1068+
1069+ return NULL ;
1070+ }
1071+
9791072int bpf_percpu_hash_copy (struct bpf_map * map , void * key , void * value )
9801073{
1074+ struct bpf_htab * htab = container_of (map , struct bpf_htab , map );
9811075 struct htab_elem * l ;
9821076 void __percpu * pptr ;
9831077 int ret = - ENOENT ;
@@ -993,6 +1087,8 @@ int bpf_percpu_hash_copy(struct bpf_map *map, void *key, void *value)
9931087 l = __htab_map_lookup_elem (map , key );
9941088 if (!l )
9951089 goto out ;
1090+ if (htab_is_lru (htab ))
1091+ bpf_lru_node_set_ref (& l -> lru_node );
9961092 pptr = htab_elem_get_ptr (l , map -> key_size );
9971093 for_each_possible_cpu (cpu ) {
9981094 bpf_long_memcpy (value + off ,
@@ -1008,10 +1104,16 @@ int bpf_percpu_hash_copy(struct bpf_map *map, void *key, void *value)
10081104int bpf_percpu_hash_update (struct bpf_map * map , void * key , void * value ,
10091105 u64 map_flags )
10101106{
1107+ struct bpf_htab * htab = container_of (map , struct bpf_htab , map );
10111108 int ret ;
10121109
10131110 rcu_read_lock ();
1014- ret = __htab_percpu_map_update_elem (map , key , value , map_flags , true);
1111+ if (htab_is_lru (htab ))
1112+ ret = __htab_lru_percpu_map_update_elem (map , key , value ,
1113+ map_flags , true);
1114+ else
1115+ ret = __htab_percpu_map_update_elem (map , key , value , map_flags ,
1116+ true);
10151117 rcu_read_unlock ();
10161118
10171119 return ret ;
@@ -1031,11 +1133,26 @@ static struct bpf_map_type_list htab_percpu_type __read_mostly = {
10311133 .type = BPF_MAP_TYPE_PERCPU_HASH ,
10321134};
10331135
1136+ static const struct bpf_map_ops htab_lru_percpu_ops = {
1137+ .map_alloc = htab_map_alloc ,
1138+ .map_free = htab_map_free ,
1139+ .map_get_next_key = htab_map_get_next_key ,
1140+ .map_lookup_elem = htab_lru_percpu_map_lookup_elem ,
1141+ .map_update_elem = htab_lru_percpu_map_update_elem ,
1142+ .map_delete_elem = htab_lru_map_delete_elem ,
1143+ };
1144+
1145+ static struct bpf_map_type_list htab_lru_percpu_type __read_mostly = {
1146+ .ops = & htab_lru_percpu_ops ,
1147+ .type = BPF_MAP_TYPE_LRU_PERCPU_HASH ,
1148+ };
1149+
10341150static int __init register_htab_map (void )
10351151{
10361152 bpf_register_map_type (& htab_type );
10371153 bpf_register_map_type (& htab_percpu_type );
10381154 bpf_register_map_type (& htab_lru_type );
1155+ bpf_register_map_type (& htab_lru_percpu_type );
10391156 return 0 ;
10401157}
10411158late_initcall (register_htab_map );
0 commit comments