From: bot+bpf-ci@kernel.org
To: donggeunyoo.kernel@gmail.com,bpf@vger.kernel.org
Cc: ast@kernel.org,daniel@iogearbox.net,andrii@kernel.org,eddyz87@gmail.com,memxor@gmail.com,martin.lau@linux.dev,song@kernel.org,yonghong.song@linux.dev,jolsa@kernel.org,emil@etsalapatis.com,ihor.solodrai@linux.dev,leon.hwang@linux.dev,linux-kselftest@vger.kernel.org,linux-kernel@vger.kernel.org,donggeunyoo.kernel@gmail.com,ast@kernel.org,andrii@kernel.org,daniel@iogearbox.net,martin.lau@kernel.org,eddyz87@gmail.com,yonghong.song@linux.dev,mason@kernel.org,ihor.solodrai@linux.dev
Subject: Re: [PATCH bpf v2 2/2] selftests/bpf: Test per-cpu initialization of a BPF_F_CPU created element
Date: Wed, 23 Sep 2026 00:56:18 +0000 (UTC) [thread overview]
Message-ID: <3d31f180b472adb3b215571fa73ba38641cc93a33ea2e8e82413f37957c2d99a@mail.kernel.org> (raw)
In-Reply-To: <20260923000801.1764758-3-donggeunyoo.kernel@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 4310 bytes --]
> diff --git a/tools/testing/selftests/bpf/prog_tests/percpu_alloc.c b/tools/testing/selftests/bpf/prog_tests/percpu_alloc.c
> index a72ae0b29f6e..f853f97bb882 100644
> --- a/tools/testing/selftests/bpf/prog_tests/percpu_alloc.c
> +++ b/tools/testing/selftests/bpf/prog_tests/percpu_alloc.c
[ ... ]
> @@ -350,6 +350,80 @@ static void test_lru_percpu_hash_cpu_flag(void)
> test_percpu_map_cpu_flag(BPF_MAP_TYPE_LRU_PERCPU_HASH);
> }
>
> +/*
> + * A BPF_F_CPU update that creates an element must zero the value on the other
> + * cpus, rather than leave them holding whatever the recycled element last
> + * contained. max_entries is 1 so the second key can only reuse the element
> + * the first one released.
> + */
> +static void test_percpu_map_cpu_flag_create(enum bpf_map_type map_type, __u32 map_flags)
> +{
> + LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = map_flags);
> + const u32 stale = 0xDEADC0DE, fresh = 0xC0FFEE;
> + int nr_cpus, cpu, map_fd, err, key;
> + u32 value;
> + u64 flags;
> +
> + nr_cpus = libbpf_num_possible_cpus();
> + if (!ASSERT_GT(nr_cpus, 0, "libbpf_num_possible_cpus"))
> + return;
> +
> + if (nr_cpus < 2) {
> + test__skip();
> + return;
> + }
> +
> + map_fd = bpf_map_create(map_type, "cpu_flag_create", sizeof(key), sizeof(value), 1, &opts);
> + if (!ASSERT_GE(map_fd, 0, "bpf_map_create"))
> + return;
> +
> + key = 1;
> + value = stale;
> + err = bpf_map_update_elem(map_fd, &key, &value, BPF_F_ALL_CPUS);
> + if (!ASSERT_OK(err, "bpf_map_update_elem all_cpus"))
> + goto out;
> +
> + err = bpf_map_delete_elem(map_fd, &key);
> + if (!ASSERT_OK(err, "bpf_map_delete_elem"))
> + goto out;
> +
> + key = 2;
> + value = fresh;
> + flags = BPF_F_CPU;
> + err = bpf_map_update_elem(map_fd, &key, &value, flags);
> + if (!ASSERT_OK(err, "bpf_map_update_elem specified cpu"))
> + goto out;
> +
> + for (cpu = 0; cpu < nr_cpus; cpu++) {
> + value = 0;
> + flags = (u64)cpu << 32 | BPF_F_CPU;
> + err = bpf_map_lookup_elem_flags(map_fd, &key, &value, flags);
> + if (!ASSERT_OK(err, "bpf_map_lookup_elem_flags specified cpu"))
> + goto out;
> + if (!ASSERT_EQ(value, cpu ? 0 : fresh, "value on specified cpu"))
> + goto out;
> + }
> +
> +out:
> + close(map_fd);
> +}
> +
> +static void test_percpu_hash_cpu_flag_create(void)
> +{
> + test_percpu_map_cpu_flag_create(BPF_MAP_TYPE_PERCPU_HASH, 0);
> +}
> +
> +static void test_percpu_hash_cpu_flag_create_malloc(void)
> +{
> + test_percpu_map_cpu_flag_create(BPF_MAP_TYPE_PERCPU_HASH, BPF_F_NO_PREALLOC);
> +}
Can this test give false negatives on the BPF_F_NO_PREALLOC variant?
For preallocated maps, the comment's reasoning holds: max_entries 1 means
there's a single struct htab_elem whose per-cpu area is allocated once and
never freed. When the test deletes key 1, the element goes back to the
freelist with stale 0xDEADC0DE still in its per-cpu area. Creating key 2
gets that same element back, so if pcpu_init_value() is broken, cpu 0 will
see 0xC0FFEE but other CPUs will still see 0xDEADC0DE.
With BPF_F_NO_PREALLOC, the per-cpu area uses bpf_mem_alloc:
kernel/bpf/hashtab.c:htab_elem_free()
bpf_mem_cache_free(&htab->pcpu_ma, l->ptr_to_pptr)
which does unit_free() and pushes to the *current* CPU's free list. The
subsequent create calls bpf_mem_cache_alloc(), which does unit_alloc() and
pops from whatever CPU the second syscall runs on.
If the thread migrated between the delete and the create, unit_alloc() gets
a prefilled zero object from __alloc_percpu_gfp() rather than the
just-freed stale one, so the test passes even on a broken kernel. Only when
both syscalls run on the same CPU does the LIFO allocator return the stale
object and trigger the assertion.
Should this arm either pin the thread with sched_setaffinity() around the
delete/create pair, or loop over all CPUs to make the result deterministic?
> +
> +static void test_lru_percpu_hash_cpu_flag_create(void)
> +{
> + /* lru without prealloc is -ENOTSUPP, so there is no malloc variant */
> + test_percpu_map_cpu_flag_create(BPF_MAP_TYPE_LRU_PERCPU_HASH, 0);
> +}
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/35801690900
next prev parent reply other threads:[~2026-09-23 0:56 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-23 0:07 [PATCH bpf v2 0/2] bpf: fix per-cpu initialization of a BPF_F_CPU created hash element Donggeun Yoo
2026-09-23 0:08 ` [PATCH bpf v2 1/2] bpf: Zero-fill other CPUs when BPF_F_CPU creates a per-cpu " Donggeun Yoo
2026-09-23 0:56 ` bot+bpf-ci
2026-09-24 10:23 ` Donggeun Yoo
2026-09-23 2:09 ` Leon Hwang
2026-09-24 10:22 ` Donggeun Yoo
2026-09-23 0:08 ` [PATCH bpf v2 2/2] selftests/bpf: Test per-cpu initialization of a BPF_F_CPU created element Donggeun Yoo
2026-09-23 0:56 ` bot+bpf-ci [this message]
2026-09-24 10:23 ` Donggeun Yoo
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=3d31f180b472adb3b215571fa73ba38641cc93a33ea2e8e82413f37957c2d99a@mail.kernel.org \
--to=bot+bpf-ci@kernel.org \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=donggeunyoo.kernel@gmail.com \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=ihor.solodrai@linux.dev \
--cc=jolsa@kernel.org \
--cc=leon.hwang@linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=martin.lau@kernel.org \
--cc=martin.lau@linux.dev \
--cc=mason@kernel.org \
--cc=memxor@gmail.com \
--cc=song@kernel.org \
--cc=yonghong.song@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®