Skip to content

Commit 587f729

Browse files
Saket Kumar BhaskarKernel Patches Daemon
authored andcommitted
selftests/bpf: Fix htab_update/reenter_update selftest failure
Since commit 31158ad ("rqspinlock: Add deadlock detection and recovery") the updated path on re-entrancy now reports deadlock via -EDEADLK instead of the previous -EBUSY. Also, the way reentrancy was exercised (via fentry/lookup_elem_raw) has been fragile because lookup_elem_raw may be inlined (find_kernel_btf_id() will return -ESRCH). To fix this fentry is attached to bpf_obj_free_fields() instead of lookup_elem_raw() and: - The htab map is made to use a BTF-described struct val with a struct bpf_timer so that check_and_free_fields() reliably calls bpf_obj_free_fields() on element replacement. - The selftest is updated to do two updates to the same key (insert + replace) in prog_test. - The selftest is updated to align with expected errno with the kernel’s current behavior. Signed-off-by: Saket Kumar Bhaskar <[email protected]> Tested-by: Venkat Rao Bagalkote <[email protected]>
1 parent 1efb39d commit 587f729

File tree

2 files changed

+41
-15
lines changed

2 files changed

+41
-15
lines changed

tools/testing/selftests/bpf/prog_tests/htab_update.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,51 @@ struct htab_update_ctx {
1515
static void test_reenter_update(void)
1616
{
1717
struct htab_update *skel;
18-
unsigned int key, value;
18+
void *value = NULL;
19+
unsigned int key, value_size;
1920
int err;
2021

2122
skel = htab_update__open();
2223
if (!ASSERT_OK_PTR(skel, "htab_update__open"))
2324
return;
2425

25-
/* lookup_elem_raw() may be inlined and find_kernel_btf_id() will return -ESRCH */
26-
bpf_program__set_autoload(skel->progs.lookup_elem_raw, true);
26+
bpf_program__set_autoload(skel->progs.bpf_obj_free_fields, true);
2727
err = htab_update__load(skel);
28-
if (!ASSERT_TRUE(!err || err == -ESRCH, "htab_update__load") || err)
28+
if (!ASSERT_TRUE(!err, "htab_update__load") || err)
2929
goto out;
3030

3131
skel->bss->pid = getpid();
3232
err = htab_update__attach(skel);
3333
if (!ASSERT_OK(err, "htab_update__attach"))
3434
goto out;
3535

36-
/* Will trigger the reentrancy of bpf_map_update_elem() */
36+
value_size = bpf_map__value_size(skel->maps.htab);
37+
38+
value = calloc(1, value_size);
39+
if (!ASSERT_OK_PTR(value, "calloc value"))
40+
goto out;
41+
/*
42+
* First update: plain insert. This should NOT trigger the re-entrancy
43+
* path, because there is no old element to free yet.
44+
*/
3745
key = 0;
38-
value = 0;
39-
err = bpf_map_update_elem(bpf_map__fd(skel->maps.htab), &key, &value, 0);
40-
if (!ASSERT_OK(err, "add element"))
46+
err = bpf_map_update_elem(bpf_map__fd(skel->maps.htab), &key, value, BPF_ANY);
47+
if (!ASSERT_OK(err, "first update (insert)"))
48+
goto out;
49+
50+
/*
51+
* Second update: replace existing element with same key and trigger
52+
* the reentrancy of bpf_map_update_elem().
53+
* check_and_free_fields() calls bpf_obj_free_fields() on the old
54+
* value, which is where fentry program runs and performs a nested
55+
* bpf_map_update_elem(), triggering -EDEADLK.
56+
*/
57+
memset(value, 0, value_size);
58+
err = bpf_map_update_elem(bpf_map__fd(skel->maps.htab), &key, value, BPF_ANY);
59+
if (!ASSERT_OK(err, "second update (replace)"))
4160
goto out;
4261

43-
ASSERT_EQ(skel->bss->update_err, -EBUSY, "no reentrancy");
62+
ASSERT_EQ(skel->bss->update_err, -EDEADLK, "no reentrancy");
4463
out:
4564
htab_update__destroy(skel);
4665
}

tools/testing/selftests/bpf/progs/htab_update.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,31 @@
66

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

9+
/* Map value type: has BTF-managed field (bpf_timer) */
10+
struct val {
11+
struct bpf_timer t;
12+
__u64 payload;
13+
};
14+
915
struct {
1016
__uint(type, BPF_MAP_TYPE_HASH);
1117
__uint(max_entries, 1);
12-
__uint(key_size, sizeof(__u32));
13-
__uint(value_size, sizeof(__u32));
18+
__type(key, __u32);
19+
__type(value, struct val);
1420
} htab SEC(".maps");
1521

1622
int pid = 0;
1723
int update_err = 0;
1824

19-
SEC("?fentry/lookup_elem_raw")
20-
int lookup_elem_raw(void *ctx)
25+
SEC("?fentry/bpf_obj_free_fields")
26+
int bpf_obj_free_fields(void *ctx)
2127
{
22-
__u32 key = 0, value = 1;
28+
__u32 key = 0;
29+
struct val value = { .payload = 1 };
2330

2431
if ((bpf_get_current_pid_tgid() >> 32) != pid)
2532
return 0;
2633

27-
update_err = bpf_map_update_elem(&htab, &key, &value, 0);
34+
update_err = bpf_map_update_elem(&htab, &key, &value, BPF_ANY);
2835
return 0;
2936
}

0 commit comments

Comments
 (0)