Skip to content

Commit

Permalink
Merge pull request iovisor#3691 from chenhengqi/add-mdflush
Browse files Browse the repository at this point in the history
libbpf-tools: Add mdflush
  • Loading branch information
davemarchevsky committed Jun 24, 2022
2 parents 21e18d1 + 4f59913 commit 9627312
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 4 deletions.
1 change: 1 addition & 0 deletions libbpf-tools/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
/llcstat
/nfsdist
/nfsslower
/mdflush
/mountsnoop
/numamove
/offcputime
Expand Down
1 change: 1 addition & 0 deletions libbpf-tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ APPS = \
klockstat \
ksnoop \
llcstat \
mdflush \
mountsnoop \
numamove \
offcputime \
Expand Down
27 changes: 23 additions & 4 deletions libbpf-tools/core_fixes.bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,34 @@
*/
struct task_struct___x {
unsigned int __state;
};
} __attribute__((preserve_access_index));

static __s64 get_task_state(void *task)
/**
* commit 309dca309fc3 ("block: store a block_device pointer in struct bio")
* adds a new member bi_bdev which is a pointer to struct block_device
* see:
* https://github.com/torvalds/linux/commit/309dca309fc3
*/
struct bio___x {
struct block_device *bi_bdev;
} __attribute__((preserve_access_index));

static __always_inline __s64 get_task_state(void *task)
{
struct task_struct___x *t = task;

if (bpf_core_field_exists(t->__state))
return t->__state;
return ((struct task_struct *)task)->state;
return BPF_CORE_READ(t, __state);
return BPF_CORE_READ((struct task_struct *)task, state);
}

static __always_inline struct gendisk *get_gendisk(void *bio)
{
struct bio___x *b = bio;

if (bpf_core_field_exists(b->bi_bdev))
return BPF_CORE_READ(b, bi_bdev, bd_disk);
return BPF_CORE_READ((struct bio *)bio, bi_disk);
}

#endif /* __CORE_FIXES_BPF_H */
31 changes: 31 additions & 0 deletions libbpf-tools/mdflush.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
/* Copyright (c) 2021~2022 Hengqi Chen */
#include <vmlinux.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include "core_fixes.bpf.h"
#include "mdflush.h"

struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__type(key, __u32);
__type(value, __u32);
} events SEC(".maps");

SEC("fentry/md_flush_request")
int BPF_PROG(md_flush_request, void *mddev, void *bio)
{
__u64 pid = bpf_get_current_pid_tgid() >> 32;
struct event event = {};
struct gendisk *gendisk;

event.pid = pid;
gendisk = get_gendisk(bio);
BPF_CORE_READ_STR_INTO(event.disk, gendisk, disk_name);
bpf_get_current_comm(event.comm, sizeof(event.comm));
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));
return 0;
}

char LICENSE[] SEC("license") = "Dual BSD/GPL";
152 changes: 152 additions & 0 deletions libbpf-tools/mdflush.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */

/*
* mdflush Trace md flush events.
*
* Copyright (c) 2021~2022 Hengqi Chen
*
* Based on mdflush(8) from BCC by Brendan Gregg.
* 08-Nov-2021 Hengqi Chen Created this.
*/
#include <argp.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <time.h>

#include <bpf/libbpf.h>
#include <bpf/bpf.h>
#include "mdflush.h"
#include "mdflush.skel.h"
#include "trace_helpers.h"

#define PERF_BUFFER_PAGES 16
#define PERF_POLL_TIMEOUT_MS 100
#define warn(...) fprintf(stderr, __VA_ARGS__)

static volatile sig_atomic_t exiting = 0;
static bool verbose = false;

const char *argp_program_version = "mdflush 0.1";
const char *argp_program_bug_address =
"https://github.com/iovisor/bcc/tree/master/libbpf-tools";
const char argp_program_doc[] =
"Trace md flush events.\n"
"\n"
"USAGE: mdflush\n";

static const struct argp_option opts[] = {
{ "verbose", 'v', NULL, 0, "Verbose debug output" },
{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
{},
};

static error_t parse_arg(int key, char *arg, struct argp_state *state)
{
switch (key) {
case 'h':
argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
break;
case 'v':
verbose = true;
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}

static void sig_int(int signo)
{
exiting = 1;
}

static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
{
if (level == LIBBPF_DEBUG && !verbose)
return 0;
return vfprintf(stderr, format, args);
}

static void handle_event(void *ctx, int cpu, void *data, __u32 data_sz)
{
struct event *e = data;
time_t t;
struct tm *tm;
char ts[32];

time(&t);
tm = localtime(&t);
strftime(ts, sizeof(ts), "%H:%M:%S", tm);
printf("%-8s %-7d %-16s %-s\n",
ts, e->pid, e->comm, e->disk);
}

static void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt)
{
warn("lost %llu events on CPU #%d\n", lost_cnt, cpu);
}

int main(int argc, char **argv)
{
static const struct argp argp = {
.options = opts,
.parser = parse_arg,
.doc = argp_program_doc,
};
struct perf_buffer *pb = NULL;
struct mdflush_bpf *obj;
int err;

err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
if (err)
return err;

libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
libbpf_set_print(libbpf_print_fn);

obj = mdflush_bpf__open_and_load();
if (!obj) {
warn("failed to open/load BPF object\n");
return 1;
}

err = mdflush_bpf__attach(obj);
if (err) {
warn("failed to attach BPF programs: %d\n", err);
goto cleanup;
}

pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
handle_event, handle_lost_events, NULL, NULL);
if (!pb) {
warn("failed to open perf buffer: %d\n", err);
goto cleanup;
}

if (signal(SIGINT, sig_int) == SIG_ERR) {
warn("can't set signal handler: %s\n", strerror(errno));
err = 1;
goto cleanup;
}

printf("Tracing md flush requests... Hit Ctrl-C to end.\n");
printf("%-8s %-7s %-16s %-s\n",
"TIME", "PID", "COMM", "DEVICE");

while (!exiting) {
err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
if (err < 0 && err != -EINTR) {
warn("error polling perf buffer: %s\n", strerror(-err));
goto cleanup;
}
/* reset err to return 0 if exiting */
err = 0;
}

cleanup:
perf_buffer__free(pb);
mdflush_bpf__destroy(obj);

return err != 0;
}
15 changes: 15 additions & 0 deletions libbpf-tools/mdflush.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
/* Copyright (c) 2021~2022 Hengqi Chen */
#ifndef __MDFLUSH_H
#define __MDFLUSH_H

#define TASK_COMM_LEN 16
#define DISK_NAME_LEN 32

struct event {
__u32 pid;
char comm[TASK_COMM_LEN];
char disk[DISK_NAME_LEN];
};

#endif /* __MDFLUSH_H */

0 comments on commit 9627312

Please sign in to comment.