Commit 45dc92c3 authored by Hou Tao's avatar Hou Tao Committed by Alexei Starovoitov
Browse files

bpf: Free special fields after unlock in htab_lru_map_delete_node()



When bpf_timer is used in LRU hash map, calling check_and_free_fields()
in htab_lru_map_delete_node() will invoke bpf_timer_cancel_and_free() to
free the bpf_timer. If the timer is running on other CPUs,
hrtimer_cancel() will invoke hrtimer_cancel_wait_running() to spin on
current CPU to wait for the completion of the hrtimer callback.

Considering that the deletion has already acquired a raw-spin-lock
(bucket lock). To reduce the time holding the bucket lock, move the
invocation of check_and_free_fields() out of bucket lock. However,
because htab_lru_map_delete_node() is invoked with LRU raw spin lock
being held, the freeing of special fields still happens in a locked
scope.

Signed-off-by: default avatarHou Tao <houtao1@huawei.com>
Reviewed-by: default avatarToke Høiland-Jørgensen <toke@kernel.org>
Link: https://lore.kernel.org/r/20250117101816.2101857-2-houtao@huaweicloud.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 01f3ce53
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -824,13 +824,14 @@ static bool htab_lru_map_delete_node(void *arg, struct bpf_lru_node *node)
	hlist_nulls_for_each_entry_rcu(l, n, head, hash_node)
		if (l == tgt_l) {
			hlist_nulls_del_rcu(&l->hash_node);
			check_and_free_fields(htab, l);
			bpf_map_dec_elem_count(&htab->map);
			break;
		}

	htab_unlock_bucket(htab, b, tgt_l->hash, flags);

	if (l == tgt_l)
		check_and_free_fields(htab, l);
	return l == tgt_l;
}