@@ -59,6 +59,9 @@ struct bpf_cpu_map_entry {
5959 u32 cpu ; /* kthread CPU and map index */
6060 int map_id ; /* Back reference to map */
6161
62+ /* Used to end ownership transfer transaction */
63+ struct bpf_map * parent_map ;
64+
6265 /* XDP can run multiple RX-ring queues, need __percpu enqueue store */
6366 struct xdp_bulk_queue __percpu * bulkq ;
6467
@@ -428,6 +431,7 @@ __cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value,
428431 rcpu -> cpu = cpu ;
429432 rcpu -> map_id = map -> id ;
430433 rcpu -> value .qsize = value -> qsize ;
434+ rcpu -> parent_map = map ;
431435
432436 if (fd > 0 && __cpu_map_load_bpf_program (rcpu , map , fd ))
433437 goto free_ptr_ring ;
@@ -640,6 +644,14 @@ static int cpu_map_get_next_key(struct bpf_map *map, void *key, void *next_key)
640644
641645static long cpu_map_redirect (struct bpf_map * map , u64 index , u64 flags )
642646{
647+ /*
648+ * Redirection is a transfer of ownership of the bpf_cpu_map_entry
649+ * During the transfer the bpf_cpu_map_entry is still in the map,
650+ * so we need to prevent it from being freed.
651+ * The bpf_map_inc() increments the refcnt of the map, so the
652+ * bpf_cpu_map_entry will not be freed until the refcnt is decremented.
653+ */
654+ bpf_map_inc (map );
643655 return __bpf_xdp_redirect_map (map , index , flags , 0 ,
644656 __cpu_map_lookup_elem );
645657}
@@ -766,6 +778,16 @@ void __cpu_map_flush(struct list_head *flush_list)
766778 list_for_each_entry_safe (bq , tmp , flush_list , flush_node ) {
767779 bq_flush_to_queue (bq );
768780
781+ /*
782+ * Flush operation is the last operation of ownership transfer
783+ * transaction. Thus, we can safely clear the parent_map, decrement
784+ * the refcnt of the map and free the bpf_cpu_map_entry if needed.
785+ */
786+ struct bpf_map * map = bq -> obj -> parent_map ;
787+
788+ if (map )
789+ bpf_map_put (map );
790+
769791 /* If already running, costs spin_lock_irqsave + smb_mb */
770792 wake_up_process (bq -> obj -> kthread );
771793 }
0 commit comments