From: Ihor Solodrai <ihor.solodrai@linux.dev>
To: Emil Tsalapatis <emil@etsalapatis.com>, bpf@vger.kernel.org
Cc: ast@kernel.org, andrii@kernel.org, memxor@gmail.com,
daniel@iogearbox.net, eddyz87@gmail.com,
mattbobrowski@google.com, song@kernel.org
Subject: Re: [PATCH bpf-next 4/5] selftests/bpf: Add arena-based bitmap data structure
Date: Tue, 30 Jun 2026 14:44:10 -0700 [thread overview]
Message-ID: <c09d9126-6de1-4aec-8755-ad34a1ab9dcf@linux.dev> (raw)
In-Reply-To: <20260618085626.19633-5-emil@etsalapatis.com>
On 6/18/26 1:56 AM, Emil Tsalapatis wrote:
> Add an arena-based word-aligned bitmap data struture. The
> structure is useful as a building block, e.g., sched-ext
> uses it to represent cpumask structures.
>
> Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
> ---
> .../bpf/libarena/include/libarena/bitmap.h | 31 +++
> .../selftests/bpf/libarena/src/bitmap.bpf.c | 191 ++++++++++++++++++
> 2 files changed, 222 insertions(+)
> create mode 100644 tools/testing/selftests/bpf/libarena/include/libarena/bitmap.h
> create mode 100644 tools/testing/selftests/bpf/libarena/src/bitmap.bpf.c
>
> diff --git a/tools/testing/selftests/bpf/libarena/include/libarena/bitmap.h b/tools/testing/selftests/bpf/libarena/include/libarena/bitmap.h
> new file mode 100644
> index 000000000000..11623a82e66a
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/libarena/include/libarena/bitmap.h
> @@ -0,0 +1,31 @@
> +#pragma once
> +
> +#define BITS_PER_BYTE 8
> +#define BYTES_TO_BITS(nb) ((nb) * BITS_PER_BYTE)
> +
> +#define BITS_PER_LONG (sizeof(long) * BITS_PER_BYTE)
> +#define BITS_TO_LONGS(nr) (((nr) + BITS_PER_LONG - 1) / BITS_PER_LONG)
> +#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
> +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
> +
> +struct bitmap {
> + u64 bits[0];
> +};
> +
> +struct bitmap __arena *bmp_alloc(size_t bits);
> +void bmp_free(struct bitmap __arena *bmp);
> +
> +void bmp_set_bit(u32 bit, struct bitmap __arena *bmp);
> +void bmp_clear_bit(u32 bit, struct bitmap __arena *bmp);
> +bool bmp_test_bit(u32 bit, struct bitmap __arena *bmp);
> +bool bmp_test_and_clear_bit(u32 bit, struct bitmap __arena *bmp);
> +
> +void bmp_clear(size_t bits, struct bitmap __arena *bmp);
> +void bmp_and(size_t bits, struct bitmap __arena *dst, struct bitmap __arena *src1, struct bitmap __arena *src2);
> +void bmp_or(size_t bits, struct bitmap __arena *dst, struct bitmap __arena *src1, struct bitmap __arena *src2);
> +bool bmp_empty(size_t bits, struct bitmap __arena *bmp);
> +void bmp_copy(size_t bits, struct bitmap __arena *dst, struct bitmap __arena *src);
> +
> +bool bmp_intersects(size_t bits, struct bitmap __arena *arg1, struct bitmap __arena *arg2);
> +bool bmp_subset(size_t bits, struct bitmap __arena *big, struct bitmap __arena *small);
> +void bmp_print(size_t bits, struct bitmap __arena *bmp);
> diff --git a/tools/testing/selftests/bpf/libarena/src/bitmap.bpf.c b/tools/testing/selftests/bpf/libarena/src/bitmap.bpf.c
> new file mode 100644
> index 000000000000..a8ca814aa0c8
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/libarena/src/bitmap.bpf.c
> @@ -0,0 +1,191 @@
> +// SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
> +/*
> + * Copyright (c) 2025-2026 Meta Platforms, Inc. and affiliates.
> + * Copyright (c) 2025-2026 Emil Tsalapatis <emil@etsalapatis.com>
> + */
> +
> +#include <libarena/common.h>
> +
> +#include <libarena/asan.h>
> +#include <libarena/bitmap.h>
> +
> +__weak
> +struct bitmap __arena *bmp_alloc(size_t bits)
> +{
> + struct bitmap __arena *bmp;
> + size_t size = BITS_TO_LONGS(bits) * sizeof(bmp->bits[0]);
> +
> + /* Assume long-aligned masks. */
> + if (bits % BITS_PER_LONG)
> + return NULL;
I think this check may be dropped.
There is code below to handle non-aligned bits (bmp_last_word_mask
etc), but here we forbid them, so masking doesn't run.
And you mentioned in the cover that this is supposed to be used as
cpumask, but nr_cpu_ids is unlikely to be a multiple of 64, right?
> +
> + bmp = (struct bitmap __arena *)arena_malloc(size);
> + if (!bmp)
> + return NULL;
> +
> + bmp_clear(bits, bmp);
> +
> + return bmp;
> +}
> +
> +__weak
> +void bmp_free(struct bitmap __arena *bmp)
> +{
> + arena_free(bmp);
> +}
> +
> +__weak
> +void bmp_set_bit(u32 bit, struct bitmap __arena *bmp)
> +{
> + bmp->bits[BIT_WORD(bit)] |= BIT_MASK(bit);
> +}
> +
> +__weak
> +void bmp_clear_bit(u32 bit, struct bitmap __arena *bmp)
> +{
> + bmp->bits[BIT_WORD(bit)] &= ~BIT_MASK(bit);
> +}
> +
> +__weak
> +bool bmp_test_bit(u32 bit, struct bitmap __arena *bmp)
> +{
> + return bmp->bits[BIT_WORD(bit)] & BIT_MASK(bit);
> +}
> +
> +__weak
> +bool bmp_test_and_clear_bit(u32 bit, struct bitmap __arena *bmp)
> +{
> + u64 val = BIT_MASK(bit);
> + u32 idx = BIT_WORD(bit);
> + u64 actual;
> +
> + do {
> + u64 old = bmp->bits[idx];
> +
> + if (!(old & val))
> + return false;
> +
> + u64 new = old & ~val;
> + actual = cmpxchg(&bmp->bits[idx], old, new);
bmp_test_and_clear_bit() is atomic, but bmp_set_bit() and
bmp_clear_bit() aren't.
So the concurrent set/clear on the same word can lose updates (last
writer wins), right? Only test_and_clear seems to be safe
cross-CPU. Are we missing test_and_set?
There is a doc on atomic bitops [1], and apparently in the kernel
there is a convention to have a non-atomic variant for each RMW atomic
operation, prefixed with '__', for example: test_and_clear_bit() and
__test_and_clear_bit().
Maybe libarena should follow the same convention?
[1] https://docs.kernel.org/core-api/wrappers/atomic_bitops.html
> +
> + if (actual == old)
> + return true;
> +
> + } while (can_loop);
> +
> + return false;
> +}
> +
> [...]
next prev parent reply other threads:[~2026-06-30 21:44 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-18 8:56 [PATCH bpf-next 0/5] selftests/bpf: libarena cleanup and bitmap struct Emil Tsalapatis
2026-06-18 8:56 ` [PATCH bpf-next 1/5] libarena/selftests: Replace leftover st_ prefix with test_ Emil Tsalapatis
2026-06-30 19:21 ` Ihor Solodrai
2026-07-01 4:23 ` Emil Tsalapatis
2026-06-18 8:56 ` [PATCH bpf-next 2/5] selftests/bpf: libarena: Fix can-loop zero variable definition Emil Tsalapatis
2026-06-18 9:09 ` sashiko-bot
2026-06-25 19:15 ` Eduard Zingerman
2026-06-30 19:28 ` Ihor Solodrai
2026-07-01 4:28 ` Emil Tsalapatis
2026-06-18 8:56 ` [PATCH bpf-next 3/5] selftests/bpf: libarena: Clean up allocation state before buddy tests Emil Tsalapatis
2026-06-18 9:47 ` bot+bpf-ci
2026-06-23 23:42 ` Emil Tsalapatis
2026-06-30 20:23 ` Ihor Solodrai
2026-06-18 8:56 ` [PATCH bpf-next 4/5] selftests/bpf: Add arena-based bitmap data structure Emil Tsalapatis
2026-06-18 9:08 ` sashiko-bot
2026-06-23 23:30 ` Emil Tsalapatis
2026-06-18 9:47 ` bot+bpf-ci
2026-06-30 21:44 ` Ihor Solodrai [this message]
2026-07-01 4:33 ` Emil Tsalapatis
2026-06-18 8:56 ` [PATCH bpf-next 5/5] selftests/bpf: libarena: Add bitmap selftets Emil Tsalapatis
2026-06-30 21:46 ` Ihor Solodrai
2026-07-01 4:33 ` Emil Tsalapatis
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=c09d9126-6de1-4aec-8755-ad34a1ab9dcf@linux.dev \
--to=ihor.solodrai@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=mattbobrowski@google.com \
--cc=memxor@gmail.com \
--cc=song@kernel.org \
/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.