summaryrefslogtreecommitdiffstats
path: root/collectors/ebpf.plugin/ebpf_filesystem.c
diff options
context:
space:
mode:
Diffstat (limited to 'collectors/ebpf.plugin/ebpf_filesystem.c')
-rw-r--r--collectors/ebpf.plugin/ebpf_filesystem.c387
1 files changed, 350 insertions, 37 deletions
diff --git a/collectors/ebpf.plugin/ebpf_filesystem.c b/collectors/ebpf.plugin/ebpf_filesystem.c
index 63f592eb9..2bff738ca 100644
--- a/collectors/ebpf.plugin/ebpf_filesystem.c
+++ b/collectors/ebpf.plugin/ebpf_filesystem.c
@@ -131,6 +131,202 @@ static netdata_publish_syscall_t filesystem_publish_aggregated[NETDATA_EBPF_HIST
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
@@ -199,13 +395,15 @@ static void ebpf_create_fs_charts(int update_every)
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,
- title,
- EBPF_COMMON_DIMENSION_CALL, family,
- "filesystem.read_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
+ 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++;
@@ -214,11 +412,13 @@ static void ebpf_create_fs_charts(int update_every)
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,
- title,
- EBPF_COMMON_DIMENSION_CALL, family,
- "filesystem.write_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
+ 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++;
@@ -227,11 +427,13 @@ static void ebpf_create_fs_charts(int update_every)
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,
- title,
- EBPF_COMMON_DIMENSION_CALL, family,
- "filesystem.open_latency", NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
+ 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++;
@@ -242,9 +444,10 @@ static void ebpf_create_fs_charts(int update_every)
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, title,
- EBPF_COMMON_DIMENSION_CALL, family,
+ 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);
@@ -252,6 +455,8 @@ static void ebpf_create_fs_charts(int update_every)
efp->flags |= NETDATA_FILESYSTEM_FLAG_CHART_CREATED;
}
}
+
+ fflush(stdout);
}
/**
@@ -263,6 +468,7 @@ static void ebpf_create_fs_charts(int update_every)
*/
int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
{
+ pthread_mutex_lock(&lock);
int i;
const char *saved_name = em->thread_name;
uint64_t kernels = em->kernels;
@@ -275,17 +481,32 @@ int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
#ifdef LIBBPF_MAJOR_VERSION
ebpf_define_map_type(em->maps, em->maps_per_core, running_on_kernel);
#endif
- efp->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &efp->objects);
- if (!efp->probe_links) {
- em->thread_name = saved_name;
- em->kernels = kernels;
- em->maps = NULL;
- return -1;
+ 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->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->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;
- pthread_mutex_lock(&lock);
ebpf_update_kernel_memory(&plugin_statistics, efp->fs_maps, EBPF_ACTION_STAT_ADD);
- pthread_mutex_unlock(&lock);
// Nedeed for filesystems like btrfs
if ((efp->flags & NETDATA_FILESYSTEM_FILL_ADDRESS_TABLE) && (efp->addresses.function)) {
@@ -295,6 +516,7 @@ int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
efp->flags &= ~NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM;
}
em->thread_name = saved_name;
+ pthread_mutex_unlock(&lock);
em->kernels = kernels;
em->maps = NULL;
@@ -405,43 +627,88 @@ void ebpf_filesystem_cleanup_ebpf_data()
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;
}
}
}
/**
- * Filesystem Free
+ * Obsolete global
*
- * Cleanup variables after child threads to stop
+ * Obsolete global charts created by thread.
*
- * @param ptr thread data.
+ * @param em a pointer to `struct ebpf_module`
*/
-static void ebpf_filesystem_free(ebpf_module_t *em)
+static void ebpf_obsolete_filesystem_global(ebpf_module_t *em)
{
- pthread_mutex_lock(&ebpf_exit_cleanup);
- em->enabled = NETDATA_THREAD_EBPF_STOPPING;
- pthread_mutex_unlock(&ebpf_exit_cleanup);
-
- ebpf_filesystem_cleanup_ebpf_data();
- if (dimensions)
- ebpf_histogram_dimension_cleanup(dimensions, NETDATA_EBPF_HIST_MAX_BINS);
- freez(filesystem_hash_values);
+ int i;
+ for (i = 0; localfs[i].filesystem; i++) {
+ ebpf_filesystem_partitions_t *efp = &localfs[i];
+ if (!efp->objects)
+ continue;
- pthread_mutex_lock(&ebpf_exit_cleanup);
- em->enabled = NETDATA_THREAD_EBPF_STOPPED;
- pthread_mutex_unlock(&ebpf_exit_cleanup);
+ 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);
+ }
}
/**
@@ -454,7 +721,39 @@ static void ebpf_filesystem_free(ebpf_module_t *em)
static void ebpf_filesystem_exit(void *ptr)
{
ebpf_module_t *em = (ebpf_module_t *)ptr;
- ebpf_filesystem_free(em);
+
+ 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);
}
/*****************************************************************
@@ -608,7 +907,9 @@ static void filesystem_collector(ebpf_module_t *em)
heartbeat_t hb;
heartbeat_init(&hb);
int counter = update_every - 1;
- while (!ebpf_exit_plugin) {
+ uint32_t running_time = 0;
+ uint32_t lifetime = em->lifetime;
+ while (!ebpf_exit_plugin && running_time < lifetime) {
(void)heartbeat_next(&hb, USEC_PER_SEC);
if (ebpf_exit_plugin || ++counter != update_every)
@@ -622,6 +923,15 @@ static void filesystem_collector(ebpf_module_t *em)
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);
}
}
@@ -683,9 +993,12 @@ void *ebpf_filesystem_thread(void *ptr)
// 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)
- info("Netdata cannot monitor the filesystems used on this host.");
+ netdata_log_info("Netdata cannot monitor the filesystems used on this host.");
goto endfilesystem;
}