Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fs_watcher:跑通magic_eyes_cli && 修改之前写的这个open ebpf程序 #954

Merged
merged 1 commit into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 72 additions & 39 deletions MagicEyes/src/backend/fs/fs_watcher/bpf/open.bpf.c
Original file line number Diff line number Diff line change
@@ -1,71 +1,104 @@
#define BPF_NO_GLOBAL_DATA
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "fs_watcher.h"

#define TASK_COMM_LEN 100
#define path_size 256
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);
__type(key, pid_t);
__type(value, char[TASK_COMM_LEN]);
__type(value, struct event_open);
} data SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} 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;
struct event_open e = {};
pid_t pid = bpf_get_current_pid_tgid() >> 32;
e.pid = pid;
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;
}

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);
// 跟踪文件描述符分配过程
SEC("kprobe/get_unused_fd_flags")
int kprobe_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 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]));
//获取分配的文件描述符
e->fd = PT_REGS_RC(ctx);

bpf_printk("path name: %s,pid:%d,ppid:%d\n", e->path_name_, pid, ppid);
bpf_map_update_elem(&data,&pid,e,BPF_ANY);
return 0;
}

struct fdtable *fdt = BPF_CORE_READ(task, files, fdt);
if (fdt == NULL) {
bpf_printk("fdt\n");
bpf_ringbuf_discard(e, 0);
// 跟踪 openat 系统调用的退出
SEC("tracepoint/syscalls/sys_exit_openat")
int do_syscall_exit(struct trace_event_raw_sys_exit *ctx)
{
pid_t pid = bpf_get_current_pid_tgid() >> 32;
struct event_open *e = bpf_map_lookup_elem(&data,&pid);
if(!e){
bpf_printk("sys_exit_openat is failed to found fd\n");
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);

e->ret = ctx->ret;

// 分配 ringbuf 空间
struct event_open *new_e = bpf_ringbuf_reserve(&rb, sizeof(*new_e), 0);
if (!new_e) {
return 0; // 如果分配失败,提前返回
}

//复制数据
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->pid = e->pid;

// 手动读取文件路径,确保不超过最大长度,并添加 '\0' 结束符
int filename_len = 0;
while (filename_len < sizeof(new_e->filename) - 1) {
char c = 0;
// 读取路径中的每个字符
bpf_probe_read(&c, sizeof(c), e->filename + filename_len);
if (c == '\0') break; // 如果遇到 null 字符就停止读取
new_e->filename[filename_len++] = c;
}
// 确保字符串以 '\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;
}

char LICENSE[] SEC("license") = "GPL";
11 changes: 7 additions & 4 deletions MagicEyes/src/backend/fs/fs_watcher/include/fs_watcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
#define TASK_COMM_LEN 16

struct event_open {
int pid_;
char path_name_[path_size];
int n_;
char comm[TASK_COMM_LEN];
pid_t pid;
int dfd;
char filename[path_size];
int flags;
int fd; // 文件描述符
int ret; // 系统调用返回值
bool is_created; // 标记文件是否创建
};

/*read*/
Expand Down
121 changes: 61 additions & 60 deletions MagicEyes/src/backend/fs/fs_watcher/src/fs_watcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <time.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/resource.h>
#include <bpf/libbpf.h>
Expand All @@ -14,6 +15,7 @@
#include <inttypes.h>
#include <linux/fs.h>
#include <errno.h>
#include <fcntl.h> // 包含文件打开标志宏
#include <argp.h>
#include "fs/fs_watcher/open.skel.h"
#include "fs/fs_watcher/read.skel.h"
Expand Down Expand Up @@ -105,15 +107,13 @@ static struct env{
bool disk_io_visit;
bool block_rq_issue;
bool CacheTrack;
pid_t pid;
}env = {
.open = false,
.read = false,
.write = false,
.disk_io_visit = false,
.block_rq_issue = false,
.CacheTrack = false,
.pid = -1,
};

static const struct argp_option opts[] = {
Expand All @@ -123,7 +123,6 @@ static const struct argp_option opts[] = {
{"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"},
{"pid", 'p', "PID", 0, "Specify pid number when report weite. Only support for write report now"},
{0} // 结束标记,用于指示选项列表的结束
};

Expand All @@ -142,19 +141,7 @@ 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 'p':
if (arg) {
env.pid = atoi(arg);
if (env.pid <= 0) {
fprintf(stderr, "Invalid PID value: %s\n", arg);
argp_usage(state);
}
} else {
fprintf(stderr, "-p option requires an argument\n");
argp_usage(state);
}
break;
default:
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
Expand Down Expand Up @@ -244,38 +231,65 @@ int main(int argc,char **argv){
}
}

const char* flags_to_str(int flags) {
static char str[256];
str[0] = '\0'; // 清空字符串

if (flags & O_RDONLY) strcat(str, "O_RDONLY ");
if (flags & O_WRONLY) strcat(str, "O_WRONLY ");
if (flags & O_RDWR) strcat(str, "O_RDWR ");
if (flags & O_CREAT) strcat(str, "O_CREAT ");
if (flags & O_EXCL) strcat(str, "O_EXCL ");
if (flags & O_TRUNC) strcat(str, "O_TRUNC ");
if (flags & O_APPEND) strcat(str, "O_APPEND ");
if (flags & O_NOFOLLOW) strcat(str, "O_NOFOLLOW ");
if (flags & O_CLOEXEC) strcat(str, "O_CLOEXEC ");
if (flags & O_NONBLOCK) strcat(str, "O_NONBLOCK ");
if (flags & O_SYNC) strcat(str, "O_SYNC ");
if (flags & O_DSYNC) strcat(str, "O_DSYNC ");
if (flags & O_RSYNC) strcat(str, "O_RSYNC ");
if (flags & O_DIRECTORY) strcat(str, "O_DIRECTORY ");

// 条件编译部分:如果系统定义了 O_NOATIME 和 O_PATH
#ifdef O_NOATIME
if (flags & O_NOATIME) strcat(str, "O_NOATIME ");
#endif

#ifdef O_PATH
if (flags & O_PATH) strcat(str, "O_PATH ");
#endif

// 如果没有匹配到标志,返回 "Unknown"
if (str[0] == '\0') {
return "Unknown";
}

return str;
}

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("%-60s %-8d %-8d %-8s\n",
e->path_name_, i,e->pid_,comm);
}else{
fprintf(stderr, "Failed to lookup value for key %d\n", e->pid_);
}

}
}
}
const struct event_open *e = data;
struct tm *tm;
char ts[32];
time_t t;

time(&t);
tm = localtime(&t);
strftime(ts, sizeof(ts), "%H:%M:%S", tm);
const char *ret_str;
// 如果返回值是负数,则是错误码,使用 strerror
if (e->ret < 0) {
ret_str = strerror(-e->ret); // 负数表示错误码
} else {
// 正数表示文件描述符,直接打印文件描述符
ret_str = "Success"; // 如果是文件描述符,表示成功
}

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;
}

Expand Down Expand Up @@ -352,7 +366,7 @@ static int process_open(struct open_bpf *skel_open){

LOAD_AND_ATTACH_SKELETON_MAP(skel_open,open);

printf("%-60s %-8s %-8s %-8s\n","filenamename","fd","pid","comm");
printf("%-8s %-8s %-8s %-100s %-8s %-8s %-8s %-8s\n", "TIME","dfd","PID", "filename", "flags", "fd", "ret", "is_created");
POLL_RING_BUFFER(rb, 1000, err);

open_cleanup:
Expand Down Expand Up @@ -381,22 +395,9 @@ static int process_read(struct read_bpf *skel_read){
static int process_write(struct write_bpf *skel_write){
int err;
struct ring_buffer *rb;
int arg_index = 0;

struct dist_args d_args = {-1};


LOAD_AND_ATTACH_SKELETON(skel_write,write);

d_args.pid = env.pid;
struct bpf_map *arg_map = bpf_object__find_map_by_name((const struct bpf_object *)*(skel_write->skeleton->obj), "args_map");
err = bpf_map__update_elem(arg_map, &arg_index, sizeof(arg_index), &d_args, sizeof(d_args), BPF_ANY);

if (err < 0) {
fprintf(stderr, "ERROR: failed to update args map\n");
goto write_cleanup;
}

printf("%-8s %-8s %-8s %-8s %-8s\n","ds","inode_number","pid","real_count","count");
POLL_RING_BUFFER(rb, 1000, err);

Expand Down