xref: /aosp_15_r20/external/bcc/libbpf-tools/fsslower.bpf.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* Copyright (c) 2020 Wenbo Zhang */
3 #include <vmlinux.h>
4 #include <bpf/bpf_helpers.h>
5 #include <bpf/bpf_core_read.h>
6 #include <bpf/bpf_tracing.h>
7 #include "bits.bpf.h"
8 #include "fsslower.h"
9 
10 #define MAX_ENTRIES	8192
11 
12 const volatile pid_t target_pid = 0;
13 const volatile __u64 min_lat_ns = 0;
14 
15 struct data {
16 	__u64 ts;
17 	loff_t start;
18 	loff_t end;
19 	struct file *fp;
20 };
21 
22 struct {
23 	__uint(type, BPF_MAP_TYPE_HASH);
24 	__uint(max_entries, MAX_ENTRIES);
25 	__type(key, __u32);
26 	__type(value, struct data);
27 } starts SEC(".maps");
28 
29 struct {
30 	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
31 	__uint(key_size, sizeof(__u32));
32 	__uint(value_size, sizeof(__u32));
33 } events SEC(".maps");
34 
probe_entry(struct file * fp,loff_t start,loff_t end)35 static int probe_entry(struct file *fp, loff_t start, loff_t end)
36 {
37 	__u64 pid_tgid = bpf_get_current_pid_tgid();
38 	__u32 pid = pid_tgid >> 32;
39 	__u32 tid = (__u32)pid_tgid;
40 	struct data data;
41 
42 	if (!fp)
43 		return 0;
44 
45 	if (target_pid && target_pid != pid)
46 		return 0;
47 
48 	data.ts = bpf_ktime_get_ns();
49 	data.start = start;
50 	data.end = end;
51 	data.fp = fp;
52 	bpf_map_update_elem(&starts, &tid, &data, BPF_ANY);
53 	return 0;
54 }
55 
probe_exit(void * ctx,enum fs_file_op op,ssize_t size)56 static int probe_exit(void *ctx, enum fs_file_op op, ssize_t size)
57 {
58 	__u64 pid_tgid = bpf_get_current_pid_tgid();
59 	__u32 pid = pid_tgid >> 32;
60 	__u32 tid = (__u32)pid_tgid;
61 	__u64 end_ns, delta_ns;
62 	const __u8 *file_name;
63 	struct data *datap;
64 	struct event event = {};
65 	struct dentry *dentry;
66 	struct file *fp;
67 
68 	if (target_pid && target_pid != pid)
69 		return 0;
70 
71 	datap = bpf_map_lookup_elem(&starts, &tid);
72 	if (!datap)
73 		return 0;
74 
75 	bpf_map_delete_elem(&starts, &tid);
76 
77 	end_ns = bpf_ktime_get_ns();
78 	delta_ns = end_ns - datap->ts;
79 	if (delta_ns <= min_lat_ns)
80 		return 0;
81 
82 	event.delta_us = delta_ns / 1000;
83 	event.end_ns = end_ns;
84 	event.offset = datap->start;
85 	if (op != F_FSYNC)
86 		event.size = size;
87 	else
88 		event.size = datap->end - datap->start;
89 	event.pid = pid;
90 	event.op = op;
91 	fp = datap->fp;
92 	dentry = BPF_CORE_READ(fp, f_path.dentry);
93 	file_name = BPF_CORE_READ(dentry, d_name.name);
94 	bpf_probe_read_kernel_str(&event.file, sizeof(event.file), file_name);
95 	bpf_get_current_comm(&event.task, sizeof(event.task));
96 	bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));
97 	return 0;
98 }
99 
100 SEC("kprobe/dummy_file_read")
BPF_KPROBE(file_read_entry,struct kiocb * iocb)101 int BPF_KPROBE(file_read_entry, struct kiocb *iocb)
102 {
103 	struct file *fp = BPF_CORE_READ(iocb, ki_filp);
104 	loff_t start = BPF_CORE_READ(iocb, ki_pos);
105 
106 	return probe_entry(fp, start, 0);
107 }
108 
109 SEC("kretprobe/dummy_file_read")
BPF_KRETPROBE(file_read_exit,ssize_t ret)110 int BPF_KRETPROBE(file_read_exit, ssize_t ret)
111 {
112 	return probe_exit(ctx, F_READ, ret);
113 }
114 
115 SEC("kprobe/dummy_file_write")
BPF_KPROBE(file_write_entry,struct kiocb * iocb)116 int BPF_KPROBE(file_write_entry, struct kiocb *iocb)
117 {
118 	struct file *fp = BPF_CORE_READ(iocb, ki_filp);
119 	loff_t start = BPF_CORE_READ(iocb, ki_pos);
120 
121 	return probe_entry(fp, start, 0);
122 }
123 
124 SEC("kretprobe/dummy_file_write")
BPF_KRETPROBE(file_write_exit,ssize_t ret)125 int BPF_KRETPROBE(file_write_exit, ssize_t ret)
126 {
127 	return probe_exit(ctx, F_WRITE, ret);
128 }
129 
130 SEC("kprobe/dummy_file_open")
BPF_KPROBE(file_open_entry,struct inode * inode,struct file * file)131 int BPF_KPROBE(file_open_entry, struct inode *inode, struct file *file)
132 {
133 	return probe_entry(file, 0, 0);
134 }
135 
136 SEC("kretprobe/dummy_file_open")
BPF_KRETPROBE(file_open_exit)137 int BPF_KRETPROBE(file_open_exit)
138 {
139 	return probe_exit(ctx, F_OPEN, 0);
140 }
141 
142 SEC("kprobe/dummy_file_sync")
BPF_KPROBE(file_sync_entry,struct file * file,loff_t start,loff_t end)143 int BPF_KPROBE(file_sync_entry, struct file *file, loff_t start, loff_t end)
144 {
145 	return probe_entry(file, start, end);
146 }
147 
148 SEC("kretprobe/dummy_file_sync")
BPF_KRETPROBE(file_sync_exit)149 int BPF_KRETPROBE(file_sync_exit)
150 {
151 	return probe_exit(ctx, F_FSYNC, 0);
152 }
153 
154 SEC("fentry/dummy_file_read")
BPF_PROG(file_read_fentry,struct kiocb * iocb)155 int BPF_PROG(file_read_fentry, struct kiocb *iocb)
156 {
157 	struct file *fp = iocb->ki_filp;
158 	loff_t start = iocb->ki_pos;
159 
160 	return probe_entry(fp, start, 0);
161 }
162 
163 SEC("fexit/dummy_file_read")
BPF_PROG(file_read_fexit,struct kiocb * iocb,struct iov_iter * to,ssize_t ret)164 int BPF_PROG(file_read_fexit, struct kiocb *iocb, struct iov_iter *to, ssize_t ret)
165 {
166 	return probe_exit(ctx, F_READ, ret);
167 }
168 
169 SEC("fentry/dummy_file_write")
BPF_PROG(file_write_fentry,struct kiocb * iocb)170 int BPF_PROG(file_write_fentry, struct kiocb *iocb)
171 {
172 	struct file *fp = iocb->ki_filp;
173 	loff_t start = iocb->ki_pos;
174 
175 	return probe_entry(fp, start, 0);
176 }
177 
178 SEC("fexit/dummy_file_write")
BPF_PROG(file_write_fexit,struct kiocb * iocb,struct iov_iter * from,ssize_t ret)179 int BPF_PROG(file_write_fexit, struct kiocb *iocb, struct iov_iter *from, ssize_t ret)
180 {
181 	return probe_exit(ctx, F_WRITE, ret);
182 }
183 
184 SEC("fentry/dummy_file_open")
BPF_PROG(file_open_fentry,struct inode * inode,struct file * file)185 int BPF_PROG(file_open_fentry, struct inode *inode, struct file *file)
186 {
187 	return probe_entry(file, 0, 0);
188 }
189 
190 SEC("fexit/dummy_file_open")
BPF_PROG(file_open_fexit)191 int BPF_PROG(file_open_fexit)
192 {
193 	return probe_exit(ctx, F_OPEN, 0);
194 }
195 
196 SEC("fentry/dummy_file_sync")
BPF_PROG(file_sync_fentry,struct file * file,loff_t start,loff_t end)197 int BPF_PROG(file_sync_fentry, struct file *file, loff_t start, loff_t end)
198 {
199 	return probe_entry(file, start, end);
200 }
201 
202 SEC("fexit/dummy_file_sync")
BPF_PROG(file_sync_fexit)203 int BPF_PROG(file_sync_fexit)
204 {
205 	return probe_exit(ctx, F_FSYNC, 0);
206 }
207 
208 char LICENSE[] SEC("license") = "GPL";
209