1*387f9dfdSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*387f9dfdSAndroid Build Coastguard Worker // Copyright (c) 2020 Wenbo Zhang
3*387f9dfdSAndroid Build Coastguard Worker #include <vmlinux.h>
4*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_helpers.h>
5*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_core_read.h>
6*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf_tracing.h>
7*387f9dfdSAndroid Build Coastguard Worker #include "biosnoop.h"
8*387f9dfdSAndroid Build Coastguard Worker #include "core_fixes.bpf.h"
9*387f9dfdSAndroid Build Coastguard Worker
10*387f9dfdSAndroid Build Coastguard Worker #define MAX_ENTRIES 10240
11*387f9dfdSAndroid Build Coastguard Worker
12*387f9dfdSAndroid Build Coastguard Worker const volatile bool filter_cg = false;
13*387f9dfdSAndroid Build Coastguard Worker const volatile bool targ_queued = false;
14*387f9dfdSAndroid Build Coastguard Worker const volatile bool filter_dev = false;
15*387f9dfdSAndroid Build Coastguard Worker const volatile __u32 targ_dev = 0;
16*387f9dfdSAndroid Build Coastguard Worker const volatile __u64 min_ns = 0;
17*387f9dfdSAndroid Build Coastguard Worker
18*387f9dfdSAndroid Build Coastguard Worker extern __u32 LINUX_KERNEL_VERSION __kconfig;
19*387f9dfdSAndroid Build Coastguard Worker
20*387f9dfdSAndroid Build Coastguard Worker struct {
21*387f9dfdSAndroid Build Coastguard Worker __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
22*387f9dfdSAndroid Build Coastguard Worker __type(key, u32);
23*387f9dfdSAndroid Build Coastguard Worker __type(value, u32);
24*387f9dfdSAndroid Build Coastguard Worker __uint(max_entries, 1);
25*387f9dfdSAndroid Build Coastguard Worker } cgroup_map SEC(".maps");
26*387f9dfdSAndroid Build Coastguard Worker
27*387f9dfdSAndroid Build Coastguard Worker struct piddata {
28*387f9dfdSAndroid Build Coastguard Worker char comm[TASK_COMM_LEN];
29*387f9dfdSAndroid Build Coastguard Worker u32 pid;
30*387f9dfdSAndroid Build Coastguard Worker };
31*387f9dfdSAndroid Build Coastguard Worker
32*387f9dfdSAndroid Build Coastguard Worker struct {
33*387f9dfdSAndroid Build Coastguard Worker __uint(type, BPF_MAP_TYPE_HASH);
34*387f9dfdSAndroid Build Coastguard Worker __uint(max_entries, MAX_ENTRIES);
35*387f9dfdSAndroid Build Coastguard Worker __type(key, struct request *);
36*387f9dfdSAndroid Build Coastguard Worker __type(value, struct piddata);
37*387f9dfdSAndroid Build Coastguard Worker } infobyreq SEC(".maps");
38*387f9dfdSAndroid Build Coastguard Worker
39*387f9dfdSAndroid Build Coastguard Worker struct stage {
40*387f9dfdSAndroid Build Coastguard Worker u64 insert;
41*387f9dfdSAndroid Build Coastguard Worker u64 issue;
42*387f9dfdSAndroid Build Coastguard Worker __u32 dev;
43*387f9dfdSAndroid Build Coastguard Worker };
44*387f9dfdSAndroid Build Coastguard Worker
45*387f9dfdSAndroid Build Coastguard Worker struct {
46*387f9dfdSAndroid Build Coastguard Worker __uint(type, BPF_MAP_TYPE_HASH);
47*387f9dfdSAndroid Build Coastguard Worker __uint(max_entries, MAX_ENTRIES);
48*387f9dfdSAndroid Build Coastguard Worker __type(key, struct request *);
49*387f9dfdSAndroid Build Coastguard Worker __type(value, struct stage);
50*387f9dfdSAndroid Build Coastguard Worker } start SEC(".maps");
51*387f9dfdSAndroid Build Coastguard Worker
52*387f9dfdSAndroid Build Coastguard Worker struct {
53*387f9dfdSAndroid Build Coastguard Worker __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
54*387f9dfdSAndroid Build Coastguard Worker __uint(key_size, sizeof(u32));
55*387f9dfdSAndroid Build Coastguard Worker __uint(value_size, sizeof(u32));
56*387f9dfdSAndroid Build Coastguard Worker } events SEC(".maps");
57*387f9dfdSAndroid Build Coastguard Worker
58*387f9dfdSAndroid Build Coastguard Worker static __always_inline
trace_pid(struct request * rq)59*387f9dfdSAndroid Build Coastguard Worker int trace_pid(struct request *rq)
60*387f9dfdSAndroid Build Coastguard Worker {
61*387f9dfdSAndroid Build Coastguard Worker u64 id = bpf_get_current_pid_tgid();
62*387f9dfdSAndroid Build Coastguard Worker struct piddata piddata = {};
63*387f9dfdSAndroid Build Coastguard Worker
64*387f9dfdSAndroid Build Coastguard Worker piddata.pid = id >> 32;
65*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&piddata.comm, sizeof(&piddata.comm));
66*387f9dfdSAndroid Build Coastguard Worker bpf_map_update_elem(&infobyreq, &rq, &piddata, 0);
67*387f9dfdSAndroid Build Coastguard Worker return 0;
68*387f9dfdSAndroid Build Coastguard Worker }
69*387f9dfdSAndroid Build Coastguard Worker
70*387f9dfdSAndroid Build Coastguard Worker SEC("fentry/blk_account_io_start")
BPF_PROG(blk_account_io_start,struct request * rq)71*387f9dfdSAndroid Build Coastguard Worker int BPF_PROG(blk_account_io_start, struct request *rq)
72*387f9dfdSAndroid Build Coastguard Worker {
73*387f9dfdSAndroid Build Coastguard Worker if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
74*387f9dfdSAndroid Build Coastguard Worker return 0;
75*387f9dfdSAndroid Build Coastguard Worker
76*387f9dfdSAndroid Build Coastguard Worker return trace_pid(rq);
77*387f9dfdSAndroid Build Coastguard Worker }
78*387f9dfdSAndroid Build Coastguard Worker
79*387f9dfdSAndroid Build Coastguard Worker SEC("tp_btf/block_io_start")
BPF_PROG(block_io_start,struct request * rq)80*387f9dfdSAndroid Build Coastguard Worker int BPF_PROG(block_io_start, struct request *rq)
81*387f9dfdSAndroid Build Coastguard Worker {
82*387f9dfdSAndroid Build Coastguard Worker if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
83*387f9dfdSAndroid Build Coastguard Worker return 0;
84*387f9dfdSAndroid Build Coastguard Worker
85*387f9dfdSAndroid Build Coastguard Worker return trace_pid(rq);
86*387f9dfdSAndroid Build Coastguard Worker }
87*387f9dfdSAndroid Build Coastguard Worker
88*387f9dfdSAndroid Build Coastguard Worker SEC("kprobe/blk_account_io_merge_bio")
BPF_KPROBE(blk_account_io_merge_bio,struct request * rq)89*387f9dfdSAndroid Build Coastguard Worker int BPF_KPROBE(blk_account_io_merge_bio, struct request *rq)
90*387f9dfdSAndroid Build Coastguard Worker {
91*387f9dfdSAndroid Build Coastguard Worker if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
92*387f9dfdSAndroid Build Coastguard Worker return 0;
93*387f9dfdSAndroid Build Coastguard Worker
94*387f9dfdSAndroid Build Coastguard Worker return trace_pid(rq);
95*387f9dfdSAndroid Build Coastguard Worker }
96*387f9dfdSAndroid Build Coastguard Worker
97*387f9dfdSAndroid Build Coastguard Worker static __always_inline
trace_rq_start(struct request * rq,bool insert)98*387f9dfdSAndroid Build Coastguard Worker int trace_rq_start(struct request *rq, bool insert)
99*387f9dfdSAndroid Build Coastguard Worker {
100*387f9dfdSAndroid Build Coastguard Worker struct stage *stagep, stage = {};
101*387f9dfdSAndroid Build Coastguard Worker u64 ts = bpf_ktime_get_ns();
102*387f9dfdSAndroid Build Coastguard Worker
103*387f9dfdSAndroid Build Coastguard Worker stagep = bpf_map_lookup_elem(&start, &rq);
104*387f9dfdSAndroid Build Coastguard Worker if (!stagep) {
105*387f9dfdSAndroid Build Coastguard Worker struct gendisk *disk = get_disk(rq);
106*387f9dfdSAndroid Build Coastguard Worker
107*387f9dfdSAndroid Build Coastguard Worker stage.dev = disk ? MKDEV(BPF_CORE_READ(disk, major),
108*387f9dfdSAndroid Build Coastguard Worker BPF_CORE_READ(disk, first_minor)) : 0;
109*387f9dfdSAndroid Build Coastguard Worker if (filter_dev && targ_dev != stage.dev)
110*387f9dfdSAndroid Build Coastguard Worker return 0;
111*387f9dfdSAndroid Build Coastguard Worker stagep = &stage;
112*387f9dfdSAndroid Build Coastguard Worker }
113*387f9dfdSAndroid Build Coastguard Worker if (insert)
114*387f9dfdSAndroid Build Coastguard Worker stagep->insert = ts;
115*387f9dfdSAndroid Build Coastguard Worker else
116*387f9dfdSAndroid Build Coastguard Worker stagep->issue = ts;
117*387f9dfdSAndroid Build Coastguard Worker if (stagep == &stage)
118*387f9dfdSAndroid Build Coastguard Worker bpf_map_update_elem(&start, &rq, stagep, 0);
119*387f9dfdSAndroid Build Coastguard Worker return 0;
120*387f9dfdSAndroid Build Coastguard Worker }
121*387f9dfdSAndroid Build Coastguard Worker
122*387f9dfdSAndroid Build Coastguard Worker SEC("tp_btf/block_rq_insert")
BPF_PROG(block_rq_insert)123*387f9dfdSAndroid Build Coastguard Worker int BPF_PROG(block_rq_insert)
124*387f9dfdSAndroid Build Coastguard Worker {
125*387f9dfdSAndroid Build Coastguard Worker if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
126*387f9dfdSAndroid Build Coastguard Worker return 0;
127*387f9dfdSAndroid Build Coastguard Worker
128*387f9dfdSAndroid Build Coastguard Worker /**
129*387f9dfdSAndroid Build Coastguard Worker * commit a54895fa (v5.11-rc1) changed tracepoint argument list
130*387f9dfdSAndroid Build Coastguard Worker * from TP_PROTO(struct request_queue *q, struct request *rq)
131*387f9dfdSAndroid Build Coastguard Worker * to TP_PROTO(struct request *rq)
132*387f9dfdSAndroid Build Coastguard Worker */
133*387f9dfdSAndroid Build Coastguard Worker if (LINUX_KERNEL_VERSION >= KERNEL_VERSION(5, 11, 0))
134*387f9dfdSAndroid Build Coastguard Worker return trace_rq_start((void *)ctx[0], true);
135*387f9dfdSAndroid Build Coastguard Worker else
136*387f9dfdSAndroid Build Coastguard Worker return trace_rq_start((void *)ctx[1], true);
137*387f9dfdSAndroid Build Coastguard Worker }
138*387f9dfdSAndroid Build Coastguard Worker
139*387f9dfdSAndroid Build Coastguard Worker SEC("tp_btf/block_rq_issue")
BPF_PROG(block_rq_issue)140*387f9dfdSAndroid Build Coastguard Worker int BPF_PROG(block_rq_issue)
141*387f9dfdSAndroid Build Coastguard Worker {
142*387f9dfdSAndroid Build Coastguard Worker if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
143*387f9dfdSAndroid Build Coastguard Worker return 0;
144*387f9dfdSAndroid Build Coastguard Worker
145*387f9dfdSAndroid Build Coastguard Worker /**
146*387f9dfdSAndroid Build Coastguard Worker * commit a54895fa (v5.11-rc1) changed tracepoint argument list
147*387f9dfdSAndroid Build Coastguard Worker * from TP_PROTO(struct request_queue *q, struct request *rq)
148*387f9dfdSAndroid Build Coastguard Worker * to TP_PROTO(struct request *rq)
149*387f9dfdSAndroid Build Coastguard Worker */
150*387f9dfdSAndroid Build Coastguard Worker if (LINUX_KERNEL_VERSION >= KERNEL_VERSION(5, 11, 0))
151*387f9dfdSAndroid Build Coastguard Worker return trace_rq_start((void *)ctx[0], false);
152*387f9dfdSAndroid Build Coastguard Worker else
153*387f9dfdSAndroid Build Coastguard Worker return trace_rq_start((void *)ctx[1], false);
154*387f9dfdSAndroid Build Coastguard Worker }
155*387f9dfdSAndroid Build Coastguard Worker
156*387f9dfdSAndroid Build Coastguard Worker SEC("tp_btf/block_rq_complete")
BPF_PROG(block_rq_complete,struct request * rq,int error,unsigned int nr_bytes)157*387f9dfdSAndroid Build Coastguard Worker int BPF_PROG(block_rq_complete, struct request *rq, int error,
158*387f9dfdSAndroid Build Coastguard Worker unsigned int nr_bytes)
159*387f9dfdSAndroid Build Coastguard Worker {
160*387f9dfdSAndroid Build Coastguard Worker if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
161*387f9dfdSAndroid Build Coastguard Worker return 0;
162*387f9dfdSAndroid Build Coastguard Worker
163*387f9dfdSAndroid Build Coastguard Worker u64 ts = bpf_ktime_get_ns();
164*387f9dfdSAndroid Build Coastguard Worker struct piddata *piddatap;
165*387f9dfdSAndroid Build Coastguard Worker struct event event = {};
166*387f9dfdSAndroid Build Coastguard Worker struct stage *stagep;
167*387f9dfdSAndroid Build Coastguard Worker s64 delta;
168*387f9dfdSAndroid Build Coastguard Worker
169*387f9dfdSAndroid Build Coastguard Worker stagep = bpf_map_lookup_elem(&start, &rq);
170*387f9dfdSAndroid Build Coastguard Worker if (!stagep)
171*387f9dfdSAndroid Build Coastguard Worker return 0;
172*387f9dfdSAndroid Build Coastguard Worker delta = (s64)(ts - stagep->issue);
173*387f9dfdSAndroid Build Coastguard Worker if (delta < 0 || delta < min_ns)
174*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
175*387f9dfdSAndroid Build Coastguard Worker piddatap = bpf_map_lookup_elem(&infobyreq, &rq);
176*387f9dfdSAndroid Build Coastguard Worker if (!piddatap) {
177*387f9dfdSAndroid Build Coastguard Worker event.comm[0] = '?';
178*387f9dfdSAndroid Build Coastguard Worker } else {
179*387f9dfdSAndroid Build Coastguard Worker __builtin_memcpy(&event.comm, piddatap->comm,
180*387f9dfdSAndroid Build Coastguard Worker sizeof(event.comm));
181*387f9dfdSAndroid Build Coastguard Worker event.pid = piddatap->pid;
182*387f9dfdSAndroid Build Coastguard Worker }
183*387f9dfdSAndroid Build Coastguard Worker event.delta = delta;
184*387f9dfdSAndroid Build Coastguard Worker if (targ_queued && BPF_CORE_READ(rq, q, elevator)) {
185*387f9dfdSAndroid Build Coastguard Worker if (!stagep->insert)
186*387f9dfdSAndroid Build Coastguard Worker event.qdelta = -1; /* missed or don't insert entry */
187*387f9dfdSAndroid Build Coastguard Worker else
188*387f9dfdSAndroid Build Coastguard Worker event.qdelta = stagep->issue - stagep->insert;
189*387f9dfdSAndroid Build Coastguard Worker }
190*387f9dfdSAndroid Build Coastguard Worker event.ts = ts;
191*387f9dfdSAndroid Build Coastguard Worker event.sector = BPF_CORE_READ(rq, __sector);
192*387f9dfdSAndroid Build Coastguard Worker event.len = BPF_CORE_READ(rq, __data_len);
193*387f9dfdSAndroid Build Coastguard Worker event.cmd_flags = BPF_CORE_READ(rq, cmd_flags);
194*387f9dfdSAndroid Build Coastguard Worker event.dev = stagep->dev;
195*387f9dfdSAndroid Build Coastguard Worker bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event,
196*387f9dfdSAndroid Build Coastguard Worker sizeof(event));
197*387f9dfdSAndroid Build Coastguard Worker
198*387f9dfdSAndroid Build Coastguard Worker cleanup:
199*387f9dfdSAndroid Build Coastguard Worker bpf_map_delete_elem(&start, &rq);
200*387f9dfdSAndroid Build Coastguard Worker bpf_map_delete_elem(&infobyreq, &rq);
201*387f9dfdSAndroid Build Coastguard Worker return 0;
202*387f9dfdSAndroid Build Coastguard Worker }
203*387f9dfdSAndroid Build Coastguard Worker
204*387f9dfdSAndroid Build Coastguard Worker char LICENSE[] SEC("license") = "GPL";
205