From: sashiko-bot@kernel.org
To: "Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>
Cc: bpf@vger.kernel.org, linux-trace-kernel@vger.kernel.org
Subject: Re: [RFC PATCH 15/16] selftests/membarrier: Check the memory barriers of each thread
Date: Fri, 13 Nov 2026 13:46:03 +0000 [thread overview]
Message-ID: <sashiko-outbox-212919@kernel.org> (raw)
In-Reply-To: <20261113131903.157186-16-mathieu.desnoyers@efficios.com>
Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [Medium] selftests/membarrier: run_target() pins CPU before
registering BPF slot
- [Medium] selftests/membarrier: bpf_setup() fails instead of skipping
on missing BPF configs
- [Low] selftests/membarrier: reset_shared() reuses BPF counter slots of
exiting tasks
--
commit 3ab38ee940d58df6774d85bc12aa7c4563dfeb02
Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
selftests/membarrier: Check the memory barriers of each thread
This commit adds the membarrier_test_barrier selftest, which uses BPF
kprobes and the sched_switch tracepoint on x86-64 to count per-thread
memory barriers executed during expedited membarrier commands and context
switches.
> diff --git a/tools/testing/selftests/membarrier/membarrier_test_barrier.c b/tools/testing/selftests/membarrier/membarrier_test_barrier.c
> new file mode 100644
> index 0000000000000..46502d2712425
> --- /dev/null
> +++ b/tools/testing/selftests/membarrier/membarrier_test_barrier.c
> @@ -0,0 +1,1253 @@
[ ... ]
> +static const char *bpf_setup(void)
> +{
> + struct bpf_program *prog;
> + libbpf_print_fn_t print;
> + struct bpf_map *map;
> + const char *err;
> +
> + setup_pid = getpid();
> + atexit(bpf_teardown);
> + if (geteuid())
> + return "this test needs root";
> + if (access("/sys/kernel/btf/vmlinux", R_OK))
> + return "the kernel has no BTF (CONFIG_DEBUG_INFO_BTF)";
> + kcore_fd = open("/proc/kcore", O_RDONLY | O_CLOEXEC);
> + if (kcore_fd < 0)
> + return "cannot read /proc/kcore (CONFIG_PROC_KCORE)";
> + setup_broken = true;
> + bpf_obj = bpf_object__open_file(BPF_OBJECT, NULL);
> + if (!bpf_obj)
> + return "cannot open " BPF_OBJECT;
> + if (bpf_object__load(bpf_obj))
> + return "cannot load the BPF programs";
> + site_prog = bpf_object__find_program_by_name(bpf_obj, "barrier_site");
> + prog = bpf_object__find_program_by_name(bpf_obj, "register_thread");
> + map = bpf_object__find_map_by_name(bpf_obj, "counters");
> + if (!site_prog || !prog || !map)
> + return "incomplete BPF object";
> + register_fd = bpf_program__fd(prog);
> + counters_fd = bpf_map__fd(map);
> + map = bpf_object__find_map_by_name(bpf_obj, "site_hits");
> + hits_fd = map ? bpf_map__fd(map) : -1;
> + /* The exec test case passes these two to the new program. */
> + if (fcntl(register_fd, F_SETFD, 0) || fcntl(counters_fd, F_SETFD, 0))
> + return "fcntl failed";
> + signal(SIGINT, restore_optprobes);
> + signal(SIGTERM, restore_optprobes);
> + signal(SIGHUP, restore_optprobes);
> + if (!set_optprobes('0'))
> + return "cannot write " OPTPROBES_FILE;
> + prog = bpf_object__find_program_by_name(bpf_obj, "sched_switch");
> + switch_link = prog ? bpf_program__attach(prog) : NULL;
> + if (!switch_link)
> + return "cannot attach to the sched_switch tracepoint";
[Severity: Medium]
Does setting setup_broken = true before bpf_object__load() and
bpf_program__attach() cause main() to fail instead of skipping when the
kernel lacks required BPF features?
A kernel with CONFIG_DEBUG_INFO_BTF=y and CONFIG_PROC_KCORE=y can still
lack CONFIG_BPF_EVENTS=y (needed to load kprobe/tracing programs and
BPF_MAP_TYPE_TASK_STORAGE) or have BPF JIT disabled (needed to attach
tp_btf/sched_switch). When bpf_object__load() or bpf_program__attach()
fails for those reasons, setup_broken is already true, so main() exits via
ksft_exit_fail_msg() rather than ksft_exit_skip().
[ ... ]
> +/* Run the checks of a target. */
> +static void run_target(const struct target *target)
> +{
> + struct target_stats *stats = &shared->stats[target->idx];
> + const uint64_t *counters;
> + long deadline = now_ms() + target->ms;
> + unsigned long checks = 0;
> + uint64_t first_ipi, first_sched_in;
> +
> + if (target->cpu >= 0 && pin_to_cpu(target->cpu))
> + setup_error("sched_setaffinity");
> + counters = map_counters();
[Severity: Medium]
Does calling pin_to_cpu(target->cpu) before map_counters() miss the
lazy-TLB context switch in global_expedited_lazy_tlb?
In global_expedited_lazy_tlb, the child pins itself to cpus[1] and then
cpus[2] so that cpus[1]'s idle thread borrows its mm, and then calls
run_target() with target.cpu = cpus[1]. Because pin_to_cpu() migrates the
child back onto cpus[1] before map_counters() runs register_thread to
populate task_slot, the switch from the lazy-TLB idle thread back to the
child on cpus[1] runs while slot_of(next) is still 0:
tools/testing/selftests/membarrier/membarrier_test_barrier.bpf.c:sched_switch() {
...
slot = slot_of(next);
state->slot = slot;
state->owed = 0;
/* The cases which need a barrier after the store to rq->curr. */
if (slot && next->mm && prev->mm != next->mm) {
state->owed = OWES_BARRIER;
count(slot, 1U << MBT_SCHED_IN);
}
...
}
As a result, sched_switch never sets OWES_BARRIER or increments
MBT_SCHED_IN for that lazy-TLB switch. Calling map_counters() before
pin_to_cpu(target->cpu) registers the thread in task_slot before it
migrates back to cpus[1].
[ ... ]
> +static void reset_shared(void)
> +{
> + memset(shared, 0, sizeof(*shared));
> +}
[Severity: Low]
Can zeroing shared->next_slot in reset_shared() let an exiting task from a
finished test case clobber the BPF counters of a new thread in the next
test case?
pthread_join() and waitpid() return during do_exit() before the dying task
reaches its final context switch in do_task_dead(), while its task_slot
entry remains attached until free_task().
CPU0 CPU1
join_targets() / child_ok()
reset_shared()
shared->next_slot = 0
start_targets()
map_counters()
register_thread() (slot 1)
do_exit()
do_task_dead()
__schedule()
sched_switch() (prev slot 1)
count(1, 1U << MBT_SCHED_OUT)
<-- increments new thread's
counters
Preserving shared->next_slot across reset_shared() avoids reusing counter
slots across test cases.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113131903.157186-1-mathieu.desnoyers@efficios.com?part=15
next prev parent reply other threads:[~2026-11-13 13:46 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 13:18 [RFC PATCH 00/16] membarrier: fixes, selftests and documentation Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 01/16] sched/membarrier: Fix stale runqueue state after a lazy mm switch Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 02/16] sched/membarrier: Report only completed registrations Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 03/16] selftests/membarrier: Rebuild the tests when their header changes Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 04/16] selftests/membarrier: Issue the sync core command in its test Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 05/16] selftests/membarrier: Run the tests on nohz_full kernels Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 06/16] selftests/membarrier: Test which CPUs the expedited commands interrupt Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 07/16] selftests/membarrier: Test command arguments and registration lifetime Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 08/16] LoongArch: membarrier: Add full memory barrier in switch_mm() Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 09/16] parisc: " Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 10/16] Documentation/membarrier: Update the per-architecture barrier list Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 11/16] Documentation/features: Update the membarrier sync core requirements Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:18 ` [RFC PATCH 12/16] x86/entry: Remove stale membarrier sync core comments Mathieu Desnoyers
2026-11-13 13:18 ` Mathieu Desnoyers
2026-11-13 13:19 ` [RFC PATCH 13/16] selftests/membarrier: Add litmus tests of the memory ordering Mathieu Desnoyers
2026-11-13 13:19 ` Mathieu Desnoyers
2026-11-13 13:19 ` [RFC PATCH 14/16] MAINTAINERS: Add the membarrier selftests to MEMBARRIER SUPPORT Mathieu Desnoyers
2026-11-13 13:19 ` Mathieu Desnoyers
2026-11-13 13:19 ` [RFC PATCH 15/16] selftests/membarrier: Check the memory barriers of each thread Mathieu Desnoyers
2026-11-13 13:19 ` Mathieu Desnoyers
2026-11-13 13:46 ` sashiko-bot [this message]
2026-11-13 14:37 ` Mathieu Desnoyers
2026-11-13 13:19 ` [RFC PATCH 16/16] selftests/membarrier: Check the core serialization of the sync core command Mathieu Desnoyers
2026-11-13 13:19 ` Mathieu Desnoyers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-212919@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.