123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023 |
- // SPDX-License-Identifier: GPL-3.0-or-later
- #include "ebpf_filesystem.h"
- struct config fs_config = { .first_section = NULL,
- .last_section = NULL,
- .mutex = NETDATA_MUTEX_INITIALIZER,
- .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
- .rwlock = AVL_LOCK_INITIALIZER } };
- ebpf_local_maps_t ext4_maps[] = {{.name = "tbl_ext4", .internal_input = NETDATA_KEY_CALLS_SYNC,
- .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
- #endif
- },
- {.name = "tmp_ext4", .internal_input = 4192, .user_input = 4192,
- .type = NETDATA_EBPF_MAP_CONTROLLER,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
- #endif
- },
- {.name = NULL, .internal_input = 0, .user_input = 0,
- .type = NETDATA_EBPF_MAP_CONTROLLER,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
- #endif
- }};
- ebpf_local_maps_t xfs_maps[] = {{.name = "tbl_xfs", .internal_input = NETDATA_KEY_CALLS_SYNC,
- .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
- #endif
- },
- {.name = "tmp_xfs", .internal_input = 4192, .user_input = 4192,
- .type = NETDATA_EBPF_MAP_CONTROLLER,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
- #endif
- },
- {.name = NULL, .internal_input = 0, .user_input = 0,
- .type = NETDATA_EBPF_MAP_CONTROLLER,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
- #endif
- }};
- ebpf_local_maps_t nfs_maps[] = {{.name = "tbl_nfs", .internal_input = NETDATA_KEY_CALLS_SYNC,
- .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
- #endif
- },
- {.name = "tmp_nfs", .internal_input = 4192, .user_input = 4192,
- .type = NETDATA_EBPF_MAP_CONTROLLER,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
- #endif
- },
- {.name = NULL, .internal_input = 0, .user_input = 0,
- .type = NETDATA_EBPF_MAP_CONTROLLER,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
- #endif
- }};
- ebpf_local_maps_t zfs_maps[] = {{.name = "tbl_zfs", .internal_input = NETDATA_KEY_CALLS_SYNC,
- .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
- #endif
- },
- {.name = "tmp_zfs", .internal_input = 4192, .user_input = 4192,
- .type = NETDATA_EBPF_MAP_CONTROLLER,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
- #endif
- },
- {.name = NULL, .internal_input = 0, .user_input = 0,
- .type = NETDATA_EBPF_MAP_CONTROLLER,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
- #endif
- }};
- ebpf_local_maps_t btrfs_maps[] = {{.name = "tbl_btrfs", .internal_input = NETDATA_KEY_CALLS_SYNC,
- .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
- #endif
- },
- {.name = "tbl_ext_addr", .internal_input = 1, .user_input = 1,
- .type = NETDATA_EBPF_MAP_CONTROLLER,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
- #endif
- },
- {.name = "tmp_btrfs", .internal_input = 4192, .user_input = 4192,
- .type = NETDATA_EBPF_MAP_CONTROLLER,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
- #endif
- },
- {.name = NULL, .internal_input = 0, .user_input = 0,
- .type = NETDATA_EBPF_MAP_CONTROLLER,
- .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
- #ifdef LIBBPF_MAJOR_VERSION
- .map_type = BPF_MAP_TYPE_PERCPU_HASH
- #endif
- }};
- static netdata_syscall_stat_t filesystem_aggregated_data[NETDATA_EBPF_HIST_MAX_BINS];
- static netdata_publish_syscall_t filesystem_publish_aggregated[NETDATA_EBPF_HIST_MAX_BINS];
- char **dimensions = NULL;
- static netdata_idx_t *filesystem_hash_values = NULL;
- #ifdef LIBBPF_MAJOR_VERSION
- /**
- * FS disable kprobe
- *
- * Disable kprobes, because system will use trampolines.
- * We are not calling this function for while, because we are prioritizing kprobes. We opted by this road, because
- * distribution are still not deliverying necessary btf files per FS.
- *
- * @param obj FS object loaded.
- */
- static void ebpf_fs_disable_kprobe(struct filesystem_bpf *obj)
- {
- // kprobe
- bpf_program__set_autoload(obj->progs.netdata_fs_file_read_probe, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_file_write_probe, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_file_open_probe, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_probe, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_getattr_probe, false);
- // kretprobe
- bpf_program__set_autoload(obj->progs.netdata_fs_file_read_retprobe, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_file_write_retprobe, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_file_open_retprobe, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_retprobe, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_getattr_retprobe, false);
- }
- /**
- * Disable trampoline
- *
- * Disable trampolines to use kprobes.
- *
- * @param obj FS object loaded.
- */
- static void ebpf_fs_disable_trampoline(struct filesystem_bpf *obj)
- {
- // entry
- bpf_program__set_autoload(obj->progs.netdata_fs_file_read_entry, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_file_write_entry, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_file_open_entry, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_getattr_entry, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_entry, false);
- // exit
- bpf_program__set_autoload(obj->progs.netdata_fs_file_read_exit, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_file_write_exit, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_file_open_exit, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_getattr_exit, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_exit, false);
- }
- /**
- * Set targets
- *
- * Set targets for each objects.
- *
- * @param obj FS object loaded.
- * @param functions array with function names.
- */
- static void ebpf_fs_set_target(struct filesystem_bpf *obj, const char **functions)
- {
- // entry
- bpf_program__set_attach_target(obj->progs.netdata_fs_file_read_entry, 0,
- functions[NETDATA_KEY_BTF_READ]);
- bpf_program__set_attach_target(obj->progs.netdata_fs_file_write_entry, 0,
- functions[NETDATA_KEY_BTF_WRITE]);
- bpf_program__set_attach_target(obj->progs.netdata_fs_file_open_entry, 0,
- functions[NETDATA_KEY_BTF_OPEN]);
- bpf_program__set_attach_target(obj->progs.netdata_fs_getattr_entry, 0,
- functions[NETDATA_KEY_BTF_SYNC_ATTR]);
- // exit
- bpf_program__set_attach_target(obj->progs.netdata_fs_file_read_exit, 0,
- functions[NETDATA_KEY_BTF_READ]);
- bpf_program__set_attach_target(obj->progs.netdata_fs_file_write_exit, 0,
- functions[NETDATA_KEY_BTF_WRITE]);
- bpf_program__set_attach_target(obj->progs.netdata_fs_file_open_exit, 0,
- functions[NETDATA_KEY_BTF_OPEN]);
- bpf_program__set_attach_target(obj->progs.netdata_fs_getattr_exit, 0,
- functions[NETDATA_KEY_BTF_SYNC_ATTR]);
- if (functions[NETDATA_KEY_BTF_OPEN2]) {
- bpf_program__set_attach_target(obj->progs.netdata_fs_2nd_file_open_entry, 0,
- functions[NETDATA_KEY_BTF_OPEN2]);
- bpf_program__set_attach_target(obj->progs.netdata_fs_2nd_file_open_exit, 0,
- functions[NETDATA_KEY_BTF_OPEN2]);
- } else {
- bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_entry, false);
- bpf_program__set_autoload(obj->progs.netdata_fs_2nd_file_open_exit, false);
- }
- }
- /**
- * Attach Kprobe
- *
- * Attach kprobe on targets
- *
- * @param obj FS object loaded.
- * @param functions array with function names.
- */
- static int ebpf_fs_attach_kprobe(struct filesystem_bpf *obj, const char **functions)
- {
- // kprobe
- obj->links.netdata_fs_file_read_probe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_read_probe,
- false, functions[NETDATA_KEY_BTF_READ]);
- if (libbpf_get_error(obj->links.netdata_fs_file_read_probe))
- return -1;
- obj->links.netdata_fs_file_write_probe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_write_probe,
- false, functions[NETDATA_KEY_BTF_WRITE]);
- if (libbpf_get_error(obj->links.netdata_fs_file_write_probe))
- return -1;
- obj->links.netdata_fs_file_open_probe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_open_probe,
- false, functions[NETDATA_KEY_BTF_OPEN]);
- if (libbpf_get_error(obj->links.netdata_fs_file_open_probe))
- return -1;
- obj->links.netdata_fs_getattr_probe = bpf_program__attach_kprobe(obj->progs.netdata_fs_getattr_probe,
- false, functions[NETDATA_KEY_BTF_SYNC_ATTR]);
- if (libbpf_get_error(obj->links.netdata_fs_getattr_probe))
- return -1;
- // kretprobe
- obj->links.netdata_fs_file_read_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_read_retprobe,
- false, functions[NETDATA_KEY_BTF_READ]);
- if (libbpf_get_error(obj->links.netdata_fs_file_read_retprobe))
- return -1;
- obj->links.netdata_fs_file_write_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_write_retprobe,
- false, functions[NETDATA_KEY_BTF_WRITE]);
- if (libbpf_get_error(obj->links.netdata_fs_file_write_retprobe))
- return -1;
- obj->links.netdata_fs_file_open_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_fs_file_open_retprobe,
- false, functions[NETDATA_KEY_BTF_OPEN]);
- if (libbpf_get_error(obj->links.netdata_fs_file_open_retprobe))
- return -1;
- obj->links.netdata_fs_getattr_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_fs_getattr_retprobe,
- false, functions[NETDATA_KEY_BTF_SYNC_ATTR]);
- if (libbpf_get_error(obj->links.netdata_fs_getattr_retprobe))
- return -1;
- if (functions[NETDATA_KEY_BTF_OPEN2]) {
- obj->links.netdata_fs_2nd_file_open_probe = bpf_program__attach_kprobe(obj->progs.netdata_fs_2nd_file_open_probe,
- false, functions[NETDATA_KEY_BTF_OPEN2]);
- if (libbpf_get_error(obj->links.netdata_fs_2nd_file_open_probe))
- return -1;
- obj->links.netdata_fs_2nd_file_open_retprobe = bpf_program__attach_kprobe(obj->progs.netdata_fs_2nd_file_open_retprobe,
- false, functions[NETDATA_KEY_BTF_OPEN2]);
- if (libbpf_get_error(obj->links.netdata_fs_2nd_file_open_retprobe))
- return -1;
- }
- return 0;
- }
- /**
- * Load and Attach
- *
- * Load binary and attach to targets.
- *
- * @param map Structure with information about maps.
- * @param obj FS object loaded.
- * @param functions array with function names.
- * @param bf sttruct with btf file loaded.
- */
- static inline int ebpf_fs_load_and_attach(ebpf_local_maps_t *map, struct filesystem_bpf *obj,
- const char **functions, struct btf *bf)
- {
- if (bf) {
- ebpf_fs_disable_kprobe(obj);
- ebpf_fs_set_target(obj, functions);
- } else {
- ebpf_fs_disable_trampoline(obj);
- }
- int ret = filesystem_bpf__load(obj);
- if (ret) {
- fprintf(stderr, "failed to load BPF object: %d\n", ret);
- return -1;
- }
- if (bf)
- ret = filesystem_bpf__attach(obj);
- else
- ret = ebpf_fs_attach_kprobe(obj, functions);
- if (!ret)
- map->map_fd = bpf_map__fd(obj->maps.tbl_fs);;
- return ret;
- }
- #endif
- /*****************************************************************
- *
- * COMMON FUNCTIONS
- *
- *****************************************************************/
- /**
- * Create Filesystem chart
- *
- * Create latency charts
- *
- * @param update_every value to overwrite the update frequency set by the server.
- */
- static void ebpf_obsolete_fs_charts(int update_every)
- {
- int i;
- uint32_t test = NETDATA_FILESYSTEM_FLAG_CHART_CREATED | NETDATA_FILESYSTEM_REMOVE_CHARTS;
- for (i = 0; localfs[i].filesystem; i++) {
- ebpf_filesystem_partitions_t *efp = &localfs[i];
- uint32_t flags = efp->flags;
- if ((flags & test) == test) {
- flags &= ~NETDATA_FILESYSTEM_FLAG_CHART_CREATED;
- ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hread.name,
- efp->hread.title,
- EBPF_COMMON_DIMENSION_CALL, efp->family_name,
- NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hread.order, update_every);
- ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hwrite.name,
- efp->hwrite.title,
- EBPF_COMMON_DIMENSION_CALL, efp->family_name,
- NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hwrite.order, update_every);
- ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hopen.name, efp->hopen.title,
- EBPF_COMMON_DIMENSION_CALL, efp->family_name,
- NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hopen.order, update_every);
- ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hadditional.name, efp->hadditional.title,
- EBPF_COMMON_DIMENSION_CALL, efp->family_name,
- NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hadditional.order,
- update_every);
- }
- efp->flags = flags;
- }
- }
- /**
- * Create Filesystem chart
- *
- * Create latency charts
- *
- * @param update_every value to overwrite the update frequency set by the server.
- */
- static void ebpf_create_fs_charts(int update_every)
- {
- static int order = NETDATA_CHART_PRIO_EBPF_FILESYSTEM_CHARTS;
- char chart_name[64], title[256], family[64], ctx[64];
- int i;
- uint32_t test = NETDATA_FILESYSTEM_FLAG_CHART_CREATED|NETDATA_FILESYSTEM_REMOVE_CHARTS;
- for (i = 0; localfs[i].filesystem; i++) {
- ebpf_filesystem_partitions_t *efp = &localfs[i];
- uint32_t flags = efp->flags;
- if (flags & NETDATA_FILESYSTEM_FLAG_HAS_PARTITION && !(flags & test)) {
- snprintfz(title, 255, "%s latency for each read request.", efp->filesystem);
- snprintfz(family, 63, "%s_latency", efp->family);
- snprintfz(chart_name, 63, "%s_read_latency", efp->filesystem);
- efp->hread.name = strdupz(chart_name);
- efp->hread.title = strdupz(title);
- efp->hread.ctx = NULL;
- efp->hread.order = order;
- efp->family_name = strdupz(family);
- ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hread.name,
- efp->hread.title,
- EBPF_COMMON_DIMENSION_CALL, efp->family_name,
- "filesystem.read_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order,
- ebpf_create_global_dimension,
- filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
- update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
- order++;
- snprintfz(title, 255, "%s latency for each write request.", efp->filesystem);
- snprintfz(chart_name, 63, "%s_write_latency", efp->filesystem);
- efp->hwrite.name = strdupz(chart_name);
- efp->hwrite.title = strdupz(title);
- efp->hwrite.ctx = NULL;
- efp->hwrite.order = order;
- ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hwrite.name,
- efp->hwrite.title,
- EBPF_COMMON_DIMENSION_CALL, efp->family_name,
- "filesystem.write_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order,
- ebpf_create_global_dimension,
- filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
- update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
- order++;
- snprintfz(title, 255, "%s latency for each open request.", efp->filesystem);
- snprintfz(chart_name, 63, "%s_open_latency", efp->filesystem);
- efp->hopen.name = strdupz(chart_name);
- efp->hopen.title = strdupz(title);
- efp->hopen.ctx = NULL;
- efp->hopen.order = order;
- ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hopen.name,
- efp->hopen.title,
- EBPF_COMMON_DIMENSION_CALL, efp->family_name,
- "filesystem.open_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order,
- ebpf_create_global_dimension,
- filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
- update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
- order++;
- char *type = (efp->flags & NETDATA_FILESYSTEM_ATTR_CHARTS) ? "attribute" : "sync";
- snprintfz(title, 255, "%s latency for each %s request.", efp->filesystem, type);
- snprintfz(chart_name, 63, "%s_%s_latency", efp->filesystem, type);
- snprintfz(ctx, 63, "filesystem.%s_latency", type);
- efp->hadditional.name = strdupz(chart_name);
- efp->hadditional.title = strdupz(title);
- efp->hadditional.ctx = strdupz(ctx);
- efp->hadditional.order = order;
- ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hadditional.name, efp->hadditional.title,
- EBPF_COMMON_DIMENSION_CALL, efp->family_name,
- ctx, NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
- filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
- update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
- order++;
- efp->flags |= NETDATA_FILESYSTEM_FLAG_CHART_CREATED;
- }
- }
- fflush(stdout);
- }
- /**
- * Initialize eBPF data
- *
- * @param em main thread structure.
- *
- * @return it returns 0 on success and -1 otherwise.
- */
- int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
- {
- pthread_mutex_lock(&lock);
- int i;
- const char *saved_name = em->info.thread_name;
- uint64_t kernels = em->kernels;
- for (i = 0; localfs[i].filesystem; i++) {
- ebpf_filesystem_partitions_t *efp = &localfs[i];
- if (!efp->probe_links && efp->flags & NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM) {
- em->info.thread_name = efp->filesystem;
- em->kernels = efp->kernels;
- em->maps = efp->fs_maps;
- #ifdef LIBBPF_MAJOR_VERSION
- ebpf_define_map_type(em->maps, em->maps_per_core, running_on_kernel);
- #endif
- if (em->load & EBPF_LOAD_LEGACY) {
- efp->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &efp->objects);
- if (!efp->probe_links) {
- em->info.thread_name = saved_name;
- em->kernels = kernels;
- em->maps = NULL;
- pthread_mutex_unlock(&lock);
- return -1;
- }
- }
- #ifdef LIBBPF_MAJOR_VERSION
- else {
- efp->fs_obj = filesystem_bpf__open();
- if (!efp->fs_obj) {
- em->info.thread_name = saved_name;
- em->kernels = kernels;
- return -1;
- } else {
- if (ebpf_fs_load_and_attach(em->maps, efp->fs_obj,
- efp->functions, NULL))
- return -1;
- }
- }
- #endif
- efp->flags |= NETDATA_FILESYSTEM_FLAG_HAS_PARTITION;
- ebpf_update_kernel_memory(&plugin_statistics, efp->fs_maps, EBPF_ACTION_STAT_ADD);
- // Nedeed for filesystems like btrfs
- if ((efp->flags & NETDATA_FILESYSTEM_FILL_ADDRESS_TABLE) && (efp->addresses.function)) {
- ebpf_load_addresses(&efp->addresses, efp->fs_maps[NETDATA_ADDR_FS_TABLE].map_fd);
- }
- }
- efp->flags &= ~NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM;
- }
- em->info.thread_name = saved_name;
- pthread_mutex_unlock(&lock);
- em->kernels = kernels;
- em->maps = NULL;
- if (!dimensions) {
- dimensions = ebpf_fill_histogram_dimension(NETDATA_EBPF_HIST_MAX_BINS);
- memset(filesystem_aggregated_data, 0 , NETDATA_EBPF_HIST_MAX_BINS * sizeof(netdata_syscall_stat_t));
- memset(filesystem_publish_aggregated, 0 , NETDATA_EBPF_HIST_MAX_BINS * sizeof(netdata_publish_syscall_t));
- filesystem_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
- }
- return 0;
- }
- /**
- * Read Local partitions
- *
- * @return the total of partitions that will be monitored
- */
- static int ebpf_read_local_partitions()
- {
- char filename[FILENAME_MAX + 1];
- snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", netdata_configured_host_prefix);
- procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
- if(unlikely(!ff)) {
- snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", netdata_configured_host_prefix);
- ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
- if(unlikely(!ff)) return 0;
- }
- ff = procfile_readall(ff);
- if(unlikely(!ff))
- return 0;
- int count = 0;
- unsigned long l, i, lines = procfile_lines(ff);
- for (i = 0; localfs[i].filesystem; i++) {
- localfs[i].flags |= NETDATA_FILESYSTEM_REMOVE_CHARTS;
- }
- for(l = 0; l < lines ; l++) {
- // In "normal" situation the expected value is at column 7
- // When `shared` options is added to mount information, the filesystem is at column 8
- // Finally when we have systemd starting netdata, it will be at column 9
- unsigned long index = procfile_linewords(ff, l) - 3;
- char *fs = procfile_lineword(ff, l, index);
- for (i = 0; localfs[i].filesystem; i++) {
- ebpf_filesystem_partitions_t *w = &localfs[i];
- if (w->enabled && (!strcmp(fs, w->filesystem) ||
- (w->optional_filesystem && !strcmp(fs, w->optional_filesystem)))) {
- localfs[i].flags |= NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM;
- localfs[i].flags &= ~NETDATA_FILESYSTEM_REMOVE_CHARTS;
- count++;
- break;
- }
- }
- }
- procfile_close(ff);
- return count;
- }
- /**
- * Update partition
- *
- * Update the partition structures before to plot
- *
- * @param em main thread structure
- *
- * @return 0 on success and -1 otherwise.
- */
- static int ebpf_update_partitions(ebpf_module_t *em)
- {
- static time_t update_every = 0;
- time_t curr = now_realtime_sec();
- if (curr < update_every)
- return 0;
- update_every = curr + 5 * em->update_every;
- if (!ebpf_read_local_partitions()) {
- em->optional = -1;
- return -1;
- }
- if (ebpf_filesystem_initialize_ebpf_data(em)) {
- return -1;
- }
- return 0;
- }
- /*****************************************************************
- *
- * CLEANUP FUNCTIONS
- *
- *****************************************************************/
- /*
- * Cleanup eBPF data
- */
- void ebpf_filesystem_cleanup_ebpf_data()
- {
- int i;
- for (i = 0; localfs[i].filesystem; i++) {
- ebpf_filesystem_partitions_t *efp = &localfs[i];
- if (efp->probe_links) {
- freez(efp->family_name);
- efp->family_name = NULL;
- freez(efp->hread.name);
- efp->hread.name = NULL;
- freez(efp->hread.title);
- efp->hread.title = NULL;
- freez(efp->hwrite.name);
- efp->hwrite.name = NULL;
- freez(efp->hwrite.title);
- efp->hwrite.title = NULL;
- freez(efp->hopen.name);
- efp->hopen.name = NULL;
- freez(efp->hopen.title);
- efp->hopen.title = NULL;
- freez(efp->hadditional.name);
- efp->hadditional.name = NULL;
- freez(efp->hadditional.title);
- efp->hadditional.title = NULL;
- freez(efp->hadditional.ctx);
- efp->hadditional.ctx = NULL;
- }
- }
- }
- /**
- * Obsolete global
- *
- * Obsolete global charts created by thread.
- *
- * @param em a pointer to `struct ebpf_module`
- */
- static void ebpf_obsolete_filesystem_global(ebpf_module_t *em)
- {
- int i;
- for (i = 0; localfs[i].filesystem; i++) {
- ebpf_filesystem_partitions_t *efp = &localfs[i];
- if (!efp->objects)
- continue;
- ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
- efp->hread.name,
- efp->hread.title,
- EBPF_COMMON_DIMENSION_CALL,
- efp->family_name,
- NETDATA_EBPF_CHART_TYPE_STACKED,
- "filesystem.read_latency",
- efp->hread.order,
- em->update_every);
- ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
- efp->hwrite.name,
- efp->hwrite.title,
- EBPF_COMMON_DIMENSION_CALL,
- efp->family_name,
- NETDATA_EBPF_CHART_TYPE_STACKED,
- "filesystem.write_latency",
- efp->hwrite.order,
- em->update_every);
- ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
- efp->hopen.name,
- efp->hopen.title,
- EBPF_COMMON_DIMENSION_CALL,
- efp->family_name,
- NETDATA_EBPF_CHART_TYPE_STACKED,
- "filesystem.open_latency",
- efp->hopen.order,
- em->update_every);
- ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY,
- efp->hadditional.name,
- efp->hadditional.title,
- EBPF_COMMON_DIMENSION_CALL,
- efp->family_name,
- NETDATA_EBPF_CHART_TYPE_STACKED,
- efp->hadditional.ctx,
- efp->hadditional.order,
- em->update_every);
- }
- }
- /**
- * Filesystem exit
- *
- * Cancel child thread.
- *
- * @param ptr thread data.
- */
- static void ebpf_filesystem_exit(void *ptr)
- {
- ebpf_module_t *em = (ebpf_module_t *)ptr;
- if (em->enabled == NETDATA_THREAD_EBPF_FUNCTION_RUNNING) {
- pthread_mutex_lock(&lock);
- ebpf_obsolete_filesystem_global(em);
- pthread_mutex_unlock(&lock);
- fflush(stdout);
- }
- ebpf_filesystem_cleanup_ebpf_data();
- if (dimensions) {
- ebpf_histogram_dimension_cleanup(dimensions, NETDATA_EBPF_HIST_MAX_BINS);
- dimensions = NULL;
- }
- freez(filesystem_hash_values);
- int i;
- for (i = 0; localfs[i].filesystem; i++) {
- ebpf_filesystem_partitions_t *efp = &localfs[i];
- if (!efp->probe_links)
- continue;
- ebpf_unload_legacy_code(efp->objects, efp->probe_links);
- efp->objects = NULL;
- efp->probe_links = NULL;
- efp->flags = NETDATA_FILESYSTEM_FLAG_NO_PARTITION;
- }
- pthread_mutex_lock(&ebpf_exit_cleanup);
- em->enabled = NETDATA_THREAD_EBPF_STOPPED;
- ebpf_update_stats(&plugin_statistics, em);
- pthread_mutex_unlock(&ebpf_exit_cleanup);
- }
- /*****************************************************************
- *
- * MAIN THREAD
- *
- *****************************************************************/
- /**
- * Select hist
- *
- * Select a histogram to store data.
- *
- * @param efp pointer for the structure with pointers.
- * @param id histogram selector
- *
- * @return It returns a pointer for the histogram
- */
- static inline netdata_ebpf_histogram_t *select_hist(ebpf_filesystem_partitions_t *efp, uint32_t *idx, uint32_t id)
- {
- if (id < NETDATA_KEY_CALLS_READ) {
- *idx = id;
- return &efp->hread;
- } else if (id < NETDATA_KEY_CALLS_WRITE) {
- *idx = id - NETDATA_KEY_CALLS_READ;
- return &efp->hwrite;
- } else if (id < NETDATA_KEY_CALLS_OPEN) {
- *idx = id - NETDATA_KEY_CALLS_WRITE;
- return &efp->hopen;
- } else if (id < NETDATA_KEY_CALLS_SYNC ){
- *idx = id - NETDATA_KEY_CALLS_OPEN;
- return &efp->hadditional;
- }
- return NULL;
- }
- /**
- * Read hard disk table
- *
- * @param efp structure with filesystem monitored
- * @param fd file descriptor to get data.
- * @param maps_per_core do I need to read all cores?
- *
- * Read the table with number of calls for all functions
- */
- static void read_filesystem_table(ebpf_filesystem_partitions_t *efp, int fd, int maps_per_core)
- {
- netdata_idx_t *values = filesystem_hash_values;
- uint32_t key;
- uint32_t idx;
- for (key = 0; key < NETDATA_KEY_CALLS_SYNC; key++) {
- netdata_ebpf_histogram_t *w = select_hist(efp, &idx, key);
- if (!w) {
- continue;
- }
- int test = bpf_map_lookup_elem(fd, &key, values);
- if (test < 0) {
- continue;
- }
- uint64_t total = 0;
- int i;
- int end = (maps_per_core) ? ebpf_nprocs : 1;
- for (i = 0; i < end; i++) {
- total += values[i];
- }
- if (idx >= NETDATA_EBPF_HIST_MAX_BINS)
- idx = NETDATA_EBPF_HIST_MAX_BINS - 1;
- w->histogram[idx] = total;
- }
- }
- /**
- * Read hard disk table
- *
- * Read the table with number of calls for all functions
- *
- * @param maps_per_core do I need to read all cores?
- */
- static void read_filesystem_tables(int maps_per_core)
- {
- int i;
- for (i = 0; localfs[i].filesystem; i++) {
- ebpf_filesystem_partitions_t *efp = &localfs[i];
- if (efp->flags & NETDATA_FILESYSTEM_FLAG_HAS_PARTITION) {
- read_filesystem_table(efp, efp->fs_maps[NETDATA_MAIN_FS_TABLE].map_fd, maps_per_core);
- }
- }
- }
- /**
- * Socket read hash
- *
- * This is the thread callback.
- * This thread is necessary, because we cannot freeze the whole plugin to read the data on very busy socket.
- *
- * @param ptr It is a NULL value for this thread.
- *
- * @return It always returns NULL.
- */
- void ebpf_filesystem_read_hash(ebpf_module_t *em)
- {
- ebpf_obsolete_fs_charts(em->update_every);
- (void) ebpf_update_partitions(em);
- if (em->optional)
- return;
- read_filesystem_tables(em->maps_per_core);
- }
- /**
- * Send Hard disk data
- *
- * Send hard disk information to Netdata.
- */
- static void ebpf_histogram_send_data()
- {
- uint32_t i;
- uint32_t test = NETDATA_FILESYSTEM_FLAG_HAS_PARTITION | NETDATA_FILESYSTEM_REMOVE_CHARTS;
- for (i = 0; localfs[i].filesystem; i++) {
- ebpf_filesystem_partitions_t *efp = &localfs[i];
- if ((efp->flags & test) == NETDATA_FILESYSTEM_FLAG_HAS_PARTITION) {
- write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hread.name,
- efp->hread.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
- write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hwrite.name,
- efp->hwrite.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
- write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hopen.name,
- efp->hopen.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
- write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hadditional.name,
- efp->hadditional.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
- }
- }
- }
- /**
- * Main loop for this collector.
- *
- * @param em main structure for this thread
- */
- static void filesystem_collector(ebpf_module_t *em)
- {
- int update_every = em->update_every;
- heartbeat_t hb;
- heartbeat_init(&hb);
- int counter = update_every - 1;
- uint32_t running_time = 0;
- uint32_t lifetime = em->lifetime;
- while (!ebpf_plugin_exit && running_time < lifetime) {
- (void)heartbeat_next(&hb, USEC_PER_SEC);
- if (ebpf_plugin_exit || ++counter != update_every)
- continue;
- counter = 0;
- ebpf_filesystem_read_hash(em);
- pthread_mutex_lock(&lock);
- ebpf_create_fs_charts(update_every);
- ebpf_histogram_send_data();
- pthread_mutex_unlock(&lock);
- pthread_mutex_lock(&ebpf_exit_cleanup);
- if (running_time && !em->running_time)
- running_time = update_every;
- else
- running_time += update_every;
- em->running_time = running_time;
- pthread_mutex_unlock(&ebpf_exit_cleanup);
- }
- }
- /*****************************************************************
- *
- * ENTRY THREAD
- *
- *****************************************************************/
- /**
- * Update Filesystem
- *
- * Update file system structure using values read from configuration file.
- */
- static void ebpf_update_filesystem()
- {
- char dist[NETDATA_FS_MAX_DIST_NAME + 1];
- int i;
- for (i = 0; localfs[i].filesystem; i++) {
- snprintfz(dist, NETDATA_FS_MAX_DIST_NAME, "%sdist", localfs[i].filesystem);
- localfs[i].enabled = appconfig_get_boolean(&fs_config, NETDATA_FILESYSTEM_CONFIG_NAME, dist,
- CONFIG_BOOLEAN_YES);
- }
- }
- /**
- * Set maps
- *
- * When thread is initialized the variable fs_maps is set as null,
- * this function fills the variable before to use.
- */
- static void ebpf_set_maps()
- {
- localfs[NETDATA_FS_LOCALFS_EXT4].fs_maps = ext4_maps;
- localfs[NETDATA_FS_LOCALFS_XFS].fs_maps = xfs_maps;
- localfs[NETDATA_FS_LOCALFS_NFS].fs_maps = nfs_maps;
- localfs[NETDATA_FS_LOCALFS_ZFS].fs_maps = zfs_maps;
- localfs[NETDATA_FS_LOCALFS_BTRFS].fs_maps = btrfs_maps;
- }
- /**
- * Filesystem thread
- *
- * Thread used to generate socket charts.
- *
- * @param ptr a pointer to `struct ebpf_module`
- *
- * @return It always return NULL
- */
- void *ebpf_filesystem_thread(void *ptr)
- {
- netdata_thread_cleanup_push(ebpf_filesystem_exit, ptr);
- ebpf_module_t *em = (ebpf_module_t *)ptr;
- ebpf_set_maps();
- ebpf_update_filesystem();
- // Initialize optional as zero, to identify when there are not partitions to monitor
- em->optional = 0;
- #ifdef LIBBPF_MAJOR_VERSION
- ebpf_adjust_thread_load(em, default_btf);
- #endif
- if (ebpf_update_partitions(em)) {
- if (em->optional)
- netdata_log_info("Netdata cannot monitor the filesystems used on this host.");
- goto endfilesystem;
- }
- int algorithms[NETDATA_EBPF_HIST_MAX_BINS];
- ebpf_fill_algorithms(algorithms, NETDATA_EBPF_HIST_MAX_BINS, NETDATA_EBPF_INCREMENTAL_IDX);
- ebpf_global_labels(filesystem_aggregated_data, filesystem_publish_aggregated, dimensions, dimensions,
- algorithms, NETDATA_EBPF_HIST_MAX_BINS);
- pthread_mutex_lock(&lock);
- ebpf_create_fs_charts(em->update_every);
- ebpf_update_stats(&plugin_statistics, em);
- pthread_mutex_unlock(&lock);
- filesystem_collector(em);
- endfilesystem:
- ebpf_update_disabled_plugin_stats(em);
- netdata_thread_cleanup_pop(1);
- return NULL;
- }
|