mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
selftests/bpf: Avoid a page fault in rcu_reentry while the handler is armed
The test arms a handler at rcu_segcblist_enqueue() for its thread. Then it
deletes an element of a task storage map. The delete gets to
rcu_segcblist_enqueue(), and the handler does a nested delete there.
The handler fires at the first rcu_segcblist_enqueue() in the thread. A
page fault can be the first:
skel->bss->target_pid = tid the handler is armed
the next insn is in a page that is not in memory
asm_exc_page_fault
filemap_fault
v9fs_issue_read
p9_req_put
irq_work_run
rcu_defer_drain
rcu_segcblist_enqueue
the handler deletes the element
bpf_map_delete_elem() -ENOENT
test_rcu_reentry:FAIL:boot_delete unexpected error: -2 (errno 2)
The result depends on the layout of test_progs. In the binary that failed,
test_rcu_reentry() crosses the end of a page immediately after the store.
This binary fails each time when it is on 9p. A copy of the same file on
ext4 passes.
Move the store and the delete to a function. Call it one time without a pid
and with a bad fd. This call brings the text and .bss into memory, and it
does not arm the handler.
Fixes: 0464f587c6 ("selftests/bpf: Add a call_srcu() re-entry reproducer")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261027190314.1440199-11-alexei.starovoitov@gmail.com
This commit is contained in:
parent
2ad395a384
commit
3c0ca9f9a9
|
|
@ -23,10 +23,17 @@ static bool have_tree_srcu(void)
|
|||
return kallsyms_find("srcu_expedite_current", &addr) == 0;
|
||||
}
|
||||
|
||||
/* Arm the handler for this thread, then trigger call_rcu_tasks_trace(). */
|
||||
static noinline int arm_and_delete(struct rcu_reentry *skel, int pid, int map_fd, int *pidfd)
|
||||
{
|
||||
skel->bss->target_pid = pid;
|
||||
return bpf_map_delete_elem(map_fd, pidfd);
|
||||
}
|
||||
|
||||
void test_rcu_reentry(void)
|
||||
{
|
||||
struct rcu_reentry *skel;
|
||||
int err, pidfd = -1, map_fd;
|
||||
int err, pidfd = -1, bad_fd = -1, map_fd;
|
||||
cpu_set_t set, old_set;
|
||||
bool affinity_saved;
|
||||
__u64 val = 1;
|
||||
|
|
@ -63,9 +70,13 @@ void test_rcu_reentry(void)
|
|||
if (!ASSERT_OK(err, "boot_create"))
|
||||
goto restore;
|
||||
|
||||
/* Arm the handler for this thread, then trigger call_rcu_tasks_trace(). */
|
||||
skel->bss->target_pid = syscall(__NR_gettid);
|
||||
err = bpf_map_delete_elem(map_fd, &pidfd);
|
||||
/*
|
||||
* The handler fires at the first rcu_segcblist_enqueue() in this thread, and it deletes
|
||||
* the element. A page fault can get there too, when the file system reads the page.
|
||||
* Go through the same code first, without a pid, to bring its text and .bss in.
|
||||
*/
|
||||
arm_and_delete(skel, 0, map_fd, &bad_fd);
|
||||
err = arm_and_delete(skel, syscall(__NR_gettid), map_fd, &pidfd);
|
||||
if (!ASSERT_OK(err, "boot_delete"))
|
||||
goto restore;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user