1*387f9dfdSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*387f9dfdSAndroid Build Coastguard Worker // Copyright (c) 2020 Anton Protopopov
3*387f9dfdSAndroid Build Coastguard Worker //
4*387f9dfdSAndroid Build Coastguard Worker // Based on vfsstat(8) from BCC by Brendan Gregg
5*387f9dfdSAndroid Build Coastguard Worker #include <argp.h>
6*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
7*387f9dfdSAndroid Build Coastguard Worker #include <time.h>
8*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf.h>
9*387f9dfdSAndroid Build Coastguard Worker #include "vfsstat.h"
10*387f9dfdSAndroid Build Coastguard Worker #include "vfsstat.skel.h"
11*387f9dfdSAndroid Build Coastguard Worker #include "btf_helpers.h"
12*387f9dfdSAndroid Build Coastguard Worker #include "trace_helpers.h"
13*387f9dfdSAndroid Build Coastguard Worker
14*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_version = "vfsstat 0.1";
15*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_bug_address =
16*387f9dfdSAndroid Build Coastguard Worker "https://github.com/iovisor/bcc/tree/master/libbpf-tools";
17*387f9dfdSAndroid Build Coastguard Worker static const char argp_program_doc[] =
18*387f9dfdSAndroid Build Coastguard Worker "\nvfsstat: Count some VFS calls\n"
19*387f9dfdSAndroid Build Coastguard Worker "\n"
20*387f9dfdSAndroid Build Coastguard Worker "EXAMPLES:\n"
21*387f9dfdSAndroid Build Coastguard Worker " vfsstat # interval one second\n"
22*387f9dfdSAndroid Build Coastguard Worker " vfsstat 5 3 # interval five seconds, three output lines\n";
23*387f9dfdSAndroid Build Coastguard Worker static char args_doc[] = "[interval [count]]";
24*387f9dfdSAndroid Build Coastguard Worker
25*387f9dfdSAndroid Build Coastguard Worker static const struct argp_option opts[] = {
26*387f9dfdSAndroid Build Coastguard Worker { "verbose", 'v', NULL, 0, "Verbose debug output" },
27*387f9dfdSAndroid Build Coastguard Worker { NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
28*387f9dfdSAndroid Build Coastguard Worker {},
29*387f9dfdSAndroid Build Coastguard Worker };
30*387f9dfdSAndroid Build Coastguard Worker
31*387f9dfdSAndroid Build Coastguard Worker static struct env {
32*387f9dfdSAndroid Build Coastguard Worker bool verbose;
33*387f9dfdSAndroid Build Coastguard Worker int count;
34*387f9dfdSAndroid Build Coastguard Worker int interval;
35*387f9dfdSAndroid Build Coastguard Worker } env = {
36*387f9dfdSAndroid Build Coastguard Worker .interval = 1, /* once a second */
37*387f9dfdSAndroid Build Coastguard Worker };
38*387f9dfdSAndroid Build Coastguard Worker
parse_arg(int key,char * arg,struct argp_state * state)39*387f9dfdSAndroid Build Coastguard Worker static error_t parse_arg(int key, char *arg, struct argp_state *state)
40*387f9dfdSAndroid Build Coastguard Worker {
41*387f9dfdSAndroid Build Coastguard Worker long interval;
42*387f9dfdSAndroid Build Coastguard Worker long count;
43*387f9dfdSAndroid Build Coastguard Worker
44*387f9dfdSAndroid Build Coastguard Worker switch (key) {
45*387f9dfdSAndroid Build Coastguard Worker case 'h':
46*387f9dfdSAndroid Build Coastguard Worker argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
47*387f9dfdSAndroid Build Coastguard Worker break;
48*387f9dfdSAndroid Build Coastguard Worker case 'v':
49*387f9dfdSAndroid Build Coastguard Worker env.verbose = true;
50*387f9dfdSAndroid Build Coastguard Worker break;
51*387f9dfdSAndroid Build Coastguard Worker case ARGP_KEY_ARG:
52*387f9dfdSAndroid Build Coastguard Worker switch (state->arg_num) {
53*387f9dfdSAndroid Build Coastguard Worker case 0:
54*387f9dfdSAndroid Build Coastguard Worker errno = 0;
55*387f9dfdSAndroid Build Coastguard Worker interval = strtol(arg, NULL, 10);
56*387f9dfdSAndroid Build Coastguard Worker if (errno || interval <= 0 || interval > INT_MAX) {
57*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "invalid interval: %s\n", arg);
58*387f9dfdSAndroid Build Coastguard Worker argp_usage(state);
59*387f9dfdSAndroid Build Coastguard Worker }
60*387f9dfdSAndroid Build Coastguard Worker env.interval = interval;
61*387f9dfdSAndroid Build Coastguard Worker break;
62*387f9dfdSAndroid Build Coastguard Worker case 1:
63*387f9dfdSAndroid Build Coastguard Worker errno = 0;
64*387f9dfdSAndroid Build Coastguard Worker count = strtol(arg, NULL, 10);
65*387f9dfdSAndroid Build Coastguard Worker if (errno || count < 0 || count > INT_MAX) {
66*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "invalid count: %s\n", arg);
67*387f9dfdSAndroid Build Coastguard Worker argp_usage(state);
68*387f9dfdSAndroid Build Coastguard Worker }
69*387f9dfdSAndroid Build Coastguard Worker env.count = count;
70*387f9dfdSAndroid Build Coastguard Worker break;
71*387f9dfdSAndroid Build Coastguard Worker default:
72*387f9dfdSAndroid Build Coastguard Worker argp_usage(state);
73*387f9dfdSAndroid Build Coastguard Worker break;
74*387f9dfdSAndroid Build Coastguard Worker }
75*387f9dfdSAndroid Build Coastguard Worker break;
76*387f9dfdSAndroid Build Coastguard Worker default:
77*387f9dfdSAndroid Build Coastguard Worker return ARGP_ERR_UNKNOWN;
78*387f9dfdSAndroid Build Coastguard Worker }
79*387f9dfdSAndroid Build Coastguard Worker return 0;
80*387f9dfdSAndroid Build Coastguard Worker }
81*387f9dfdSAndroid Build Coastguard Worker
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)82*387f9dfdSAndroid Build Coastguard Worker static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
83*387f9dfdSAndroid Build Coastguard Worker {
84*387f9dfdSAndroid Build Coastguard Worker if (level == LIBBPF_DEBUG && !env.verbose)
85*387f9dfdSAndroid Build Coastguard Worker return 0;
86*387f9dfdSAndroid Build Coastguard Worker return vfprintf(stderr, format, args);
87*387f9dfdSAndroid Build Coastguard Worker }
88*387f9dfdSAndroid Build Coastguard Worker
strftime_now(char * s,size_t max,const char * format)89*387f9dfdSAndroid Build Coastguard Worker static const char *strftime_now(char *s, size_t max, const char *format)
90*387f9dfdSAndroid Build Coastguard Worker {
91*387f9dfdSAndroid Build Coastguard Worker struct tm *tm;
92*387f9dfdSAndroid Build Coastguard Worker time_t t;
93*387f9dfdSAndroid Build Coastguard Worker
94*387f9dfdSAndroid Build Coastguard Worker t = time(NULL);
95*387f9dfdSAndroid Build Coastguard Worker tm = localtime(&t);
96*387f9dfdSAndroid Build Coastguard Worker if (tm == NULL) {
97*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "localtime: %s\n", strerror(errno));
98*387f9dfdSAndroid Build Coastguard Worker return "<failed>";
99*387f9dfdSAndroid Build Coastguard Worker }
100*387f9dfdSAndroid Build Coastguard Worker if (strftime(s, max, format, tm) == 0) {
101*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "strftime error\n");
102*387f9dfdSAndroid Build Coastguard Worker return "<failed>";
103*387f9dfdSAndroid Build Coastguard Worker }
104*387f9dfdSAndroid Build Coastguard Worker return s;
105*387f9dfdSAndroid Build Coastguard Worker }
106*387f9dfdSAndroid Build Coastguard Worker
107*387f9dfdSAndroid Build Coastguard Worker static const char *stat_types_names[] = {
108*387f9dfdSAndroid Build Coastguard Worker [S_READ] = "READ",
109*387f9dfdSAndroid Build Coastguard Worker [S_WRITE] = "WRITE",
110*387f9dfdSAndroid Build Coastguard Worker [S_FSYNC] = "FSYNC",
111*387f9dfdSAndroid Build Coastguard Worker [S_OPEN] = "OPEN",
112*387f9dfdSAndroid Build Coastguard Worker [S_CREATE] = "CREATE",
113*387f9dfdSAndroid Build Coastguard Worker };
114*387f9dfdSAndroid Build Coastguard Worker
print_header(void)115*387f9dfdSAndroid Build Coastguard Worker static void print_header(void)
116*387f9dfdSAndroid Build Coastguard Worker {
117*387f9dfdSAndroid Build Coastguard Worker int i;
118*387f9dfdSAndroid Build Coastguard Worker
119*387f9dfdSAndroid Build Coastguard Worker printf("%-8s ", "TIME");
120*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < S_MAXSTAT; i++)
121*387f9dfdSAndroid Build Coastguard Worker printf(" %6s/s", stat_types_names[i]);
122*387f9dfdSAndroid Build Coastguard Worker printf("\n");
123*387f9dfdSAndroid Build Coastguard Worker }
124*387f9dfdSAndroid Build Coastguard Worker
print_and_reset_stats(__u64 stats[S_MAXSTAT])125*387f9dfdSAndroid Build Coastguard Worker static void print_and_reset_stats(__u64 stats[S_MAXSTAT])
126*387f9dfdSAndroid Build Coastguard Worker {
127*387f9dfdSAndroid Build Coastguard Worker char s[16];
128*387f9dfdSAndroid Build Coastguard Worker __u64 val;
129*387f9dfdSAndroid Build Coastguard Worker int i;
130*387f9dfdSAndroid Build Coastguard Worker
131*387f9dfdSAndroid Build Coastguard Worker printf("%-8s: ", strftime_now(s, sizeof(s), "%H:%M:%S"));
132*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < S_MAXSTAT; i++) {
133*387f9dfdSAndroid Build Coastguard Worker val = __atomic_exchange_n(&stats[i], 0, __ATOMIC_RELAXED);
134*387f9dfdSAndroid Build Coastguard Worker printf(" %8llu", val / env.interval);
135*387f9dfdSAndroid Build Coastguard Worker }
136*387f9dfdSAndroid Build Coastguard Worker printf("\n");
137*387f9dfdSAndroid Build Coastguard Worker }
138*387f9dfdSAndroid Build Coastguard Worker
main(int argc,char ** argv)139*387f9dfdSAndroid Build Coastguard Worker int main(int argc, char **argv)
140*387f9dfdSAndroid Build Coastguard Worker {
141*387f9dfdSAndroid Build Coastguard Worker LIBBPF_OPTS(bpf_object_open_opts, open_opts);
142*387f9dfdSAndroid Build Coastguard Worker static const struct argp argp = {
143*387f9dfdSAndroid Build Coastguard Worker .options = opts,
144*387f9dfdSAndroid Build Coastguard Worker .parser = parse_arg,
145*387f9dfdSAndroid Build Coastguard Worker .doc = argp_program_doc,
146*387f9dfdSAndroid Build Coastguard Worker .args_doc = args_doc,
147*387f9dfdSAndroid Build Coastguard Worker };
148*387f9dfdSAndroid Build Coastguard Worker struct vfsstat_bpf *skel;
149*387f9dfdSAndroid Build Coastguard Worker int err;
150*387f9dfdSAndroid Build Coastguard Worker
151*387f9dfdSAndroid Build Coastguard Worker err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
152*387f9dfdSAndroid Build Coastguard Worker if (err)
153*387f9dfdSAndroid Build Coastguard Worker return err;
154*387f9dfdSAndroid Build Coastguard Worker
155*387f9dfdSAndroid Build Coastguard Worker libbpf_set_print(libbpf_print_fn);
156*387f9dfdSAndroid Build Coastguard Worker
157*387f9dfdSAndroid Build Coastguard Worker
158*387f9dfdSAndroid Build Coastguard Worker err = ensure_core_btf(&open_opts);
159*387f9dfdSAndroid Build Coastguard Worker if (err) {
160*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "failed to fetch necessary BTF for CO-RE: %s\n", strerror(-err));
161*387f9dfdSAndroid Build Coastguard Worker return 1;
162*387f9dfdSAndroid Build Coastguard Worker }
163*387f9dfdSAndroid Build Coastguard Worker
164*387f9dfdSAndroid Build Coastguard Worker skel = vfsstat_bpf__open();
165*387f9dfdSAndroid Build Coastguard Worker if (!skel) {
166*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "failed to open BPF skelect\n");
167*387f9dfdSAndroid Build Coastguard Worker return 1;
168*387f9dfdSAndroid Build Coastguard Worker }
169*387f9dfdSAndroid Build Coastguard Worker
170*387f9dfdSAndroid Build Coastguard Worker /* It fallbacks to kprobes when kernel does not support fentry. */
171*387f9dfdSAndroid Build Coastguard Worker if (fentry_can_attach("vfs_read", NULL)) {
172*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(skel->progs.kprobe_vfs_read, false);
173*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(skel->progs.kprobe_vfs_write, false);
174*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(skel->progs.kprobe_vfs_fsync, false);
175*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(skel->progs.kprobe_vfs_open, false);
176*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(skel->progs.kprobe_vfs_create, false);
177*387f9dfdSAndroid Build Coastguard Worker } else {
178*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(skel->progs.fentry_vfs_read, false);
179*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(skel->progs.fentry_vfs_write, false);
180*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(skel->progs.fentry_vfs_fsync, false);
181*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(skel->progs.fentry_vfs_open, false);
182*387f9dfdSAndroid Build Coastguard Worker bpf_program__set_autoload(skel->progs.fentry_vfs_create, false);
183*387f9dfdSAndroid Build Coastguard Worker }
184*387f9dfdSAndroid Build Coastguard Worker
185*387f9dfdSAndroid Build Coastguard Worker err = vfsstat_bpf__load(skel);
186*387f9dfdSAndroid Build Coastguard Worker if (err) {
187*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "failed to load BPF skelect: %d\n", err);
188*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
189*387f9dfdSAndroid Build Coastguard Worker }
190*387f9dfdSAndroid Build Coastguard Worker
191*387f9dfdSAndroid Build Coastguard Worker if (!skel->bss) {
192*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "Memory-mapping BPF maps is supported starting from Linux 5.7, please upgrade.\n");
193*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
194*387f9dfdSAndroid Build Coastguard Worker }
195*387f9dfdSAndroid Build Coastguard Worker
196*387f9dfdSAndroid Build Coastguard Worker err = vfsstat_bpf__attach(skel);
197*387f9dfdSAndroid Build Coastguard Worker if (err) {
198*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "failed to attach BPF programs: %s\n",
199*387f9dfdSAndroid Build Coastguard Worker strerror(-err));
200*387f9dfdSAndroid Build Coastguard Worker goto cleanup;
201*387f9dfdSAndroid Build Coastguard Worker }
202*387f9dfdSAndroid Build Coastguard Worker
203*387f9dfdSAndroid Build Coastguard Worker print_header();
204*387f9dfdSAndroid Build Coastguard Worker do {
205*387f9dfdSAndroid Build Coastguard Worker sleep(env.interval);
206*387f9dfdSAndroid Build Coastguard Worker print_and_reset_stats(skel->bss->stats);
207*387f9dfdSAndroid Build Coastguard Worker } while (!env.count || --env.count);
208*387f9dfdSAndroid Build Coastguard Worker
209*387f9dfdSAndroid Build Coastguard Worker cleanup:
210*387f9dfdSAndroid Build Coastguard Worker vfsstat_bpf__destroy(skel);
211*387f9dfdSAndroid Build Coastguard Worker cleanup_core_btf(&open_opts);
212*387f9dfdSAndroid Build Coastguard Worker
213*387f9dfdSAndroid Build Coastguard Worker return err != 0;
214*387f9dfdSAndroid Build Coastguard Worker }
215