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
8*387f9dfdSAndroid Build Coastguard Worker #include "biolatency.h"
9*387f9dfdSAndroid Build Coastguard Worker #include "bits.bpf.h"
10*387f9dfdSAndroid Build Coastguard Worker #include "core_fixes.bpf.h"
11*387f9dfdSAndroid Build Coastguard Worker
12*387f9dfdSAndroid Build Coastguard Worker #define MAX_ENTRIES 10240
13*387f9dfdSAndroid Build Coastguard Worker
14*387f9dfdSAndroid Build Coastguard Worker extern int LINUX_KERNEL_VERSION __kconfig;
15*387f9dfdSAndroid Build Coastguard Worker
16*387f9dfdSAndroid Build Coastguard Worker const volatile bool filter_cg = false;
17*387f9dfdSAndroid Build Coastguard Worker const volatile bool targ_per_disk = false;
18*387f9dfdSAndroid Build Coastguard Worker const volatile bool targ_per_flag = false;
19*387f9dfdSAndroid Build Coastguard Worker const volatile bool targ_queued = false;
20*387f9dfdSAndroid Build Coastguard Worker const volatile bool targ_ms = false;
21*387f9dfdSAndroid Build Coastguard Worker const volatile bool filter_dev = false;
22*387f9dfdSAndroid Build Coastguard Worker const volatile __u32 targ_dev = 0;
23*387f9dfdSAndroid Build Coastguard Worker
24*387f9dfdSAndroid Build Coastguard Worker struct {
25*387f9dfdSAndroid Build Coastguard Worker __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY);
26*387f9dfdSAndroid Build Coastguard Worker __type(key, u32);
27*387f9dfdSAndroid Build Coastguard Worker __type(value, u32);
28*387f9dfdSAndroid Build Coastguard Worker __uint(max_entries, 1);
29*387f9dfdSAndroid Build Coastguard Worker } cgroup_map SEC(".maps");
30*387f9dfdSAndroid Build Coastguard Worker
31*387f9dfdSAndroid Build Coastguard Worker struct {
32*387f9dfdSAndroid Build Coastguard Worker __uint(type, BPF_MAP_TYPE_HASH);
33*387f9dfdSAndroid Build Coastguard Worker __uint(max_entries, MAX_ENTRIES);
34*387f9dfdSAndroid Build Coastguard Worker __type(key, struct request *);
35*387f9dfdSAndroid Build Coastguard Worker __type(value, u64);
36*387f9dfdSAndroid Build Coastguard Worker } start SEC(".maps");
37*387f9dfdSAndroid Build Coastguard Worker
38*387f9dfdSAndroid Build Coastguard Worker static struct hist initial_hist;
39*387f9dfdSAndroid Build Coastguard Worker
40*387f9dfdSAndroid Build Coastguard Worker struct {
41*387f9dfdSAndroid Build Coastguard Worker __uint(type, BPF_MAP_TYPE_HASH);
42*387f9dfdSAndroid Build Coastguard Worker __uint(max_entries, MAX_ENTRIES);
43*387f9dfdSAndroid Build Coastguard Worker __type(key, struct hist_key);
44*387f9dfdSAndroid Build Coastguard Worker __type(value, struct hist);
45*387f9dfdSAndroid Build Coastguard Worker } hists SEC(".maps");
46*387f9dfdSAndroid Build Coastguard Worker
trace_rq_start(struct request * rq,int issue)47*387f9dfdSAndroid Build Coastguard Worker static int __always_inline trace_rq_start(struct request *rq, int issue)
48*387f9dfdSAndroid Build Coastguard Worker {
49*387f9dfdSAndroid Build Coastguard Worker u64 ts;
50*387f9dfdSAndroid Build Coastguard Worker
51*387f9dfdSAndroid Build Coastguard Worker if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
52*387f9dfdSAndroid Build Coastguard Worker return 0;
53*387f9dfdSAndroid Build Coastguard Worker
54*387f9dfdSAndroid Build Coastguard Worker if (issue && targ_queued && BPF_CORE_READ(rq, q, elevator))
55*387f9dfdSAndroid Build Coastguard Worker return 0;
56*387f9dfdSAndroid Build Coastguard Worker
57*387f9dfdSAndroid Build Coastguard Worker ts = bpf_ktime_get_ns();
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard Worker if (filter_dev) {
60*387f9dfdSAndroid Build Coastguard Worker struct gendisk *disk = get_disk(rq);
61*387f9dfdSAndroid Build Coastguard Worker u32 dev;
62*387f9dfdSAndroid Build Coastguard Worker
63*387f9dfdSAndroid Build Coastguard Worker dev = disk ? MKDEV(BPF_CORE_READ(disk, major),
64*387f9dfdSAndroid Build Coastguard Worker BPF_CORE_READ(disk, first_minor)) : 0;
65*387f9dfdSAndroid Build Coastguard Worker if (targ_dev != dev)
66*387f9dfdSAndroid Build Coastguard Worker return 0;
67*387f9dfdSAndroid Build Coastguard Worker }
68*387f9dfdSAndroid Build Coastguard Worker bpf_map_update_elem(&start, &rq, &ts, 0);
69*387f9dfdSAndroid Build Coastguard Worker return 0;
70*387f9dfdSAndroid Build Coastguard Worker }
71*387f9dfdSAndroid Build Coastguard Worker
handle_block_rq_insert(__u64 * ctx)72*387f9dfdSAndroid Build Coastguard Worker static int handle_block_rq_insert(__u64 *ctx)
73*387f9dfdSAndroid Build Coastguard Worker {
74*387f9dfdSAndroid Build Coastguard Worker /**
75*387f9dfdSAndroid Build Coastguard Worker * commit a54895fa (v5.11-rc1) changed tracepoint argument list
76*387f9dfdSAndroid Build Coastguard Worker * from TP_PROTO(struct request_queue *q, struct request *rq)
77*387f9dfdSAndroid Build Coastguard Worker * to TP_PROTO(struct request *rq)
78*387f9dfdSAndroid Build Coastguard Worker */
79*387f9dfdSAndroid Build Coastguard Worker if (LINUX_KERNEL_VERSION < KERNEL_VERSION(5, 11, 0))
80*387f9dfdSAndroid Build Coastguard Worker return trace_rq_start((void *)ctx[1], false);
81*387f9dfdSAndroid Build Coastguard Worker else
82*387f9dfdSAndroid Build Coastguard Worker return trace_rq_start((void *)ctx[0], false);
83*387f9dfdSAndroid Build Coastguard Worker }
84*387f9dfdSAndroid Build Coastguard Worker
handle_block_rq_issue(__u64 * ctx)85*387f9dfdSAndroid Build Coastguard Worker static int handle_block_rq_issue(__u64 *ctx)
86*387f9dfdSAndroid Build Coastguard Worker {
87*387f9dfdSAndroid Build Coastguard Worker /**
88*387f9dfdSAndroid Build Coastguard Worker * commit a54895fa (v5.11-rc1) changed tracepoint argument list
89*387f9dfdSAndroid Build Coastguard Worker * from TP_PROTO(struct request_queue *q, struct request *rq)
90*387f9dfdSAndroid Build Coastguard Worker * to TP_PROTO(struct request *rq)
91*387f9dfdSAndroid Build Coastguard Worker */
92*387f9dfdSAndroid Build Coastguard Worker if (LINUX_KERNEL_VERSION < KERNEL_VERSION(5, 11, 0))
93*387f9dfdSAndroid Build Coastguard Worker return trace_rq_start((void *)ctx[1], true);
94*387f9dfdSAndroid Build Coastguard Worker else
95*387f9dfdSAndroid Build Coastguard Worker return trace_rq_start((void *)ctx[0], true);
96*387f9dfdSAndroid Build Coastguard Worker }
97*387f9dfdSAndroid Build Coastguard Worker
handle_block_rq_complete(struct request * rq,int error,unsigned int nr_bytes)98*387f9dfdSAndroid Build Coastguard Worker static int handle_block_rq_complete(struct request *rq, int error, unsigned int nr_bytes)
99*387f9dfdSAndroid Build Coastguard Worker {
100*387f9dfdSAndroid Build Coastguard Worker u64 slot, *tsp, ts = bpf_ktime_get_ns();
101*387f9dfdSAndroid Build Coastguard Worker struct hist_key hkey = {};
102*387f9dfdSAndroid Build Coastguard Worker struct hist *histp;
103*387f9dfdSAndroid Build Coastguard Worker s64 delta;
104*387f9dfdSAndroid Build Coastguard Worker u64 udelta;
105*387f9dfdSAndroid Build Coastguard Worker
106*387f9dfdSAndroid Build Coastguard Worker if (filter_cg && !bpf_current_task_under_cgroup(&cgroup_map, 0))
107*387f9dfdSAndroid Build Coastguard Worker return 0;
108*387f9dfdSAndroid Build Coastguard Worker
109*387f9dfdSAndroid Build Coastguard Worker tsp = bpf_map_lookup_elem(&start, &rq);
110*387f9dfdSAndroid Build Coastguard Worker if (!tsp)
111*387f9dfdSAndroid Build Coastguard Worker return 0;
112*387f9dfdSAndroid Build Coastguard Worker
113*387f9dfdSAndroid Build Coastguard Worker delta = (s64)(ts - *tsp);
114*387f9dfdSAndroid Build Coastguard Worker if (delta < 0)
115*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
116*387f9dfdSAndroid Build Coastguard Worker
117*387f9dfdSAndroid Build Coastguard Worker udelta = (u64)delta;
118*387f9dfdSAndroid Build Coastguard Worker
119*387f9dfdSAndroid Build Coastguard Worker if (targ_per_disk) {
120*387f9dfdSAndroid Build Coastguard Worker struct gendisk *disk = get_disk(rq);
121*387f9dfdSAndroid Build Coastguard Worker
122*387f9dfdSAndroid Build Coastguard Worker hkey.dev = disk ? MKDEV(BPF_CORE_READ(disk, major),
123*387f9dfdSAndroid Build Coastguard Worker BPF_CORE_READ(disk, first_minor)) : 0;
124*387f9dfdSAndroid Build Coastguard Worker }
125*387f9dfdSAndroid Build Coastguard Worker if (targ_per_flag)
126*387f9dfdSAndroid Build Coastguard Worker hkey.cmd_flags = BPF_CORE_READ(rq, cmd_flags);
127*387f9dfdSAndroid Build Coastguard Worker
128*387f9dfdSAndroid Build Coastguard Worker histp = bpf_map_lookup_elem(&hists, &hkey);
129*387f9dfdSAndroid Build Coastguard Worker if (!histp) {
130*387f9dfdSAndroid Build Coastguard Worker bpf_map_update_elem(&hists, &hkey, &initial_hist, 0);
131*387f9dfdSAndroid Build Coastguard Worker histp = bpf_map_lookup_elem(&hists, &hkey);
132*387f9dfdSAndroid Build Coastguard Worker if (!histp)
133*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
134*387f9dfdSAndroid Build Coastguard Worker }
135*387f9dfdSAndroid Build Coastguard Worker
136*387f9dfdSAndroid Build Coastguard Worker if (targ_ms)
137*387f9dfdSAndroid Build Coastguard Worker udelta /= 1000000U;
138*387f9dfdSAndroid Build Coastguard Worker else
139*387f9dfdSAndroid Build Coastguard Worker udelta /= 1000U;
140*387f9dfdSAndroid Build Coastguard Worker slot = log2l(udelta);
141*387f9dfdSAndroid Build Coastguard Worker if (slot >= MAX_SLOTS)
142*387f9dfdSAndroid Build Coastguard Worker slot = MAX_SLOTS - 1;
143*387f9dfdSAndroid Build Coastguard Worker __sync_fetch_and_add(&histp->slots[slot], 1);
144*387f9dfdSAndroid Build Coastguard Worker
145*387f9dfdSAndroid Build Coastguard Worker cleanup:
146*387f9dfdSAndroid Build Coastguard Worker bpf_map_delete_elem(&start, &rq);
147*387f9dfdSAndroid Build Coastguard Worker return 0;
148*387f9dfdSAndroid Build Coastguard Worker }
149*387f9dfdSAndroid Build Coastguard Worker
150*387f9dfdSAndroid Build Coastguard Worker SEC("tp_btf/block_rq_insert")
block_rq_insert_btf(u64 * ctx)151*387f9dfdSAndroid Build Coastguard Worker int block_rq_insert_btf(u64 *ctx)
152*387f9dfdSAndroid Build Coastguard Worker {
153*387f9dfdSAndroid Build Coastguard Worker return handle_block_rq_insert(ctx);
154*387f9dfdSAndroid Build Coastguard Worker }
155*387f9dfdSAndroid Build Coastguard Worker
156*387f9dfdSAndroid Build Coastguard Worker SEC("tp_btf/block_rq_issue")
block_rq_issue_btf(u64 * ctx)157*387f9dfdSAndroid Build Coastguard Worker int block_rq_issue_btf(u64 *ctx)
158*387f9dfdSAndroid Build Coastguard Worker {
159*387f9dfdSAndroid Build Coastguard Worker return handle_block_rq_issue(ctx);
160*387f9dfdSAndroid Build Coastguard Worker }
161*387f9dfdSAndroid Build Coastguard Worker
162*387f9dfdSAndroid Build Coastguard Worker SEC("tp_btf/block_rq_complete")
BPF_PROG(block_rq_complete_btf,struct request * rq,int error,unsigned int nr_bytes)163*387f9dfdSAndroid Build Coastguard Worker int BPF_PROG(block_rq_complete_btf, struct request *rq, int error, unsigned int nr_bytes)
164*387f9dfdSAndroid Build Coastguard Worker {
165*387f9dfdSAndroid Build Coastguard Worker return handle_block_rq_complete(rq, error, nr_bytes);
166*387f9dfdSAndroid Build Coastguard Worker }
167*387f9dfdSAndroid Build Coastguard Worker
168*387f9dfdSAndroid Build Coastguard Worker SEC("raw_tp/block_rq_insert")
BPF_PROG(block_rq_insert)169*387f9dfdSAndroid Build Coastguard Worker int BPF_PROG(block_rq_insert)
170*387f9dfdSAndroid Build Coastguard Worker {
171*387f9dfdSAndroid Build Coastguard Worker return handle_block_rq_insert(ctx);
172*387f9dfdSAndroid Build Coastguard Worker }
173*387f9dfdSAndroid Build Coastguard Worker
174*387f9dfdSAndroid Build Coastguard Worker SEC("raw_tp/block_rq_issue")
BPF_PROG(block_rq_issue)175*387f9dfdSAndroid Build Coastguard Worker int BPF_PROG(block_rq_issue)
176*387f9dfdSAndroid Build Coastguard Worker {
177*387f9dfdSAndroid Build Coastguard Worker return handle_block_rq_issue(ctx);
178*387f9dfdSAndroid Build Coastguard Worker }
179*387f9dfdSAndroid Build Coastguard Worker
180*387f9dfdSAndroid Build Coastguard Worker SEC("raw_tp/block_rq_complete")
BPF_PROG(block_rq_complete,struct request * rq,int error,unsigned int nr_bytes)181*387f9dfdSAndroid Build Coastguard Worker int BPF_PROG(block_rq_complete, struct request *rq, int error, unsigned int nr_bytes)
182*387f9dfdSAndroid Build Coastguard Worker {
183*387f9dfdSAndroid Build Coastguard Worker return handle_block_rq_complete(rq, error, nr_bytes);
184*387f9dfdSAndroid Build Coastguard Worker }
185*387f9dfdSAndroid Build Coastguard Worker
186*387f9dfdSAndroid Build Coastguard Worker char LICENSE[] SEC("license") = "GPL";
187