xref: /linux/tools/testing/selftests/bpf/progs/kmem_cache_iter.c (revision 25768de50b1f2dbb6ea44bd5148a87fe2c9c3688)
1a496d0cdSNamhyung Kim // SPDX-License-Identifier: GPL-2.0
2a496d0cdSNamhyung Kim /* Copyright (c) 2024 Google */
3e626a13fSAndrii Nakryiko #include <vmlinux.h>
4a496d0cdSNamhyung Kim #include <bpf/bpf_helpers.h>
5a496d0cdSNamhyung Kim #include <bpf/bpf_tracing.h>
6*e5e4799eSNamhyung Kim #include "bpf_experimental.h"
7a496d0cdSNamhyung Kim 
8a496d0cdSNamhyung Kim char _license[] SEC("license") = "GPL";
9a496d0cdSNamhyung Kim 
10a496d0cdSNamhyung Kim #define SLAB_NAME_MAX  32
11a496d0cdSNamhyung Kim 
12a496d0cdSNamhyung Kim struct kmem_cache_result {
13a496d0cdSNamhyung Kim 	char name[SLAB_NAME_MAX];
14a496d0cdSNamhyung Kim 	long obj_size;
15a496d0cdSNamhyung Kim };
16a496d0cdSNamhyung Kim 
17a496d0cdSNamhyung Kim struct {
18a496d0cdSNamhyung Kim 	__uint(type, BPF_MAP_TYPE_HASH);
19a496d0cdSNamhyung Kim 	__uint(key_size, sizeof(void *));
20a496d0cdSNamhyung Kim 	__uint(value_size, SLAB_NAME_MAX);
21a496d0cdSNamhyung Kim 	__uint(max_entries, 1);
22a496d0cdSNamhyung Kim } slab_hash SEC(".maps");
23a496d0cdSNamhyung Kim 
24a496d0cdSNamhyung Kim struct {
25a496d0cdSNamhyung Kim 	__uint(type, BPF_MAP_TYPE_ARRAY);
26a496d0cdSNamhyung Kim 	__uint(key_size, sizeof(int));
27a496d0cdSNamhyung Kim 	__uint(value_size, sizeof(struct kmem_cache_result));
28a496d0cdSNamhyung Kim 	__uint(max_entries, 1024);
29a496d0cdSNamhyung Kim } slab_result SEC(".maps");
30a496d0cdSNamhyung Kim 
31a496d0cdSNamhyung Kim extern struct kmem_cache *bpf_get_kmem_cache(u64 addr) __ksym;
32a496d0cdSNamhyung Kim 
33a496d0cdSNamhyung Kim /* Result, will be checked by userspace */
34a496d0cdSNamhyung Kim int task_struct_found;
35a496d0cdSNamhyung Kim int kmem_cache_seen;
36*e5e4799eSNamhyung Kim int open_coded_seen;
37a496d0cdSNamhyung Kim 
38a496d0cdSNamhyung Kim SEC("iter/kmem_cache")
39a496d0cdSNamhyung Kim int slab_info_collector(struct bpf_iter__kmem_cache *ctx)
40a496d0cdSNamhyung Kim {
41a496d0cdSNamhyung Kim 	struct seq_file *seq = ctx->meta->seq;
42a496d0cdSNamhyung Kim 	struct kmem_cache *s = ctx->s;
43a496d0cdSNamhyung Kim 	struct kmem_cache_result *r;
44a496d0cdSNamhyung Kim 	int idx;
45a496d0cdSNamhyung Kim 
46a496d0cdSNamhyung Kim 	if (s) {
47a496d0cdSNamhyung Kim 		/* To make sure if the slab_iter implements the seq interface
48a496d0cdSNamhyung Kim 		 * properly and it's also useful for debugging.
49a496d0cdSNamhyung Kim 		 */
50a496d0cdSNamhyung Kim 		BPF_SEQ_PRINTF(seq, "%s: %u\n", s->name, s->size);
51a496d0cdSNamhyung Kim 
52a496d0cdSNamhyung Kim 		idx = kmem_cache_seen;
53a496d0cdSNamhyung Kim 		r = bpf_map_lookup_elem(&slab_result, &idx);
54a496d0cdSNamhyung Kim 		if (r == NULL)
55a496d0cdSNamhyung Kim 			return 0;
56a496d0cdSNamhyung Kim 
57a496d0cdSNamhyung Kim 		kmem_cache_seen++;
58a496d0cdSNamhyung Kim 
59a496d0cdSNamhyung Kim 		/* Save name and size to match /proc/slabinfo */
60a496d0cdSNamhyung Kim 		bpf_probe_read_kernel_str(r->name, sizeof(r->name), s->name);
61a496d0cdSNamhyung Kim 		r->obj_size = s->size;
62a496d0cdSNamhyung Kim 
63a496d0cdSNamhyung Kim 		if (!bpf_strncmp(r->name, 11, "task_struct"))
64a496d0cdSNamhyung Kim 			bpf_map_update_elem(&slab_hash, &s, r->name, BPF_NOEXIST);
65a496d0cdSNamhyung Kim 	}
66a496d0cdSNamhyung Kim 
67a496d0cdSNamhyung Kim 	return 0;
68a496d0cdSNamhyung Kim }
69a496d0cdSNamhyung Kim 
70a496d0cdSNamhyung Kim SEC("raw_tp/bpf_test_finish")
71a496d0cdSNamhyung Kim int BPF_PROG(check_task_struct)
72a496d0cdSNamhyung Kim {
73a496d0cdSNamhyung Kim 	u64 curr = bpf_get_current_task();
74a496d0cdSNamhyung Kim 	struct kmem_cache *s;
75a496d0cdSNamhyung Kim 	char *name;
76a496d0cdSNamhyung Kim 
77a496d0cdSNamhyung Kim 	s = bpf_get_kmem_cache(curr);
78a496d0cdSNamhyung Kim 	if (s == NULL) {
79a496d0cdSNamhyung Kim 		task_struct_found = -1;
80a496d0cdSNamhyung Kim 		return 0;
81a496d0cdSNamhyung Kim 	}
82a496d0cdSNamhyung Kim 	name = bpf_map_lookup_elem(&slab_hash, &s);
83a496d0cdSNamhyung Kim 	if (name && !bpf_strncmp(name, 11, "task_struct"))
84a496d0cdSNamhyung Kim 		task_struct_found = 1;
85a496d0cdSNamhyung Kim 	else
86a496d0cdSNamhyung Kim 		task_struct_found = -2;
87a496d0cdSNamhyung Kim 	return 0;
88a496d0cdSNamhyung Kim }
89*e5e4799eSNamhyung Kim 
90*e5e4799eSNamhyung Kim SEC("syscall")
91*e5e4799eSNamhyung Kim int open_coded_iter(const void *ctx)
92*e5e4799eSNamhyung Kim {
93*e5e4799eSNamhyung Kim 	struct kmem_cache *s;
94*e5e4799eSNamhyung Kim 
95*e5e4799eSNamhyung Kim 	bpf_for_each(kmem_cache, s) {
96*e5e4799eSNamhyung Kim 		struct kmem_cache_result *r;
97*e5e4799eSNamhyung Kim 
98*e5e4799eSNamhyung Kim 		r = bpf_map_lookup_elem(&slab_result, &open_coded_seen);
99*e5e4799eSNamhyung Kim 		if (!r)
100*e5e4799eSNamhyung Kim 			break;
101*e5e4799eSNamhyung Kim 
102*e5e4799eSNamhyung Kim 		if (r->obj_size != s->size)
103*e5e4799eSNamhyung Kim 			break;
104*e5e4799eSNamhyung Kim 
105*e5e4799eSNamhyung Kim 		open_coded_seen++;
106*e5e4799eSNamhyung Kim 	}
107*e5e4799eSNamhyung Kim 	return 0;
108*e5e4799eSNamhyung Kim }
109