Skip to content

[pull] master from torvalds:master #1851

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 26, 2025
Prev Previous commit
Next Next commit
selftests/bpf: add test for softlock when modifying hashmap while ite…
…rating

Add test that modifies the map while it's being iterated in such a way that
hangs the kernel thread unless the _safe fix is applied to
bpf_for_each_hash_elem.

Signed-off-by: Brandon Kammerdiener <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Alexei Starovoitov <[email protected]>
Acked-by: Hou Tao <[email protected]>
  • Loading branch information
bkammerd authored and Alexei Starovoitov committed Apr 25, 2025
commit 3d9c463f959f41cd6616ebf8a5d15e9d3ef04f16
37 changes: 37 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/for_each.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "for_each_array_map_elem.skel.h"
#include "for_each_map_elem_write_key.skel.h"
#include "for_each_multi_maps.skel.h"
#include "for_each_hash_modify.skel.h"

static unsigned int duration;

Expand Down Expand Up @@ -203,6 +204,40 @@ static void test_multi_maps(void)
for_each_multi_maps__destroy(skel);
}

static void test_hash_modify(void)
{
struct for_each_hash_modify *skel;
int max_entries, i, err;
__u64 key, val;

LIBBPF_OPTS(bpf_test_run_opts, topts,
.data_in = &pkt_v4,
.data_size_in = sizeof(pkt_v4),
.repeat = 1
);

skel = for_each_hash_modify__open_and_load();
if (!ASSERT_OK_PTR(skel, "for_each_hash_modify__open_and_load"))
return;

max_entries = bpf_map__max_entries(skel->maps.hashmap);
for (i = 0; i < max_entries; i++) {
key = i;
val = i;
err = bpf_map__update_elem(skel->maps.hashmap, &key, sizeof(key),
&val, sizeof(val), BPF_ANY);
if (!ASSERT_OK(err, "map_update"))
goto out;
}

err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_pkt_access), &topts);
ASSERT_OK(err, "bpf_prog_test_run_opts");
ASSERT_OK(topts.retval, "retval");

out:
for_each_hash_modify__destroy(skel);
}

void test_for_each(void)
{
if (test__start_subtest("hash_map"))
Expand All @@ -213,4 +248,6 @@ void test_for_each(void)
test_write_map_key();
if (test__start_subtest("multi_maps"))
test_multi_maps();
if (test__start_subtest("hash_modify"))
test_hash_modify();
}
30 changes: 30 additions & 0 deletions tools/testing/selftests/bpf/progs/for_each_hash_modify.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2025 Intel Corporation */
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>

char _license[] SEC("license") = "GPL";

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 128);
__type(key, __u64);
__type(value, __u64);
} hashmap SEC(".maps");

static int cb(struct bpf_map *map, __u64 *key, __u64 *val, void *arg)
{
bpf_map_delete_elem(map, key);
bpf_map_update_elem(map, key, val, 0);
return 0;
}

SEC("tc")
int test_pkt_access(struct __sk_buff *skb)
{
(void)skb;

bpf_for_each_map_elem(&hashmap, cb, NULL, 0);

return 0;
}