diff --git a/collect-module-adapt-to-the-5.10-kernel.patch b/collect-module-adapt-to-the-5.10-kernel.patch index 03aab3793aef415fbb0f6f97288dc45137718089..4359a5a6a106cad1e201a62e6664c4cb6dc27221 100644 --- a/collect-module-adapt-to-the-5.10-kernel.patch +++ b/collect-module-adapt-to-the-5.10-kernel.patch @@ -63,1654 +63,1654 @@ index 0000000..cedd3ce --- /dev/null +++ b/service/sentryCollector.service @@ -0,0 +1,12 @@ -+[Unit] -+Description = Collection module added for sysSentry -+ -+[Service] -+ExecStart=/usr/bin/python3 /usr/bin/sentryCollector -+ExecStop=/bin/kill $MAINPID -+KillMode=process -+Restart=on-failure -+RestartSec=10s -+ -+[Install] -+WantedBy = multi-user.target ++[Unit] ++Description = Collection module added for sysSentry ++ ++[Service] ++ExecStart=/usr/bin/python3 /usr/bin/sentryCollector ++ExecStop=/bin/kill $MAINPID ++KillMode=process ++Restart=on-failure ++RestartSec=10s ++ ++[Install] ++WantedBy = multi-user.target diff --git a/src/c/ebpf_collector/Makefile b/src/c/ebpf_collector/Makefile new file mode 100644 index 0000000..a432637 --- /dev/null +++ b/src/c/ebpf_collector/Makefile @@ -0,0 +1,38 @@ -+# 定义编译器 -+CC = clang -+ -+ARCH := $(shell uname -m | sed 's/x86_64/x86/' | sed 's/aarch64/arm64/' | sed 's/ppc64le/powerpc/' | sed 's/mips.*/mips/') -+ -+# 定义内核态编译选项 -+KERNEL_CFLAGS = -O2 -g -target bpf -D__TARGET_ARCH_$(ARCH) -+ -+# 定义用户态编译选项 -+USER_CFLAGS = -g -lbpf -+ -+# 定义目标文件 -+KERNEL_TARGET = ebpf_collector.bpf.o -+USER_TARGET = ebpf_collector -+SKELETON_HEADER = ebpf_collector.skel.h -+ -+# 默认目标 -+all: $(KERNEL_TARGET) $(SKELETON_HEADER) $(USER_TARGET) -+ -+# 编译内核态文件 -+$(KERNEL_TARGET): ebpf_collector.bpf.c -+ $(CC) $(KERNEL_CFLAGS) -c $< -o $@ -+ -+# 生成骨架文件 -+$(SKELETON_HEADER): $(KERNEL_TARGET) -+ bpftool gen skeleton $< > $@ -+ rm -f $< -+ -+# 编译用户态文件 -+$(USER_TARGET): ebpf_collector.c $(SKELETON_HEADER) -+ $(CC) $(USER_CFLAGS) $< -o $@ -+ -+# 清理生成的文件 -+clean: -+ rm -f $(KERNEL_TARGET) $(SKELETON_HEADER) $(USER_TARGET) -+ -+# 伪目标,避免与文件名冲突 -+.PHONY: all clean ++# 定义编译器 ++CC = clang ++ ++ARCH := $(shell uname -m | sed 's/x86_64/x86/' | sed 's/aarch64/arm64/' | sed 's/ppc64le/powerpc/' | sed 's/mips.*/mips/') ++ ++# 定义内核态编译选项 ++KERNEL_CFLAGS = -O2 -g -target bpf -D__TARGET_ARCH_$(ARCH) ++ ++# 定义用户态编译选项 ++USER_CFLAGS = -g -lbpf ++ ++# 定义目标文件 ++KERNEL_TARGET = ebpf_collector.bpf.o ++USER_TARGET = ebpf_collector ++SKELETON_HEADER = ebpf_collector.skel.h ++ ++# 默认目标 ++all: $(KERNEL_TARGET) $(SKELETON_HEADER) $(USER_TARGET) ++ ++# 编译内核态文件 ++$(KERNEL_TARGET): ebpf_collector.bpf.c ++ $(CC) $(KERNEL_CFLAGS) -c $< -o $@ ++ ++# 生成骨架文件 ++$(SKELETON_HEADER): $(KERNEL_TARGET) ++ bpftool gen skeleton $< > $@ ++ rm -f $< ++ ++# 编译用户态文件 ++$(USER_TARGET): ebpf_collector.c $(SKELETON_HEADER) ++ $(CC) $(USER_CFLAGS) $< -o $@ ++ ++# 清理生成的文件 ++clean: ++ rm -f $(KERNEL_TARGET) $(SKELETON_HEADER) $(USER_TARGET) ++ ++# 伪目标,避免与文件名冲突 ++.PHONY: all clean diff --git a/src/c/ebpf_collector/ebpf_collector.bpf.c b/src/c/ebpf_collector/ebpf_collector.bpf.c new file mode 100644 index 0000000..6640f9a --- /dev/null +++ b/src/c/ebpf_collector/ebpf_collector.bpf.c @@ -0,0 +1,950 @@ -+/* -+ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. -+ * Description: ebpf collector program -+ * Author: Zhang Nan -+ * Create: 2024-09-27 -+ */ -+ -+#include "vmlinux.h" -+#include -+#include -+#include -+#include "ebpf_collector.h" -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_HASH); -+ __uint(max_entries, 10000); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct io_counter)); -+} blk_map SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_ARRAY); -+ __uint(max_entries, 128); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct stage_data)); -+} blk_res SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_HASH); -+ __uint(max_entries, 10000); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct io_counter)); -+} bio_map SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_ARRAY); -+ __uint(max_entries, 128); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct stage_data)); -+} bio_res SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_HASH); -+ __uint(max_entries, 10000); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct io_counter)); -+} wbt_map SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_ARRAY); -+ __uint(max_entries, 128); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct stage_data)); -+} wbt_res SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_HASH); -+ __uint(max_entries, 1000); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(u64)); -+} wbt_args SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_HASH); -+ __uint(max_entries, 10000); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct io_counter)); -+} tag_map SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_ARRAY); -+ __uint(max_entries, 128); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct stage_data)); -+} tag_res SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_HASH); -+ __uint(max_entries, 1000); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(u64)); -+} tag_args SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_HASH); -+ __uint(max_entries, MAX_IO_TIME); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct time_range_io_count)); -+} blk_res_2 SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_HASH); -+ __uint(max_entries, MAX_IO_TIME); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct time_range_io_count)); -+} bio_res_2 SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_HASH); -+ __uint(max_entries, MAX_IO_TIME); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct time_range_io_count)); -+} wbt_res_2 SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_HASH); -+ __uint(max_entries, MAX_IO_TIME); -+ __uint(key_size, sizeof(u32)); -+ __uint(value_size, sizeof(struct time_range_io_count)); -+} tag_res_2 SEC(".maps"); -+ -+struct { -+ __uint(type, BPF_MAP_TYPE_RINGBUF); -+ __uint(max_entries, 256 * 1024); -+} ringbuf SEC(".maps"); -+ -+ -+static void log_event(u32 stage, u32 period, u32 err) { -+ struct event *e; -+ void *data = bpf_ringbuf_reserve(&ringbuf, sizeof(struct event), 0); -+ if (!data) -+ return; -+ -+ e = (struct event *)data; -+ e->stage = stage; -+ e->period = period; -+ e->err = err; -+ -+ bpf_ringbuf_submit(e, 0); -+} -+ -+static __always_inline void blk_fill_rwbs(char *rwbs, unsigned int op) -+{ -+ switch (op & REQ_OP_MASK) { -+ case REQ_OP_WRITE: -+ case REQ_OP_WRITE_SAME: -+ rwbs[0] = 'W'; -+ break; -+ case REQ_OP_DISCARD: -+ rwbs[0] = 'D'; -+ break; -+ case REQ_OP_SECURE_ERASE: -+ rwbs[0] = 'E'; -+ break; -+ case REQ_OP_FLUSH: -+ rwbs[0] = 'F'; -+ break; -+ case REQ_OP_READ: -+ rwbs[0] = 'R'; -+ break; -+ default: -+ rwbs[0] = 'N'; -+ } -+ -+ if (op & REQ_FUA) { -+ rwbs[1] = 'F'; -+ } else { -+ rwbs[1] = '#'; -+ } -+ if (op & REQ_RAHEAD) { -+ rwbs[2] = 'A'; -+ } else { -+ rwbs[2] = '#'; -+ } -+ if (op & REQ_SYNC) { -+ rwbs[3] = 'S'; -+ } else { -+ rwbs[3] = '#'; -+ } -+ if (op & REQ_META) { -+ rwbs[4] = 'M'; -+ } else { -+ rwbs[4] = '#'; -+ } -+} -+ -+static void update_curr_data_in_start(struct stage_data *curr_data, struct update_params *params) { -+ if (curr_data && params) { -+ curr_data->start_count += 1; -+ curr_data->major = params->major; -+ curr_data->first_minor = params->first_minor; -+ blk_fill_rwbs(curr_data->io_type, params->cmd_flags); -+ } -+} -+ -+static void update_curr_data_in_finish(struct stage_data *curr_data, struct update_params *params, u64 duration) { -+ if (curr_data && params) { -+ curr_data->finish_count += 1; -+ curr_data->major = params->major; -+ curr_data->first_minor = params->first_minor; -+ blk_fill_rwbs(curr_data->io_type, params->cmd_flags); -+ if (duration > DURATION_THRESHOLD) { -+ curr_data->finish_over_time += 1; -+ } -+ } -+} -+ -+static void init_io_counter(struct io_counter *counterp, int major, int first_minor) { -+ if (counterp) { -+ counterp->start_time = bpf_ktime_get_ns(); -+ counterp->major = major; -+ counterp->first_minor = first_minor; -+ } -+} -+ -+int find_matching_key_rq_driver(int major, int first_minor) { -+ int key = 0; -+ for (size_t i = 0; i < MAP_SIZE; i++) { -+ struct stage_data *curr_data = bpf_map_lookup_elem(&blk_res, &key); -+ struct stage_data tmp_data; -+ bpf_core_read(&tmp_data, sizeof(tmp_data), curr_data); -+ if (tmp_data.major == major && tmp_data.first_minor == first_minor) { -+ return key; -+ } -+ key++; -+ } -+ return key; -+} -+ -+int find_matching_key_bio(int major, int first_minor) { -+ int key = 0; -+ for (size_t i = 0; i < MAP_SIZE; i++) { -+ struct stage_data *curr_data = bpf_map_lookup_elem(&bio_res, &key); -+ struct stage_data tmp_data; -+ bpf_core_read(&tmp_data, sizeof(tmp_data), curr_data); -+ if (tmp_data.major == major && tmp_data.first_minor == first_minor) { -+ return key; -+ } -+ key++; -+ } -+ return key; -+} -+ -+int find_matching_key_wbt(int major, int first_minor) { -+ int key = 0; -+ for (size_t i = 0; i < MAP_SIZE; i++) { -+ struct stage_data *curr_data = bpf_map_lookup_elem(&wbt_res, &key); -+ struct stage_data tmp_data; -+ bpf_core_read(&tmp_data, sizeof(tmp_data), curr_data); -+ if (tmp_data.major == major && tmp_data.first_minor == first_minor) { -+ return key; -+ } -+ key++; -+ } -+ return key; -+} -+ -+int find_matching_key_get_tag(int major, int first_minor) { -+ int key = 0; -+ for (size_t i = 0; i < MAP_SIZE; i++) { -+ struct stage_data *curr_data = bpf_map_lookup_elem(&tag_res, &key); -+ struct stage_data tmp_data; -+ bpf_core_read(&tmp_data, sizeof(tmp_data), curr_data); -+ if (tmp_data.major == major && tmp_data.first_minor == first_minor) { -+ return key; -+ } -+ key++; -+ } -+ return key; -+} -+ -+// start rq_driver -+SEC("kprobe/blk_mq_start_request") -+int kprobe_blk_mq_start_request(struct pt_regs *regs) { -+ struct request *rq; -+ struct gendisk *curr_rq_disk; -+ int major, first_minor; -+ unsigned int cmd_flags; -+ -+ rq = (struct request *)PT_REGS_PARM1(regs); -+ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &rq->rq_disk); -+ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); -+ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); -+ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &rq->cmd_flags); -+ -+ if (major == 0) { -+ log_event(STAGE_RQ_DRIVER, PERIOD_START, ERROR_MAJOR_ZERO); -+ return 0; -+ } -+ -+ u32 key = find_matching_key_rq_driver(major, first_minor); -+ if (key >= MAP_SIZE) { -+ return 0; -+ } -+ -+ struct io_counter *counterp, zero = {}; -+ init_io_counter(&zero, major, first_minor); -+ counterp = bpf_map_lookup_elem(&blk_map, &rq); -+ if (counterp) { -+ return 0; -+ } -+ -+ long err = bpf_map_update_elem(&blk_map, &rq, &zero, BPF_NOEXIST); -+ if (err) { -+ log_event(STAGE_RQ_DRIVER, PERIOD_START, ERROR_UPDATE_FAIL); -+ return 0; -+ } -+ -+ u64 curr_start_range = zero.start_time / THRESHOLD; -+ -+ struct update_params params = { -+ .major = major, -+ .first_minor = first_minor, -+ .cmd_flags = cmd_flags, -+ .curr_start_range = curr_start_range, -+ }; -+ -+ struct stage_data *curr_data; -+ curr_data = bpf_map_lookup_elem(&blk_res, &key); -+ if (!curr_data) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 0, -+ .finish_over_time = 0, -+ .duration = 0, -+ .major = major, -+ .first_minor = first_minor, -+ .io_type = "", -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&blk_res, &key, &new_data, 0); -+ } else { -+ update_curr_data_in_start(curr_data, ¶ms); -+ } -+ -+ struct time_range_io_count *curr_data_time_range; -+ curr_data_time_range = bpf_map_lookup_elem(&blk_res_2, &curr_start_range); -+ if (curr_data_time_range == NULL) { -+ struct time_range_io_count new_data = { .count = {0} }; -+ bpf_map_update_elem(&blk_res_2, &curr_start_range, &new_data, 0); -+ } else { -+ if (key < MAP_SIZE && key >= 0) { -+ __sync_fetch_and_add(&curr_data_time_range->count[key], 1); -+ } -+ } -+ return 0; -+} -+ -+// finish rq_driver -+SEC("kprobe/blk_mq_free_request") -+int kprobe_blk_mq_free_request(struct pt_regs *regs) -+{ -+ struct request *rq; -+ struct gendisk *curr_rq_disk; -+ int major, first_minor; -+ unsigned int cmd_flags; -+ struct io_counter *counterp; -+ -+ rq = (struct request *)PT_REGS_PARM1(regs); -+ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &rq->rq_disk); -+ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); -+ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); -+ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &rq->cmd_flags); -+ -+ if (major == 0) { -+ log_event(STAGE_RQ_DRIVER, PERIOD_END, ERROR_MAJOR_ZERO); -+ return 0; -+ } -+ -+ u32 key = find_matching_key_rq_driver(major, first_minor); -+ if (key >= MAP_SIZE) { -+ return 0; -+ } -+ -+ counterp = bpf_map_lookup_elem(&blk_map, &rq); -+ if (!counterp) { -+ return 0; -+ } -+ -+ u64 duration = bpf_ktime_get_ns() - counterp->start_time; -+ u64 curr_start_range = counterp->start_time / THRESHOLD; -+ -+ struct update_params params = { -+ .major = major, -+ .first_minor = first_minor, -+ .cmd_flags = cmd_flags, -+ .curr_start_range = curr_start_range, -+ }; -+ -+ struct stage_data *curr_data; -+ curr_data = bpf_map_lookup_elem(&blk_res, &key); -+ if (curr_data == NULL && duration > DURATION_THRESHOLD) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 1, -+ .finish_over_time = 1, -+ .duration = 0, -+ .major = major, -+ .first_minor = first_minor, -+ .io_type = "", -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&blk_res, &key, &new_data, 0); -+ } else if (curr_data == NULL) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 1, -+ .finish_over_time = 0, -+ .duration = 0, -+ .major = major, -+ .first_minor = first_minor, -+ .io_type = "", -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&blk_res, &key, &new_data, 0); -+ } else { -+ curr_data->duration += duration; -+ update_curr_data_in_finish(curr_data, ¶ms, duration); -+ } -+ -+ struct time_range_io_count *curr_data_time_range; -+ curr_data_time_range = bpf_map_lookup_elem(&blk_res_2, &curr_start_range); -+ if (curr_data_time_range == NULL) { -+ struct time_range_io_count new_data = { .count = {0} }; -+ bpf_map_update_elem(&blk_res_2, &curr_start_range, &new_data, 0); -+ } else { -+ if (key < MAP_SIZE && curr_data_time_range->count[key] > 0) { -+ __sync_fetch_and_add(&curr_data_time_range->count[key], -1); -+ } -+ } -+ bpf_map_delete_elem(&blk_map, &rq); -+ return 0; -+} -+ -+// start bio -+SEC("kprobe/blk_mq_submit_bio") -+int kprobe_blk_mq_submit_bio(struct pt_regs *regs) -+{ -+ struct bio *bio; -+ struct gendisk *curr_rq_disk; -+ int major, first_minor; -+ unsigned int cmd_flags; -+ -+ bio = (struct bio *)PT_REGS_PARM1(regs); -+ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &bio->bi_disk); -+ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); -+ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); -+ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &bio->bi_opf); -+ -+ if (major == 0) { -+ log_event(STAGE_BIO, PERIOD_START, ERROR_MAJOR_ZERO); -+ return 0; -+ } -+ -+ int key = find_matching_key_bio(major, first_minor); -+ if (key >= MAP_SIZE) { -+ return 0; -+ } -+ -+ struct io_counter *counterp, zero = {}; -+ init_io_counter(&zero, major, first_minor); -+ -+ counterp = bpf_map_lookup_elem(&bio_map, &bio); -+ if (counterp) { -+ return 0; -+ } -+ -+ long err = bpf_map_update_elem(&bio_map, &bio, &zero, BPF_NOEXIST); -+ if (err) { -+ log_event(STAGE_BIO, PERIOD_START, ERROR_UPDATE_FAIL); -+ return 0; -+ } -+ -+ u64 curr_start_range = zero.start_time / THRESHOLD; -+ -+ struct update_params params = { -+ .major = major, -+ .first_minor = first_minor, -+ .cmd_flags = cmd_flags, -+ .curr_start_range = curr_start_range, -+ }; -+ -+ struct stage_data *curr_data; -+ curr_data = bpf_map_lookup_elem(&bio_res, &key); -+ if (curr_data == NULL) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 0, -+ .finish_over_time = 0, -+ .duration = 0, -+ .major = major, -+ .first_minor = first_minor, -+ .io_type = "", -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&bio_res, &key, &new_data, 0); -+ } else { -+ update_curr_data_in_start(curr_data, ¶ms); -+ } -+ -+ struct time_range_io_count *curr_data_time_range; -+ curr_data_time_range = bpf_map_lookup_elem(&bio_res_2, &curr_start_range); -+ if (curr_data_time_range == NULL) { -+ struct time_range_io_count new_data = { .count = {0} }; -+ bpf_map_update_elem(&bio_res_2, &curr_start_range, &new_data, 0); -+ } else { -+ if (key < MAP_SIZE && key >= 0) { -+ __sync_fetch_and_add(&curr_data_time_range->count[key], 1); -+ } -+ } -+ return 0; -+} -+ -+// finish bio -+SEC("kprobe/bio_endio") -+int kprobe_bio_endio(struct pt_regs *regs) -+{ -+ struct bio *bio; -+ struct gendisk *curr_rq_disk; -+ int major, first_minor; -+ unsigned int cmd_flags; -+ -+ bio = (struct bio *)PT_REGS_PARM1(regs); -+ // bpf_core_read(&bd, sizeof(bd), &bio->bi_disk); -+ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &bio->bi_disk); -+ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); -+ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); -+ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &bio->bi_opf); -+ -+ if (major == 0) { -+ log_event(STAGE_BIO, PERIOD_END, ERROR_MAJOR_ZERO); -+ return 0; -+ } -+ -+ u32 key = find_matching_key_bio(major, first_minor); -+ if (key >= MAP_SIZE) { -+ return 0; -+ } -+ -+ void *delete_map = NULL; -+ struct io_counter *counterp = bpf_map_lookup_elem(&bio_map, &bio); -+ if (!counterp) { -+ return 0; -+ } -+ -+ delete_map = &bio_map; -+ -+ u64 duration = bpf_ktime_get_ns() - counterp->start_time; -+ u64 curr_start_range = counterp->start_time / THRESHOLD; -+ -+ struct update_params params = { -+ .major = major, -+ .first_minor = first_minor, -+ .cmd_flags = cmd_flags, -+ .curr_start_range = curr_start_range, -+ }; -+ -+ struct stage_data *curr_data; -+ curr_data = bpf_map_lookup_elem(&bio_res, &key); -+ if (curr_data == NULL && duration > DURATION_THRESHOLD) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 1, -+ .finish_over_time = 1, -+ .duration = 0, -+ .major = major, -+ .first_minor = first_minor, -+ .io_type = "", -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&bio_res, &key, &new_data, 0); -+ } else if (curr_data == NULL) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 1, -+ .finish_over_time = 0, -+ .duration = 0, -+ .major = major, -+ .first_minor = first_minor, -+ .io_type = "", -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&bio_res, &key, &new_data, 0); -+ } else { -+ curr_data->duration += duration; -+ update_curr_data_in_finish(curr_data, ¶ms, duration); -+ } -+ -+ struct time_range_io_count *curr_data_time_range; -+ curr_data_time_range = bpf_map_lookup_elem(&bio_res_2, &curr_start_range); -+ if (curr_data_time_range == NULL) { -+ struct time_range_io_count new_data = { .count = {0} }; -+ bpf_map_update_elem(&bio_res_2, &curr_start_range, &new_data, 0); -+ } else { -+ if (key < MAP_SIZE && curr_data_time_range->count[key] > 0) { -+ __sync_fetch_and_add(&curr_data_time_range->count[key], -1); -+ } -+ } -+ bpf_map_delete_elem(delete_map, &bio); -+ return 0; -+} -+ -+// start get_tag -+SEC("kprobe/blk_mq_get_tag") -+int kprobe_blk_mq_get_tag(struct pt_regs *regs) -+{ -+ u64 tagkey = bpf_get_current_task(); -+ u64 value = (u64)PT_REGS_PARM1(regs); -+ (void)bpf_map_update_elem(&tag_args, &tagkey, &value, BPF_ANY); -+ -+ struct blk_mq_alloc_data *bd; -+ struct request_queue *q; -+ struct backing_dev_info *backing_dev_info; -+ struct device *owner; -+ dev_t devt; -+ unsigned int cmd_flags = 0; -+ -+ bd = (struct blk_mq_alloc_data *)value; -+ bpf_core_read(&q, sizeof(q), &bd->q); -+ bpf_core_read(&backing_dev_info, sizeof(backing_dev_info), &q->backing_dev_info); -+ bpf_core_read(&owner, sizeof(owner), &backing_dev_info->owner); -+ bpf_core_read(&devt, sizeof(devt), &owner->devt); -+ int major = MAJOR(devt); -+ int first_minor = MINOR(devt); -+ -+ if (major == 0) { -+ log_event(STAGE_GET_TAG, PERIOD_START, ERROR_MAJOR_ZERO); -+ return 0; -+ } -+ -+ u32 key = find_matching_key_get_tag(major, first_minor); -+ if (key >= MAP_SIZE) { -+ return 0; -+ } -+ -+ struct io_counter *counterp, zero = {}; -+ init_io_counter(&zero, major, first_minor); -+ counterp = bpf_map_lookup_elem(&tag_map, &tagkey); -+ if (counterp) { -+ return 0; -+ } -+ long err = bpf_map_update_elem(&tag_map, &tagkey, &zero, BPF_NOEXIST); -+ if (err) { -+ log_event(STAGE_GET_TAG, PERIOD_START, ERROR_UPDATE_FAIL); -+ return 0; -+ } -+ -+ u64 curr_start_range = zero.start_time / THRESHOLD; -+ -+ struct update_params params = { -+ .major = major, -+ .first_minor = first_minor, -+ .cmd_flags = cmd_flags, -+ .curr_start_range = curr_start_range, -+ }; -+ -+ struct stage_data *curr_data; -+ curr_data = bpf_map_lookup_elem(&tag_res, &key); -+ if (!curr_data) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 0, -+ .finish_over_time = 0, -+ .duration = 0, -+ .major = major, -+ .first_minor = first_minor, -+ .io_type = "", -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&tag_res, &key, &new_data, 0); -+ } else { -+ update_curr_data_in_start(curr_data, ¶ms); -+ } -+ -+ struct time_range_io_count *curr_data_time_range; -+ curr_data_time_range = bpf_map_lookup_elem(&tag_res_2, &curr_start_range); -+ if (curr_data_time_range == NULL) { -+ struct time_range_io_count new_data = { .count = {0} }; -+ bpf_map_update_elem(&tag_res_2, &curr_start_range, &new_data, 0); -+ } else { -+ if (key < MAP_SIZE && key >= 0) { -+ __sync_fetch_and_add(&curr_data_time_range->count[key], 1); -+ } -+ } -+ return 0; -+} -+ -+// finish get_tag -+SEC("kretprobe/blk_mq_get_tag") -+int kretprobe_blk_mq_get_tag(struct pt_regs *regs) -+{ -+ u64 tagkey = bpf_get_current_task(); -+ u64 *tagargs = (u64 *)bpf_map_lookup_elem(&tag_args, &tagkey); -+ if (tagargs == NULL) { -+ bpf_map_delete_elem(&tag_args, &tagkey); -+ return 0; -+ } -+ -+ struct blk_mq_alloc_data *bd; -+ struct request_queue *q; -+ struct backing_dev_info *backing_dev_info; -+ struct device *owner; -+ dev_t devt; -+ unsigned int cmd_flags = 0; -+ -+ bd = (struct blk_mq_alloc_data *)*tagargs; -+ bpf_core_read(&q, sizeof(q), &bd->q); -+ bpf_core_read(&backing_dev_info, sizeof(backing_dev_info), &q->backing_dev_info); -+ bpf_core_read(&owner, sizeof(owner), &backing_dev_info->owner); -+ bpf_core_read(&devt, sizeof(devt), &owner->devt); -+ int major = MAJOR(devt); -+ int first_minor = MINOR(devt); -+ -+ if (major == 0) { -+ log_event(STAGE_GET_TAG, PERIOD_END, ERROR_MAJOR_ZERO); -+ return 0; -+ } -+ -+ u32 key = find_matching_key_get_tag(major, first_minor); -+ if (key >= MAP_SIZE) { -+ return 0; -+ } -+ -+ struct io_counter *counterp = bpf_map_lookup_elem(&tag_map, &tagkey); -+ if (!counterp) { -+ return 0; -+ } -+ -+ u64 duration = bpf_ktime_get_ns() - counterp->start_time; -+ u64 curr_start_range = counterp->start_time / THRESHOLD; -+ -+ struct update_params params = { -+ .major = major, -+ .first_minor = first_minor, -+ .cmd_flags = cmd_flags, -+ .curr_start_range = curr_start_range, -+ }; -+ -+ struct stage_data *curr_data; -+ curr_data = bpf_map_lookup_elem(&tag_res, &key); -+ if (curr_data == NULL && duration > DURATION_THRESHOLD) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 1, -+ .finish_over_time = 1, -+ .duration = 0, -+ .major = major, -+ .first_minor = first_minor, -+ .io_type = "", -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&tag_res, &key, &new_data, 0); -+ } else if (curr_data == NULL) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 1, -+ .finish_over_time = 0, -+ .duration = 0, -+ .major = major, -+ .first_minor = first_minor, -+ .io_type = "", -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&tag_res, &key, &new_data, 0); -+ } else { -+ curr_data->duration += duration; -+ update_curr_data_in_finish(curr_data, ¶ms, duration); -+ } -+ -+ struct time_range_io_count *curr_data_time_range; -+ curr_data_time_range = bpf_map_lookup_elem(&tag_res_2, &curr_start_range); -+ if (curr_data_time_range == NULL) { -+ struct time_range_io_count new_data = { .count = {0} }; -+ bpf_map_update_elem(&tag_res_2, &curr_start_range, &new_data, 0); -+ } else { -+ if (key < MAP_SIZE && curr_data_time_range->count[key] > 0) { -+ __sync_fetch_and_add(&curr_data_time_range->count[key], -1); -+ } -+ } -+ -+ bpf_map_delete_elem(&tag_map, &tagkey); -+ bpf_map_delete_elem(&tag_args, &tagkey); -+ return 0; -+} -+ -+// start wbt -+SEC("kprobe/wbt_wait") -+int kprobe_wbt_wait(struct pt_regs *regs) -+{ -+ u64 wbtkey = bpf_get_current_task(); -+ u64 value = (u64)PT_REGS_PARM2(regs); -+ (void)bpf_map_update_elem(&wbt_args, &wbtkey, &value, BPF_ANY); -+ -+ struct bio *bio; -+ struct gendisk *curr_rq_disk; -+ int major, first_minor; -+ unsigned int cmd_flags; -+ -+ bio = (struct bio *)value; -+ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &bio->bi_disk); -+ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); -+ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); -+ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &bio->bi_opf); -+ -+ if (major == 0) { -+ log_event(STAGE_WBT, PERIOD_START, ERROR_MAJOR_ZERO); -+ return 0; -+ } -+ -+ u32 key = find_matching_key_wbt(major, first_minor); -+ if (key >= MAP_SIZE) { -+ return 0; -+ } -+ -+ struct io_counter *counterp, zero = {}; -+ init_io_counter(&zero, major, first_minor); -+ counterp = bpf_map_lookup_elem(&wbt_map, &wbtkey); -+ if (counterp) { -+ return 0; -+ } -+ long err = bpf_map_update_elem(&wbt_map, &wbtkey, &zero, BPF_NOEXIST); -+ if (err) { -+ log_event(STAGE_WBT, PERIOD_START, ERROR_UPDATE_FAIL); -+ return 0; -+ } -+ -+ u64 curr_start_range = zero.start_time / THRESHOLD; -+ -+ struct update_params params = { -+ .major = major, -+ .first_minor = first_minor, -+ .cmd_flags = cmd_flags, -+ .curr_start_range = curr_start_range, -+ }; -+ -+ struct stage_data *curr_data; -+ curr_data = bpf_map_lookup_elem(&wbt_res, &key); -+ if (!curr_data) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 0, -+ .finish_over_time = 0, -+ .duration = 0, -+ .major = major, -+ .first_minor = first_minor, -+ .io_type = "", -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&wbt_res, &key, &new_data, 0); -+ } else { -+ update_curr_data_in_start(curr_data, ¶ms); -+ } -+ -+ struct time_range_io_count *curr_data_time_range; -+ curr_data_time_range = bpf_map_lookup_elem(&wbt_res_2, &curr_start_range); -+ if (curr_data_time_range == NULL) { -+ struct time_range_io_count new_data = { .count = {0} }; -+ bpf_map_update_elem(&wbt_res_2, &curr_start_range, &new_data, 0); -+ } else { -+ if (key < MAP_SIZE && key >= 0) { -+ __sync_fetch_and_add(&curr_data_time_range->count[key], 1); -+ } -+ } -+ return 0; -+} -+ -+// finish wbt -+SEC("kretprobe/wbt_wait") -+int kretprobe_wbt_wait(struct pt_regs *regs) -+{ -+ u64 wbtkey = bpf_get_current_task(); -+ u64 *wbtargs = (u64 *)bpf_map_lookup_elem(&wbt_args, &wbtkey); -+ if (wbtargs == NULL) { -+ bpf_map_delete_elem(&wbt_args, &wbtkey); -+ return 0; -+ } -+ -+ struct bio *bio; -+ struct gendisk *curr_rq_disk; -+ int major, first_minor; -+ unsigned int cmd_flags; -+ -+ bio = (struct bio *)(*wbtargs); -+ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &bio->bi_disk); -+ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); -+ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); -+ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &bio->bi_opf); -+ -+ if (major == 0) { -+ log_event(STAGE_WBT, PERIOD_END, ERROR_MAJOR_ZERO); -+ return 0; -+ } -+ -+ u32 key = find_matching_key_wbt(major, first_minor); -+ if (key >= MAP_SIZE) { -+ return 0; -+ } -+ -+ struct io_counter *counterp = bpf_map_lookup_elem(&wbt_map, &wbtkey); -+ if (!counterp) { -+ return 0; -+ } -+ -+ u64 duration = bpf_ktime_get_ns() - counterp->start_time; -+ u64 curr_start_range = counterp->start_time / THRESHOLD; -+ -+ struct update_params params = { -+ .major = major, -+ .first_minor = first_minor, -+ .cmd_flags = cmd_flags, -+ .curr_start_range = curr_start_range, -+ }; -+ -+ struct stage_data *curr_data; -+ curr_data = bpf_map_lookup_elem(&wbt_res, &key); -+ if (curr_data == NULL && duration > DURATION_THRESHOLD) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 1, -+ .finish_over_time = 1, -+ .duration = 0, -+ .major = major, -+ .first_minor = first_minor, -+ .io_type = "", -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&wbt_res, &key, &new_data, 0); -+ } else if (curr_data == NULL) { -+ struct stage_data new_data = { -+ .start_count = 1, -+ .finish_count = 1, -+ .finish_over_time = 0, -+ .duration = 0, -+ .io_type = "", -+ .major = major, -+ .first_minor = first_minor, -+ }; -+ blk_fill_rwbs(new_data.io_type, cmd_flags); -+ bpf_map_update_elem(&wbt_res, &key, &new_data, 0); -+ } else { -+ curr_data->duration += duration; -+ update_curr_data_in_finish(curr_data, ¶ms, duration); -+ } -+ -+ struct time_range_io_count *curr_data_time_range; -+ curr_data_time_range = bpf_map_lookup_elem(&wbt_res_2, &curr_start_range); -+ if (curr_data_time_range == NULL) { -+ struct time_range_io_count new_data = { .count = {0} }; -+ bpf_map_update_elem(&wbt_res_2, &curr_start_range, &new_data, 0); -+ } else { -+ if (key < MAP_SIZE && curr_data_time_range->count[key] > 0) { -+ __sync_fetch_and_add(&curr_data_time_range->count[key], -1); -+ } -+ } -+ bpf_map_delete_elem(&wbt_map, &wbtkey); -+ bpf_map_delete_elem(&wbt_args, &wbtkey); -+ return 0; -+} -+ -+char _license[] SEC("license") = "GPL"; ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * Description: ebpf collector program ++ * Author: Zhang Nan ++ * Create: 2024-09-27 ++ */ ++ ++#include "vmlinux.h" ++#include ++#include ++#include ++#include "ebpf_collector.h" ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_HASH); ++ __uint(max_entries, 10000); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct io_counter)); ++} blk_map SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_ARRAY); ++ __uint(max_entries, 128); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct stage_data)); ++} blk_res SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_HASH); ++ __uint(max_entries, 10000); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct io_counter)); ++} bio_map SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_ARRAY); ++ __uint(max_entries, 128); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct stage_data)); ++} bio_res SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_HASH); ++ __uint(max_entries, 10000); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct io_counter)); ++} wbt_map SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_ARRAY); ++ __uint(max_entries, 128); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct stage_data)); ++} wbt_res SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_HASH); ++ __uint(max_entries, 1000); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(u64)); ++} wbt_args SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_HASH); ++ __uint(max_entries, 10000); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct io_counter)); ++} tag_map SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_ARRAY); ++ __uint(max_entries, 128); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct stage_data)); ++} tag_res SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_HASH); ++ __uint(max_entries, 1000); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(u64)); ++} tag_args SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_HASH); ++ __uint(max_entries, MAX_IO_TIME); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct time_range_io_count)); ++} blk_res_2 SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_HASH); ++ __uint(max_entries, MAX_IO_TIME); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct time_range_io_count)); ++} bio_res_2 SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_HASH); ++ __uint(max_entries, MAX_IO_TIME); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct time_range_io_count)); ++} wbt_res_2 SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_HASH); ++ __uint(max_entries, MAX_IO_TIME); ++ __uint(key_size, sizeof(u32)); ++ __uint(value_size, sizeof(struct time_range_io_count)); ++} tag_res_2 SEC(".maps"); ++ ++struct { ++ __uint(type, BPF_MAP_TYPE_RINGBUF); ++ __uint(max_entries, 256 * 1024); ++} ringbuf SEC(".maps"); ++ ++ ++static void log_event(u32 stage, u32 period, u32 err) { ++ struct event *e; ++ void *data = bpf_ringbuf_reserve(&ringbuf, sizeof(struct event), 0); ++ if (!data) ++ return; ++ ++ e = (struct event *)data; ++ e->stage = stage; ++ e->period = period; ++ e->err = err; ++ ++ bpf_ringbuf_submit(e, 0); ++} ++ ++static __always_inline void blk_fill_rwbs(char *rwbs, unsigned int op) ++{ ++ switch (op & REQ_OP_MASK) { ++ case REQ_OP_WRITE: ++ case REQ_OP_WRITE_SAME: ++ rwbs[0] = 'W'; ++ break; ++ case REQ_OP_DISCARD: ++ rwbs[0] = 'D'; ++ break; ++ case REQ_OP_SECURE_ERASE: ++ rwbs[0] = 'E'; ++ break; ++ case REQ_OP_FLUSH: ++ rwbs[0] = 'F'; ++ break; ++ case REQ_OP_READ: ++ rwbs[0] = 'R'; ++ break; ++ default: ++ rwbs[0] = 'N'; ++ } ++ ++ if (op & REQ_FUA) { ++ rwbs[1] = 'F'; ++ } else { ++ rwbs[1] = '#'; ++ } ++ if (op & REQ_RAHEAD) { ++ rwbs[2] = 'A'; ++ } else { ++ rwbs[2] = '#'; ++ } ++ if (op & REQ_SYNC) { ++ rwbs[3] = 'S'; ++ } else { ++ rwbs[3] = '#'; ++ } ++ if (op & REQ_META) { ++ rwbs[4] = 'M'; ++ } else { ++ rwbs[4] = '#'; ++ } ++} ++ ++static void update_curr_data_in_start(struct stage_data *curr_data, struct update_params *params) { ++ if (curr_data && params) { ++ curr_data->start_count += 1; ++ curr_data->major = params->major; ++ curr_data->first_minor = params->first_minor; ++ blk_fill_rwbs(curr_data->io_type, params->cmd_flags); ++ } ++} ++ ++static void update_curr_data_in_finish(struct stage_data *curr_data, struct update_params *params, u64 duration) { ++ if (curr_data && params) { ++ curr_data->finish_count += 1; ++ curr_data->major = params->major; ++ curr_data->first_minor = params->first_minor; ++ blk_fill_rwbs(curr_data->io_type, params->cmd_flags); ++ if (duration > DURATION_THRESHOLD) { ++ curr_data->finish_over_time += 1; ++ } ++ } ++} ++ ++static void init_io_counter(struct io_counter *counterp, int major, int first_minor) { ++ if (counterp) { ++ counterp->start_time = bpf_ktime_get_ns(); ++ counterp->major = major; ++ counterp->first_minor = first_minor; ++ } ++} ++ ++int find_matching_key_rq_driver(int major, int first_minor) { ++ int key = 0; ++ for (size_t i = 0; i < MAP_SIZE; i++) { ++ struct stage_data *curr_data = bpf_map_lookup_elem(&blk_res, &key); ++ struct stage_data tmp_data; ++ bpf_core_read(&tmp_data, sizeof(tmp_data), curr_data); ++ if (tmp_data.major == major && tmp_data.first_minor == first_minor) { ++ return key; ++ } ++ key++; ++ } ++ return key; ++} ++ ++int find_matching_key_bio(int major, int first_minor) { ++ int key = 0; ++ for (size_t i = 0; i < MAP_SIZE; i++) { ++ struct stage_data *curr_data = bpf_map_lookup_elem(&bio_res, &key); ++ struct stage_data tmp_data; ++ bpf_core_read(&tmp_data, sizeof(tmp_data), curr_data); ++ if (tmp_data.major == major && tmp_data.first_minor == first_minor) { ++ return key; ++ } ++ key++; ++ } ++ return key; ++} ++ ++int find_matching_key_wbt(int major, int first_minor) { ++ int key = 0; ++ for (size_t i = 0; i < MAP_SIZE; i++) { ++ struct stage_data *curr_data = bpf_map_lookup_elem(&wbt_res, &key); ++ struct stage_data tmp_data; ++ bpf_core_read(&tmp_data, sizeof(tmp_data), curr_data); ++ if (tmp_data.major == major && tmp_data.first_minor == first_minor) { ++ return key; ++ } ++ key++; ++ } ++ return key; ++} ++ ++int find_matching_key_get_tag(int major, int first_minor) { ++ int key = 0; ++ for (size_t i = 0; i < MAP_SIZE; i++) { ++ struct stage_data *curr_data = bpf_map_lookup_elem(&tag_res, &key); ++ struct stage_data tmp_data; ++ bpf_core_read(&tmp_data, sizeof(tmp_data), curr_data); ++ if (tmp_data.major == major && tmp_data.first_minor == first_minor) { ++ return key; ++ } ++ key++; ++ } ++ return key; ++} ++ ++// start rq_driver ++SEC("kprobe/blk_mq_start_request") ++int kprobe_blk_mq_start_request(struct pt_regs *regs) { ++ struct request *rq; ++ struct gendisk *curr_rq_disk; ++ int major, first_minor; ++ unsigned int cmd_flags; ++ ++ rq = (struct request *)PT_REGS_PARM1(regs); ++ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &rq->rq_disk); ++ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); ++ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); ++ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &rq->cmd_flags); ++ ++ if (major == 0) { ++ log_event(STAGE_RQ_DRIVER, PERIOD_START, ERROR_MAJOR_ZERO); ++ return 0; ++ } ++ ++ u32 key = find_matching_key_rq_driver(major, first_minor); ++ if (key >= MAP_SIZE) { ++ return 0; ++ } ++ ++ struct io_counter *counterp, zero = {}; ++ init_io_counter(&zero, major, first_minor); ++ counterp = bpf_map_lookup_elem(&blk_map, &rq); ++ if (counterp) { ++ return 0; ++ } ++ ++ long err = bpf_map_update_elem(&blk_map, &rq, &zero, BPF_NOEXIST); ++ if (err) { ++ log_event(STAGE_RQ_DRIVER, PERIOD_START, ERROR_UPDATE_FAIL); ++ return 0; ++ } ++ ++ u64 curr_start_range = zero.start_time / THRESHOLD; ++ ++ struct update_params params = { ++ .major = major, ++ .first_minor = first_minor, ++ .cmd_flags = cmd_flags, ++ .curr_start_range = curr_start_range, ++ }; ++ ++ struct stage_data *curr_data; ++ curr_data = bpf_map_lookup_elem(&blk_res, &key); ++ if (!curr_data) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 0, ++ .finish_over_time = 0, ++ .duration = 0, ++ .major = major, ++ .first_minor = first_minor, ++ .io_type = "", ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&blk_res, &key, &new_data, 0); ++ } else { ++ update_curr_data_in_start(curr_data, ¶ms); ++ } ++ ++ struct time_range_io_count *curr_data_time_range; ++ curr_data_time_range = bpf_map_lookup_elem(&blk_res_2, &curr_start_range); ++ if (curr_data_time_range == NULL) { ++ struct time_range_io_count new_data = { .count = {0} }; ++ bpf_map_update_elem(&blk_res_2, &curr_start_range, &new_data, 0); ++ } else { ++ if (key < MAP_SIZE && key >= 0) { ++ __sync_fetch_and_add(&curr_data_time_range->count[key], 1); ++ } ++ } ++ return 0; ++} ++ ++// finish rq_driver ++SEC("kprobe/blk_mq_free_request") ++int kprobe_blk_mq_free_request(struct pt_regs *regs) ++{ ++ struct request *rq; ++ struct gendisk *curr_rq_disk; ++ int major, first_minor; ++ unsigned int cmd_flags; ++ struct io_counter *counterp; ++ ++ rq = (struct request *)PT_REGS_PARM1(regs); ++ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &rq->rq_disk); ++ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); ++ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); ++ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &rq->cmd_flags); ++ ++ if (major == 0) { ++ log_event(STAGE_RQ_DRIVER, PERIOD_END, ERROR_MAJOR_ZERO); ++ return 0; ++ } ++ ++ u32 key = find_matching_key_rq_driver(major, first_minor); ++ if (key >= MAP_SIZE) { ++ return 0; ++ } ++ ++ counterp = bpf_map_lookup_elem(&blk_map, &rq); ++ if (!counterp) { ++ return 0; ++ } ++ ++ u64 duration = bpf_ktime_get_ns() - counterp->start_time; ++ u64 curr_start_range = counterp->start_time / THRESHOLD; ++ ++ struct update_params params = { ++ .major = major, ++ .first_minor = first_minor, ++ .cmd_flags = cmd_flags, ++ .curr_start_range = curr_start_range, ++ }; ++ ++ struct stage_data *curr_data; ++ curr_data = bpf_map_lookup_elem(&blk_res, &key); ++ if (curr_data == NULL && duration > DURATION_THRESHOLD) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 1, ++ .finish_over_time = 1, ++ .duration = 0, ++ .major = major, ++ .first_minor = first_minor, ++ .io_type = "", ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&blk_res, &key, &new_data, 0); ++ } else if (curr_data == NULL) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 1, ++ .finish_over_time = 0, ++ .duration = 0, ++ .major = major, ++ .first_minor = first_minor, ++ .io_type = "", ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&blk_res, &key, &new_data, 0); ++ } else { ++ curr_data->duration += duration; ++ update_curr_data_in_finish(curr_data, ¶ms, duration); ++ } ++ ++ struct time_range_io_count *curr_data_time_range; ++ curr_data_time_range = bpf_map_lookup_elem(&blk_res_2, &curr_start_range); ++ if (curr_data_time_range == NULL) { ++ struct time_range_io_count new_data = { .count = {0} }; ++ bpf_map_update_elem(&blk_res_2, &curr_start_range, &new_data, 0); ++ } else { ++ if (key < MAP_SIZE && curr_data_time_range->count[key] > 0) { ++ __sync_fetch_and_add(&curr_data_time_range->count[key], -1); ++ } ++ } ++ bpf_map_delete_elem(&blk_map, &rq); ++ return 0; ++} ++ ++// start bio ++SEC("kprobe/blk_mq_submit_bio") ++int kprobe_blk_mq_submit_bio(struct pt_regs *regs) ++{ ++ struct bio *bio; ++ struct gendisk *curr_rq_disk; ++ int major, first_minor; ++ unsigned int cmd_flags; ++ ++ bio = (struct bio *)PT_REGS_PARM1(regs); ++ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &bio->bi_disk); ++ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); ++ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); ++ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &bio->bi_opf); ++ ++ if (major == 0) { ++ log_event(STAGE_BIO, PERIOD_START, ERROR_MAJOR_ZERO); ++ return 0; ++ } ++ ++ int key = find_matching_key_bio(major, first_minor); ++ if (key >= MAP_SIZE) { ++ return 0; ++ } ++ ++ struct io_counter *counterp, zero = {}; ++ init_io_counter(&zero, major, first_minor); ++ ++ counterp = bpf_map_lookup_elem(&bio_map, &bio); ++ if (counterp) { ++ return 0; ++ } ++ ++ long err = bpf_map_update_elem(&bio_map, &bio, &zero, BPF_NOEXIST); ++ if (err) { ++ log_event(STAGE_BIO, PERIOD_START, ERROR_UPDATE_FAIL); ++ return 0; ++ } ++ ++ u64 curr_start_range = zero.start_time / THRESHOLD; ++ ++ struct update_params params = { ++ .major = major, ++ .first_minor = first_minor, ++ .cmd_flags = cmd_flags, ++ .curr_start_range = curr_start_range, ++ }; ++ ++ struct stage_data *curr_data; ++ curr_data = bpf_map_lookup_elem(&bio_res, &key); ++ if (curr_data == NULL) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 0, ++ .finish_over_time = 0, ++ .duration = 0, ++ .major = major, ++ .first_minor = first_minor, ++ .io_type = "", ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&bio_res, &key, &new_data, 0); ++ } else { ++ update_curr_data_in_start(curr_data, ¶ms); ++ } ++ ++ struct time_range_io_count *curr_data_time_range; ++ curr_data_time_range = bpf_map_lookup_elem(&bio_res_2, &curr_start_range); ++ if (curr_data_time_range == NULL) { ++ struct time_range_io_count new_data = { .count = {0} }; ++ bpf_map_update_elem(&bio_res_2, &curr_start_range, &new_data, 0); ++ } else { ++ if (key < MAP_SIZE && key >= 0) { ++ __sync_fetch_and_add(&curr_data_time_range->count[key], 1); ++ } ++ } ++ return 0; ++} ++ ++// finish bio ++SEC("kprobe/bio_endio") ++int kprobe_bio_endio(struct pt_regs *regs) ++{ ++ struct bio *bio; ++ struct gendisk *curr_rq_disk; ++ int major, first_minor; ++ unsigned int cmd_flags; ++ ++ bio = (struct bio *)PT_REGS_PARM1(regs); ++ // bpf_core_read(&bd, sizeof(bd), &bio->bi_disk); ++ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &bio->bi_disk); ++ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); ++ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); ++ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &bio->bi_opf); ++ ++ if (major == 0) { ++ log_event(STAGE_BIO, PERIOD_END, ERROR_MAJOR_ZERO); ++ return 0; ++ } ++ ++ u32 key = find_matching_key_bio(major, first_minor); ++ if (key >= MAP_SIZE) { ++ return 0; ++ } ++ ++ void *delete_map = NULL; ++ struct io_counter *counterp = bpf_map_lookup_elem(&bio_map, &bio); ++ if (!counterp) { ++ return 0; ++ } ++ ++ delete_map = &bio_map; ++ ++ u64 duration = bpf_ktime_get_ns() - counterp->start_time; ++ u64 curr_start_range = counterp->start_time / THRESHOLD; ++ ++ struct update_params params = { ++ .major = major, ++ .first_minor = first_minor, ++ .cmd_flags = cmd_flags, ++ .curr_start_range = curr_start_range, ++ }; ++ ++ struct stage_data *curr_data; ++ curr_data = bpf_map_lookup_elem(&bio_res, &key); ++ if (curr_data == NULL && duration > DURATION_THRESHOLD) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 1, ++ .finish_over_time = 1, ++ .duration = 0, ++ .major = major, ++ .first_minor = first_minor, ++ .io_type = "", ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&bio_res, &key, &new_data, 0); ++ } else if (curr_data == NULL) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 1, ++ .finish_over_time = 0, ++ .duration = 0, ++ .major = major, ++ .first_minor = first_minor, ++ .io_type = "", ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&bio_res, &key, &new_data, 0); ++ } else { ++ curr_data->duration += duration; ++ update_curr_data_in_finish(curr_data, ¶ms, duration); ++ } ++ ++ struct time_range_io_count *curr_data_time_range; ++ curr_data_time_range = bpf_map_lookup_elem(&bio_res_2, &curr_start_range); ++ if (curr_data_time_range == NULL) { ++ struct time_range_io_count new_data = { .count = {0} }; ++ bpf_map_update_elem(&bio_res_2, &curr_start_range, &new_data, 0); ++ } else { ++ if (key < MAP_SIZE && curr_data_time_range->count[key] > 0) { ++ __sync_fetch_and_add(&curr_data_time_range->count[key], -1); ++ } ++ } ++ bpf_map_delete_elem(delete_map, &bio); ++ return 0; ++} ++ ++// start get_tag ++SEC("kprobe/blk_mq_get_tag") ++int kprobe_blk_mq_get_tag(struct pt_regs *regs) ++{ ++ u64 tagkey = bpf_get_current_task(); ++ u64 value = (u64)PT_REGS_PARM1(regs); ++ (void)bpf_map_update_elem(&tag_args, &tagkey, &value, BPF_ANY); ++ ++ struct blk_mq_alloc_data *bd; ++ struct request_queue *q; ++ struct backing_dev_info *backing_dev_info; ++ struct device *owner; ++ dev_t devt; ++ unsigned int cmd_flags = 0; ++ ++ bd = (struct blk_mq_alloc_data *)value; ++ bpf_core_read(&q, sizeof(q), &bd->q); ++ bpf_core_read(&backing_dev_info, sizeof(backing_dev_info), &q->backing_dev_info); ++ bpf_core_read(&owner, sizeof(owner), &backing_dev_info->owner); ++ bpf_core_read(&devt, sizeof(devt), &owner->devt); ++ int major = MAJOR(devt); ++ int first_minor = MINOR(devt); ++ ++ if (major == 0) { ++ log_event(STAGE_GET_TAG, PERIOD_START, ERROR_MAJOR_ZERO); ++ return 0; ++ } ++ ++ u32 key = find_matching_key_get_tag(major, first_minor); ++ if (key >= MAP_SIZE) { ++ return 0; ++ } ++ ++ struct io_counter *counterp, zero = {}; ++ init_io_counter(&zero, major, first_minor); ++ counterp = bpf_map_lookup_elem(&tag_map, &tagkey); ++ if (counterp) { ++ return 0; ++ } ++ long err = bpf_map_update_elem(&tag_map, &tagkey, &zero, BPF_NOEXIST); ++ if (err) { ++ log_event(STAGE_GET_TAG, PERIOD_START, ERROR_UPDATE_FAIL); ++ return 0; ++ } ++ ++ u64 curr_start_range = zero.start_time / THRESHOLD; ++ ++ struct update_params params = { ++ .major = major, ++ .first_minor = first_minor, ++ .cmd_flags = cmd_flags, ++ .curr_start_range = curr_start_range, ++ }; ++ ++ struct stage_data *curr_data; ++ curr_data = bpf_map_lookup_elem(&tag_res, &key); ++ if (!curr_data) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 0, ++ .finish_over_time = 0, ++ .duration = 0, ++ .major = major, ++ .first_minor = first_minor, ++ .io_type = "", ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&tag_res, &key, &new_data, 0); ++ } else { ++ update_curr_data_in_start(curr_data, ¶ms); ++ } ++ ++ struct time_range_io_count *curr_data_time_range; ++ curr_data_time_range = bpf_map_lookup_elem(&tag_res_2, &curr_start_range); ++ if (curr_data_time_range == NULL) { ++ struct time_range_io_count new_data = { .count = {0} }; ++ bpf_map_update_elem(&tag_res_2, &curr_start_range, &new_data, 0); ++ } else { ++ if (key < MAP_SIZE && key >= 0) { ++ __sync_fetch_and_add(&curr_data_time_range->count[key], 1); ++ } ++ } ++ return 0; ++} ++ ++// finish get_tag ++SEC("kretprobe/blk_mq_get_tag") ++int kretprobe_blk_mq_get_tag(struct pt_regs *regs) ++{ ++ u64 tagkey = bpf_get_current_task(); ++ u64 *tagargs = (u64 *)bpf_map_lookup_elem(&tag_args, &tagkey); ++ if (tagargs == NULL) { ++ bpf_map_delete_elem(&tag_args, &tagkey); ++ return 0; ++ } ++ ++ struct blk_mq_alloc_data *bd; ++ struct request_queue *q; ++ struct backing_dev_info *backing_dev_info; ++ struct device *owner; ++ dev_t devt; ++ unsigned int cmd_flags = 0; ++ ++ bd = (struct blk_mq_alloc_data *)*tagargs; ++ bpf_core_read(&q, sizeof(q), &bd->q); ++ bpf_core_read(&backing_dev_info, sizeof(backing_dev_info), &q->backing_dev_info); ++ bpf_core_read(&owner, sizeof(owner), &backing_dev_info->owner); ++ bpf_core_read(&devt, sizeof(devt), &owner->devt); ++ int major = MAJOR(devt); ++ int first_minor = MINOR(devt); ++ ++ if (major == 0) { ++ log_event(STAGE_GET_TAG, PERIOD_END, ERROR_MAJOR_ZERO); ++ return 0; ++ } ++ ++ u32 key = find_matching_key_get_tag(major, first_minor); ++ if (key >= MAP_SIZE) { ++ return 0; ++ } ++ ++ struct io_counter *counterp = bpf_map_lookup_elem(&tag_map, &tagkey); ++ if (!counterp) { ++ return 0; ++ } ++ ++ u64 duration = bpf_ktime_get_ns() - counterp->start_time; ++ u64 curr_start_range = counterp->start_time / THRESHOLD; ++ ++ struct update_params params = { ++ .major = major, ++ .first_minor = first_minor, ++ .cmd_flags = cmd_flags, ++ .curr_start_range = curr_start_range, ++ }; ++ ++ struct stage_data *curr_data; ++ curr_data = bpf_map_lookup_elem(&tag_res, &key); ++ if (curr_data == NULL && duration > DURATION_THRESHOLD) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 1, ++ .finish_over_time = 1, ++ .duration = 0, ++ .major = major, ++ .first_minor = first_minor, ++ .io_type = "", ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&tag_res, &key, &new_data, 0); ++ } else if (curr_data == NULL) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 1, ++ .finish_over_time = 0, ++ .duration = 0, ++ .major = major, ++ .first_minor = first_minor, ++ .io_type = "", ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&tag_res, &key, &new_data, 0); ++ } else { ++ curr_data->duration += duration; ++ update_curr_data_in_finish(curr_data, ¶ms, duration); ++ } ++ ++ struct time_range_io_count *curr_data_time_range; ++ curr_data_time_range = bpf_map_lookup_elem(&tag_res_2, &curr_start_range); ++ if (curr_data_time_range == NULL) { ++ struct time_range_io_count new_data = { .count = {0} }; ++ bpf_map_update_elem(&tag_res_2, &curr_start_range, &new_data, 0); ++ } else { ++ if (key < MAP_SIZE && curr_data_time_range->count[key] > 0) { ++ __sync_fetch_and_add(&curr_data_time_range->count[key], -1); ++ } ++ } ++ ++ bpf_map_delete_elem(&tag_map, &tagkey); ++ bpf_map_delete_elem(&tag_args, &tagkey); ++ return 0; ++} ++ ++// start wbt ++SEC("kprobe/wbt_wait") ++int kprobe_wbt_wait(struct pt_regs *regs) ++{ ++ u64 wbtkey = bpf_get_current_task(); ++ u64 value = (u64)PT_REGS_PARM2(regs); ++ (void)bpf_map_update_elem(&wbt_args, &wbtkey, &value, BPF_ANY); ++ ++ struct bio *bio; ++ struct gendisk *curr_rq_disk; ++ int major, first_minor; ++ unsigned int cmd_flags; ++ ++ bio = (struct bio *)value; ++ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &bio->bi_disk); ++ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); ++ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); ++ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &bio->bi_opf); ++ ++ if (major == 0) { ++ log_event(STAGE_WBT, PERIOD_START, ERROR_MAJOR_ZERO); ++ return 0; ++ } ++ ++ u32 key = find_matching_key_wbt(major, first_minor); ++ if (key >= MAP_SIZE) { ++ return 0; ++ } ++ ++ struct io_counter *counterp, zero = {}; ++ init_io_counter(&zero, major, first_minor); ++ counterp = bpf_map_lookup_elem(&wbt_map, &wbtkey); ++ if (counterp) { ++ return 0; ++ } ++ long err = bpf_map_update_elem(&wbt_map, &wbtkey, &zero, BPF_NOEXIST); ++ if (err) { ++ log_event(STAGE_WBT, PERIOD_START, ERROR_UPDATE_FAIL); ++ return 0; ++ } ++ ++ u64 curr_start_range = zero.start_time / THRESHOLD; ++ ++ struct update_params params = { ++ .major = major, ++ .first_minor = first_minor, ++ .cmd_flags = cmd_flags, ++ .curr_start_range = curr_start_range, ++ }; ++ ++ struct stage_data *curr_data; ++ curr_data = bpf_map_lookup_elem(&wbt_res, &key); ++ if (!curr_data) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 0, ++ .finish_over_time = 0, ++ .duration = 0, ++ .major = major, ++ .first_minor = first_minor, ++ .io_type = "", ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&wbt_res, &key, &new_data, 0); ++ } else { ++ update_curr_data_in_start(curr_data, ¶ms); ++ } ++ ++ struct time_range_io_count *curr_data_time_range; ++ curr_data_time_range = bpf_map_lookup_elem(&wbt_res_2, &curr_start_range); ++ if (curr_data_time_range == NULL) { ++ struct time_range_io_count new_data = { .count = {0} }; ++ bpf_map_update_elem(&wbt_res_2, &curr_start_range, &new_data, 0); ++ } else { ++ if (key < MAP_SIZE && key >= 0) { ++ __sync_fetch_and_add(&curr_data_time_range->count[key], 1); ++ } ++ } ++ return 0; ++} ++ ++// finish wbt ++SEC("kretprobe/wbt_wait") ++int kretprobe_wbt_wait(struct pt_regs *regs) ++{ ++ u64 wbtkey = bpf_get_current_task(); ++ u64 *wbtargs = (u64 *)bpf_map_lookup_elem(&wbt_args, &wbtkey); ++ if (wbtargs == NULL) { ++ bpf_map_delete_elem(&wbt_args, &wbtkey); ++ return 0; ++ } ++ ++ struct bio *bio; ++ struct gendisk *curr_rq_disk; ++ int major, first_minor; ++ unsigned int cmd_flags; ++ ++ bio = (struct bio *)(*wbtargs); ++ bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &bio->bi_disk); ++ bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); ++ bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); ++ bpf_core_read(&cmd_flags, sizeof(cmd_flags), &bio->bi_opf); ++ ++ if (major == 0) { ++ log_event(STAGE_WBT, PERIOD_END, ERROR_MAJOR_ZERO); ++ return 0; ++ } ++ ++ u32 key = find_matching_key_wbt(major, first_minor); ++ if (key >= MAP_SIZE) { ++ return 0; ++ } ++ ++ struct io_counter *counterp = bpf_map_lookup_elem(&wbt_map, &wbtkey); ++ if (!counterp) { ++ return 0; ++ } ++ ++ u64 duration = bpf_ktime_get_ns() - counterp->start_time; ++ u64 curr_start_range = counterp->start_time / THRESHOLD; ++ ++ struct update_params params = { ++ .major = major, ++ .first_minor = first_minor, ++ .cmd_flags = cmd_flags, ++ .curr_start_range = curr_start_range, ++ }; ++ ++ struct stage_data *curr_data; ++ curr_data = bpf_map_lookup_elem(&wbt_res, &key); ++ if (curr_data == NULL && duration > DURATION_THRESHOLD) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 1, ++ .finish_over_time = 1, ++ .duration = 0, ++ .major = major, ++ .first_minor = first_minor, ++ .io_type = "", ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&wbt_res, &key, &new_data, 0); ++ } else if (curr_data == NULL) { ++ struct stage_data new_data = { ++ .start_count = 1, ++ .finish_count = 1, ++ .finish_over_time = 0, ++ .duration = 0, ++ .io_type = "", ++ .major = major, ++ .first_minor = first_minor, ++ }; ++ blk_fill_rwbs(new_data.io_type, cmd_flags); ++ bpf_map_update_elem(&wbt_res, &key, &new_data, 0); ++ } else { ++ curr_data->duration += duration; ++ update_curr_data_in_finish(curr_data, ¶ms, duration); ++ } ++ ++ struct time_range_io_count *curr_data_time_range; ++ curr_data_time_range = bpf_map_lookup_elem(&wbt_res_2, &curr_start_range); ++ if (curr_data_time_range == NULL) { ++ struct time_range_io_count new_data = { .count = {0} }; ++ bpf_map_update_elem(&wbt_res_2, &curr_start_range, &new_data, 0); ++ } else { ++ if (key < MAP_SIZE && curr_data_time_range->count[key] > 0) { ++ __sync_fetch_and_add(&curr_data_time_range->count[key], -1); ++ } ++ } ++ bpf_map_delete_elem(&wbt_map, &wbtkey); ++ bpf_map_delete_elem(&wbt_args, &wbtkey); ++ return 0; ++} ++ ++char _license[] SEC("license") = "GPL"; diff --git a/src/c/ebpf_collector/ebpf_collector.c b/src/c/ebpf_collector/ebpf_collector.c new file mode 100644 index 0000000..bc29a2c --- /dev/null +++ b/src/c/ebpf_collector/ebpf_collector.c @@ -0,0 +1,498 @@ -+/* -+ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. -+ * Description: ebpf collector program -+ * Author: Zhang Nan -+ * Create: 2024-09-27 -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "ebpf_collector.h" -+#include "ebpf_collector.skel.h" -+ -+#define BLK_MAP (bpf_map__fd(skel->maps.blk_map)) -+#define BLK_RES (bpf_map__fd(skel->maps.blk_res)) -+#define BIO_MAP (bpf_map__fd(skel->maps.bio_map)) -+#define BIO_RES (bpf_map__fd(skel->maps.bio_res)) -+#define WBT_MAP (bpf_map__fd(skel->maps.wbt_map)) -+#define WBT_RES (bpf_map__fd(skel->maps.wbt_res)) -+#define TAG_MAP (bpf_map__fd(skel->maps.tag_map)) -+#define TAG_RES (bpf_map__fd(skel->maps.tag_res)) -+#define BLK_RES_2 (bpf_map__fd(skel->maps.blk_res_2)) -+#define BIO_RES_2 (bpf_map__fd(skel->maps.bio_res_2)) -+#define WBT_RES_2 (bpf_map__fd(skel->maps.wbt_res_2)) -+#define TAG_RES_2 (bpf_map__fd(skel->maps.tag_res_2)) -+ -+#define MAX_LINE_LENGTH 1024 -+#define MAX_SECTION_NAME_LENGTH 256 -+#define CONFIG_FILE "/etc/sysSentry/collector.conf" -+ -+typedef struct { -+ int major; -+ int minor; -+} DeviceInfo; -+ -+typedef enum { -+ LOG_LEVEL_NONE, -+ LOG_LEVEL_DEBUG, -+ LOG_LEVEL_INFO, -+ LOG_LEVEL_WARNING, -+ LOG_LEVEL_ERROR -+} LogLevel; -+ -+LogLevel currentLogLevel = LOG_LEVEL_INFO; -+ -+static volatile bool exiting; -+ -+const char argp_program_doc[] = -+"Show block device I/O pattern.\n" -+"\n" -+"USAGE: ebpf_collector [--help]\n" -+"\n" -+"EXAMPLES:\n" -+" ebpf_collector # show block I/O pattern\n"; -+ -+static const struct argp_option opts[] = { -+ { NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" }, -+ {}, -+}; -+ -+static error_t parse_arg(int key, char *arg, struct argp_state *state) { -+ static int pos_args; -+ -+ switch (key) { -+ case 'h': -+ argp_state_help(state, stderr, ARGP_HELP_STD_HELP); -+ break; -+ default: -+ return ARGP_ERR_UNKNOWN; -+ } -+ return 0; -+} -+ -+void logMessage(LogLevel level, const char *format, ...){ -+ if (level >= currentLogLevel) { -+ va_list args; -+ va_start(args, format); -+ vprintf(format, args); -+ va_end(args); -+ } -+} -+ -+static void sig_handler(int sig) -+{ -+ exiting = true; -+} -+ -+char* extract_device_name(const char *path) { -+ const char *dev_dir = "/dev/"; -+ char *name = strrchr(path, '/') + 1; -+ if (strncmp(dev_dir, path, strlen(dev_dir)) == 0) { -+ return strdup(name); -+ } -+ return NULL; -+} -+ -+char* find_device_name(dev_t dev) { -+ DIR *dir; -+ struct dirent *entry; -+ struct stat sb; -+ char *device_name = NULL; -+ char path[1024]; -+ -+ dir = opendir("/dev"); -+ if (dir == NULL) { -+ perror("Failed to open /dev"); -+ return NULL; -+ } -+ -+ while ((entry = readdir(dir)) != NULL) { -+ snprintf(path, sizeof(path), "/dev/%s", entry->d_name); -+ -+ if (entry->d_type == DT_DIR || entry->d_type == DT_LNK) { -+ continue; -+ } -+ -+ if (stat(path, &sb) == -1) { -+ continue; -+ } -+ -+ if (major(sb.st_rdev) == major(dev) && minor(sb.st_rdev) == minor(dev)) { -+ device_name = extract_device_name(path); -+ break; -+ } -+ } -+ -+ closedir(dir); -+ return device_name; -+} -+ -+static void update_io_dump(int fd, int *io_dump, int map_size, char *stage) { -+ struct time_range_io_count time_count; -+ u32 io_dump_key = 0; -+ struct sysinfo info; -+ sysinfo(&info); -+ int count_time = 150; -+ u32 curr_time = info.uptime; -+ while (count_time >= 0) { -+ io_dump_key = curr_time - count_time; -+ int err = bpf_map_lookup_elem(fd, &io_dump_key, &time_count); -+ if (err < 0) { -+ count_time -= 1; -+ continue; -+ } -+ if ((curr_time - io_dump_key) >= 2) { -+ int isempty = 1; -+ for (int key = 0; key < map_size; key++) { -+ if (time_count.count[key] > 0) { -+ io_dump[key] += time_count.count[key]; -+ isempty = 0; -+ } -+ } -+ if (isempty || (curr_time - io_dump_key) > IO_DUMP_THRESHOLD) { -+ bpf_map_delete_elem(fd, &io_dump_key); -+ } -+ } -+ count_time -= 1; -+ } -+} -+ -+static int print_map_res(int fd, char *stage, int map_size, int *io_dump) -+{ -+ struct stage_data counter; -+ int key = 0; -+ -+ logMessage(LOG_LEVEL_DEBUG, "print_map_res map_size: %d\n", map_size); -+ for (key = 0; key < map_size; key++) { -+ int err = bpf_map_lookup_elem(fd, &key, &counter); -+ if (err < 0) { -+ logMessage(LOG_LEVEL_ERROR, "failed to lookup %s map_res: %d\n", stage, err); -+ return -1; -+ } -+ -+ size_t length = strlen(counter.io_type); -+ char io_type; -+ if (length > 0) { -+ logMessage(LOG_LEVEL_DEBUG, "io_type have value.\n"); -+ io_type = counter.io_type[0]; -+ } else { -+ logMessage(LOG_LEVEL_DEBUG, "io_type not value.\n"); -+ io_type = '\0'; -+ } -+ int major = counter.major; -+ int first_minor = counter.first_minor; -+ dev_t dev = makedev(major, first_minor); -+ char *device_name = find_device_name(dev); -+ logMessage(LOG_LEVEL_DEBUG, "device_name: %s, stage: %s, io_type: %c\n", device_name, stage, io_type); -+ if (device_name && io_type) { -+ printf("%-7s %10llu %10llu %d %c %s\n", -+ stage, -+ counter.finish_count, -+ counter.duration, -+ io_dump[key], -+ io_type, -+ device_name -+ ); -+ fflush(stdout); -+ } -+ } -+ -+ return 0; -+} -+ -+int init_map(int fd, const char *map_name, int device_count, DeviceInfo *devices) { -+ struct stage_data init_data = {0}; -+ -+ memset(init_data.io_type, 0, sizeof(init_data.io_type)); -+ -+ for (int i = 0; i < device_count; i++) { -+ init_data.major = devices[i].major; -+ init_data.first_minor = devices[i].minor; -+ if (bpf_map_update_elem(fd, &i, &init_data, BPF_ANY) != 0) { -+ logMessage(LOG_LEVEL_ERROR, "Failed to initialize map %s at index %d\n", map_name, i); -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+char *read_config_value(const char *file, const char *section, const char *key) { -+ FILE *fp = fopen(file, "r"); -+ if (fp == NULL) { -+ logMessage(LOG_LEVEL_ERROR, "Failed to open config file.\n"); -+ return NULL; -+ } -+ -+ char line[MAX_LINE_LENGTH]; -+ char current_section[MAX_SECTION_NAME_LENGTH] = {0}; -+ char *value = NULL; -+ -+ while (fgets(line, sizeof(line), fp) != NULL) { -+ line[strcspn(line, "\n")] = 0; -+ -+ if (line[0] == '\0' || line[0] == ';' || line[0] == '#') { -+ continue; -+ } -+ -+ if (line[0] == '[') { -+ sscanf(line, "[%255[^]]", current_section); -+ continue; -+ } -+ -+ if (strcmp(current_section, section) == 0) { -+ char *delimiter = "="; -+ char *token = strtok(line, delimiter); -+ if (token != NULL) { -+ if (strcmp(token, key) == 0) { -+ token = strtok(NULL, delimiter); -+ if (token != NULL) { -+ value = strdup(token); -+ break; -+ } -+ } -+ } -+ } -+ } -+ -+ fclose(fp); -+ return value; -+} -+ -+void setLogLevel(const char *levelStr) { -+ if (strcmp(levelStr, "info") == 0) { -+ currentLogLevel = LOG_LEVEL_INFO; -+ } -+ else if (strcmp(levelStr, "warning") == 0) { -+ currentLogLevel = LOG_LEVEL_WARNING; -+ } -+ else if (strcmp(levelStr, "error") == 0) { -+ currentLogLevel = LOG_LEVEL_ERROR; -+ } -+ else if (strcmp(levelStr, "debug") == 0) { -+ currentLogLevel = LOG_LEVEL_DEBUG; -+ } -+ else if (strcmp(levelStr, "none") == 0) { -+ currentLogLevel = LOG_LEVEL_NONE; -+ } -+ else { -+ logMessage(LOG_LEVEL_ERROR, "unknown log level: %s\n", levelStr); -+ } -+} -+ -+int check_for_device(const char *device_name) { -+ char path[256]; -+ snprintf(path, sizeof(path), "/sys/block/%s", device_name); -+ -+ DIR *dir = opendir(path); -+ if (dir == NULL) { -+ return 0; -+ } -+ -+ struct dirent *entry; -+ while ((entry = readdir(dir)) != NULL) { -+ struct stat statbuf; -+ if (stat(path, &statbuf) == 0) { -+ if (S_ISDIR(statbuf.st_mode)) { -+ closedir(dir); -+ return 1; -+ } -+ } -+ } -+ closedir(dir); -+ return 0; -+} -+ -+// 处理事件的回调函数 -+static int handle_event(void *ctx, void *data, size_t data_sz) { -+ struct event *e = (struct event *)data; -+ logMessage(LOG_LEVEL_ERROR, "kernelspace error happen, stage: %d, period: %d, error: %d\n", e->stage, e->period, e->err); -+ return 0; -+} -+ -+int main(int argc, char **argv) { -+ struct partitions *partitions = NULL; -+ const struct partition *partition; -+ static const struct argp argp = { -+ .options = opts, -+ .parser = parse_arg, -+ .doc = argp_program_doc, -+ }; -+ int err; -+ char filename[256]; -+ DIR *dir; -+ struct dirent *entry; -+ char path[1024]; -+ int major, minor; -+ DeviceInfo devices[MAP_SIZE]; -+ int device_count = 0; -+ struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; -+ setrlimit(RLIMIT_MEMLOCK, &r); -+ -+ char *level = read_config_value(CONFIG_FILE, "log", "level"); -+ if (level != NULL) { -+ if (level[strlen(level) - 1] == '\r') { -+ size_t len = strlen(level); -+ level[len - 1] = '\0'; -+ } -+ setLogLevel(level); -+ free(level); -+ } else { -+ logMessage(LOG_LEVEL_INFO, "the log level is incorrectly configured. the default log level is info.\n"); -+ } -+ logMessage(LOG_LEVEL_DEBUG, "finish config parse.\n"); -+ -+ err = argp_parse(&argp, argc, argv, 0, NULL, NULL); -+ if (err) { -+ logMessage(LOG_LEVEL_ERROR, "argp parse failed.\n"); -+ return err; -+ } -+ -+ signal(SIGINT, sig_handler); -+ signal(SIGTERM, sig_handler); -+ -+ dir = opendir("/dev"); -+ if (dir == NULL) { -+ logMessage(LOG_LEVEL_ERROR, "Failed to open /dev directory.\n"); -+ return EXIT_FAILURE; -+ } -+ -+ while ((entry = readdir(dir)) != NULL) { -+ if (entry->d_type != DT_BLK) { -+ continue; -+ } -+ snprintf(path, sizeof(path), "/dev/%s", entry->d_name); -+ struct stat statbuf; -+ if (lstat(path, &statbuf) != 0 && !S_ISBLK(statbuf.st_mode)) { -+ continue; -+ } -+ if (!strncmp(entry->d_name, "dm-", 3) || !strncmp(entry->d_name, "loop", 4) || -+ !strncmp(entry->d_name, "md", 2)) { -+ continue; -+ } -+ if (!check_for_device(entry->d_name)) { -+ continue; -+ } -+ -+ devices[device_count].major = major(statbuf.st_rdev); -+ devices[device_count].minor = minor(statbuf.st_rdev); -+ device_count++; -+ if (device_count >= MAP_SIZE) { -+ logMessage(LOG_LEVEL_DEBUG, " device_count moren than MAP_SIZE.\n"); -+ break; -+ } -+ } -+ -+ closedir(dir); -+ -+ struct ebpf_collector_bpf *skel = ebpf_collector_bpf__open(); -+ if (!skel) { -+ logMessage(LOG_LEVEL_ERROR, "Failed to open and load BPF skeleton\n"); -+ return 1; -+ } -+ -+ // 加载 BPF 程序到内核中 -+ err = ebpf_collector_bpf__load(skel); -+ if (err) { -+ logMessage(LOG_LEVEL_ERROR, "Failed to load BPF skeleton: %d\n", err); -+ ebpf_collector_bpf__destroy(skel); -+ return 1; -+ } -+ -+ // 附加 BPF 程序到 kprobe -+ err = ebpf_collector_bpf__attach(skel); -+ if (err) { -+ logMessage(LOG_LEVEL_ERROR, "Failed to attach BPF skeleton: %d\n", err); -+ ebpf_collector_bpf__destroy(skel); -+ return 1; -+ } -+ -+ // 初始化环形缓冲区读取器 -+ struct ring_buffer *rb = NULL; -+ rb = ring_buffer__new(bpf_map__fd(skel->maps.ringbuf), handle_event, NULL, NULL); -+ if (!rb) { -+ return 1; -+ } -+ -+ -+ if (init_map(BLK_RES, "blk_res_map", device_count, devices)) { -+ logMessage(LOG_LEVEL_ERROR, "blk_res_map failed.\n"); -+ ebpf_collector_bpf__destroy(skel); -+ return 1; -+ } -+ -+ if (init_map(BIO_RES, "blo_res_map", device_count, devices) != 0) { -+ logMessage(LOG_LEVEL_ERROR, "blo_res_map failed.\n"); -+ ebpf_collector_bpf__destroy(skel); -+ return 1; -+ } -+ if (init_map(WBT_RES, "wbt_res_map", device_count, devices) != 0) { -+ logMessage(LOG_LEVEL_ERROR, "wbt_res_map failed.\n"); -+ ebpf_collector_bpf__destroy(skel); -+ return 1; -+ } -+ if (init_map(TAG_RES, "tag_res_map", device_count, devices) != 0) { -+ logMessage(LOG_LEVEL_ERROR, "tag_res_map failed.\n"); -+ ebpf_collector_bpf__destroy(skel); -+ return 1; -+ } -+ -+ for (;;) { -+ -+ sleep(1); -+ -+ err = ring_buffer__poll(rb, 100); -+ -+ int io_dump_blk[MAP_SIZE] = {0}; -+ update_io_dump(BLK_RES_2, io_dump_blk, device_count,"rq_driver"); -+ err = print_map_res(BLK_RES, "rq_driver", device_count, io_dump_blk); -+ if (err) { -+ logMessage(LOG_LEVEL_ERROR, "print_map_res rq_driver error.\n"); -+ break; -+ } -+ -+ int io_dump_bio[MAP_SIZE] = {0}; -+ update_io_dump(BIO_RES_2, io_dump_bio, device_count,"bio"); -+ err = print_map_res(BIO_RES, "bio", device_count, io_dump_bio); -+ if (err) { -+ logMessage(LOG_LEVEL_ERROR, "print_map_res bio error.\n"); -+ break; -+ } -+ -+ int io_dump_tag[MAP_SIZE] = {0}; -+ update_io_dump(TAG_RES_2, io_dump_tag, device_count,"gettag"); -+ err = print_map_res(TAG_RES, "gettag", device_count, io_dump_tag); -+ if (err) { -+ logMessage(LOG_LEVEL_ERROR, "print_map_res gettag error.\n"); -+ break; -+ } -+ -+ int io_dump_wbt[MAP_SIZE] = {0}; -+ update_io_dump(WBT_RES_2, io_dump_wbt, device_count,"wbt"); -+ err = print_map_res(WBT_RES, "wbt", device_count, io_dump_wbt); -+ if (err) { -+ logMessage(LOG_LEVEL_ERROR, "print_map_res wbt error.\n"); -+ break; -+ } -+ -+ if (exiting) { -+ logMessage(LOG_LEVEL_DEBUG, "exit program.\n"); -+ break; -+ } -+ } -+ -+ ring_buffer__free(rb); -+ ebpf_collector_bpf__destroy(skel); -+ return -err; -+} ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * Description: ebpf collector program ++ * Author: Zhang Nan ++ * Create: 2024-09-27 ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ebpf_collector.h" ++#include "ebpf_collector.skel.h" ++ ++#define BLK_MAP (bpf_map__fd(skel->maps.blk_map)) ++#define BLK_RES (bpf_map__fd(skel->maps.blk_res)) ++#define BIO_MAP (bpf_map__fd(skel->maps.bio_map)) ++#define BIO_RES (bpf_map__fd(skel->maps.bio_res)) ++#define WBT_MAP (bpf_map__fd(skel->maps.wbt_map)) ++#define WBT_RES (bpf_map__fd(skel->maps.wbt_res)) ++#define TAG_MAP (bpf_map__fd(skel->maps.tag_map)) ++#define TAG_RES (bpf_map__fd(skel->maps.tag_res)) ++#define BLK_RES_2 (bpf_map__fd(skel->maps.blk_res_2)) ++#define BIO_RES_2 (bpf_map__fd(skel->maps.bio_res_2)) ++#define WBT_RES_2 (bpf_map__fd(skel->maps.wbt_res_2)) ++#define TAG_RES_2 (bpf_map__fd(skel->maps.tag_res_2)) ++ ++#define MAX_LINE_LENGTH 1024 ++#define MAX_SECTION_NAME_LENGTH 256 ++#define CONFIG_FILE "/etc/sysSentry/collector.conf" ++ ++typedef struct { ++ int major; ++ int minor; ++} DeviceInfo; ++ ++typedef enum { ++ LOG_LEVEL_NONE, ++ LOG_LEVEL_DEBUG, ++ LOG_LEVEL_INFO, ++ LOG_LEVEL_WARNING, ++ LOG_LEVEL_ERROR ++} LogLevel; ++ ++LogLevel currentLogLevel = LOG_LEVEL_INFO; ++ ++static volatile bool exiting; ++ ++const char argp_program_doc[] = ++"Show block device I/O pattern.\n" ++"\n" ++"USAGE: ebpf_collector [--help]\n" ++"\n" ++"EXAMPLES:\n" ++" ebpf_collector # show block I/O pattern\n"; ++ ++static const struct argp_option opts[] = { ++ { NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" }, ++ {}, ++}; ++ ++static error_t parse_arg(int key, char *arg, struct argp_state *state) { ++ static int pos_args; ++ ++ switch (key) { ++ case 'h': ++ argp_state_help(state, stderr, ARGP_HELP_STD_HELP); ++ break; ++ default: ++ return ARGP_ERR_UNKNOWN; ++ } ++ return 0; ++} ++ ++void logMessage(LogLevel level, const char *format, ...){ ++ if (level >= currentLogLevel) { ++ va_list args; ++ va_start(args, format); ++ vprintf(format, args); ++ va_end(args); ++ } ++} ++ ++static void sig_handler(int sig) ++{ ++ exiting = true; ++} ++ ++char* extract_device_name(const char *path) { ++ const char *dev_dir = "/dev/"; ++ char *name = strrchr(path, '/') + 1; ++ if (strncmp(dev_dir, path, strlen(dev_dir)) == 0) { ++ return strdup(name); ++ } ++ return NULL; ++} ++ ++char* find_device_name(dev_t dev) { ++ DIR *dir; ++ struct dirent *entry; ++ struct stat sb; ++ char *device_name = NULL; ++ char path[1024]; ++ ++ dir = opendir("/dev"); ++ if (dir == NULL) { ++ perror("Failed to open /dev"); ++ return NULL; ++ } ++ ++ while ((entry = readdir(dir)) != NULL) { ++ snprintf(path, sizeof(path), "/dev/%s", entry->d_name); ++ ++ if (entry->d_type == DT_DIR || entry->d_type == DT_LNK) { ++ continue; ++ } ++ ++ if (stat(path, &sb) == -1) { ++ continue; ++ } ++ ++ if (major(sb.st_rdev) == major(dev) && minor(sb.st_rdev) == minor(dev)) { ++ device_name = extract_device_name(path); ++ break; ++ } ++ } ++ ++ closedir(dir); ++ return device_name; ++} ++ ++static void update_io_dump(int fd, int *io_dump, int map_size, char *stage) { ++ struct time_range_io_count time_count; ++ u32 io_dump_key = 0; ++ struct sysinfo info; ++ sysinfo(&info); ++ int count_time = 150; ++ u32 curr_time = info.uptime; ++ while (count_time >= 0) { ++ io_dump_key = curr_time - count_time; ++ int err = bpf_map_lookup_elem(fd, &io_dump_key, &time_count); ++ if (err < 0) { ++ count_time -= 1; ++ continue; ++ } ++ if ((curr_time - io_dump_key) >= 2) { ++ int isempty = 1; ++ for (int key = 0; key < map_size; key++) { ++ if (time_count.count[key] > 0) { ++ io_dump[key] += time_count.count[key]; ++ isempty = 0; ++ } ++ } ++ if (isempty || (curr_time - io_dump_key) > IO_DUMP_THRESHOLD) { ++ bpf_map_delete_elem(fd, &io_dump_key); ++ } ++ } ++ count_time -= 1; ++ } ++} ++ ++static int print_map_res(int fd, char *stage, int map_size, int *io_dump) ++{ ++ struct stage_data counter; ++ int key = 0; ++ ++ logMessage(LOG_LEVEL_DEBUG, "print_map_res map_size: %d\n", map_size); ++ for (key = 0; key < map_size; key++) { ++ int err = bpf_map_lookup_elem(fd, &key, &counter); ++ if (err < 0) { ++ logMessage(LOG_LEVEL_ERROR, "failed to lookup %s map_res: %d\n", stage, err); ++ return -1; ++ } ++ ++ size_t length = strlen(counter.io_type); ++ char io_type; ++ if (length > 0) { ++ logMessage(LOG_LEVEL_DEBUG, "io_type have value.\n"); ++ io_type = counter.io_type[0]; ++ } else { ++ logMessage(LOG_LEVEL_DEBUG, "io_type not value.\n"); ++ io_type = '\0'; ++ } ++ int major = counter.major; ++ int first_minor = counter.first_minor; ++ dev_t dev = makedev(major, first_minor); ++ char *device_name = find_device_name(dev); ++ logMessage(LOG_LEVEL_DEBUG, "device_name: %s, stage: %s, io_type: %c\n", device_name, stage, io_type); ++ if (device_name && io_type) { ++ printf("%-7s %10llu %10llu %d %c %s\n", ++ stage, ++ counter.finish_count, ++ counter.duration, ++ io_dump[key], ++ io_type, ++ device_name ++ ); ++ fflush(stdout); ++ } ++ } ++ ++ return 0; ++} ++ ++int init_map(int fd, const char *map_name, int device_count, DeviceInfo *devices) { ++ struct stage_data init_data = {0}; ++ ++ memset(init_data.io_type, 0, sizeof(init_data.io_type)); ++ ++ for (int i = 0; i < device_count; i++) { ++ init_data.major = devices[i].major; ++ init_data.first_minor = devices[i].minor; ++ if (bpf_map_update_elem(fd, &i, &init_data, BPF_ANY) != 0) { ++ logMessage(LOG_LEVEL_ERROR, "Failed to initialize map %s at index %d\n", map_name, i); ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++char *read_config_value(const char *file, const char *section, const char *key) { ++ FILE *fp = fopen(file, "r"); ++ if (fp == NULL) { ++ logMessage(LOG_LEVEL_ERROR, "Failed to open config file.\n"); ++ return NULL; ++ } ++ ++ char line[MAX_LINE_LENGTH]; ++ char current_section[MAX_SECTION_NAME_LENGTH] = {0}; ++ char *value = NULL; ++ ++ while (fgets(line, sizeof(line), fp) != NULL) { ++ line[strcspn(line, "\n")] = 0; ++ ++ if (line[0] == '\0' || line[0] == ';' || line[0] == '#') { ++ continue; ++ } ++ ++ if (line[0] == '[') { ++ sscanf(line, "[%255[^]]", current_section); ++ continue; ++ } ++ ++ if (strcmp(current_section, section) == 0) { ++ char *delimiter = "="; ++ char *token = strtok(line, delimiter); ++ if (token != NULL) { ++ if (strcmp(token, key) == 0) { ++ token = strtok(NULL, delimiter); ++ if (token != NULL) { ++ value = strdup(token); ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ fclose(fp); ++ return value; ++} ++ ++void setLogLevel(const char *levelStr) { ++ if (strcmp(levelStr, "info") == 0) { ++ currentLogLevel = LOG_LEVEL_INFO; ++ } ++ else if (strcmp(levelStr, "warning") == 0) { ++ currentLogLevel = LOG_LEVEL_WARNING; ++ } ++ else if (strcmp(levelStr, "error") == 0) { ++ currentLogLevel = LOG_LEVEL_ERROR; ++ } ++ else if (strcmp(levelStr, "debug") == 0) { ++ currentLogLevel = LOG_LEVEL_DEBUG; ++ } ++ else if (strcmp(levelStr, "none") == 0) { ++ currentLogLevel = LOG_LEVEL_NONE; ++ } ++ else { ++ logMessage(LOG_LEVEL_ERROR, "unknown log level: %s\n", levelStr); ++ } ++} ++ ++int check_for_device(const char *device_name) { ++ char path[256]; ++ snprintf(path, sizeof(path), "/sys/block/%s", device_name); ++ ++ DIR *dir = opendir(path); ++ if (dir == NULL) { ++ return 0; ++ } ++ ++ struct dirent *entry; ++ while ((entry = readdir(dir)) != NULL) { ++ struct stat statbuf; ++ if (stat(path, &statbuf) == 0) { ++ if (S_ISDIR(statbuf.st_mode)) { ++ closedir(dir); ++ return 1; ++ } ++ } ++ } ++ closedir(dir); ++ return 0; ++} ++ ++// 处理事件的回调函数 ++static int handle_event(void *ctx, void *data, size_t data_sz) { ++ struct event *e = (struct event *)data; ++ logMessage(LOG_LEVEL_ERROR, "kernelspace error happen, stage: %d, period: %d, error: %d\n", e->stage, e->period, e->err); ++ return 0; ++} ++ ++int main(int argc, char **argv) { ++ struct partitions *partitions = NULL; ++ const struct partition *partition; ++ static const struct argp argp = { ++ .options = opts, ++ .parser = parse_arg, ++ .doc = argp_program_doc, ++ }; ++ int err; ++ char filename[256]; ++ DIR *dir; ++ struct dirent *entry; ++ char path[1024]; ++ int major, minor; ++ DeviceInfo devices[MAP_SIZE]; ++ int device_count = 0; ++ struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; ++ setrlimit(RLIMIT_MEMLOCK, &r); ++ ++ char *level = read_config_value(CONFIG_FILE, "log", "level"); ++ if (level != NULL) { ++ if (level[strlen(level) - 1] == '\r') { ++ size_t len = strlen(level); ++ level[len - 1] = '\0'; ++ } ++ setLogLevel(level); ++ free(level); ++ } else { ++ logMessage(LOG_LEVEL_INFO, "the log level is incorrectly configured. the default log level is info.\n"); ++ } ++ logMessage(LOG_LEVEL_DEBUG, "finish config parse.\n"); ++ ++ err = argp_parse(&argp, argc, argv, 0, NULL, NULL); ++ if (err) { ++ logMessage(LOG_LEVEL_ERROR, "argp parse failed.\n"); ++ return err; ++ } ++ ++ signal(SIGINT, sig_handler); ++ signal(SIGTERM, sig_handler); ++ ++ dir = opendir("/dev"); ++ if (dir == NULL) { ++ logMessage(LOG_LEVEL_ERROR, "Failed to open /dev directory.\n"); ++ return EXIT_FAILURE; ++ } ++ ++ while ((entry = readdir(dir)) != NULL) { ++ if (entry->d_type != DT_BLK) { ++ continue; ++ } ++ snprintf(path, sizeof(path), "/dev/%s", entry->d_name); ++ struct stat statbuf; ++ if (lstat(path, &statbuf) != 0 && !S_ISBLK(statbuf.st_mode)) { ++ continue; ++ } ++ if (!strncmp(entry->d_name, "dm-", 3) || !strncmp(entry->d_name, "loop", 4) || ++ !strncmp(entry->d_name, "md", 2)) { ++ continue; ++ } ++ if (!check_for_device(entry->d_name)) { ++ continue; ++ } ++ ++ devices[device_count].major = major(statbuf.st_rdev); ++ devices[device_count].minor = minor(statbuf.st_rdev); ++ device_count++; ++ if (device_count >= MAP_SIZE) { ++ logMessage(LOG_LEVEL_DEBUG, " device_count moren than MAP_SIZE.\n"); ++ break; ++ } ++ } ++ ++ closedir(dir); ++ ++ struct ebpf_collector_bpf *skel = ebpf_collector_bpf__open(); ++ if (!skel) { ++ logMessage(LOG_LEVEL_ERROR, "Failed to open and load BPF skeleton\n"); ++ return 1; ++ } ++ ++ // 加载 BPF 程序到内核中 ++ err = ebpf_collector_bpf__load(skel); ++ if (err) { ++ logMessage(LOG_LEVEL_ERROR, "Failed to load BPF skeleton: %d\n", err); ++ ebpf_collector_bpf__destroy(skel); ++ return 1; ++ } ++ ++ // 附加 BPF 程序到 kprobe ++ err = ebpf_collector_bpf__attach(skel); ++ if (err) { ++ logMessage(LOG_LEVEL_ERROR, "Failed to attach BPF skeleton: %d\n", err); ++ ebpf_collector_bpf__destroy(skel); ++ return 1; ++ } ++ ++ // 初始化环形缓冲区读取器 ++ struct ring_buffer *rb = NULL; ++ rb = ring_buffer__new(bpf_map__fd(skel->maps.ringbuf), handle_event, NULL, NULL); ++ if (!rb) { ++ return 1; ++ } ++ ++ ++ if (init_map(BLK_RES, "blk_res_map", device_count, devices)) { ++ logMessage(LOG_LEVEL_ERROR, "blk_res_map failed.\n"); ++ ebpf_collector_bpf__destroy(skel); ++ return 1; ++ } ++ ++ if (init_map(BIO_RES, "blo_res_map", device_count, devices) != 0) { ++ logMessage(LOG_LEVEL_ERROR, "blo_res_map failed.\n"); ++ ebpf_collector_bpf__destroy(skel); ++ return 1; ++ } ++ if (init_map(WBT_RES, "wbt_res_map", device_count, devices) != 0) { ++ logMessage(LOG_LEVEL_ERROR, "wbt_res_map failed.\n"); ++ ebpf_collector_bpf__destroy(skel); ++ return 1; ++ } ++ if (init_map(TAG_RES, "tag_res_map", device_count, devices) != 0) { ++ logMessage(LOG_LEVEL_ERROR, "tag_res_map failed.\n"); ++ ebpf_collector_bpf__destroy(skel); ++ return 1; ++ } ++ ++ for (;;) { ++ ++ sleep(1); ++ ++ err = ring_buffer__poll(rb, 100); ++ ++ int io_dump_blk[MAP_SIZE] = {0}; ++ update_io_dump(BLK_RES_2, io_dump_blk, device_count,"rq_driver"); ++ err = print_map_res(BLK_RES, "rq_driver", device_count, io_dump_blk); ++ if (err) { ++ logMessage(LOG_LEVEL_ERROR, "print_map_res rq_driver error.\n"); ++ break; ++ } ++ ++ int io_dump_bio[MAP_SIZE] = {0}; ++ update_io_dump(BIO_RES_2, io_dump_bio, device_count,"bio"); ++ err = print_map_res(BIO_RES, "bio", device_count, io_dump_bio); ++ if (err) { ++ logMessage(LOG_LEVEL_ERROR, "print_map_res bio error.\n"); ++ break; ++ } ++ ++ int io_dump_tag[MAP_SIZE] = {0}; ++ update_io_dump(TAG_RES_2, io_dump_tag, device_count,"gettag"); ++ err = print_map_res(TAG_RES, "gettag", device_count, io_dump_tag); ++ if (err) { ++ logMessage(LOG_LEVEL_ERROR, "print_map_res gettag error.\n"); ++ break; ++ } ++ ++ int io_dump_wbt[MAP_SIZE] = {0}; ++ update_io_dump(WBT_RES_2, io_dump_wbt, device_count,"wbt"); ++ err = print_map_res(WBT_RES, "wbt", device_count, io_dump_wbt); ++ if (err) { ++ logMessage(LOG_LEVEL_ERROR, "print_map_res wbt error.\n"); ++ break; ++ } ++ ++ if (exiting) { ++ logMessage(LOG_LEVEL_DEBUG, "exit program.\n"); ++ break; ++ } ++ } ++ ++ ring_buffer__free(rb); ++ ebpf_collector_bpf__destroy(skel); ++ return -err; ++} diff --git a/src/c/ebpf_collector/ebpf_collector.h b/src/c/ebpf_collector/ebpf_collector.h new file mode 100644 index 0000000..3405dd8 --- /dev/null +++ b/src/c/ebpf_collector/ebpf_collector.h @@ -0,0 +1,110 @@ -+/* -+ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. -+ * Description: ebpf collector program -+ * Author: Zhang Nan -+ * Create: 2024-09-27 -+ */ -+#ifndef __EBPFCOLLECTOR_H -+#define __EBPFCOLLECTOR_H -+ -+typedef long long unsigned int u64; -+typedef unsigned int u32; -+ -+#define MAX_IO_TIME 130 -+#define IO_DUMP_THRESHOLD 120 -+#define THRESHOLD 1000000000 -+#define DURATION_THRESHOLD 500000000 -+ -+#define RWBS_LEN 8 -+ -+#define REQ_OP_BITS 8 -+#define REQ_OP_MASK ((1 << REQ_OP_BITS) - 1) -+#define REQ_FUA (1ULL << __REQ_FUA) -+#define REQ_RAHEAD (1ULL << __REQ_RAHEAD) -+#define REQ_SYNC (1ULL << __REQ_SYNC) -+#define REQ_META (1ULL << __REQ_META) -+#define REQ_PREFLUSH (1ULL << __REQ_PREFLUSH) -+#define REQ_OP_READ 0 -+#define REQ_OP_WRITE 1 -+#define REQ_OP_FLUSH 2 -+#define REQ_OP_DISCARD 3 -+#define REQ_OP_SECURE_ERASE 5 -+#define REQ_OP_WRITE_SAME 7 -+#define MAP_SIZE 15 -+ -+#define RWBS_LEN 8 -+#define MINORBITS 20 -+#define MINORMASK ((1U << MINORBITS) - 1) -+ -+#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) -+#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) -+ -+#ifndef NULL -+#define NULL (void *)0 -+#endif -+ -+// 阶段 -+#define STAGE_RQ_DRIVER 1 -+#define STAGE_BIO 2 -+#define STAGE_WBT 3 -+#define STAGE_GET_TAG 4 -+ -+// 时期 -+#define PERIOD_START 1 -+#define PERIOD_END 2 -+ -+// 错误码 -+#define ERROR_MAJOR_ZERO 1 -+#define ERROR_KEY_OVERFLOW 2 -+#define ERROR_KEY_EXIST 3 -+#define ERROR_UPDATE_FAIL 4 -+#define ERROR_KEY_NOEXIST 5 -+ -+enum stage_type { -+ BIO=0, -+ WBT, -+ GET_TAG, -+ DEADLINE, -+ BFQ, -+ KYBER, -+ RQ_DRIVER, -+ MAX_STAGE_TYPE, -+}; -+ -+struct stage_data { -+ u64 start_count; -+ u64 finish_count; -+ u64 finish_over_time; -+ u64 duration; -+ int major; -+ int first_minor; -+ char io_type[RWBS_LEN]; -+}; -+ -+struct io_counter { -+ u64 duration; -+ u64 start_time; -+ u32 isend; -+ int major; -+ int first_minor; -+}; -+ -+struct update_params { -+ int major; -+ int first_minor; -+ unsigned int cmd_flags; -+ u64 curr_start_range; -+}; -+ -+struct time_range_io_count -+{ -+ u32 count[MAP_SIZE]; -+}; -+ -+struct event { -+ u32 stage; -+ u64 period; -+ u32 err; -+}; -+ -+#endif /* __EBPFCOLLECTOR_H */ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * Description: ebpf collector program ++ * Author: Zhang Nan ++ * Create: 2024-09-27 ++ */ ++#ifndef __EBPFCOLLECTOR_H ++#define __EBPFCOLLECTOR_H ++ ++typedef long long unsigned int u64; ++typedef unsigned int u32; ++ ++#define MAX_IO_TIME 130 ++#define IO_DUMP_THRESHOLD 120 ++#define THRESHOLD 1000000000 ++#define DURATION_THRESHOLD 500000000 ++ ++#define RWBS_LEN 8 ++ ++#define REQ_OP_BITS 8 ++#define REQ_OP_MASK ((1 << REQ_OP_BITS) - 1) ++#define REQ_FUA (1ULL << __REQ_FUA) ++#define REQ_RAHEAD (1ULL << __REQ_RAHEAD) ++#define REQ_SYNC (1ULL << __REQ_SYNC) ++#define REQ_META (1ULL << __REQ_META) ++#define REQ_PREFLUSH (1ULL << __REQ_PREFLUSH) ++#define REQ_OP_READ 0 ++#define REQ_OP_WRITE 1 ++#define REQ_OP_FLUSH 2 ++#define REQ_OP_DISCARD 3 ++#define REQ_OP_SECURE_ERASE 5 ++#define REQ_OP_WRITE_SAME 7 ++#define MAP_SIZE 15 ++ ++#define RWBS_LEN 8 ++#define MINORBITS 20 ++#define MINORMASK ((1U << MINORBITS) - 1) ++ ++#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) ++#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) ++ ++#ifndef NULL ++#define NULL (void *)0 ++#endif ++ ++// 阶段 ++#define STAGE_RQ_DRIVER 1 ++#define STAGE_BIO 2 ++#define STAGE_WBT 3 ++#define STAGE_GET_TAG 4 ++ ++// 时期 ++#define PERIOD_START 1 ++#define PERIOD_END 2 ++ ++// 错误码 ++#define ERROR_MAJOR_ZERO 1 ++#define ERROR_KEY_OVERFLOW 2 ++#define ERROR_KEY_EXIST 3 ++#define ERROR_UPDATE_FAIL 4 ++#define ERROR_KEY_NOEXIST 5 ++ ++enum stage_type { ++ BIO=0, ++ WBT, ++ GET_TAG, ++ DEADLINE, ++ BFQ, ++ KYBER, ++ RQ_DRIVER, ++ MAX_STAGE_TYPE, ++}; ++ ++struct stage_data { ++ u64 start_count; ++ u64 finish_count; ++ u64 finish_over_time; ++ u64 duration; ++ int major; ++ int first_minor; ++ char io_type[RWBS_LEN]; ++}; ++ ++struct io_counter { ++ u64 duration; ++ u64 start_time; ++ u32 isend; ++ int major; ++ int first_minor; ++}; ++ ++struct update_params { ++ int major; ++ int first_minor; ++ unsigned int cmd_flags; ++ u64 curr_start_range; ++}; ++ ++struct time_range_io_count ++{ ++ u32 count[MAP_SIZE]; ++}; ++ ++struct event { ++ u32 stage; ++ u64 period; ++ u32 err; ++}; ++ ++#endif /* __EBPFCOLLECTOR_H */ diff --git a/src/c/ebpf_collector/vmlinux.h b/src/c/ebpf_collector/vmlinux.h new file mode 100644 index 0000000..b2cc6e1 --- /dev/null +++ b/src/c/ebpf_collector/vmlinux.h @@ -0,0 +1,10 @@ -+#ifndef __VMLINUX_H_ENTRY__ -+#define __VMLINUX_H_ENTRY__ -+ -+#if defined(__TARGET_ARCH_x86) -+#include "vmlinux_x86_64.h" -+#elif defined(__TARGET_ARCH_arm64) -+#include "vmlinux_aarch64.h" -+#endif -+ -+#endif ++#ifndef __VMLINUX_H_ENTRY__ ++#define __VMLINUX_H_ENTRY__ ++ ++#if defined(__TARGET_ARCH_x86) ++#include "vmlinux_x86_64.h" ++#elif defined(__TARGET_ARCH_arm64) ++#include "vmlinux_aarch64.h" ++#endif ++ ++#endif diff --git a/src/c/ebpf_collector/vmlinux_aarch64.h b/src/c/ebpf_collector/vmlinux_aarch64.h new file mode 100644 index 0000000..5283e43 diff --git a/fix-bug-of-ebpf-and-ai_block_io.patch b/fix-bug-of-ebpf-and-ai_block_io.patch new file mode 100644 index 0000000000000000000000000000000000000000..5ba10ede9ef0519e74c90647b52444c9f1d0fb6e --- /dev/null +++ b/fix-bug-of-ebpf-and-ai_block_io.patch @@ -0,0 +1,397 @@ +From 480c0fc479ec882786cdb58d699cf84ce5995531 Mon Sep 17 00:00:00 2001 +From: zhuofeng +Date: Fri, 14 Feb 2025 09:42:27 +0800 +Subject: [PATCH] fix bug of ebpf and ai_block_io + +--- + src/c/ebpf_collector/ebpf_collector.bpf.c | 357 ------------------ + .../sentryPlugins/ai_block_io/detector.py | 3 +- + 2 files changed, 2 insertions(+), 358 deletions(-) + +diff --git a/src/c/ebpf_collector/ebpf_collector.bpf.c b/src/c/ebpf_collector/ebpf_collector.bpf.c +index 417618d..7a2f481 100644 +--- a/src/c/ebpf_collector/ebpf_collector.bpf.c ++++ b/src/c/ebpf_collector/ebpf_collector.bpf.c +@@ -590,361 +590,4 @@ int kprobe_bio_endio(struct pt_regs *regs) + return 0; + } + +-// start get_tag +-SEC("kprobe/blk_mq_get_tag") +-int kprobe_blk_mq_get_tag(struct pt_regs *regs) +-{ +- u64 tagkey = bpf_get_current_task(); +- u64 value = (u64)PT_REGS_PARM1(regs); +- (void)bpf_map_update_elem(&tag_args, &tagkey, &value, BPF_ANY); +- +- struct blk_mq_alloc_data *bd; +- struct request_queue *q; +- struct backing_dev_info *backing_dev_info; +- struct device *owner; +- dev_t devt; +- unsigned int cmd_flags = 0; +- +- bd = (struct blk_mq_alloc_data *)value; +- bpf_core_read(&q, sizeof(q), &bd->q); +- bpf_core_read(&backing_dev_info, sizeof(backing_dev_info), &q->backing_dev_info); +- bpf_core_read(&owner, sizeof(owner), &backing_dev_info->owner); +- bpf_core_read(&devt, sizeof(devt), &owner->devt); +- int major = MAJOR(devt); +- int first_minor = MINOR(devt); +- +- if (major == 0) { +- log_event(STAGE_GET_TAG, PERIOD_START, ERROR_MAJOR_ZERO); +- return 0; +- } +- +- u32 key = find_matching_key_get_tag(major, first_minor); +- if (key >= MAP_SIZE) { +- return 0; +- } +- +- struct io_counter *counterp, zero = {}; +- init_io_counter(&zero, major, first_minor); +- counterp = bpf_map_lookup_elem(&tag_map, &tagkey); +- if (counterp) { +- return 0; +- } +- long err = bpf_map_update_elem(&tag_map, &tagkey, &zero, BPF_NOEXIST); +- if (err) { +- log_event(STAGE_GET_TAG, PERIOD_START, ERROR_UPDATE_FAIL); +- return 0; +- } +- +- u64 curr_start_range = zero.start_time / THRESHOLD; +- +- struct update_params params = { +- .major = major, +- .first_minor = first_minor, +- .cmd_flags = cmd_flags, +- .curr_start_range = curr_start_range, +- }; +- +- struct stage_data *curr_data; +- curr_data = bpf_map_lookup_elem(&tag_res, &key); +- if (!curr_data) { +- struct stage_data new_data = { +- .start_count = 1, +- .finish_count = 0, +- .finish_over_time = 0, +- .duration = 0, +- .major = major, +- .first_minor = first_minor, +- .io_type = "", +- }; +- blk_fill_rwbs(new_data.io_type, cmd_flags); +- bpf_map_update_elem(&tag_res, &key, &new_data, 0); +- } else { +- update_curr_data_in_start(curr_data, ¶ms); +- } +- +- struct time_range_io_count *curr_data_time_range; +- curr_data_time_range = bpf_map_lookup_elem(&tag_res_2, &curr_start_range); +- if (curr_data_time_range == NULL) { +- struct time_range_io_count new_data = { .count = {0} }; +- bpf_map_update_elem(&tag_res_2, &curr_start_range, &new_data, 0); +- } else { +- if (key < MAP_SIZE && key >= 0) { +- __sync_fetch_and_add(&curr_data_time_range->count[key], 1); +- } +- } +- return 0; +-} +- +-// finish get_tag +-SEC("kretprobe/blk_mq_get_tag") +-int kretprobe_blk_mq_get_tag(struct pt_regs *regs) +-{ +- u64 tagkey = bpf_get_current_task(); +- u64 *tagargs = (u64 *)bpf_map_lookup_elem(&tag_args, &tagkey); +- if (tagargs == NULL) { +- bpf_map_delete_elem(&tag_args, &tagkey); +- return 0; +- } +- +- struct blk_mq_alloc_data *bd; +- struct request_queue *q; +- struct backing_dev_info *backing_dev_info; +- struct device *owner; +- dev_t devt; +- unsigned int cmd_flags = 0; +- +- bd = (struct blk_mq_alloc_data *)*tagargs; +- bpf_core_read(&q, sizeof(q), &bd->q); +- bpf_core_read(&backing_dev_info, sizeof(backing_dev_info), &q->backing_dev_info); +- bpf_core_read(&owner, sizeof(owner), &backing_dev_info->owner); +- bpf_core_read(&devt, sizeof(devt), &owner->devt); +- int major = MAJOR(devt); +- int first_minor = MINOR(devt); +- +- if (major == 0) { +- log_event(STAGE_GET_TAG, PERIOD_END, ERROR_MAJOR_ZERO); +- return 0; +- } +- +- u32 key = find_matching_key_get_tag(major, first_minor); +- if (key >= MAP_SIZE) { +- return 0; +- } +- +- struct io_counter *counterp = bpf_map_lookup_elem(&tag_map, &tagkey); +- if (!counterp) { +- return 0; +- } +- +- u64 duration = bpf_ktime_get_ns() - counterp->start_time; +- u64 curr_start_range = counterp->start_time / THRESHOLD; +- +- struct update_params params = { +- .major = major, +- .first_minor = first_minor, +- .cmd_flags = cmd_flags, +- .curr_start_range = curr_start_range, +- }; +- +- struct stage_data *curr_data; +- curr_data = bpf_map_lookup_elem(&tag_res, &key); +- if (curr_data == NULL && duration > DURATION_THRESHOLD) { +- struct stage_data new_data = { +- .start_count = 1, +- .finish_count = 1, +- .finish_over_time = 1, +- .duration = 0, +- .major = major, +- .first_minor = first_minor, +- .io_type = "", +- }; +- blk_fill_rwbs(new_data.io_type, cmd_flags); +- bpf_map_update_elem(&tag_res, &key, &new_data, 0); +- } else if (curr_data == NULL) { +- struct stage_data new_data = { +- .start_count = 1, +- .finish_count = 1, +- .finish_over_time = 0, +- .duration = 0, +- .major = major, +- .first_minor = first_minor, +- .io_type = "", +- }; +- blk_fill_rwbs(new_data.io_type, cmd_flags); +- bpf_map_update_elem(&tag_res, &key, &new_data, 0); +- } else { +- curr_data->duration += duration; +- update_curr_data_in_finish(curr_data, ¶ms, duration); +- } +- +- struct time_range_io_count *curr_data_time_range; +- curr_data_time_range = bpf_map_lookup_elem(&tag_res_2, &curr_start_range); +- if (curr_data_time_range == NULL) { +- struct time_range_io_count new_data = { .count = {0} }; +- bpf_map_update_elem(&tag_res_2, &curr_start_range, &new_data, 0); +- } else { +- if (key < MAP_SIZE && curr_data_time_range->count[key] > 0) { +- __sync_fetch_and_add(&curr_data_time_range->count[key], -1); +- } +- } +- +- bpf_map_delete_elem(&tag_map, &tagkey); +- bpf_map_delete_elem(&tag_args, &tagkey); +- return 0; +-} +- +-// start wbt +-SEC("kprobe/wbt_wait") +-int kprobe_wbt_wait(struct pt_regs *regs) +-{ +- u64 wbtkey = bpf_get_current_task(); +- u64 value = (u64)PT_REGS_PARM2(regs); +- (void)bpf_map_update_elem(&wbt_args, &wbtkey, &value, BPF_ANY); +- +- struct bio *bio; +- struct gendisk *curr_rq_disk; +- int major, first_minor; +- unsigned int cmd_flags; +- +- bio = (struct bio *)value; +- bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &bio->bi_disk); +- bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); +- bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); +- bpf_core_read(&cmd_flags, sizeof(cmd_flags), &bio->bi_opf); +- +- if (major == 0) { +- log_event(STAGE_WBT, PERIOD_START, ERROR_MAJOR_ZERO); +- return 0; +- } +- +- u32 key = find_matching_key_wbt(major, first_minor); +- if (key >= MAP_SIZE) { +- return 0; +- } +- +- struct io_counter *counterp, zero = {}; +- init_io_counter(&zero, major, first_minor); +- counterp = bpf_map_lookup_elem(&wbt_map, &wbtkey); +- if (counterp) { +- return 0; +- } +- long err = bpf_map_update_elem(&wbt_map, &wbtkey, &zero, BPF_NOEXIST); +- if (err) { +- log_event(STAGE_WBT, PERIOD_START, ERROR_UPDATE_FAIL); +- return 0; +- } +- +- u64 curr_start_range = zero.start_time / THRESHOLD; +- +- struct update_params params = { +- .major = major, +- .first_minor = first_minor, +- .cmd_flags = cmd_flags, +- .curr_start_range = curr_start_range, +- }; +- +- struct stage_data *curr_data; +- curr_data = bpf_map_lookup_elem(&wbt_res, &key); +- if (!curr_data) { +- struct stage_data new_data = { +- .start_count = 1, +- .finish_count = 0, +- .finish_over_time = 0, +- .duration = 0, +- .major = major, +- .first_minor = first_minor, +- .io_type = "", +- }; +- blk_fill_rwbs(new_data.io_type, cmd_flags); +- bpf_map_update_elem(&wbt_res, &key, &new_data, 0); +- } else { +- update_curr_data_in_start(curr_data, ¶ms); +- } +- +- struct time_range_io_count *curr_data_time_range; +- curr_data_time_range = bpf_map_lookup_elem(&wbt_res_2, &curr_start_range); +- if (curr_data_time_range == NULL) { +- struct time_range_io_count new_data = { .count = {0} }; +- bpf_map_update_elem(&wbt_res_2, &curr_start_range, &new_data, 0); +- } else { +- if (key < MAP_SIZE && key >= 0) { +- __sync_fetch_and_add(&curr_data_time_range->count[key], 1); +- } +- } +- return 0; +-} +- +-// finish wbt +-SEC("kretprobe/wbt_wait") +-int kretprobe_wbt_wait(struct pt_regs *regs) +-{ +- u64 wbtkey = bpf_get_current_task(); +- u64 *wbtargs = (u64 *)bpf_map_lookup_elem(&wbt_args, &wbtkey); +- if (wbtargs == NULL) { +- bpf_map_delete_elem(&wbt_args, &wbtkey); +- return 0; +- } +- +- struct bio *bio; +- struct gendisk *curr_rq_disk; +- int major, first_minor; +- unsigned int cmd_flags; +- +- bio = (struct bio *)(*wbtargs); +- bpf_core_read(&curr_rq_disk, sizeof(curr_rq_disk), &bio->bi_disk); +- bpf_core_read(&major, sizeof(major), &curr_rq_disk->major); +- bpf_core_read(&first_minor, sizeof(first_minor), &curr_rq_disk->first_minor); +- bpf_core_read(&cmd_flags, sizeof(cmd_flags), &bio->bi_opf); +- +- if (major == 0) { +- log_event(STAGE_WBT, PERIOD_END, ERROR_MAJOR_ZERO); +- return 0; +- } +- +- u32 key = find_matching_key_wbt(major, first_minor); +- if (key >= MAP_SIZE) { +- return 0; +- } +- +- struct io_counter *counterp = bpf_map_lookup_elem(&wbt_map, &wbtkey); +- if (!counterp) { +- return 0; +- } +- +- u64 duration = bpf_ktime_get_ns() - counterp->start_time; +- u64 curr_start_range = counterp->start_time / THRESHOLD; +- +- struct update_params params = { +- .major = major, +- .first_minor = first_minor, +- .cmd_flags = cmd_flags, +- .curr_start_range = curr_start_range, +- }; +- +- struct stage_data *curr_data; +- curr_data = bpf_map_lookup_elem(&wbt_res, &key); +- if (curr_data == NULL && duration > DURATION_THRESHOLD) { +- struct stage_data new_data = { +- .start_count = 1, +- .finish_count = 1, +- .finish_over_time = 1, +- .duration = 0, +- .major = major, +- .first_minor = first_minor, +- .io_type = "", +- }; +- blk_fill_rwbs(new_data.io_type, cmd_flags); +- bpf_map_update_elem(&wbt_res, &key, &new_data, 0); +- } else if (curr_data == NULL) { +- struct stage_data new_data = { +- .start_count = 1, +- .finish_count = 1, +- .finish_over_time = 0, +- .duration = 0, +- .io_type = "", +- .major = major, +- .first_minor = first_minor, +- }; +- blk_fill_rwbs(new_data.io_type, cmd_flags); +- bpf_map_update_elem(&wbt_res, &key, &new_data, 0); +- } else { +- curr_data->duration += duration; +- update_curr_data_in_finish(curr_data, ¶ms, duration); +- } +- +- struct time_range_io_count *curr_data_time_range; +- curr_data_time_range = bpf_map_lookup_elem(&wbt_res_2, &curr_start_range); +- if (curr_data_time_range == NULL) { +- struct time_range_io_count new_data = { .count = {0} }; +- bpf_map_update_elem(&wbt_res_2, &curr_start_range, &new_data, 0); +- } else { +- if (key < MAP_SIZE && curr_data_time_range->count[key] > 0) { +- __sync_fetch_and_add(&curr_data_time_range->count[key], -1); +- } +- } +- bpf_map_delete_elem(&wbt_map, &wbtkey); +- bpf_map_delete_elem(&wbt_args, &wbtkey); +- return 0; +-} +- + char _license[] SEC("license") = "GPL"; +diff --git a/src/python/sentryPlugins/ai_block_io/detector.py b/src/python/sentryPlugins/ai_block_io/detector.py +index 27fb7f7..2688cb1 100644 +--- a/src/python/sentryPlugins/ai_block_io/detector.py ++++ b/src/python/sentryPlugins/ai_block_io/detector.py +@@ -55,11 +55,12 @@ class Detector: + detection_result = self._slidingWindow.is_slow_io_event(metric_value) + # 检测到慢周期,由Detector负责打印info级别日志 + if detection_result[0][1]: ++ ai_threshold = "None" if detection_result[2] is None else round(detection_result[2], 3) + logging.info(f'[abnormal_period]: disk: {self._metric_name.disk_name}, ' + f'stage: {self._metric_name.stage_name}, ' + f'iotype: {self._metric_name.io_access_type_name}, ' + f'type: {self._metric_name.metric_name}, ' +- f'ai_threshold: {round(detection_result[2], 3)}, ' ++ f'ai_threshold: {ai_threshold}, ' + f'curr_val: {metric_value}') + else: + logging.debug(f'Detection result: {str(detection_result)}') +-- +2.33.0 + diff --git a/sysSentry.spec b/sysSentry.spec index 1089f8dafdb9245e132b202ef0367219c1aba12c..ed4a4103462d18437a7bd9e5dab4033ba6336416 100644 --- a/sysSentry.spec +++ b/sysSentry.spec @@ -4,7 +4,7 @@ Summary: System Inspection Framework Name: sysSentry Version: 1.0.2 -Release: 30 +Release: 31 License: Mulan PSL v2 Group: System Environment/Daemons Source0: https://gitee.com/openeuler/sysSentry/releases/download/v%{version}/%{name}-%{version}.tar.gz @@ -40,6 +40,7 @@ Patch27: add-pyxalarm-and-pySentryNotify-add-multi-users-supp.patch Patch28: adapt_5.10_kenel_for_syssentry.patch Patch29: collect-module-adapt-to-the-5.10-kernel.patch Patch30: add-avg_block_io-and-ai_block_io.patch +Patch31: fix-bug-of-ebpf-and-ai_block_io.patch BuildRequires: cmake gcc-c++ BuildRequires: python3 python3-setuptools @@ -357,6 +358,12 @@ rm -rf %{buildroot} %attr(0550,root,root) %{python3_sitelib}/sentryCollector/__pycache__/collect_plugin* %changelog +* Fri Feb 14 2025 zhuofeng - 1.0.2-31 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC:fix bug of ebpf and ai_block_io + * Sun Jan 26 2025 zhuofeng - 1.0.2-30 - Type:bugfix - CVE:NA