From: Leon Hwang <leon.hwang@linux.dev>
To: bpf@vger.kernel.org
Cc: ast@kernel.org, andrii@kernel.org, daniel@iogearbox.net,
olsajiri@gmail.com, yonghong.song@linux.dev, song@kernel.org,
eddyz87@gmail.com, dxu@dxuuu.xyz, deso@posteo.net,
leon.hwang@linux.dev, kernel-patches-bot@fb.com
Subject: [PATCH bpf-next v3 4/6] bpf: Introduce BPF_F_CPU flag for percpu_cgroup_storage maps
Date: Fri, 22 Aug 2025 00:08:15 +0800 [thread overview]
Message-ID: <20250821160817.70285-5-leon.hwang@linux.dev> (raw)
In-Reply-To: <20250821160817.70285-1-leon.hwang@linux.dev>
Introduce BPF_F_ALL_CPUS flag support for percpu_cgroup_storage maps to
allow updating values for all CPUs with a single value.
Introduce BPF_F_CPU flag support for percpu_cgroup_storage maps to allow
updating value for specified CPU.
This enhancement enables:
* Efficient update values across all CPUs with a single value when
BPF_F_ALL_CPUS is set for update_elem API.
* Targeted update or lookup for a specified CPU when BPF_F_CPU is set.
The BPF_F_CPU flag is passed via map_flags of lookup_elem and update_elem
APIs along with embedded cpu field.
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
include/linux/bpf-cgroup.h | 5 ++--
include/linux/bpf.h | 5 ++--
kernel/bpf/local_storage.c | 47 +++++++++++++++++++++++++++++---------
kernel/bpf/syscall.c | 12 ++++------
4 files changed, 46 insertions(+), 23 deletions(-)
diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
index aedf573bdb426..1cb28660aa866 100644
--- a/include/linux/bpf-cgroup.h
+++ b/include/linux/bpf-cgroup.h
@@ -172,7 +172,8 @@ void bpf_cgroup_storage_link(struct bpf_cgroup_storage *storage,
void bpf_cgroup_storage_unlink(struct bpf_cgroup_storage *storage);
int bpf_cgroup_storage_assign(struct bpf_prog_aux *aux, struct bpf_map *map);
-int bpf_percpu_cgroup_storage_copy(struct bpf_map *map, void *key, void *value);
+int bpf_percpu_cgroup_storage_copy(struct bpf_map *map, void *key, void *value,
+ u64 flags);
int bpf_percpu_cgroup_storage_update(struct bpf_map *map, void *key,
void *value, u64 flags);
@@ -467,7 +468,7 @@ static inline struct bpf_cgroup_storage *bpf_cgroup_storage_alloc(
static inline void bpf_cgroup_storage_free(
struct bpf_cgroup_storage *storage) {}
static inline int bpf_percpu_cgroup_storage_copy(struct bpf_map *map, void *key,
- void *value) {
+ void *value, u64 flags) {
return 0;
}
static inline int bpf_percpu_cgroup_storage_update(struct bpf_map *map,
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index dc715eef9cbf4..2684ba32bba0a 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -3733,12 +3733,13 @@ static inline int bpf_map_check_cpu_flags(u64 flags, bool check_all_cpus)
return 0;
}
-static inline bool bpf_map_support_cpu_flags(enum bpf_map_type map_type)
+static inline bool bpf_map_is_percpu(enum bpf_map_type map_type)
{
switch (map_type) {
case BPF_MAP_TYPE_PERCPU_ARRAY:
case BPF_MAP_TYPE_PERCPU_HASH:
case BPF_MAP_TYPE_LRU_PERCPU_HASH:
+ case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE:
return true;
default:
return false;
@@ -3756,7 +3757,7 @@ static inline int bpf_map_check_flags(struct bpf_map *map, u64 flags, bool check
if (!(flags & BPF_F_CPU) && flags >> 32)
return -EINVAL;
- if ((flags & (BPF_F_CPU | BPF_F_ALL_CPUS)) && !bpf_map_support_cpu_flags(map->map_type))
+ if ((flags & (BPF_F_CPU | BPF_F_ALL_CPUS)) && !bpf_map_is_percpu(map->map_type))
return -EINVAL;
return 0;
diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c
index c93a756e035c0..ee60b8cee4e90 100644
--- a/kernel/bpf/local_storage.c
+++ b/kernel/bpf/local_storage.c
@@ -180,18 +180,22 @@ static long cgroup_storage_update_elem(struct bpf_map *map, void *key,
}
int bpf_percpu_cgroup_storage_copy(struct bpf_map *_map, void *key,
- void *value)
+ void *value, u64 map_flags)
{
struct bpf_cgroup_storage_map *map = map_to_storage(_map);
struct bpf_cgroup_storage *storage;
- int cpu, off = 0;
+ int cpu, off = 0, err;
u32 size;
+ err = bpf_map_check_cpu_flags(map_flags, false);
+ if (err)
+ return err;
+
rcu_read_lock();
storage = cgroup_storage_lookup(map, key, false);
if (!storage) {
- rcu_read_unlock();
- return -ENOENT;
+ err = -ENOENT;
+ goto unlock;
}
/* per_cpu areas are zero-filled and bpf programs can only
@@ -199,13 +203,19 @@ int bpf_percpu_cgroup_storage_copy(struct bpf_map *_map, void *key,
* will not leak any kernel data
*/
size = round_up(_map->value_size, 8);
+ if (map_flags & BPF_F_CPU) {
+ cpu = map_flags >> 32;
+ bpf_long_memcpy(value, per_cpu_ptr(storage->percpu_buf, cpu), size);
+ goto unlock;
+ }
for_each_possible_cpu(cpu) {
bpf_long_memcpy(value + off,
per_cpu_ptr(storage->percpu_buf, cpu), size);
off += size;
}
+unlock:
rcu_read_unlock();
- return 0;
+ return err;
}
int bpf_percpu_cgroup_storage_update(struct bpf_map *_map, void *key,
@@ -213,17 +223,21 @@ int bpf_percpu_cgroup_storage_update(struct bpf_map *_map, void *key,
{
struct bpf_cgroup_storage_map *map = map_to_storage(_map);
struct bpf_cgroup_storage *storage;
- int cpu, off = 0;
+ int cpu, off = 0, err;
u32 size;
- if (map_flags != BPF_ANY && map_flags != BPF_EXIST)
+ if ((u32)map_flags & ~(BPF_ANY | BPF_EXIST | BPF_F_CPU | BPF_F_ALL_CPUS))
return -EINVAL;
+ err = bpf_map_check_cpu_flags(map_flags, true);
+ if (err)
+ return err;
+
rcu_read_lock();
storage = cgroup_storage_lookup(map, key, false);
if (!storage) {
- rcu_read_unlock();
- return -ENOENT;
+ err = -ENOENT;
+ goto unlock;
}
/* the user space will provide round_up(value_size, 8) bytes that
@@ -233,13 +247,24 @@ int bpf_percpu_cgroup_storage_update(struct bpf_map *_map, void *key,
* so no kernel data leaks possible
*/
size = round_up(_map->value_size, 8);
+ if (map_flags & BPF_F_CPU) {
+ cpu = map_flags >> 32;
+ bpf_long_memcpy(per_cpu_ptr(storage->percpu_buf, cpu), value, size);
+ goto unlock;
+ }
for_each_possible_cpu(cpu) {
bpf_long_memcpy(per_cpu_ptr(storage->percpu_buf, cpu),
value + off, size);
- off += size;
+ /* same user-provided value is used if
+ * BPF_F_ALL_CPUS is specified, otherwise value is
+ * an array of per-cpu values.
+ */
+ if (!(map_flags & BPF_F_ALL_CPUS))
+ off += size;
}
+unlock:
rcu_read_unlock();
- return 0;
+ return err;
}
static int cgroup_storage_get_next_key(struct bpf_map *_map, void *key,
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 430f013f38f06..3fc52cd0c12de 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -133,13 +133,9 @@ bool bpf_map_write_active(const struct bpf_map *map)
static u32 bpf_map_value_size(const struct bpf_map *map, u64 flags)
{
- if (bpf_map_support_cpu_flags(map->map_type) && (flags & (BPF_F_CPU | BPF_F_ALL_CPUS)))
- return round_up(map->value_size, 8);
- else if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
- map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
- map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY ||
- map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE)
- return round_up(map->value_size, 8) * num_possible_cpus();
+ if (bpf_map_is_percpu(map->map_type))
+ return flags & (BPF_F_CPU | BPF_F_ALL_CPUS) ? round_up(map->value_size, 8) :
+ round_up(map->value_size, 8) * num_possible_cpus();
else if (IS_FD_MAP(map))
return sizeof(u32);
else
@@ -318,7 +314,7 @@ static int bpf_map_copy_value(struct bpf_map *map, void *key, void *value,
} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
err = bpf_percpu_array_copy(map, key, value, flags);
} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
- err = bpf_percpu_cgroup_storage_copy(map, key, value);
+ err = bpf_percpu_cgroup_storage_copy(map, key, value, flags);
} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
err = bpf_stackmap_copy(map, key, value);
} else if (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map)) {
--
2.50.1
next prev parent reply other threads:[~2025-08-21 16:08 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-21 16:08 [PATCH bpf-next v3 0/6] Introduce BPF_F_CPU flag for percpu maps Leon Hwang
2025-08-21 16:08 ` [PATCH bpf-next v3 1/6] bpf: Introduce internal check_map_flags helper function Leon Hwang
2025-08-22 22:14 ` Andrii Nakryiko
2025-08-26 15:24 ` Leon Hwang
2025-08-26 22:50 ` Andrii Nakryiko
2025-08-21 16:08 ` [PATCH bpf-next v3 2/6] bpf: Introduce BPF_F_CPU flag for percpu_array maps Leon Hwang
2025-08-22 22:14 ` Andrii Nakryiko
2025-08-26 14:45 ` Leon Hwang
2025-08-21 16:08 ` [PATCH bpf-next v3 3/6] bpf: Introduce BPF_F_CPU flag for percpu_hash and lru_percpu_hash maps Leon Hwang
2025-08-22 22:14 ` Andrii Nakryiko
2025-08-26 15:14 ` Leon Hwang
2025-08-21 16:08 ` Leon Hwang [this message]
2025-08-21 16:08 ` [PATCH bpf-next v3 5/6] libbpf: Support BPF_F_CPU for percpu maps Leon Hwang
2025-08-22 22:20 ` Andrii Nakryiko
2025-08-26 15:35 ` Leon Hwang
2025-08-26 22:50 ` Andrii Nakryiko
2025-08-21 16:08 ` [PATCH bpf-next v3 6/6] selftests/bpf: Add cases to test BPF_F_CPU flag Leon Hwang
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=20250821160817.70285-5-leon.hwang@linux.dev \
--to=leon.hwang@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=deso@posteo.net \
--cc=dxu@dxuuu.xyz \
--cc=eddyz87@gmail.com \
--cc=kernel-patches-bot@fb.com \
--cc=olsajiri@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 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.