提交 1e4dd73d 编写于 作者: H Hou Tao 提交者: Zheng Zengkai

selftests/bpf: add demo for file read pattern detection

hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I53R0H
CVE: NA
backport: openEuler-22.03-LTS

---------------------------

It attaches eBPF program into fs_file_read() and fs_file_release()
respectively. The program for fs_file_read() will record read
history, calculate read pattern and set f_mode for specific file,
And program for fs_file_release() will clean the saved read history.
Signed-off-by: NHou Tao <houtao1@huawei.com>
Reviewed-by: NKuohai Xu <xukuohai@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: NZhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 a257f0fa
...@@ -38,6 +38,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test ...@@ -38,6 +38,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test
test_netcnt test_tcpnotify_user test_sysctl \ test_netcnt test_tcpnotify_user test_sysctl \
test_progs-no_alu32 \ test_progs-no_alu32 \
test_current_pid_tgid_new_ns test_current_pid_tgid_new_ns
TEST_GEN_PROGS += file_read_pattern
# Also test bpf-gcc, if present # Also test bpf-gcc, if present
ifneq ($(BPF_GCC),) ifneq ($(BPF_GCC),)
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2021. Huawei Technologies Co., Ltd */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <linux/bpf.h>
#include <linux/err.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "bpf_rlimit.h"
#define READ_TP_NAME "fs_file_read"
#define RELEASE_TP_NAME "fs_file_release"
int main(int argc, char *argv[])
{
const char *name = "./file_read_pattern_prog.o";
struct bpf_object *obj;
const char *prog_name;
struct bpf_program *prog;
int unused;
int err;
int read_fd;
int release_fd;
err = bpf_prog_load(name, BPF_PROG_TYPE_UNSPEC, &obj, &unused);
if (err) {
printf("Failed to load program\n");
return err;
}
prog_name = "raw_tracepoint.w/" READ_TP_NAME;
prog = bpf_object__find_program_by_title(obj, prog_name);
if (!prog) {
printf("no prog %s\n", prog_name);
err = -EINVAL;
goto out;
}
read_fd = bpf_raw_tracepoint_open(READ_TP_NAME, bpf_program__fd(prog));
if (read_fd < 0) {
err = -errno;
printf("Failed to attach raw tracepoint %s\n", READ_TP_NAME);
goto out;
}
prog_name = "raw_tracepoint/" RELEASE_TP_NAME;
prog = bpf_object__find_program_by_title(obj, prog_name);
if (!prog) {
printf("no prog %s\n", prog_name);
err = -EINVAL;
goto out;
}
release_fd = bpf_raw_tracepoint_open(RELEASE_TP_NAME,
bpf_program__fd(prog));
if (release_fd < 0) {
err = -errno;
printf("Failed to attach raw tracepoint %s\n", RELEASE_TP_NAME);
goto out;
}
pause();
close(release_fd);
close(read_fd);
out:
bpf_object__close(obj);
return err;
}
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2021. Huawei Technologies Co., Ltd */
#include <stdbool.h>
#include <string.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#ifndef __always_inline
#define __always_inline inline __attribute__((always_inline))
#endif
/* Need to keep consistent with definitions in include/linux/fs.h */
#define FMODE_CTL_RANDOM 0x1
#define FMODE_CTL_WILLNEED 0x2
struct fs_file_read_ctx {
const unsigned char *name;
unsigned int f_ctl_mode;
unsigned int rsvd;
/* clear from f_ctl_mode */
unsigned int clr_f_ctl_mode;
/* set into f_ctl_mode */
unsigned int set_f_ctl_mode;
unsigned long key;
/* file size */
long long i_size;
/* previous page index */
long long prev_index;
/* current page index */
long long index;
};
struct fs_file_read_args {
struct fs_file_read_ctx *ctx;
int version;
};
struct fs_file_release_args {
void *inode;
void *filp;
};
struct file_rd_hist {
__u64 last_nsec;
__u32 seq_nr;
__u32 tot_nr;
};
struct bpf_map_def SEC("maps") htab = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(long),
.value_size = sizeof(struct file_rd_hist),
.max_entries = 10000,
};
static __always_inline bool is_expected_file(void *name)
{
char prefix[5];
int err;
err = bpf_probe_read_str(&prefix, sizeof(prefix), name);
if (err <= 0)
return false;
return !strncmp(prefix, "blk_", 4);
}
SEC("raw_tracepoint.w/fs_file_read")
int fs_file_read(struct fs_file_read_args *args)
{
const char fmt[] = "elapsed %llu, seq %u, tot %u\n";
struct fs_file_read_ctx *rd_ctx = args->ctx;
struct file_rd_hist *hist;
struct file_rd_hist new_hist;
__u64 key;
__u64 now;
bool first;
if (!is_expected_file((void *)rd_ctx->name))
return 0;
if (rd_ctx->i_size <= (4 << 20)) {
rd_ctx->set_f_ctl_mode = FMODE_CTL_WILLNEED;
return 0;
}
first = false;
now = bpf_ktime_get_ns();
key = rd_ctx->key;
hist = bpf_map_lookup_elem(&htab, &key);
if (!hist) {
__builtin_memset(&new_hist, 0, sizeof(new_hist));
new_hist.last_nsec = now;
first = true;
hist = &new_hist;
}
if (rd_ctx->index >= rd_ctx->prev_index &&
rd_ctx->index - rd_ctx->prev_index <= 1)
hist->seq_nr += 1;
hist->tot_nr += 1;
bpf_trace_printk(fmt, sizeof(fmt), now - hist->last_nsec,
hist->seq_nr, hist->tot_nr);
if (first) {
bpf_map_update_elem(&htab, &key, hist, 0);
return 0;
}
/* 500ms or 10 read */
if (now - hist->last_nsec >= 500000000ULL || hist->tot_nr >= 10) {
if (hist->tot_nr >= 10) {
if (hist->seq_nr <= hist->tot_nr * 3 / 10)
rd_ctx->set_f_ctl_mode = FMODE_CTL_RANDOM;
else if (hist->seq_nr >= hist->tot_nr * 7 / 10)
rd_ctx->clr_f_ctl_mode = FMODE_CTL_RANDOM;
}
hist->last_nsec = now;
hist->tot_nr = 0;
hist->seq_nr = 0;
}
return 0;
}
SEC("raw_tracepoint/fs_file_release")
int fs_file_release(struct fs_file_release_args *args)
{
__u64 key = (unsigned long)args->filp;
void *value;
value = bpf_map_lookup_elem(&htab, &key);
if (value)
bpf_map_delete_elem(&htab, &key);
return 0;
}
char _license[] SEC("license") = "GPL";
__u32 _version SEC("version") = 1;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册