加载eBPF程序失败

问题描述 投票:0回答:1

我是 eBPF 新手,为了学习尝试调整现有

filetop
的概念,来自 https://github.com/iovisor/bcc/blob/master/tools/filetop.py

这与

htop
类似,但适用于磁盘 io。对于文件名列 该工具仅打印文件名,而不打印绝对路径。为了打印绝对路径而不仅仅是文件名,我使用
dentry_path_raw
函数从 dentry 对象获取完整路径如何使用 dentry_path_raw()

新的

ebpf
代码看起来像这样,而使用空间Python代码也是如此。

#include <uapi/linux/ptrace.h>
#include <linux/blkdev.h>
#include <linux/fs.h>

// the key for the output summary
struct info_t {
    unsigned long inode;
    dev_t dev;
    dev_t rdev;
    u32 pid;
    u32 name_len;
    char comm[TASK_COMM_LEN];
    // de->d_name.name may point to de->d_iname so limit len accordingly
    char* name;
    char type;
};

// the value of the output summary
struct val_t {
    u64 reads;
    u64 writes;
    u64 rbytes;
    u64 wbytes;
};

BPF_HASH(counts, struct info_t, struct val_t);

static int do_entry(struct pt_regs *ctx, struct file *file,
    char __user *buf, size_t count, int is_read)
{
    u32 tgid = bpf_get_current_pid_tgid() >> 32;
    if (TGID_FILTER)
        return 0;

    u32 pid = bpf_get_current_pid_tgid();

    // skip I/O lacking a filename
    struct dentry *de = file->f_path.dentry;
    int mode = file->f_inode->i_mode;
    struct qstr d_name = de->d_name;
    if (d_name.len == 0 || TYPE_FILTER)
        return 0;

    // store counts and sizes by pid & file
    struct info_t info = {
        .pid = pid,
        .inode = file->f_inode->i_ino,
        .dev = file->f_inode->i_sb->s_dev,
        .rdev = file->f_inode->i_rdev,
    };
    bpf_get_current_comm(&info.comm, sizeof(info.comm));
    info.name_len = d_name.len;
    //bpf_probe_read_kernel(&info.name, sizeof(info.name), d_name.name);
    dentry_path_raw(de, info.name, 32);

    if (S_ISREG(mode)) {
        info.type = 'R';
    } else if (S_ISSOCK(mode)) {
        info.type = 'S';
    } else {
        info.type = 'O';
    }

    struct val_t *valp, zero = {};
    valp = counts.lookup_or_try_init(&info, &zero);
    if (valp) {
        if (is_read) {
            valp->reads++;
            valp->rbytes += count;
        } else {
            valp->writes++;
            valp->wbytes += count;
        }
    }

    return 0;
}

int trace_read_entry(struct pt_regs *ctx, struct file *file,
    char __user *buf, size_t count)
{
    return do_entry(ctx, file, buf, count, 1);
}

int trace_write_entry(struct pt_regs *ctx, struct file *file,
    char __user *buf, size_t count)
{
    return do_entry(ctx, file, buf, count, 0);
}

实际代码可以在这里找到

我收到的上述代码的错误在这里

bpf: Failed to load program: Invalid argument
jump out of range from insn 38 to 148
processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

Traceback (most recent call last):
  File "/home/jayendra/data/ebpf/listen.py", line 170, in <module>
    b.attach_kprobe(event="vfs_read", fn_name="trace_read_entry")
  File "/usr/lib/python3/dist-packages/bcc/__init__.py", line 851, in attach_kprobe
    fn = self.load_func(fn_name, BPF.KPROBE)
  File "/usr/lib/python3/dist-packages/bcc/__init__.py", line 526, in load_func
    raise Exception("Failed to load BPF program %s: %s" %
Exception: Failed to load BPF program b'trace_read_entry': Invalid argument
ebpf
1个回答
0
投票

您不能从 BPF 程序中调用任意内核函数。不过,您可以使用 BPF 助手

bpf_d_path
来解决这个问题:

long bpf_d_path(struct path *path, char *buf, u32 sz)

您可以在内核源代码中找到使用示例,但基本思想是在您的情况下按如下方式调用它:

ret = bpf_d_path(&file->f_path, info.name, 32);
if (ret < 0)
    ... handle error ...

请注意,此帮助程序需要 Linux v5.10。

© www.soinside.com 2019 - 2024. All rights reserved.