From 1fce494d349cad013edf1e491af0a4f91e1b2146 Mon Sep 17 00:00:00 2001 From: shangfan <45649554+sf1999817@users.noreply.github.com> Date: Tue, 15 Oct 2024 04:49:46 +0000 Subject: [PATCH] add fs_watcher to MagicEyes Signed-off-by: shangfan <45649554+sf1999817@users.noreply.github.com> --- .../fs/fs_watcher/bpf/CacheTrack.bpf.c | 120 +++++ .../fs/fs_watcher/bpf/block_rq_issue.bpf.c | 69 +++ .../fs/fs_watcher/bpf/disk_io_visit.bpf.c | 71 +++ .../src/backend/fs/fs_watcher/bpf/open.bpf.c | 102 +++-- .../src/backend/fs/fs_watcher/bpf/read.bpf.c | 79 +++- .../src/backend/fs/fs_watcher/bpf/write.bpf.c | 51 ++- .../fs/fs_watcher/include/fs_watcher.h | 61 +++ .../backend/fs/fs_watcher/src/fs_watcher.c | 413 ++++++++++++++++++ 8 files changed, 890 insertions(+), 76 deletions(-) create mode 100644 MagicEyes/src/backend/fs/fs_watcher/bpf/CacheTrack.bpf.c create mode 100644 MagicEyes/src/backend/fs/fs_watcher/bpf/block_rq_issue.bpf.c create mode 100644 MagicEyes/src/backend/fs/fs_watcher/bpf/disk_io_visit.bpf.c create mode 100644 MagicEyes/src/backend/fs/fs_watcher/include/fs_watcher.h create mode 100644 MagicEyes/src/backend/fs/fs_watcher/src/fs_watcher.c diff --git a/MagicEyes/src/backend/fs/fs_watcher/bpf/CacheTrack.bpf.c b/MagicEyes/src/backend/fs/fs_watcher/bpf/CacheTrack.bpf.c new file mode 100644 index 000000000..608c59967 --- /dev/null +++ b/MagicEyes/src/backend/fs/fs_watcher/bpf/CacheTrack.bpf.c @@ -0,0 +1,120 @@ +#include "vmlinux.h" +#include +#include +#include +#include "fs_watcher.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +// struct { +// __uint(type, BPF_MAP_TYPE_HASH); +// __uint(max_entries, 1024); +// __type(key, char[30] ); +// __type(value,struct event_CacheTrack); +// } data SEC(".maps"); + +// struct { +// __uint(type, BPF_MAP_TYPE_HASH); +// __uint(max_entries, 1024); +// __type(key, u64 ); +// __type(value,struct event_CacheTrack); +// } unique_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rb SEC(".maps"); + + +SEC("tracepoint/writeback/writeback_dirty_inode_start") +int trace_writeback_start(struct trace_event_raw_writeback_dirty_inode_template *ctx){ + pid_t pid = bpf_get_current_pid_tgid() >> 32; + u64 timestamp = bpf_ktime_get_ns(); + struct event_CacheTrack event_info ={}; + char name[32]; + + event_info.ino = ctx->ino; + + event_info.state = ctx->state; + + event_info.flags = ctx->flags; + + event_info.time = timestamp; + + // bpf_probe_read(name, sizeof(name), ctx->name); // 从 ctx 复制设备名称 + + // 检查 name 是否为空字符串 + // if (name[0] == '\0') { + // return 0; + // } + // if(name == NULL) + // return 0; + + // __builtin_memcpy(event_info.name, name, sizeof(name)); + // bpf_printk("comm_123:%s\n",event_info.name); + + struct event_CacheTrack *ring_event = bpf_ringbuf_reserve(&rb, sizeof(struct event_CacheTrack), 0); + if (!ring_event) + return 0; + + __builtin_memcpy(ring_event, &event_info, sizeof(event_info)); + + bpf_printk("event_info_ino:%d\n",event_info.ino); + + bpf_ringbuf_submit(ring_event, 0); + + + // bpf_map_update_elem(&data,name,&event_info,BPF_ANY); + // bpf_map_update_elem(&unique_map,&event_info.queue_id,&event_info,BPF_ANY); + return 0; +} + +// SEC("tracepoint/writeback/writeback_written") +// int trace_writeback_end(struct trace_event_raw_writeback_work_class *ctx) { +// bpf_printk("2222222\n"); +// u64 timestamp = bpf_ktime_get_ns(); +// char name[30]; +// bpf_probe_read_str(name, sizeof(name), ctx->name); // 从 ctx 复制设备名称 + +// if(name == NULL) +// return 0; + +// bpf_printk("comm:%s\n",name); + +// struct event_CacheTrack *e = bpf_map_lookup_elem(&data,name); +// if(!e){ +// bpf_printk("e failed\n"); +// return 0; +// } + + +// struct event_CacheTrack *q = bpf_map_lookup_elem(&unique_map,&e->queue_id); +// if(!q){ +// bpf_printk("q failed\n"); +// return 0; +// } + +// struct event_CacheTrack *q_event = bpf_ringbuf_reserve(&rb, sizeof(struct event_CacheTrack), 0); +// if (!q_event){ +// bpf_printk("Ring buffer is full!\n"); +// return 0; +// } + +// q_event->nr_pages = ctx->nr_pages; +// q_event->sb_dev = ctx->sb_dev; +// q_event->sync_mode = ctx->sync_mode; +// q_event->for_kupdate = ctx->for_kupdate; +// q_event->range_cyclic = ctx->range_cyclic; +// q_event->for_background = ctx->for_background; +// q_event->reason = ctx->reason; +// q_event->cgroup_ino = ctx->cgroup_ino; +// q_event->time = timestamp - q->start_timestamp; + +// bpf_printk("time:%llu\n",q_event->time); +// bpf_printk("123\n"); + +// bpf_ringbuf_submit(q_event, 0); + +// return 0; + +// } \ No newline at end of file diff --git a/MagicEyes/src/backend/fs/fs_watcher/bpf/block_rq_issue.bpf.c b/MagicEyes/src/backend/fs/fs_watcher/bpf/block_rq_issue.bpf.c new file mode 100644 index 000000000..8f2da61ba --- /dev/null +++ b/MagicEyes/src/backend/fs/fs_watcher/bpf/block_rq_issue.bpf.c @@ -0,0 +1,69 @@ +#include "vmlinux.h" +#include +#include +#include +#include "fs_watcher.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key, u32); // 使用进程 PID 作为键 + __type(value, u64); // I/O 总大小作为值 +} io_size_map SEC(".maps"); + +SEC("tracepoint/block/block_rq_issue") +int tracepoint_block_rq_issue(struct trace_event_raw_block_rq_completion *ctx) { + struct event_block_rq_issue *e; + u32 pid = bpf_get_current_pid_tgid() >> 32; // 获取进程 ID + u64 *size, total_size; + + // 分配 ringbuf 空间 + e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) { + return 0; // 如果分配失败,提前返回 + } + + // 获取当前进程名 + bpf_get_current_comm(e->comm, sizeof(e->comm)); + + // 填充事件数据 + e->timestamp = bpf_ktime_get_ns(); + e->dev = ctx->dev; + e->sector = ctx->sector; + e->nr_sectors = ctx->nr_sector; + + // 日志输出调试信息 + bpf_printk("PID: %u, Sector: %d, nr_sectors: %d\n", pid, ctx->sector, ctx->nr_sector); + + // 查找或初始化该进程的 I/O 总大小 + size = bpf_map_lookup_elem(&io_size_map, &pid); + if (size) { + total_size = *size; + } else { + total_size = 0; + } + + // 计算本次 I/O 请求的大小 + const u64 sector_size = 512; // 标准扇区大小 + total_size += ctx->nr_sector * sector_size; + + // 更新 I/O 总大小 + bpf_map_update_elem(&io_size_map, &pid, &total_size, BPF_ANY); + + e->total_io = total_size; + + // 日志输出当前总 I/O 大小 + bpf_printk("Updated Total I/O for PID %u: %llu\n", pid, total_size); + + // 提交事件 + bpf_ringbuf_submit(e, 0); + + return 0; +} \ No newline at end of file diff --git a/MagicEyes/src/backend/fs/fs_watcher/bpf/disk_io_visit.bpf.c b/MagicEyes/src/backend/fs/fs_watcher/bpf/disk_io_visit.bpf.c new file mode 100644 index 000000000..d3457bb84 --- /dev/null +++ b/MagicEyes/src/backend/fs/fs_watcher/bpf/disk_io_visit.bpf.c @@ -0,0 +1,71 @@ +#include "vmlinux.h" +#include +#include +#include +#include "fs_watcher.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +// 定义 ringbuf,用于传输事件信息 +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rb SEC(".maps"); + +// 进程名与 I/O 计数映射 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key, char[TASK_COMM_LEN]); + __type(value, u32); +} io_count_map SEC(".maps"); + +// 这里挂载点得是这个struct trace_event_raw_block_rq_completion *ctx +SEC("tracepoint/block/block_rq_complete") +int tracepoint_block_visit(struct trace_event_raw_block_rq_completion *ctx) { + struct event_disk_io_visit *e; + u32 *count, new_count; + char comm[TASK_COMM_LEN]; + + // 获取当前进程名 + bpf_get_current_comm(comm, sizeof(comm)); + + // 查找或初始化该进程的I/O计数 + count = bpf_map_lookup_elem(&io_count_map, comm); + if (count) { + new_count = *count + 1; + } else { + new_count = 1; + } + bpf_map_update_elem(&io_count_map, comm, &new_count, BPF_ANY); + + // 分配 ringbuf 空间 + e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) { + return 0; // 如果分配失败,提前返回 + } + + // 填充事件数据 + e->timestamp = bpf_ktime_get_ns(); + e->blk_dev = ctx->dev; // 直接读取块设备号 + e->sectors = ctx->nr_sector; // 读取操作的扇区数 + + // 判断读写标识符 (检查 rwbs 数组的内容) + if (ctx->rwbs[0] == 'R') { + e->rwbs = 1; // 1 表示读操作 + } else { + e->rwbs = 0; // 0 表示写操作 + } + + // 更新 I/O 操作计数 + e->count = new_count; + + // 复制进程名 + __builtin_memcpy(e->comm, comm, sizeof(comm)); + bpf_printk("comm : %s\n",e->comm); + + // 提交事件 + bpf_ringbuf_submit(e, 0); + + return 0; +} \ No newline at end of file diff --git a/MagicEyes/src/backend/fs/fs_watcher/bpf/open.bpf.c b/MagicEyes/src/backend/fs/fs_watcher/bpf/open.bpf.c index 50d0bb29c..5824bb774 100644 --- a/MagicEyes/src/backend/fs/fs_watcher/bpf/open.bpf.c +++ b/MagicEyes/src/backend/fs/fs_watcher/bpf/open.bpf.c @@ -1,63 +1,71 @@ -#include "vmlinux.h" -#include //包含了BPF 辅助函数 +#define BPF_NO_GLOBAL_DATA +#include +#include #include -#include "open.h" +#include +#include "fs_watcher.h" -char LICENSE[] SEC("license") = "Dual BSD/GPL"; +#define TASK_COMM_LEN 100 +#define path_size 256 -// 定义哈希映射 struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); __type(key, pid_t); - __type(value, u64); -} fdtmp SEC(".maps"); + __type(value, char[TASK_COMM_LEN]); +} data SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); -} rb SEC(".maps"); - -SEC("kprobe/do_sys_openat2") -int BPF_KPROBE(do_sys_openat2) -{ - struct fs_t fs; - pid_t pid; - - //pid - pid = bpf_get_current_pid_tgid() >> 32; - fs.pid = pid; - - //uid - fs.uid = bpf_get_current_uid_gid(); - - //fd,file descriptor - int fd = PT_REGS_RC(ctx); - if (fd >= 0) - fs.fd = fd; - else - fs.fd= -1; - - //time - unsigned long long ts = bpf_ktime_get_ns(); - fs.ts = ts; - bpf_map_update_elem(&fdtmp, &pid, &ts, BPF_ANY); - - //从环形缓冲区(ring buffer)中分配一块内存来存储一个名为 struct fs_t 类型的数据,并将该内存块的指针赋值给指针变量 e - struct fs_t *e; +} rb SEC(".maps"); // 环形缓冲区 + + +SEC("tracepoint/syscalls/sys_enter_openat") +int do_syscall_trace(struct trace_event_raw_sys_enter *ctx) +{ + struct event_open *e; + char comm[TASK_COMM_LEN]; + bpf_get_current_comm(&comm,sizeof(comm)); e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); - if (!e) return 0; - - //给变量e赋值 - e->pid = fs.pid; - e->uid = fs.uid; - e->fd = fs.fd; - e->ts = fs.ts; - bpf_get_current_comm(e->comm, sizeof(e->comm)); - - // 成功地将其提交到用户空间进行后期处理 + if (!e) + return 0; + + char filename[path_size]; + struct task_struct *task = (struct task_struct *)bpf_get_current_task(), + *real_parent; + if (task == NULL) { + bpf_printk("task\n"); + bpf_ringbuf_discard(e, 0); + return 0; + } + int pid = bpf_get_current_pid_tgid() >> 32, tgid; + + bpf_map_update_elem(&data, &pid, &comm, BPF_ANY); + + int ppid = BPF_CORE_READ(task, real_parent, tgid); + + bpf_probe_read_str(e->path_name_, sizeof(e->path_name_), + (void *)(ctx->args[1])); + + bpf_printk("path name: %s,pid:%d,ppid:%d\n", e->path_name_, pid, ppid); + + struct fdtable *fdt = BPF_CORE_READ(task, files, fdt); + if (fdt == NULL) { + bpf_printk("fdt\n"); + bpf_ringbuf_discard(e, 0); + return 0; + } + + unsigned int i = 0, count = 0, n = BPF_CORE_READ(fdt, max_fds); + bpf_printk("n:%d\n", n); + + e->n_ = n; + e->pid_ = pid; + bpf_ringbuf_submit(e, 0); - return 0; + return 0; } +char LICENSE[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/MagicEyes/src/backend/fs/fs_watcher/bpf/read.bpf.c b/MagicEyes/src/backend/fs/fs_watcher/bpf/read.bpf.c index 26fef3053..ec6ee3b2c 100644 --- a/MagicEyes/src/backend/fs/fs_watcher/bpf/read.bpf.c +++ b/MagicEyes/src/backend/fs/fs_watcher/bpf/read.bpf.c @@ -1,15 +1,27 @@ #include "vmlinux.h" #include #include -#include "read.h" +#include +#include "fs_watcher.h" +#define MAX_FILENAME_LEN 256 char LICENSE[] SEC("license") = "Dual BSD/GPL"; +// 手动定义文件类型宏 +#define S_IFMT 0170000 // 文件类型掩码 +#define S_IFREG 0100000 // 普通文件 +#define S_IFCHR 0020000 // 字符设备 +#define S_IFDIR 0040000 // 目录 +#define S_IFLNK 0120000 // 符号链接 +#define S_IFBLK 0060000 // 块设备 +#define S_IFIFO 0010000 // FIFO(命名管道) +#define S_IFSOCK 0140000 // 套接字 + struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); __type(key, pid_t); - __type(value, u64); + __type(value, MAX_FILENAME_LEN); } data SEC(".maps"); struct { @@ -19,28 +31,69 @@ struct { const volatile unsigned long long min_duration_ns = 0; -SEC("tracepoint/syscalls/sys_enter_read") - -int trace_enter_read(void *ctx) +SEC("kprobe/vfs_read") +int kprobe_enter_read(struct pt_regs *ctx) { + struct file *filp = (struct file *)PT_REGS_PARM1(ctx);   pid_t pid; - struct event *e; + struct event_read *e; u64 ts; - pid = bpf_get_current_pid_tgid() >> 32; - ts = bpf_ktime_get_ns(); - bpf_map_update_elem(&data, &pid, &ts, BPF_ANY); + char buf[256]; + pid = bpf_get_current_pid_tgid() >> 32; + ts = bpf_ktime_get_ns()/1000; + int count_size = PT_REGS_RC(ctx); if (min_duration_ns) return 0; + + //获取文件路径结构体 + struct dentry *dentry = BPF_CORE_READ(filp, f_path.dentry); + if(!dentry){ + bpf_printk("Failed to read dentry\n"); + return 0; + } + struct qstr d_name = BPF_CORE_READ(dentry,d_name); + + //读文件名称到缓冲区 + int ret = bpf_probe_read_kernel(buf, sizeof(buf), d_name.name); + if(ret != 0){ + bpf_printk("failed to read file name\n"); + } + // 判断文件类型,并过滤掉设备文件 + unsigned short file_type = BPF_CORE_READ(dentry, d_inode, i_mode) & S_IFMT; + bpf_map_update_elem(&data, &pid, &buf, BPF_ANY); + switch (file_type) { + case S_IFREG: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFCHR: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFDIR: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFLNK: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFBLK: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFIFO: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFSOCK: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + default: + bpf_printk("other!!!"); + break; + } /* reserve sample from BPF ringbuf */ e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); if (!e) return 0; - e->pid = pid; e->duration_ns = ts; - /* successfully submit it to user-space for post-processing */ bpf_ringbuf_submit(e, 0); return 0; -} - +} \ No newline at end of file diff --git a/MagicEyes/src/backend/fs/fs_watcher/bpf/write.bpf.c b/MagicEyes/src/backend/fs/fs_watcher/bpf/write.bpf.c index 4eea72d4c..6ce3cbe19 100644 --- a/MagicEyes/src/backend/fs/fs_watcher/bpf/write.bpf.c +++ b/MagicEyes/src/backend/fs/fs_watcher/bpf/write.bpf.c @@ -1,16 +1,16 @@ #include "vmlinux.h" #include #include -#include "write.h" +#include +#include "fs_watcher.h" char LICENSE[] SEC("license") = "Dual BSD/GPL"; - - +#define PATH_MAX 256 struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); __type(key, pid_t); - __type(value, u64); + __type(value, int); } data SEC(".maps"); struct { @@ -18,26 +18,45 @@ struct { __uint(max_entries,256 * 1024); } rb SEC(".maps"); -const volatile unsigned long long min_duration_ns = 0; - -SEC("tracepoint/syscalls/sys_enter_write") -int kprobe_sys_enter_write( void *ctx) +SEC("kprobe/vfs_write") +int kprobe_vfs_write(struct pt_regs *ctx) { pid_t pid; struct fs_t *e; - u64 ts; - pid = bpf_get_current_pid_tgid() >> 32; - ts = bpf_ktime_get_ns(); - bpf_map_update_elem(&data,&pid,&ts,BPF_ANY); - if(min_duration_ns) + unsigned long inode_number;//定义用于存储inode号码的变量 + + //探测的是第一个参数,文件指针,读取inode_number + struct file *filp = (struct file *)PT_REGS_PARM1(ctx);   + struct dentry *dentry = BPF_CORE_READ(filp,f_path.dentry); + if(!dentry){ + bpf_printk("Failed to read dentry\n"); + return 0; + } + struct inode *inode = BPF_CORE_READ(dentry,d_inode); + if(!inode){ + bpf_printk("Failed to read inode\n"); return 0; - e = bpf_ringbuf_reserve(&rb,sizeof(*e),0); + } + int ret = bpf_probe_read_kernel(&inode_number,sizeof(inode_number),&inode->i_ino); + + //探测的是第三个参数,要写入的字节数 + size_t count = (size_t)PT_REGS_PARM3(ctx); + + //这是vfs_write的返回值,它是一个实际写入的字节数 + size_t real_count = PT_REGS_RC(ctx); + + pid = bpf_get_current_pid_tgid() >> 32; + e = bpf_ringbuf_reserve(&rb,sizeof(*e),0); if(!e) return 0; + e->pid = pid; - e->duration_ns = ts; + e->real_count = real_count; + e->count = count; + e->inode_number = inode_number; - bpf_ringbuf_submit(e,0); + //这里将获取到的文件指针不为空时 + bpf_ringbuf_submit(e, 0); return 0; } \ No newline at end of file diff --git a/MagicEyes/src/backend/fs/fs_watcher/include/fs_watcher.h b/MagicEyes/src/backend/fs/fs_watcher/include/fs_watcher.h new file mode 100644 index 000000000..0368491fb --- /dev/null +++ b/MagicEyes/src/backend/fs/fs_watcher/include/fs_watcher.h @@ -0,0 +1,61 @@ +#ifndef __FS_WATCHER_H +#define __FS_WATCHER_H + +/*open*/ +#define path_size 256 +#define TASK_COMM_LEN 16 + +struct event_open { + int pid_; + char path_name_[path_size]; + int n_; + char comm[TASK_COMM_LEN]; +}; + +/*read*/ + +struct event_read { + int pid; + unsigned long long duration_ns; +}; + +/*write*/ +struct fs_t { + unsigned long inode_number; + pid_t pid; + size_t real_count; + size_t count; +}; + +/*disk_io_visit*/ +struct event_disk_io_visit { + long timestamp; // 时间戳 + int blk_dev; // 块设备号 + int sectors; // 访问的扇区数 + int rwbs; // 读写标识符,1表示读操作,0表示写操作 + int count; // I/O 操作计数 + char comm[TASK_COMM_LEN]; // 进程名 +}; + +/*block_rq_issue*/ +struct event_block_rq_issue { + long timestamp; // 时间戳 + int dev; // 设备号 + int sector; // 扇区号 + int nr_sectors; // 扇区数 + char comm[TASK_COMM_LEN]; // 进程名 + int total_io; //I/O总大小 +}; + + +/*CacheTrack*/ +struct event_CacheTrack{ + pid_t pid; + long long time; //耗时 + // char name[32]; // 设备名称 + ino_t ino; // inode 号 + unsigned long state; // inode 状态 + unsigned long flags; // inode 标志 +}; + +#endif /* __MEM_WATCHER_H */ \ No newline at end of file diff --git a/MagicEyes/src/backend/fs/fs_watcher/src/fs_watcher.c b/MagicEyes/src/backend/fs/fs_watcher/src/fs_watcher.c new file mode 100644 index 000000000..a2e3d05cb --- /dev/null +++ b/MagicEyes/src/backend/fs/fs_watcher/src/fs_watcher.c @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +/* Copyright (c) 2020 Facebook */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fs/fs_watcher/open.skel.h" +#include "fs/fs_watcher/read.skel.h" +#include "fs/fs_watcher/write.skel.h" +#include "fs/fs_watcher/disk_io_visit.skel.h" +#include "fs/fs_watcher/block_rq_issue.skel.h" +#include "fs/fs_watcher/CacheTrack.skel.h" +#include "fs_watcher/include/fs_watcher.h" + +const char argp_program_doc[] = "fs_watcher is used to monitor various system calls and disk I/O events.\n\n" + "Usage: fs_watcher [OPTION...]\n\n" + "Options:"; + +#define PROCESS_SKEL(skel, func) \ + skel = func##_bpf__open(); \ + if (!skel) { \ + fprintf(stderr, "Failed to open and load BPF skeleton\n"); \ + return 1; \ + } \ + process_##func(skel) + + +#define POLL_RING_BUFFER(rb, timeout, err) \ + while (!exiting) { \ + sleep(1); \ + err = ring_buffer__poll(rb, timeout); \ + if (err == -EINTR) { \ + err = 0; \ + break; \ + } \ + if (err < 0) { \ + printf("Error polling perf buffer: %d\n", err); \ + break; \ + } \ + } + +#define LOAD_AND_ATTACH_SKELETON(skel, event) \ + do { \ + err = event##_bpf__load(skel); \ + if (err) { \ + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + err = event##_bpf__attach(skel); \ + if (err) { \ + fprintf(stderr, "Failed to attach BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event_##event, NULL, NULL); \ + if (!rb) { \ + fprintf(stderr, "Failed to create ring buffer\n"); \ + goto event##_cleanup; \ + } \ + } while(0) + + +#define LOAD_AND_ATTACH_SKELETON_MAP(skel, event) \ + do { \ + err = event##_bpf__load(skel); \ + if (err) { \ + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + err = event##_bpf__attach(skel); \ + if (err) { \ + fprintf(stderr, "Failed to attach BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + int map_fd = bpf_map__fd(skel->maps.data); \ + if(!map_fd){ \ + fprintf(stderr, "Failed to find BPF map\n"); \ + return -1; \ + } \ + rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event_##event, &map_fd, NULL); \ + if (!rb) { \ + fprintf(stderr, "Failed to create ring buffer\n"); \ + goto event##_cleanup; \ + } \ + } while(0) + +static struct env{ + bool open; + bool read; + bool write; + bool disk_io_visit; + bool block_rq_issue; + bool CacheTrack; +}env = { + .open = false, + .read = false, + .write = false, + .disk_io_visit = false, + .block_rq_issue = false, + .CacheTrack = false, +}; + +static const struct argp_option opts[] = { + {"open", 'o', 0, 0, "Print open system call report"}, + {"read", 'r', 0, 0, "Print read system call report"}, + {"write", 'w', 0, 0, "Print write system call report"}, + {"disk_io_visit", 'd', 0, 0, "Print disk I/O visit report"}, + {"block_rq_issue", 'b', 0, 0, "Print block I/O request submission events. Reports when block I/O requests are submitted to device drivers."}, + {"CacheTrack", 't' , 0 ,0 , "WriteBack dirty lagency and other information"}, + {0} // 结束标记,用于指示选项列表的结束 +}; + + +static error_t parse_arg(int key, char *arg, struct argp_state *state) { + switch(key){ + case 'o': + env.open = true;break; + case 'r': + env.read = true;break; + case 'w': + env.write = true;break; + case 'd': + env.disk_io_visit = true;break; + case 'b': + env.block_rq_issue = true;break; + case 't': + env.CacheTrack = true;break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static const struct argp argp = { + .options = opts, + .parser = parse_arg, + .doc = argp_program_doc, + .help_filter = NULL +}; +#define warn(...) fprintf(stderr, __VA_ARGS__) + +static int libbpf_print_fn(enum libbpf_print_level level, const char *format, + va_list args) +{ + return vfprintf(stderr, format, args); +} + +static volatile bool exiting = false; + +static void sig_handler(int sig) +{ + exiting = true; +} + +static int handle_event_open(void *ctx, void *data, size_t data_sz); +static int handle_event_read(void *ctx, void *data, size_t data_sz); +static int handle_event_write(void *ctx, void *data, size_t data_sz); +static int handle_event_disk_io_visit(void *ctx, void *data, size_t data_sz); +static int handle_event_block_rq_issue(void *ctx, void *data, size_t data_sz); +static int handle_event_CacheTrack(void *ctx, void *data, size_t data_sz); + +static int process_open(struct open_bpf *skel_open); +static int process_read(struct read_bpf *skel_read); +static int process_write(struct write_bpf *skel_write); +static int process_disk_io_visit(struct disk_io_visit_bpf *skel_disk_io_visit); +static int process_block_rq_issue(struct block_rq_issue_bpf *skel_block_rq_issue); +static int process_CacheTrack(struct CacheTrack_bpf *skel_CacheTrack); + + + +int main(int argc,char **argv){ + + int err; + struct open_bpf *skel_open; + struct read_bpf *skel_read; + struct write_bpf *skel_write; + struct disk_io_visit_bpf *skel_disk_io_visit; + struct block_rq_issue_bpf *skel_block_rq_issue; + struct CacheTrack_bpf *skel_CacheTrack; + + + libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + + + /* Set up libbpf errors and debug info callback */ + libbpf_set_print(libbpf_print_fn); + + /* Cleaner handling of Ctrl-C */ + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + signal(SIGALRM, sig_handler); + + + err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + printf("success!\n"); + if (err) + return err; + + if(env.open){ + PROCESS_SKEL(skel_open,open); + }else if(env.read){ + PROCESS_SKEL(skel_read,read); + }else if(env.write){ + PROCESS_SKEL(skel_write,write); + }else if(env.disk_io_visit){ + PROCESS_SKEL(skel_disk_io_visit,disk_io_visit); + }else if(env.block_rq_issue){ + PROCESS_SKEL(skel_block_rq_issue,block_rq_issue); + }else if(env.CacheTrack){ + PROCESS_SKEL(skel_CacheTrack,CacheTrack); + }else{ + fprintf(stderr, "No function selected. Use -h for help.\n"); + return 1; + } +} + +static int handle_event_open(void *ctx, void *data, size_t data_sz) +{ + struct event_open *e = (struct event_open *)data; + char *filename = strrchr(e->path_name_, '/'); + ++filename; + + char fd_path[path_size]; + char actual_path[path_size]; + char comm[TASK_COMM_LEN]; + int i = 0; + int map_fd = *(int *)ctx;//传递map得文件描述符 + + + for (; i < e->n_; ++i) { + snprintf(fd_path, sizeof(fd_path), "/proc/%d/fd/%d", e->pid_, + i); + ssize_t len = + readlink(fd_path, actual_path, sizeof(actual_path) - 1); + if (len != -1) { + actual_path[len] = '\0'; + int result = strcmp(e->path_name_, actual_path); + if (result == 0) { + if(bpf_map_lookup_elem(map_fd,&e->pid_,&comm)==0){ + printf("get , filename:%s , fd:%d , pid:%d ,comm:%s\n", + e->path_name_, i,e->pid_,comm); + }else{ + fprintf(stderr, "Failed to lookup value for key %d\n", e->pid_); + } + + } + } + } + return 0; +} + + +static int handle_event_read(void *ctx, void *data, size_t data_sz) +{ + const struct event_read *e = data; + struct tm *tm; + char ts[32]; + time_t t; + + time(&t); + tm = localtime(&t); + strftime(ts, sizeof(ts), "%H:%M:%S", tm); + + printf("%-8s %-7d %-7llu\n", ts, e->pid,e->duration_ns); + return 0; +} + +static int handle_event_write(void *ctx, void *data, size_t data_sz) +{ + const struct fs_t *e = data; + struct tm *tm; + char ts[32]; + time_t t; + time(&t); + tm = localtime(&t); + strftime(ts, sizeof(ts), "%H:%M:%S", tm); + printf("ts:%-8s pid:%-7ld inode_number:%-3ld cout:%-3ld real_count:%-3ld\n", ts, e->pid,e->inode_number,e->count,e->real_count); + return 0; +} + +static int handle_event_disk_io_visit(void *ctx, void *data,unsigned long data_sz) { + const struct event_disk_io_visit *e = data; + + printf("%-10llu %-9d %-7d %-4d %-7d %-16s\n", + e->timestamp, e->blk_dev, e->sectors, e->rwbs, e->count, e->comm); + + return 0; +} + +static int handle_event_block_rq_issue(void *ctx, void *data,unsigned long data_sz) { + const struct event_block_rq_issue *e = data; + printf("%-10llu %-9d %-7d %-4d %-16s Total I/O: %" PRIu64 "\n", + e->timestamp, e->dev, e->sector, e->nr_sectors, e->comm, e->total_io); + + return 0; +} + +static int handle_event_CacheTrack(void *ctx, void *data,unsigned long data_sz) { + const struct event_CacheTrack *event = data; + printf("%-20lld %-19lu %-20lu %-5lu\n", event->time, event->ino, event->state, event->flags); + + return 0; +} + +static int process_open(struct open_bpf *skel_open){ + int err; + struct ring_buffer *rb; + + LOAD_AND_ATTACH_SKELETON_MAP(skel_open,open); + + printf("%-8s %-8s %-8s %-8s\n","filenamename","fd","pid","comm"); + POLL_RING_BUFFER(rb, 1000, err); + +open_cleanup: + ring_buffer__free(rb); + open_bpf__destroy(skel_open); + + return err; +} + +static int process_read(struct read_bpf *skel_read){ + int err; + struct ring_buffer *rb; + + LOAD_AND_ATTACH_SKELETON(skel_read,read); + + printf("%-8s %-8s %-8s %-8s\n","filename","fd","pid","ds"); + POLL_RING_BUFFER(rb, 1000, err); + +read_cleanup: + ring_buffer__free(rb); + read_bpf__destroy(skel_read); + + return err; +} + +static int process_write(struct write_bpf *skel_write){ + int err; + struct ring_buffer *rb; + + LOAD_AND_ATTACH_SKELETON(skel_write,write); + + printf("%-8s %-8s %-8s %-8s %-8s\n","ds","inode_number","pid","real_count","count"); + POLL_RING_BUFFER(rb, 1000, err); + +write_cleanup: + ring_buffer__free(rb); + write_bpf__destroy(skel_write); + + return err; +} + +static int process_disk_io_visit(struct disk_io_visit_bpf *skel_disk_io_visit){ + int err; + struct ring_buffer *rb; + + LOAD_AND_ATTACH_SKELETON(skel_disk_io_visit,disk_io_visit); + printf("%-18s %-7s %-7s %-4s %-7s %-16s\n","TIME", "DEV", "SECTOR", "RWBS", "COUNT", "COMM"); + POLL_RING_BUFFER(rb, 1000, err); + +disk_io_visit_cleanup: + ring_buffer__free(rb); + disk_io_visit_bpf__destroy(skel_disk_io_visit); + + return err; + +} + +static int process_block_rq_issue(struct block_rq_issue_bpf *skel_block_rq_issue){ + int err; + struct ring_buffer *rb; + + LOAD_AND_ATTACH_SKELETON(skel_block_rq_issue,block_rq_issue); + printf("%-18s %-7s %-7s %-4s %-16s %-5sn","TIME", "DEV", "SECTOR", "SECTORS","COMM","Total_Size"); + POLL_RING_BUFFER(rb, 1000, err); + +block_rq_issue_cleanup: + ring_buffer__free(rb); + block_rq_issue_bpf__destroy(skel_block_rq_issue); + + return err; + +} + +static int process_CacheTrack(struct CacheTrack_bpf *skel_CacheTrack){ + int err; + struct ring_buffer *rb; + + LOAD_AND_ATTACH_SKELETON(skel_CacheTrack,CacheTrack); + printf("%-20s %-19s %-20s %-5s\n","TIME", "INO","STATE","FLAGS"); + POLL_RING_BUFFER(rb, 1000, err); + +CacheTrack_cleanup: + ring_buffer__free(rb); + CacheTrack_bpf__destroy(skel_CacheTrack); + + return err; + +} \ No newline at end of file