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 60e11158a..13bd7e6c3 100644 --- a/MagicEyes/src/backend/fs/fs_watcher/bpf/open.bpf.c +++ b/MagicEyes/src/backend/fs/fs_watcher/bpf/open.bpf.c @@ -1,4 +1,4 @@ -#include +#include "vmlinux.h" #include #include #include @@ -6,9 +6,6 @@ char LICENSE[] SEC("license") = "GPL"; -#define O_CREAT 0x0200 // 手动定义 O_CREAT 标志的常量值 -#define O_WRONLY 01 /* open for writing only */ - struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); @@ -30,32 +27,31 @@ int do_syscall_trace(struct trace_event_raw_sys_enter *ctx) e.dfd = ctx->args[0];// 目录文件描述符 bpf_probe_read_user_str(e.filename, sizeof(e.filename), (const char *)ctx->args[1]); // 文件路径 e.flags = ctx->args[2]; // 打开标志 - - // 如果包含 O_CREAT 标志,则标记为文件创建 - if (e.flags & O_CREAT || (e.flags & O_WRONLY) ) { - e.is_created = true; - } else { - e.is_created = false; - } bpf_map_update_elem(&data,&pid,&e,BPF_ANY); return 0; } -// 跟踪文件描述符分配过程 -SEC("kprobe/get_unused_fd_flags") -int kprobe_get_unused_fd_flags(struct pt_regs *ctx){ +//跟踪文件描述符分配过程 +SEC("kretprobe/get_unused_fd_flags") +int kretprobe_get_unused_fd_flags(struct pt_regs *ctx){ pid_t pid = bpf_get_current_pid_tgid() >> 32; struct event_open *e = bpf_map_lookup_elem(&data,&pid); if(!e){ bpf_printk("get_unused_fd_flags is failed to found fd\n"); return 0; } + //获取分配的文件描述符 + int fd = PT_REGS_RC(ctx); - //获取分配的文件描述符 - e->fd = PT_REGS_RC(ctx); - - bpf_map_update_elem(&data,&pid,e,BPF_ANY); + if (fd <= 0) { + bpf_printk("get_unused_fd_flags: syscall failed with error %d\n", fd); + return 0; + } else { + bpf_printk("get_unused_fd_flags: allocated fd %d\n", fd); + e->fd = fd; + bpf_map_update_elem(&data, &pid, e, BPF_ANY); + } return 0; } @@ -72,7 +68,7 @@ int do_syscall_exit(struct trace_event_raw_sys_exit *ctx) e->ret = ctx->ret; - // 分配 ringbuf 空间 + // 分配 ringbuf 空间 struct event_open *new_e = bpf_ringbuf_reserve(&rb, sizeof(*new_e), 0); if (!new_e) { return 0; // 如果分配失败,提前返回 @@ -82,8 +78,7 @@ int do_syscall_exit(struct trace_event_raw_sys_exit *ctx) new_e->dfd = e->dfd; new_e->flags = e->flags; new_e->fd = e->fd; - new_e->ret =e->ret; - new_e->is_created = e->is_created; + new_e->ret = e->ret; new_e->pid = e->pid; // 手动读取文件路径,确保不超过最大长度,并添加 '\0' 结束符 @@ -98,7 +93,6 @@ int do_syscall_exit(struct trace_event_raw_sys_exit *ctx) // 确保字符串以 '\0' 结束 new_e->filename[filename_len] = '\0'; bpf_printk("Opening file: %s, pid: %d, flags: %d\n", new_e->filename, pid, e->flags); - bpf_ringbuf_submit(new_e, 0); return 0; } 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 ec6ee3b2c..37a784560 100644 --- a/MagicEyes/src/backend/fs/fs_watcher/bpf/read.bpf.c +++ b/MagicEyes/src/backend/fs/fs_watcher/bpf/read.bpf.c @@ -3,7 +3,6 @@ #include #include #include "fs_watcher.h" -#define MAX_FILENAME_LEN 256 char LICENSE[] SEC("license") = "Dual BSD/GPL"; @@ -21,7 +20,7 @@ struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); __type(key, pid_t); - __type(value, MAX_FILENAME_LEN); + __type(value, struct event_read); } data SEC(".maps"); struct { @@ -29,22 +28,16 @@ struct { __uint(max_entries, 256 * 1024); } rb SEC(".maps"); -const volatile unsigned long long min_duration_ns = 0; - 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_read *e; - u64 ts; - 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; - + bpf_printk("enter vfs_read\n"); + struct event_read e = {}; + struct file *filp = (struct file *)PT_REGS_PARM1(ctx); + pid_t pid = bpf_get_current_pid_tgid() >> 32; + e.pid = pid; //获取进程pid + size_t count = (size_t)PT_REGS_PARM3(ctx); // 获取请求读取的字节数 + //获取文件路径结构体 struct dentry *dentry = BPF_CORE_READ(filp, f_path.dentry); if(!dentry){ @@ -52,48 +45,24 @@ int kprobe_enter_read(struct pt_regs *ctx) 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"); - } + bpf_probe_read_str(e.filename, sizeof(e.filename), d_name.name); // 读取文件名 + e.count_size = count; //读取的字节数 // 判断文件类型,并过滤掉设备文件 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; - } + e.file_type = file_type; + + bpf_printk("pid: %d, filename: %s, count_size: %d\n", e.pid, e.filename, e.count_size); + /* 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; + struct event_read *e_ring = bpf_ringbuf_reserve(&rb, sizeof(e), 0); + if (!e_ring) { + return 0; + } + + // 将数据填充到 ring buffer 中 + *e_ring = e; + + // 提交数据到 ring buffer + bpf_ringbuf_submit(e_ring, 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 index ed049ab13..d70537644 100644 --- a/MagicEyes/src/backend/fs/fs_watcher/include/fs_watcher.h +++ b/MagicEyes/src/backend/fs/fs_watcher/include/fs_watcher.h @@ -6,20 +6,20 @@ #define TASK_COMM_LEN 16 struct event_open { - pid_t pid; - int dfd; - char filename[path_size]; - int flags; - int fd; // 文件描述符 - int ret; // 系统调用返回值 - bool is_created; // 标记文件是否创建 + pid_t pid; // 进程 ID + int dfd; // 目录文件描述符 + char filename[256]; // 文件路径 + int flags; // 打开标志 + int fd; // 文件描述符 + int ret; // 系统调用返回值 }; /*read*/ - struct event_read { - int pid; - unsigned long long duration_ns; + int pid; + char filename[256]; // 文件名 + int count_size; // 读取的字节数 + unsigned short file_type; // 文件类型 }; /*write*/ @@ -64,9 +64,4 @@ struct event_CacheTrack{ long long time_complete; // 写回开始时间 }; -/*send pid to ebpf*/ -struct dist_args { - pid_t pid; -}; -#endif /* __MEM_WATCHER_H */ - +#endif /* __FS_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 index 9a6ef6c85..44929eaa8 100644 --- a/MagicEyes/src/backend/fs/fs_watcher/src/fs_watcher.c +++ b/MagicEyes/src/backend/fs/fs_watcher/src/fs_watcher.c @@ -16,6 +16,7 @@ #include #include #include // 包含文件打开标志宏 +#include #include #include "fs/fs_watcher/open.skel.h" #include "fs/fs_watcher/read.skel.h" @@ -26,7 +27,7 @@ #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" + "Usage: fs_watcher [OPTION...]\n" "Options:"; #define PROCESS_SKEL(skel, func) \ @@ -107,6 +108,9 @@ static struct env{ bool disk_io_visit; bool block_rq_issue; bool CacheTrack; + bool print_logo; + char *filename; //保存用户输入的用户名 + int pid; // 保存用户输入的PID }env = { .open = false, .read = false, @@ -114,15 +118,25 @@ static struct env{ .disk_io_visit = false, .block_rq_issue = false, .CacheTrack = false, + .print_logo = false, + .filename = NULL, // 默认没有文件名 + .pid = -1, // 默认没有PID }; static const struct argp_option opts[] = { - {"open", 'o', 0, 0, "Print open system call report"}, - {"read", 'r', 0, 0, "Print read system call report"}, + { 0, 0, 0, 0, "文件系统:", 1}, + {"open", 'o', 0, 0, "Track file open, capturing fd, filename, and ret"}, + {"read", 'r', 0, 0, "Track file read operations"}, {"write", 'w', 0, 0, "Print write system call report"}, + { 0, 0, 0, 0, "磁盘系统:", 2 }, {"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."}, + { 0, 0, 0, 0, "脏页回写:", 3}, {"CacheTrack", 't' , 0 ,0 , "WriteBack dirty lagency and other information"}, + { "help", 'h', 0, 0, " (帮助信息)" }, + { 0, 0, 0, 0, "参数说明:", 4}, + { "PID", 'p', "PID", 0, "(根据PID查找)"}, + {"filename", 'n', "FILENAME", 0, "(根据文件名查找)"}, {0} // 结束标记,用于指示选项列表的结束 }; @@ -141,12 +155,31 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) { env.block_rq_issue = true;break; case 't': env.CacheTrack = true;break; + case 'h': + env.print_logo = true;break; + case 'n': // 处理 -n 或 --filename 选项 + env.filename = arg; // 保存文件名 + break; + case 'p': // 处理PID + env.pid = atoi(arg); // 将字符串转为整数 + break; default: return ARGP_ERR_UNKNOWN; } return 0; } +// 打印logo函数 +void print_fs_watcher_logo() { + // 每行文字的颜色控制应该不会干扰文本对齐 + printf("\033[38;5;208m ___________ _ _____ ______________ ____________ \n"); + printf("\033[38;5;148m / ____/ ___/ | | / / |/_ __/ ____/ / / / ____/ __ \\ \n"); + printf("\033[38;5;69m / /_ \\__\\ | | /| / / /| | / / / / / /_/ / __/ / /_/ / \n"); + printf("\033[38;5;93m / __/ ___/ / | |/ |/ / ___ |/ / / /___/ __ / /___/ _, _/ \n"); + printf("\033[38;5;33m/_/ /____/ |__/|__/_/ |_/_/ \\____/_/ /_/_____/_/ |_| \n"); + printf("\033[0m\n"); +} + static const struct argp argp = { .options = opts, .parser = parse_arg, @@ -183,8 +216,6 @@ 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; @@ -207,12 +238,29 @@ int main(int argc,char **argv){ signal(SIGTERM, sig_handler); signal(SIGALRM, sig_handler); - - err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + err = argp_parse(&argp, argc, argv, 0, 0, NULL); // printf("success!\n"); if (err) return err; + // Print logo if requested + if (env.print_logo) { + print_fs_watcher_logo(); + // Print options and doc + printf("%s\n", argp.doc); + for (int i = 0; opts[i].name || opts[i].doc; i++) { + if (!opts[i].name) { + // 如果name为空,表示是分组标题,直接打印文档字段 + printf("\n%s\n", opts[i].doc); + } else { + // 否则打印选项 + printf(" -%c, --%s\t%s\n", opts[i].key, opts[i].name, opts[i].doc); + } + } + printf("\n"); + return 0; + } + if(env.open){ PROCESS_SKEL(skel_open,open); }else if(env.read){ @@ -267,16 +315,31 @@ const char* flags_to_str(int flags) { return str; } +static const char *file_type_to_str(unsigned short file_type) +{ + switch (file_type) { + case 0100000: return "Regular File"; // S_IFREG + case 0040000: return "Directory"; // S_IFDIR + case 0020000: return "Character Device"; // S_IFCHR + case 0060000: return "Block Device"; // S_IFBLK + case 0120000: return "Symbolic Link"; // S_IFLNK + case 0010000: return "FIFO"; // S_IFIFO + case 0140000: return "Socket"; // S_IFSOCK + default: return "Unknown"; // Default case + } +} + static int handle_event_open(void *ctx, void *data, size_t data_sz) { const struct event_open *e = data; - struct tm *tm; - char ts[32]; - time_t t; + struct tm *tm; + char ts[32]; + time_t t; + + time(&t); + tm = localtime(&t); + strftime(ts, sizeof(ts), "%H:%M:%S", tm); - time(&t); - tm = localtime(&t); - strftime(ts, sizeof(ts), "%H:%M:%S", tm); const char *ret_str; // 如果返回值是负数,则是错误码,使用 strerror if (e->ret < 0) { @@ -288,11 +351,18 @@ static int handle_event_open(void *ctx, void *data, size_t data_sz) const char *flags_str = flags_to_str(e->flags); - printf("%-8s %-8d %-8d %-100s %-8s %-8d %-8s %-8s\n", - ts, e->dfd, e->pid,e->filename, flags_str, e->fd, ret_str, e->is_created ? "true" : "false"); - return 0; -} + //进行PID和文件名过滤 + if ((env.pid != -1 && env.pid != e->pid) || + (env.filename != NULL && strstr(e->filename, env.filename) == NULL)) { + return 0; // 如果不匹配PID或文件名,则跳过此事件 + } + //打印过滤后的结果 + printf("%-8s %-8d %-8d %-20s %-8s %-8d %-8s\n", + ts, e->dfd, e->pid, e->filename, flags_str, e->fd, ret_str); + + return 0; +} static int handle_event_read(void *ctx, void *data, size_t data_sz) { @@ -304,8 +374,14 @@ static int handle_event_read(void *ctx, void *data, size_t data_sz) time(&t); tm = localtime(&t); strftime(ts, sizeof(ts), "%H:%M:%S", tm); + + //进行PID和文件名过滤 + if ((env.pid != -1 && env.pid != e->pid) || + (env.filename != NULL && strstr(e->filename, env.filename) == NULL)) { + return 0; // 如果不匹配PID或文件名,则跳过此事件 + } - printf("%-10s %-8d %-8llu\n",ts,e->pid,e->duration_ns); + printf("%-10s %-8d %-15s %-10zu %-20s\n",ts,e->pid,e->filename,e->count_size,file_type_to_str(e->file_type)); return 0; } @@ -365,8 +441,7 @@ static int process_open(struct open_bpf *skel_open){ struct ring_buffer *rb; LOAD_AND_ATTACH_SKELETON_MAP(skel_open,open); - - printf("%-8s %-8s %-8s %-100s %-8s %-8s %-8s %-8s\n", "TIME","dfd","PID", "filename", "flags", "fd", "ret", "is_created"); + printf("%-8s %-8s %-8s %-20s %-8s %-8s %-8s\n", "TIME", "DFD", "PID", "FILENAME", "FLAGS", "FD", "RET"); POLL_RING_BUFFER(rb, 1000, err); open_cleanup: @@ -382,7 +457,7 @@ static int process_read(struct read_bpf *skel_read){ LOAD_AND_ATTACH_SKELETON(skel_read,read); - printf("%-10s %-8s %-8s\n","TIME","PID","DS"); + printf("%-10s %-8s %-15s %-10s %-20s\n","TIME","PID","FILENAME","SIZE","FILE_TYPE"); POLL_RING_BUFFER(rb, 1000, err); read_cleanup: