summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/bpf/progs
diff options
context:
space:
mode:
authorKumar Kartikeya Dwivedi <memxor@gmail.com>2026-06-09 22:25:46 +0200
committerAlexei Starovoitov <ast@kernel.org>2026-06-09 21:23:11 -0700
commit2e7c6cb4d8437a2fe7cd95aac7ca53d7eb05e9f4 (patch)
tree703f21d578314c1ee115b1c9a44ee754bdbd90cf /tools/testing/selftests/bpf/progs
parent4b84518137ce841eca2acae83096adb829dad05c (diff)
downloadlinux-next-2e7c6cb4d8437a2fe7cd95aac7ca53d7eb05e9f4.tar.gz
linux-next-2e7c6cb4d8437a2fe7cd95aac7ca53d7eb05e9f4.zip
selftests/bpf: Exercise kptr map update lifetime
Add focused map_kptr coverage for BPF-side map updates that touch values containing referenced kptrs. The new syscall programs stash the testmod refcounted object in an array map, a preallocated hash map, and a no-prealloc hash map, then update the same map from BPF. The refcount must remain elevated after the update, while the userspace runner destroys the skeleton and reuses the existing refcount wait to confirm map teardown releases the kptr. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20260609202548.3571690-5-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/testing/selftests/bpf/progs')
-rw-r--r--tools/testing/selftests/bpf/progs/map_kptr.c89
1 files changed, 86 insertions, 3 deletions
diff --git a/tools/testing/selftests/bpf/progs/map_kptr.c b/tools/testing/selftests/bpf/progs/map_kptr.c
index e708ffbe1f61..3fbefc568e0a 100644
--- a/tools/testing/selftests/bpf/progs/map_kptr.c
+++ b/tools/testing/selftests/bpf/progs/map_kptr.c
@@ -489,8 +489,7 @@ int test_map_kptr_ref3(struct __sk_buff *ctx)
int num_of_refs;
-SEC("syscall")
-int count_ref(void *ctx)
+static __always_inline int read_ref_count(void)
{
struct prog_test_ref_kfunc *p;
unsigned long arg = 0;
@@ -500,12 +499,96 @@ int count_ref(void *ctx)
return 1;
num_of_refs = p->cnt.refs.counter;
-
bpf_kfunc_call_test_release(p);
return 0;
}
SEC("syscall")
+int count_ref(void *ctx)
+{
+ return read_ref_count();
+}
+
+static __always_inline int stash_ref_ptr(struct map_value *v)
+{
+ struct prog_test_ref_kfunc *p, *old;
+ unsigned long arg = 0;
+
+ p = bpf_kfunc_call_test_acquire(&arg);
+ if (!p)
+ return 1;
+
+ old = bpf_kptr_xchg(&v->ref_ptr, p);
+ if (old) {
+ bpf_kfunc_call_test_release(old);
+ old = bpf_kptr_xchg(&v->ref_ptr, NULL);
+ if (old)
+ bpf_kfunc_call_test_release(old);
+ return 2;
+ }
+ return 0;
+}
+
+static __always_inline int check_refs(int expected)
+{
+ int ret;
+
+ ret = read_ref_count();
+ if (ret)
+ return ret;
+ return num_of_refs == expected ? 0 : 3;
+}
+
+SEC("syscall")
+int test_array_map_update_kptr(void *ctx)
+{
+ struct map_value init = {}, *v;
+ int key = 0, ret;
+
+ v = bpf_map_lookup_elem(&array_map, &key);
+ if (!v)
+ return 1;
+ ret = stash_ref_ptr(v);
+ if (ret)
+ return ret;
+ ret = check_refs(3);
+ if (ret)
+ return ret;
+ ret = bpf_map_update_elem(&array_map, &key, &init, BPF_EXIST);
+ if (ret)
+ return 4;
+ return check_refs(3);
+}
+
+#define DEFINE_HASH_UPDATE_KPTR_TEST(name, map) \
+SEC("syscall") \
+int name(void *ctx) \
+{ \
+ struct map_value init = {}, *v; \
+ int key = 0, ret; \
+ \
+ ret = bpf_map_update_elem(&map, &key, &init, BPF_NOEXIST); \
+ if (ret) \
+ return 1; \
+ v = bpf_map_lookup_elem(&map, &key); \
+ if (!v) \
+ return 2; \
+ ret = stash_ref_ptr(v); \
+ if (ret) \
+ return ret; \
+ ret = check_refs(3); \
+ if (ret) \
+ return ret; \
+ ret = bpf_map_update_elem(&map, &key, &init, BPF_EXIST); \
+ if (ret) \
+ return 4; \
+ return check_refs(3); \
+}
+
+DEFINE_HASH_UPDATE_KPTR_TEST(test_hash_map_update_kptr, hash_map)
+DEFINE_HASH_UPDATE_KPTR_TEST(test_hash_malloc_map_update_kptr, hash_malloc_map)
+
+SEC("syscall")
int test_ls_map_kptr_ref1(void *ctx)
{
struct task_struct *current;