github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/trace/fsslower/tracer/bpf/fsslower.bpf.c (about) 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 "fsslower.h" 8 #include <gadget/mntns_filter.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 // we need this to make sure the compiler doesn't remove our struct 16 const struct event *unusedevent __attribute__((unused)); 17 18 struct data_key { 19 __u32 tid; 20 /* 21 * We need to take into account the operation to avoid losing some of 22 * them. 23 * Indeed, it is possible to enter statfs syscall while already being in 24 * an open one. 25 */ 26 enum fs_file_op op; 27 }; 28 29 struct data { 30 __u64 ts; 31 loff_t start; 32 loff_t end; 33 struct dentry *dentry; 34 }; 35 36 struct { 37 __uint(type, BPF_MAP_TYPE_HASH); 38 __uint(max_entries, MAX_ENTRIES); 39 __type(key, struct data_key); 40 __type(value, struct data); 41 } starts SEC(".maps"); 42 43 struct { 44 __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); 45 __uint(key_size, sizeof(__u32)); 46 __uint(value_size, sizeof(__u32)); 47 } events SEC(".maps"); 48 49 static int probe_entry(struct dentry *dentry, enum fs_file_op op, loff_t start, 50 loff_t end) 51 { 52 __u64 pid_tgid = bpf_get_current_pid_tgid(); 53 __u32 pid = pid_tgid >> 32; 54 __u32 tid = (__u32)pid_tgid; 55 struct data data; 56 struct data_key key = { .tid = tid, .op = op }; 57 u64 mntns_id; 58 59 if (!dentry) 60 return 0; 61 62 // TODO: Enabling this conditional causes an error while loading the program 63 // invalid argument: number of funcs in func_info doesn't match number of subprogs 64 //if (target_pid && target_pid != pid) 65 // return 0; 66 67 mntns_id = gadget_get_mntns_id(); 68 69 if (gadget_should_discard_mntns_id(mntns_id)) 70 return 0; 71 72 data.ts = bpf_ktime_get_ns(); 73 data.start = start; 74 data.end = end; 75 data.dentry = dentry; 76 bpf_map_update_elem(&starts, &key, &data, BPF_ANY); 77 return 0; 78 } 79 80 static int probe_exit(void *ctx, enum fs_file_op op, ssize_t size) 81 { 82 __u64 pid_tgid = bpf_get_current_pid_tgid(); 83 __u32 pid = pid_tgid >> 32; 84 __u32 tid = (__u32)pid_tgid; 85 __u64 end_ns, delta_ns; 86 const __u8 *file_name; 87 struct data *datap; 88 struct event event = {}; 89 struct data_key key = { .tid = tid, .op = op }; 90 struct dentry *dentry; 91 u64 mntns_id; 92 93 //if (target_pid && target_pid != pid) 94 // return 0; 95 96 datap = bpf_map_lookup_elem(&starts, &key); 97 if (!datap) 98 return 0; 99 100 bpf_map_delete_elem(&starts, &key); 101 102 end_ns = bpf_ktime_get_ns(); 103 delta_ns = end_ns - datap->ts; 104 if (delta_ns <= min_lat_ns) 105 return 0; 106 107 event.delta_us = delta_ns / 1000; 108 event.end_ns = end_ns; 109 event.offset = datap->start; 110 if (op != F_FSYNC) 111 event.size = size; 112 else 113 event.size = datap->end - datap->start; 114 event.pid = pid; 115 event.op = op; 116 event.mntns_id = gadget_get_mntns_id(); 117 event.timestamp = bpf_ktime_get_boot_ns(); 118 dentry = datap->dentry; 119 file_name = BPF_CORE_READ(dentry, d_name.name); 120 bpf_probe_read_kernel_str(&event.file, sizeof(event.file), file_name); 121 bpf_get_current_comm(&event.task, sizeof(event.task)); 122 bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, 123 sizeof(event)); 124 return 0; 125 } 126 127 SEC("kprobe/dummy_file_read") 128 int BPF_KPROBE(ig_fssl_read_e, struct kiocb *iocb) 129 { 130 struct dentry *dentry = BPF_CORE_READ(iocb, ki_filp, f_path.dentry); 131 loff_t start = BPF_CORE_READ(iocb, ki_pos); 132 133 return probe_entry(dentry, F_READ, start, 0); 134 } 135 136 SEC("kretprobe/dummy_file_read") 137 int BPF_KRETPROBE(ig_fssl_read_x, ssize_t ret) 138 { 139 return probe_exit(ctx, F_READ, ret); 140 } 141 142 SEC("kprobe/dummy_file_write") 143 int BPF_KPROBE(ig_fssl_wr_e, struct kiocb *iocb) 144 { 145 struct dentry *dentry = BPF_CORE_READ(iocb, ki_filp, f_path.dentry); 146 loff_t start = BPF_CORE_READ(iocb, ki_pos); 147 148 return probe_entry(dentry, F_WRITE, start, 0); 149 } 150 151 SEC("kretprobe/dummy_file_write") 152 int BPF_KRETPROBE(ig_fssl_wr_x, ssize_t ret) 153 { 154 return probe_exit(ctx, F_WRITE, ret); 155 } 156 157 SEC("kprobe/dummy_file_open") 158 int BPF_KPROBE(ig_fssl_open_e, struct inode *inode, struct file *file) 159 { 160 struct dentry *dentry = BPF_CORE_READ(file, f_path.dentry); 161 return probe_entry(dentry, F_OPEN, 0, 0); 162 } 163 164 SEC("kretprobe/dummy_file_open") 165 int BPF_KRETPROBE(ig_fssl_open_x) 166 { 167 return probe_exit(ctx, F_OPEN, 0); 168 } 169 170 SEC("kprobe/dummy_file_sync") 171 int BPF_KPROBE(ig_fssl_sync_e, struct file *file, loff_t start, loff_t end) 172 { 173 struct dentry *dentry = BPF_CORE_READ(file, f_path.dentry); 174 return probe_entry(dentry, F_FSYNC, start, end); 175 } 176 177 SEC("kretprobe/dummy_file_sync") 178 int BPF_KRETPROBE(ig_fssl_sync_x) 179 { 180 return probe_exit(ctx, F_FSYNC, 0); 181 } 182 183 SEC("kprobe/dummy_file_statfs") 184 int BPF_KPROBE(ig_fssl_statfs_e, struct dentry *dentry, struct kstatfs *buf) 185 { 186 return probe_entry(dentry, F_STATFS, 0, 0); 187 } 188 189 SEC("kretprobe/dummy_file_statfs") 190 int BPF_KRETPROBE(ig_fssl_statfs_x) 191 { 192 return probe_exit(ctx, F_STATFS, 0); 193 } 194 195 // Comment out the fentry/fexit functions as we don't support them yet. 196 //SEC("fentry/dummy_file_read") 197 //int BPF_PROG(file_read_fentry, struct kiocb *iocb) 198 //{ 199 // struct file *fp = iocb->ki_filp; 200 // loff_t start = iocb->ki_pos; 201 // 202 // return probe_entry(fp, start, 0); 203 //} 204 // 205 //SEC("fexit/dummy_file_read") 206 //int BPF_PROG(file_read_fexit, struct kiocb *iocb, struct iov_iter *to, ssize_t ret) 207 //{ 208 // return probe_exit(ctx, READ, ret); 209 //} 210 // 211 //SEC("fentry/dummy_file_write") 212 //int BPF_PROG(file_write_fentry, struct kiocb *iocb) 213 //{ 214 // struct file *fp = iocb->ki_filp; 215 // loff_t start = iocb->ki_pos; 216 // 217 // return probe_entry(fp, start, 0); 218 //} 219 // 220 //SEC("fexit/dummy_file_write") 221 //int BPF_PROG(file_write_fexit, struct kiocb *iocb, struct iov_iter *from, ssize_t ret) 222 //{ 223 // return probe_exit(ctx, WRITE, ret); 224 //} 225 // 226 //SEC("fentry/dummy_file_open") 227 //int BPF_PROG(file_open_fentry, struct inode *inode, struct file *file) 228 //{ 229 // return probe_entry(file, 0, 0); 230 //} 231 // 232 //SEC("fexit/dummy_file_open") 233 //int BPF_PROG(file_open_fexit) 234 //{ 235 // return probe_exit(ctx, OPEN, 0); 236 //} 237 // 238 //SEC("fentry/dummy_file_sync") 239 //int BPF_PROG(file_sync_fentry, struct file *file, loff_t start, loff_t end) 240 //{ 241 // return probe_entry(file, start, end); 242 //} 243 // 244 //SEC("fexit/dummy_file_sync") 245 //int BPF_PROG(file_sync_fexit) 246 //{ 247 // return probe_exit(ctx, FSYNC, 0); 248 //} 249 250 char LICENSE[] SEC("license") = "GPL";