From a9c3167beb0b0d6138d062fc61f222715bfe4dde Mon Sep 17 00:00:00 2001 From: thiagoftsm Date: Mon, 19 Jul 2021 14:32:48 +0000 Subject: [PATCH] eBPF btrfs (#243) Add new filesystem. --- kernel/Makefile | 3 +- kernel/btrfs_kern.c | 251 ++++++++++++++++++++++++++++++++++++++ kernel/rename_binaries.sh | 6 +- 3 files changed, 256 insertions(+), 4 deletions(-) create mode 100644 kernel/btrfs_kern.c diff --git a/kernel/Makefile b/kernel/Makefile index 16d7733d..068fe0fe 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -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 \ diff --git a/kernel/btrfs_kern.c b/kernel/btrfs_kern.c new file mode 100644 index 00000000..55fa7488 --- /dev/null +++ b/kernel/btrfs_kern.c @@ -0,0 +1,251 @@ +#define KBUILD_MODNAME "btrfs_netdata" +#include +#include +#include +#include +// Condition added because struct kiocb was moved when 4.1.0 was released +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)) +#include +#else +#include +#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"; + diff --git a/kernel/rename_binaries.sh b/kernel/rename_binaries.sh index 63128196..7944a501 100644 --- a/kernel/rename_binaries.sh +++ b/kernel/rename_binaries.sh @@ -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}"