209 lines
4.5 KiB
C
209 lines
4.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/* Copyright (c) 2020 Wenbo Zhang */
|
|
#include <vmlinux.h>
|
|
#include <bpf/bpf_helpers.h>
|
|
#include <bpf/bpf_core_read.h>
|
|
#include <bpf/bpf_tracing.h>
|
|
#include "bits.bpf.h"
|
|
#include "fsslower.h"
|
|
|
|
#define MAX_ENTRIES 8192
|
|
|
|
const volatile pid_t target_pid = 0;
|
|
const volatile __u64 min_lat_ns = 0;
|
|
|
|
struct data {
|
|
__u64 ts;
|
|
loff_t start;
|
|
loff_t end;
|
|
struct file *fp;
|
|
};
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_HASH);
|
|
__uint(max_entries, MAX_ENTRIES);
|
|
__type(key, __u32);
|
|
__type(value, struct data);
|
|
} starts SEC(".maps");
|
|
|
|
struct {
|
|
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
|
|
__uint(key_size, sizeof(__u32));
|
|
__uint(value_size, sizeof(__u32));
|
|
} events SEC(".maps");
|
|
|
|
static int probe_entry(struct file *fp, loff_t start, loff_t end)
|
|
{
|
|
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
__u32 pid = pid_tgid >> 32;
|
|
__u32 tid = (__u32)pid_tgid;
|
|
struct data data;
|
|
|
|
if (!fp)
|
|
return 0;
|
|
|
|
if (target_pid && target_pid != pid)
|
|
return 0;
|
|
|
|
data.ts = bpf_ktime_get_ns();
|
|
data.start = start;
|
|
data.end = end;
|
|
data.fp = fp;
|
|
bpf_map_update_elem(&starts, &tid, &data, BPF_ANY);
|
|
return 0;
|
|
}
|
|
|
|
static int probe_exit(void *ctx, enum fs_file_op op, ssize_t size)
|
|
{
|
|
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
__u32 pid = pid_tgid >> 32;
|
|
__u32 tid = (__u32)pid_tgid;
|
|
__u64 end_ns, delta_ns;
|
|
const __u8 *file_name;
|
|
struct data *datap;
|
|
struct event event = {};
|
|
struct dentry *dentry;
|
|
struct file *fp;
|
|
|
|
if (target_pid && target_pid != pid)
|
|
return 0;
|
|
|
|
datap = bpf_map_lookup_elem(&starts, &tid);
|
|
if (!datap)
|
|
return 0;
|
|
|
|
bpf_map_delete_elem(&starts, &tid);
|
|
|
|
end_ns = bpf_ktime_get_ns();
|
|
delta_ns = end_ns - datap->ts;
|
|
if (delta_ns <= min_lat_ns)
|
|
return 0;
|
|
|
|
event.delta_us = delta_ns / 1000;
|
|
event.end_ns = end_ns;
|
|
event.offset = datap->start;
|
|
if (op != FSYNC)
|
|
event.size = size;
|
|
else
|
|
event.size = datap->end - datap->start;
|
|
event.pid = pid;
|
|
event.op = op;
|
|
fp = datap->fp;
|
|
dentry = BPF_CORE_READ(fp, f_path.dentry);
|
|
file_name = BPF_CORE_READ(dentry, d_name.name);
|
|
bpf_probe_read_kernel_str(&event.file, sizeof(event.file), file_name);
|
|
bpf_get_current_comm(&event.task, sizeof(event.task));
|
|
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));
|
|
return 0;
|
|
}
|
|
|
|
SEC("kprobe/dummy_file_read")
|
|
int BPF_KPROBE(file_read_entry, struct kiocb *iocb)
|
|
{
|
|
struct file *fp = BPF_CORE_READ(iocb, ki_filp);
|
|
loff_t start = BPF_CORE_READ(iocb, ki_pos);
|
|
|
|
return probe_entry(fp, start, 0);
|
|
}
|
|
|
|
SEC("kretprobe/dummy_file_read")
|
|
int BPF_KRETPROBE(file_read_exit, ssize_t ret)
|
|
{
|
|
return probe_exit(ctx, READ, ret);
|
|
}
|
|
|
|
SEC("kprobe/dummy_file_write")
|
|
int BPF_KPROBE(file_write_entry, struct kiocb *iocb)
|
|
{
|
|
struct file *fp = BPF_CORE_READ(iocb, ki_filp);
|
|
loff_t start = BPF_CORE_READ(iocb, ki_pos);
|
|
|
|
return probe_entry(fp, start, 0);
|
|
}
|
|
|
|
SEC("kretprobe/dummy_file_write")
|
|
int BPF_KRETPROBE(file_write_exit, ssize_t ret)
|
|
{
|
|
return probe_exit(ctx, WRITE, ret);
|
|
}
|
|
|
|
SEC("kprobe/dummy_file_open")
|
|
int BPF_KPROBE(file_open_entry, struct inode *inode, struct file *file)
|
|
{
|
|
return probe_entry(file, 0, 0);
|
|
}
|
|
|
|
SEC("kretprobe/dummy_file_open")
|
|
int BPF_KRETPROBE(file_open_exit)
|
|
{
|
|
return probe_exit(ctx, OPEN, 0);
|
|
}
|
|
|
|
SEC("kprobe/dummy_file_sync")
|
|
int BPF_KPROBE(file_sync_entry, struct file *file, loff_t start, loff_t end)
|
|
{
|
|
return probe_entry(file, start, end);
|
|
}
|
|
|
|
SEC("kretprobe/dummy_file_sync")
|
|
int BPF_KRETPROBE(file_sync_exit)
|
|
{
|
|
return probe_exit(ctx, FSYNC, 0);
|
|
}
|
|
|
|
SEC("fentry/dummy_file_read")
|
|
int BPF_PROG(file_read_fentry, struct kiocb *iocb)
|
|
{
|
|
struct file *fp = iocb->ki_filp;
|
|
loff_t start = iocb->ki_pos;
|
|
|
|
return probe_entry(fp, start, 0);
|
|
}
|
|
|
|
SEC("fexit/dummy_file_read")
|
|
int BPF_PROG(file_read_fexit, struct kiocb *iocb, struct iov_iter *to, ssize_t ret)
|
|
{
|
|
return probe_exit(ctx, READ, ret);
|
|
}
|
|
|
|
SEC("fentry/dummy_file_write")
|
|
int BPF_PROG(file_write_fentry, struct kiocb *iocb)
|
|
{
|
|
struct file *fp = iocb->ki_filp;
|
|
loff_t start = iocb->ki_pos;
|
|
|
|
return probe_entry(fp, start, 0);
|
|
}
|
|
|
|
SEC("fexit/dummy_file_write")
|
|
int BPF_PROG(file_write_fexit, struct kiocb *iocb, struct iov_iter *from, ssize_t ret)
|
|
{
|
|
return probe_exit(ctx, WRITE, ret);
|
|
}
|
|
|
|
SEC("fentry/dummy_file_open")
|
|
int BPF_PROG(file_open_fentry, struct inode *inode, struct file *file)
|
|
{
|
|
return probe_entry(file, 0, 0);
|
|
}
|
|
|
|
SEC("fexit/dummy_file_open")
|
|
int BPF_PROG(file_open_fexit)
|
|
{
|
|
return probe_exit(ctx, OPEN, 0);
|
|
}
|
|
|
|
SEC("fentry/dummy_file_sync")
|
|
int BPF_PROG(file_sync_fentry, struct file *file, loff_t start, loff_t end)
|
|
{
|
|
return probe_entry(file, start, end);
|
|
}
|
|
|
|
SEC("fexit/dummy_file_sync")
|
|
int BPF_PROG(file_sync_fexit)
|
|
{
|
|
return probe_exit(ctx, FSYNC, 0);
|
|
}
|
|
|
|
char LICENSE[] SEC("license") = "GPL";
|