Skip to content

Commit

Permalink
eBPF btrfs (#243)
Browse files Browse the repository at this point in the history
Add new filesystem.
  • Loading branch information
thiagoftsm authored Jul 19, 2021
1 parent d41e8dd commit a9c3167
Show file tree
Hide file tree
Showing 3 changed files with 256 additions and 4 deletions.
3 changes: 2 additions & 1 deletion kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ VER_PATCH=$(shell echo $(KERNEL_VERSION) | cut -d. -f3)

CURRENT_KERNEL=$(shell echo $(VER_MAJOR)\*65536 + $(VER_MINOR)\*256 + $(VER_PATCH) |bc)

NETDATA_APPS= cachestat \
NETDATA_APPS= btrfs \
cachestat \
dc \
disk \
ext4 \
Expand Down
251 changes: 251 additions & 0 deletions kernel/btrfs_kern.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
#define KBUILD_MODNAME "btrfs_netdata"
#include <linux/bpf.h>
#include <linux/ptrace.h>
#include <linux/genhd.h>
#include <linux/version.h>
// Condition added because struct kiocb was moved when 4.1.0 was released
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0))
#include <linux/aio.h>
#else
#include <linux/fs.h>
#endif

#include "bpf_helpers.h"
#include "netdata_ebpf.h"

/************************************************************************************
*
* MAP Section
*
***********************************************************************************/

struct bpf_map_def SEC("maps") tbl_btrfs = {
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u64),
.max_entries = NETDATA_FS_MAX_ELEMENTS
};

struct bpf_map_def SEC("maps") tbl_ext_addr = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(__u32),
.value_size = sizeof(__u64),
.max_entries = 1
};

struct bpf_map_def SEC("maps") tmp_btrfs = {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
.type = BPF_MAP_TYPE_HASH,
#else
.type = BPF_MAP_TYPE_PERCPU_HASH,
#endif
.key_size = sizeof(__u32),
.value_size = sizeof(__u64),
.max_entries = 4192
};

/************************************************************************************
*
* ENTRY Section
*
***********************************************************************************/

#if (LINUX_VERSION_CODE > KERNEL_VERSION(5,0,0))
static int netdata_btrfs_entry()
#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4,19,0))
static __always_inline int netdata_btrfs_entry()
#else
static inline int netdata_btrfs_entry()
#endif
{
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 pid = (__u32)(pid_tgid >> 32);
__u64 ts = bpf_ktime_get_ns();

bpf_map_update_elem(&tmp_btrfs, &pid, &ts, BPF_ANY);

return 0;
}

// We need different probes here, because struct file_operations (btrfs_file_operations)
// was modified when 5.10 was released.
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0))
SEC("kprobe/btrfs_file_read_iter")
int netdata_btrfs_file_read_iter(struct pt_regs *ctx)
#else
SEC("kprobe/generic_file_read_iter")
int netdata_generic_file_read_iter(struct pt_regs *ctx)
#endif
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0))
__u32 key = 0;
struct kiocb *ptr = (struct kiocb *)PT_REGS_PARM1(ctx);
struct file *kf = _(ptr->ki_filp);
if (kf) {
struct file_operations *fo = _(kf->f_op);
if (fo) {
__u64 *bfo = bpf_map_lookup_elem(&tbl_ext_addr, &key);
if (bfo) {
if((__u64)fo != *bfo) {
return 0;
}
}
}
}
#endif

return netdata_btrfs_entry();
}

SEC("kprobe/btrfs_file_write_iter")
int netdata_btrfs_file_write_iter(struct pt_regs *ctx)
{
return netdata_btrfs_entry();
}

SEC("kprobe/btrfs_file_open")
int netdata_btrfs_file_open(struct pt_regs *ctx)
{
return netdata_btrfs_entry();
}

SEC("kprobe/btrfs_sync_file")
int netdata_btrfs_sync_file(struct pt_regs *ctx)
{
return netdata_btrfs_entry();
}

/************************************************************************************
*
* END Section
*
***********************************************************************************/

static void netdata_btrfs_store_bin(__u32 bin, __u32 selection)
{
__u64 *fill, data;
__u32 idx = selection * NETDATA_FS_MAX_BINS + bin;
if (idx >= NETDATA_FS_MAX_ELEMENTS)
return;

fill = bpf_map_lookup_elem(&tbl_btrfs, &idx);
if (fill) {
libnetdata_update_u64(fill, 1);
return;
}

data = 1;
bpf_map_update_elem(&tbl_btrfs, &idx, &data, BPF_ANY);
}

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0))
SEC("kretprobe/btrfs_file_read_iter")
int netdata_ret_btrfs_file_read_iter(struct pt_regs *ctx)
#else
SEC("kretprobe/generic_file_read_iter")
int netdata_ret_generic_file_read_iter(struct pt_regs *ctx)
#endif
{
__u64 *fill, data;
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 bin, pid = (__u32)(pid_tgid >> 32);

fill = bpf_map_lookup_elem(&tmp_btrfs, &pid);
if (!fill)
return 0;

data = bpf_ktime_get_ns() - *fill;
bpf_map_delete_elem(&tmp_btrfs, &pid);

// Skip entries with backward time
if ( (s64)data < 0)
return 0;

// convert to microseconds
data /= 1000;
bin = libnetdata_select_idx(data, NETDATA_FS_MAX_BINS_POS);
netdata_btrfs_store_bin(bin, NETDATA_KEY_CALLS_READ);

return 0;
}

SEC("kretprobe/btrfs_file_write_iter")
int netdata_ret_btrfs_file_write_iter(struct pt_regs *ctx)
{
__u64 *fill, data;
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 bin, pid = (__u32)(pid_tgid >> 32);

fill = bpf_map_lookup_elem(&tmp_btrfs, &pid);
if (!fill)
return 0;

data = bpf_ktime_get_ns() - *fill;
bpf_map_delete_elem(&tmp_btrfs, &pid);

// Skip entries with backward time
if ( (s64)data < 0)
return 0;

// convert to microseconds
data /= 1000;
bin = libnetdata_select_idx(data, NETDATA_FS_MAX_BINS_POS);
netdata_btrfs_store_bin(bin, NETDATA_KEY_CALLS_WRITE);

return 0;
}

SEC("kretprobe/btrfs_file_open")
int netdata_ret_btrfs_file_open(struct pt_regs *ctx)
{
__u64 *fill, data;
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 bin, pid = (__u32)(pid_tgid >> 32);

fill = bpf_map_lookup_elem(&tmp_btrfs, &pid);
if (!fill)
return 0;

data = bpf_ktime_get_ns() - *fill;
bpf_map_delete_elem(&tmp_btrfs, &pid);

// Skip entries with backward time
if ( (s64)data < 0)
return 0;

// convert to microseconds
data /= 1000;
bin = libnetdata_select_idx(data, NETDATA_FS_MAX_BINS_POS);
netdata_btrfs_store_bin(bin, NETDATA_KEY_CALLS_OPEN);

return 0;
}

SEC("kretprobe/btrfs_sync_file")
int netdata_ret_btrfs_sync_file(struct pt_regs *ctx)
{
__u64 *fill, data;
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 bin, pid = (__u32)(pid_tgid >> 32);

fill = bpf_map_lookup_elem(&tmp_btrfs, &pid);
if (!fill)
return 0;

data = bpf_ktime_get_ns() - *fill;
bpf_map_delete_elem(&tmp_btrfs, &pid);

// Skip entries with backward time
if ( (s64)data < 0)
return 0;

// convert to microseconds
data /= 1000;
bin = libnetdata_select_idx(data, NETDATA_FS_MAX_BINS_POS);
netdata_btrfs_store_bin(bin, NETDATA_KEY_CALLS_SYNC);

return 0;
}

char _license[] SEC("license") = "GPL";

6 changes: 3 additions & 3 deletions kernel/rename_binaries.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ select_kernel_version() {
elif [ "${KVER}" -ge "${VER5_10_0}" ]; then
KSELECTED="5.10";
elif [ "${KVER}" -ge "${VER4_17_0}" ]; then
KSELECTED="4.17";
KSELECTED="5.4";
elif [ "${KVER}" -ge "${VER4_15_0}" ]; then
KSELECTED="4.15";
KSELECTED="4.16";
elif [ "${KVER}" -ge "${VER4_11_0}" ]; then
KSELECTED="4.11";
KSELECTED="4.14";
fi

echo "${KSELECTED}"
Expand Down

0 comments on commit a9c3167

Please sign in to comment.