From: John Fastabend <john.fastabend@gmail.com>
To: Yafang Shao <laoar.shao@gmail.com>,
ast@kernel.org, daniel@iogearbox.net,
john.fastabend@gmail.com, andrii@kernel.org,
martin.lau@linux.dev, eddyz87@gmail.com, song@kernel.org,
yonghong.song@linux.dev, kpsingh@kernel.org, sdf@google.com,
haoluo@google.com, jolsa@kernel.org
Cc: bpf@vger.kernel.org, Yafang Shao <laoar.shao@gmail.com>
Subject: RE: [PATCH bpf-next 1/2] bpf: Add bits iterator
Date: Mon, 26 Feb 2024 15:21:49 -0800 [thread overview]
Message-ID: <65dd1d0d6e41b_20e0a208a9@john.notmuch> (raw)
In-Reply-To: <20240218114818.13585-2-laoar.shao@gmail.com>
Yafang Shao wrote:
> Add three new kfuncs for the bits iterator:
> - bpf_iter_bits_new
> Initialize a new bits iterator for a given memory area. Due to the
> limitation of bpf memalloc, the max number of bits that can be iterated
> over is limited to (4096 * 8).
> - bpf_iter_bits_next
> Get the next bit in a bpf_iter_bits
> - bpf_iter_bits_destroy
> Destroy a bpf_iter_bits
>
> The bits iterator facilitates the iteration of the bits of a memory area,
> such as cpumask. It can be used in any context and on any address.
Just curious as I see more and a more kfuncs. Did you try to implement
this with existing BPF? The main trick looks to be to get an implementation
of FIND_NEXT_BIT? Without trying seems doable with one of the bpf loop
iterators?
Also this requires a bpf_iter_bits_new across every iteration of the
BPF program or anytime we need to pick up the changes. Any reason
we can't just read the memory directly?
Thanks,
John
>
> Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
> ---
> kernel/bpf/helpers.c | 100 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 100 insertions(+)
>
> diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
> index 93edf730d288..052f63891834 100644
> --- a/kernel/bpf/helpers.c
> +++ b/kernel/bpf/helpers.c
> @@ -2542,6 +2542,103 @@ __bpf_kfunc void bpf_throw(u64 cookie)
> WARN(1, "A call to BPF exception callback should never return\n");
> }
>
> +struct bpf_iter_bits {
> + __u64 __opaque[2];
> +} __aligned(8);
> +
> +struct bpf_iter_bits_kern {
> + unsigned long *bits;
> + u32 nr_bits;
> + int bit;
> +} __aligned(8);
> +
> +/**
> + * bpf_iter_bits_new() - Initialize a new bits iterator for a given memory area
> + * @it: The new bpf_iter_bits to be created
> + * @unsafe_ptr__ign: A ponter pointing to a memory area to be iterated over
> + * @nr_bits: The number of bits to be iterated over. Due to the limitation of
> + * memalloc, it can't greater than (4096 * 8).
> + *
> + * This function initializes a new bpf_iter_bits structure for iterating over
> + * a memory area which is specified by the @unsafe_ptr__ign and @nr_bits. It
> + * copy the data of the memory area to the newly created bpf_iter_bits @it for
> + * subsequent iteration operations.
> + *
> + * On success, 0 is returned. On failure, ERR is returned.
> + */
> +__bpf_kfunc int
> +bpf_iter_bits_new(struct bpf_iter_bits *it, const void *unsafe_ptr__ign, u32 nr_bits)
> +{
> + struct bpf_iter_bits_kern *kit = (void *)it;
> + u32 size = BITS_TO_BYTES(nr_bits);
> + int err;
> +
> + BUILD_BUG_ON(sizeof(struct bpf_iter_bits_kern) != sizeof(struct bpf_iter_bits));
> + BUILD_BUG_ON(__alignof__(struct bpf_iter_bits_kern) !=
> + __alignof__(struct bpf_iter_bits));
> +
> + if (!unsafe_ptr__ign || !nr_bits) {
> + kit->bits = NULL;
> + return -EINVAL;
> + }
> +
> + kit->bits = bpf_mem_alloc(&bpf_global_ma, size);
> + if (!kit->bits)
> + return -ENOMEM;
> +
> + err = bpf_probe_read_kernel_common(kit->bits, size, unsafe_ptr__ign);
Specifically, this why can't we iterate over unsafe_ptr__ign?
> + if (err) {
> + bpf_mem_free(&bpf_global_ma, kit->bits);
> + kit->bits = NULL;
> + return err;
> + }
> +
> + kit->nr_bits = nr_bits;
> + kit->bit = -1;
> + return 0;
> +}
> +
> +/**
> + * bpf_iter_bits_next() - Get the next bit in a bpf_iter_bits
> + * @it: The bpf_iter_bits to be checked
> + *
> + * This function returns a pointer to a number representing the value of the
> + * next bit in the bits.
> + *
> + * If there are no further bit available, it returns NULL.
> + */
> +__bpf_kfunc int *bpf_iter_bits_next(struct bpf_iter_bits *it)
> +{
> + struct bpf_iter_bits_kern *kit = (void *)it;
> + const unsigned long *bits = kit->bits;
> + int bit;
> +
> + if (!bits)
> + return NULL;
> +
> + bit = find_next_bit(bits, kit->nr_bits, kit->bit + 1);
Seems like this should be ok over unsafe memory as long as find_next_bit
is bounded?
> + if (bit >= kit->nr_bits)
> + return NULL;
> +
> + kit->bit = bit;
> + return &kit->bit;
> +}
Thanks for working on this looks useful to me.
next prev parent reply other threads:[~2024-02-26 23:21 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-18 11:48 [PATCH bpf-next 0/2] bpf: Add a generic bits iterator Yafang Shao
2024-02-18 11:48 ` [PATCH bpf-next 1/2] bpf: Add " Yafang Shao
2024-02-26 23:21 ` John Fastabend [this message]
2024-02-27 0:20 ` Alexei Starovoitov
2024-02-27 0:34 ` John Fastabend
2024-02-18 11:48 ` [PATCH bpf-next 2/2] selftests/bpf: Add selftest for bits iter Yafang Shao
2024-02-22 17:36 ` Alexei Starovoitov
2024-02-23 2:29 ` Yafang Shao
2024-02-23 11:52 ` Eduard Zingerman
2024-02-25 2:29 ` Yafang Shao
2024-02-25 19:38 ` kernel test robot
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=65dd1d0d6e41b_20e0a208a9@john.notmuch \
--to=john.fastabend@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=haoluo@google.com \
--cc=jolsa@kernel.org \
--cc=kpsingh@kernel.org \
--cc=laoar.shao@gmail.com \
--cc=martin.lau@linux.dev \
--cc=sdf@google.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 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.