Skip to content

Commit 688f64e

Browse files
teawaterKernel Patches Daemon
authored andcommitted
samples/bpf: add example memcg eBPF program
Add a sample eBPF program demonstrating the new memory controller eBPF support. This example serves as both a reference implementation and a validation tool for the memcg eBPF functionality. The sample includes: - memcg_printk.bpf.c: An eBPF program that attaches to the try_charge_memcg hook and prints detailed information about memory charging events, including: * Memory cgroup name * GFP flags and page count * Reclamation options * Affected memory cgroup (when applicable) - memcg_printk.c: A userspace loader program that: * Loads the eBPF object file * Finds and attaches the memcg_ops struct ops * Keeps the program attached until interrupted * Provides proper error handling and cleanup Usage: $ ./samples/bpf/memcg_printk This will attach the eBPF program to the memcg charging path. Output can be viewed via kernel trace events (e.g., trace_printk logs). The program demonstrates: - Accessing memory cgroup context fields - Using bpf_printk for debugging and monitoring - Proper struct ops registration via libbpf - Integration with the kernel's BPF infrastructure Signed-off-by: Geliang Tang <[email protected]> Signed-off-by: Hui Zhu <[email protected]>
1 parent 3cbefa6 commit 688f64e

File tree

4 files changed

+116
-0
lines changed

4 files changed

+116
-0
lines changed

MAINTAINERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6357,6 +6357,8 @@ F: mm/memcontrol_bpf.h
63576357
F: mm/page_counter.c
63586358
F: mm/swap_cgroup.c
63596359
F: samples/cgroup/*
6360+
F: samples/memcg_printk.bpf.c
6361+
F: samples/memcg_printk.c
63606362
F: tools/testing/selftests/bpf/*/memcg_ops.c
63616363
F: tools/testing/selftests/cgroup/memcg_protection.m
63626364
F: tools/testing/selftests/cgroup/test_hugetlb_memcg.c

samples/bpf/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ tprogs-y += xdp_fwd
3737
tprogs-y += task_fd_query
3838
tprogs-y += ibumad
3939
tprogs-y += hbm
40+
tprogs-y += memcg_printk
4041

4142
# Libbpf dependencies
4243
LIBBPF_SRC = $(TOOLS_PATH)/lib/bpf
@@ -122,6 +123,7 @@ always-y += task_fd_query_kern.o
122123
always-y += ibumad_kern.o
123124
always-y += hbm_out_kern.o
124125
always-y += hbm_edt_kern.o
126+
always-y += memcg_printk.bpf.o
125127

126128
COMMON_CFLAGS = $(TPROGS_USER_CFLAGS)
127129
TPROGS_LDFLAGS = $(TPROGS_USER_LDFLAGS)

samples/bpf/memcg_printk.bpf.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include "vmlinux.h"
4+
5+
#include <bpf/bpf_helpers.h>
6+
#include <bpf/bpf_tracing.h>
7+
8+
SEC("struct_ops/try_charge_memcg")
9+
int BPF_PROG(handle_try_charge_memcg, struct try_charge_memcg *tcm)
10+
{
11+
bpf_printk(
12+
"memcg %s gfp_mask 0x%x nr_pages %lu reclaim_options 0x%lx\n",
13+
tcm->memcg->css.cgroup->kn->name,
14+
tcm->gfp_mask,
15+
tcm->nr_pages,
16+
tcm->reclaim_options);
17+
if (!tcm->charge_done)
18+
bpf_printk("memcg %s mem_over_limit %s\n",
19+
tcm->memcg->css.cgroup->kn->name,
20+
tcm->mem_over_limit->css.cgroup->kn->name);
21+
22+
return 0;
23+
}
24+
25+
SEC(".struct_ops")
26+
struct memcg_ops mcg_ops = {
27+
.try_charge_memcg = (void *)handle_try_charge_memcg,
28+
};
29+
30+
char _license[] SEC("license") = "GPL";

samples/bpf/memcg_printk.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
#define _GNU_SOURCE
3+
4+
#include <errno.h>
5+
#include <signal.h>
6+
#include <bpf/libbpf.h>
7+
8+
static bool exiting;
9+
10+
static void sig_handler(int sig)
11+
{
12+
exiting = true;
13+
}
14+
15+
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
16+
{
17+
return vfprintf(stderr, format, args);
18+
}
19+
20+
int main(int argc, char **argv)
21+
{
22+
struct bpf_object *obj = NULL;
23+
struct bpf_link *link = NULL;
24+
struct bpf_map *map;
25+
char filename[256];
26+
int err;
27+
28+
exiting = false;
29+
30+
signal(SIGINT, sig_handler);
31+
signal(SIGTERM, sig_handler);
32+
33+
libbpf_set_print(libbpf_print_fn);
34+
35+
snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]);
36+
obj = bpf_object__open_file(filename, NULL);
37+
err = libbpf_get_error(obj);
38+
if (err) {
39+
fprintf(stderr, "Failed to open BPF object file: %d\n",
40+
err);
41+
obj = NULL;
42+
goto cleanup;
43+
}
44+
45+
err = bpf_object__load(obj);
46+
if (err) {
47+
fprintf(stderr, "Failed to loading BPF object file: %d\n",
48+
err);
49+
goto cleanup;
50+
}
51+
52+
map = bpf_object__find_map_by_name(obj, "mcg_ops");
53+
if (!map) {
54+
fprintf(stderr, "Failed to find struct_ops map 'mcg_ops'\n");
55+
err = -ENOENT;
56+
goto cleanup;
57+
}
58+
59+
link = bpf_map__attach_struct_ops(map);
60+
err = libbpf_get_error(link);
61+
if (err) {
62+
fprintf(stderr, "Failed to attach struct ops: %d\n",
63+
err);
64+
link = NULL;
65+
goto cleanup;
66+
}
67+
68+
printf("Press Ctrl+C to exit...\n");
69+
70+
while (!exiting)
71+
sleep(1);
72+
73+
printf("Bye!\n");
74+
75+
cleanup:
76+
if (link)
77+
bpf_link__destroy(link);
78+
if (obj)
79+
bpf_object__close(obj);
80+
81+
return err;
82+
}

0 commit comments

Comments
 (0)