eBPF mdflush (#11681)
* mdflush: initial agent-side collector. * mdflush: fix x-axis name. * mdflush: fix issue where we iteration doesnt occur. * mdflush: update flush prio to match health. health seems to be global just as flush is, so keep them together. * mdflush: vsn bump. * mdflush: add reference to bcc tool. * mdflush: add more docs. * mdflush: change family name to indicate ebpf. * mdflush: remove "count" word in chart. * mdflush: change mdstat prios so flush comes after health.
Uman Shahzad committed
Oct 23, 2021 at 21:16 UTC
2cbced292aa58c8b76a286add3bbbcbe273b333f
15 files changed
+424
-10
CMakeLists.txt
+2
@@ -496,6 +496,8 @@ set(EBPF_PROCESS_PLUGIN_FILES
496
collectors/ebpf.plugin/ebpf_fd.h
497
collectors/ebpf.plugin/ebpf_hardirq.c
498
collectors/ebpf.plugin/ebpf_hardirq.h
499
+ collectors/ebpf.plugin/ebpf_mdflush.c
500
+ collectors/ebpf.plugin/ebpf_mdflush.h
501
collectors/ebpf.plugin/ebpf_mount.c
502
collectors/ebpf.plugin/ebpf_mount.h
503
collectors/ebpf.plugin/ebpf_filesystem.c
Makefile.am
+2
@@ -302,6 +302,8 @@ EBPF_PLUGIN_FILES = \
302
collectors/ebpf.plugin/ebpf_filesystem.h \
303
collectors/ebpf.plugin/ebpf_hardirq.c \
304
collectors/ebpf.plugin/ebpf_hardirq.h \
305
+ collectors/ebpf.plugin/ebpf_mdflush.c \
306
+ collectors/ebpf.plugin/ebpf_mdflush.h \
307
collectors/ebpf.plugin/ebpf_mount.c \
308
collectors/ebpf.plugin/ebpf_mount.h \
309
collectors/ebpf.plugin/ebpf_oomkill.c \
collectors/all.h
+7
-6
@@ -133,12 +133,13 @@
133
// MDSTAT
134
135
#define NETDATA_CHART_PRIO_MDSTAT_HEALTH 2100
136
-#define NETDATA_CHART_PRIO_MDSTAT_NONREDUNDANT 2101
137
-#define NETDATA_CHART_PRIO_MDSTAT_DISKS 2102 // 5 charts per raid
138
-#define NETDATA_CHART_PRIO_MDSTAT_MISMATCH 2103
139
-#define NETDATA_CHART_PRIO_MDSTAT_OPERATION 2104
140
-#define NETDATA_CHART_PRIO_MDSTAT_FINISH 2105
141
-#define NETDATA_CHART_PRIO_MDSTAT_SPEED 2106
136
+#define NETDATA_CHART_PRIO_MDSTAT_FLUSH 2101
137
+#define NETDATA_CHART_PRIO_MDSTAT_NONREDUNDANT 2105
138
+#define NETDATA_CHART_PRIO_MDSTAT_DISKS 2106 // 5 charts per raid
139
+#define NETDATA_CHART_PRIO_MDSTAT_MISMATCH 2107
140
+#define NETDATA_CHART_PRIO_MDSTAT_OPERATION 2108
141
+#define NETDATA_CHART_PRIO_MDSTAT_FINISH 2109
142
+#define NETDATA_CHART_PRIO_MDSTAT_SPEED 2110
143
144
// Filesystem
145
#define NETDATA_CHART_PRIO_FILESYSTEM_VFS_CLEAN 2150
collectors/ebpf.plugin/Makefile.am
+1
@@ -29,6 +29,7 @@ dist_ebpfconfig_DATA = \
29
ebpf.d/fd.conf \
30
ebpf.d/filesystem.conf \
31
ebpf.d/hardirq.conf \
32
+ ebpf.d/mdflush.conf \
33
ebpf.d/mount.conf \
34
ebpf.d/network.conf \
35
ebpf.d/oomkill.conf \
collectors/ebpf.plugin/README.md
+16
@@ -116,6 +116,20 @@ This chart monitors calls demonstrating commits from filesystem caches to disk.
116
This chart shows calls to `sync_file_range(2)` which synchronizes file segments with disk. This is the most dangerous
117
syscall to synchronize data according to its manual.
118
119
+### MD flush
120
+
121
+The eBPF plugin shows multi-device flushes happening in real time. This can be
122
+used to explain some spikes happening in
123
+[disk latency](docs/agent/collectors/ebpf.plugin#disk) charts.
124
+
125
+By default, MD flush is disabled. To enable it, configure your
126
+`/etc/netdata/ebpf.d.conf` file as:
127
+
128
+```conf
129
+[global]
130
+ mdflush = yes
131
+```
132
+
133
### Disk
134
135
The eBPF plugin also shows a chart in the Disk section when the `disk` thread is enabled. This will create the
@@ -399,6 +413,8 @@ You can also enable the following eBPF programs:
413
- `disk` : This eBPF program creates charts that show information about disk latency independent of filesystem.
414
- `filesystem` : This eBPF program creates charts that show information about some filesystem latency.
415
- `swap` : This eBPF program creates charts that show information about swap access.
416
+- `mdflush`: This eBPF program creates charts that show information about
417
+ multi-device software flushes.
418
419
## Thread configuration
420
collectors/ebpf.plugin/ebpf.c
+24
@@ -158,6 +158,11 @@ ebpf_module_t ebpf_modules[] = {
158
.apps_routine = ebpf_shm_create_apps_charts, .maps = NULL,
159
.pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &shm_config,
160
.config_file = NETDATA_DIRECTORY_SHM_CONFIG_FILE},
161
+ { .thread_name = "mdflush", .config_name = "mdflush", .enabled = 0, .start_routine = ebpf_mdflush_thread,
162
+ .update_every = EBPF_DEFAULT_UPDATE_EVERY, .global_charts = 1, .apps_charts = CONFIG_BOOLEAN_NO,
163
+ .cgroup_charts = CONFIG_BOOLEAN_NO, .mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL,
164
+ .pid_map_size = ND_EBPF_DEFAULT_PID_SIZE, .names = NULL, .cfg = &mdflush_config,
165
+ .config_file = NETDATA_DIRECTORY_MDFLUSH_CONFIG_FILE},
166
{ .thread_name = NULL, .enabled = 0, .start_routine = NULL, .update_every = EBPF_DEFAULT_UPDATE_EVERY,
167
.global_charts = 0, .apps_charts = CONFIG_BOOLEAN_NO, .cgroup_charts = CONFIG_BOOLEAN_NO,
168
.mode = MODE_ENTRY, .optional = 0, .apps_routine = NULL, .maps = NULL, .pid_map_size = 0, .names = NULL,
@@ -803,6 +808,8 @@ void ebpf_print_help()
808
"\n"
809
" [-]-hardirq Enable chart related to hard IRQ latency.\n"
810
"\n"
811
+ " [-]-mdflush Enable charts related to multi-device flush.\n"
812
+ "\n"
813
" [-]-mount Enable charts related to mount monitoring.\n"
814
"\n"
815
" [-]-net Enable network viewer charts.\n"
@@ -1259,6 +1266,13 @@ static void read_collector_values(int *disable_apps, int *disable_cgroups, int u
1266
started++;
1267
}
1268
1269
+ enabled = appconfig_get_boolean(&collector_config, EBPF_PROGRAMS_SECTION, "mdflush",
1270
+ CONFIG_BOOLEAN_NO);
1271
+ if (enabled) {
1272
+ ebpf_enable_chart(EBPF_MODULE_MDFLUSH_IDX, *disable_apps, *disable_cgroups);
1273
+ started++;
1274
+ }
1275
+
1276
if (!started){
1277
ebpf_enable_all_charts(*disable_apps, *disable_cgroups);
1278
// Read network viewer section
@@ -1370,6 +1384,7 @@ static void ebpf_parse_args(int argc, char **argv)
1384
{"softirq", no_argument, 0, 0 },
1385
{"oomkill", no_argument, 0, 0 },
1386
{"shm", no_argument, 0, 0 },
1387
+ {"mdflush", no_argument, 0, 0 },
1388
/* INSERT NEW THREADS BEFORE THIS COMMENT TO KEEP COMPATIBILITY WITH enum ebpf_module_indexes */
1389
{"all", no_argument, 0, 0 },
1390
{"version", no_argument, 0, 0 },
@@ -1511,6 +1526,13 @@ static void ebpf_parse_args(int argc, char **argv)
1526
select_threads |= 1<<EBPF_MODULE_SHM_IDX;
1527
#ifdef NETDATA_INTERNAL_CHECKS
1528
info("EBPF enabling \"SHM\" chart, because it was started with the option \"[-]-shm\".");
1529
+#endif
1530
+ break;
1531
+ }
1532
+ case EBPF_MODULE_MDFLUSH_IDX: {
1533
+ select_threads |= 1<<EBPF_MODULE_MDFLUSH_IDX;
1534
+#ifdef NETDATA_INTERNAL_CHECKS
1535
+ info("EBPF enabling \"MDFLUSH\" chart, because it was started with the option \"[-]-mdflush\".");
1536
#endif
1537
break;
1538
}
@@ -1813,6 +1835,8 @@ int main(int argc, char **argv)
1835
NULL, NULL, ebpf_modules[EBPF_MODULE_OOMKILL_IDX].start_routine},
1836
{"EBPF SHM" , NULL, NULL, 1,
1837
NULL, NULL, ebpf_modules[EBPF_MODULE_SHM_IDX].start_routine},
1838
+ {"EBPF MDFLUSH" , NULL, NULL, 1,
1839
+ NULL, NULL, ebpf_modules[EBPF_MODULE_MDFLUSH_IDX].start_routine},
1840
{NULL , NULL, NULL, 0,
1841
NULL, NULL, NULL}
1842
};
collectors/ebpf.plugin/ebpf.d.conf
+2
@@ -31,6 +31,7 @@
31
# `dcstat` : Make charts for kernel functions related to directory cache.
32
# `disk` : Monitor I/O latencies for disks
33
# `fd` : This eBPF program creates charts that show information about file manipulation.
34
+# `mdflush` : Monitors flush counts for multi-devices.
35
# `mount` : Monitor calls for syscalls mount and umount
36
# `filesystem`: Monitor calls for functions used to manipulate specific filesystems
37
# `hardirq` : Monitor latency of serving hardware interrupt requests (hard IRQs).
@@ -51,6 +52,7 @@
52
fd = yes
53
filesystem = no
54
hardirq = yes
55
+ mdflush = no
56
mount = yes
57
oomkill = yes
58
process = yes
collectors/ebpf.plugin/ebpf.d/mdflush.conf
new
+7
@@ -0,0 +1,7 @@
1
+# The `ebpf load mode` option accepts the following values :
2
+# `entry` : The eBPF collector only monitors calls for the functions, and does not show charts related to errors.
3
+# `return : In the `return` mode, the eBPF collector monitors the same kernel functions as `entry`, but also creates
4
+# new charts for the return of these functions, such as errors.
5
+#[global]
6
+# ebpf load mode = entry
7
+# update every = 1
collectors/ebpf.plugin/ebpf.h
+1
@@ -90,6 +90,7 @@ enum ebpf_main_index {
90
EBPF_MODULE_SOFTIRQ_IDX,
91
EBPF_MODULE_OOMKILL_IDX,
92
EBPF_MODULE_SHM_IDX,
93
+ EBPF_MODULE_MDFLUSH_IDX,
94
/* THREADS MUST BE INCLUDED BEFORE THIS COMMENT */
95
EBPF_OPTION_ALL_CHARTS,
96
EBPF_OPTION_VERSION,
collectors/ebpf.plugin/ebpf_apps.h
+1
@@ -24,6 +24,7 @@
24
#include "ebpf_filesystem.h"
25
#include "ebpf_hardirq.h"
26
#include "ebpf_cachestat.h"
27
+#include "ebpf_mdflush.h"
28
#include "ebpf_mount.h"
29
#include "ebpf_oomkill.h"
30
#include "ebpf_shm.h"
collectors/ebpf.plugin/ebpf_mdflush.c
new
+312
@@ -0,0 +1,312 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "ebpf.h"
4
+#include "ebpf_mdflush.h"
5
+
6
+struct config mdflush_config = { .first_section = NULL,
7
+ .last_section = NULL,
8
+ .mutex = NETDATA_MUTEX_INITIALIZER,
9
+ .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
10
+ .rwlock = AVL_LOCK_INITIALIZER } };
11
+
12
+#define MDFLUSH_MAP_COUNT 0
13
+static ebpf_local_maps_t mdflush_maps[] = {
14
+ {
15
+ .name = "tbl_mdflush",
16
+ .internal_input = 1024,
17
+ .user_input = 0,
18
+ .type = NETDATA_EBPF_MAP_STATIC,
19
+ .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED
20
+ },
21
+ /* end */
22
+ {
23
+ .name = NULL,
24
+ .internal_input = 0,
25
+ .user_input = 0,
26
+ .type = NETDATA_EBPF_MAP_CONTROLLER,
27
+ .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED
28
+ }
29
+};
30
+
31
+// store for "published" data from the reader thread, which the collector
32
+// thread will write to netdata agent.
33
+static avl_tree_lock mdflush_pub;
34
+
35
+// tmp store for mdflush values we get from a per-CPU eBPF map.
36
+static mdflush_ebpf_val_t *mdflush_ebpf_vals = NULL;
37
+
38
+static struct bpf_link **probe_links = NULL;
39
+static struct bpf_object *objects = NULL;
40
+
41
+static int read_thread_closed = 1;
42
+
43
+static struct netdata_static_thread mdflush_threads = {"MDFLUSH KERNEL",
44
+ NULL, NULL, 1, NULL,
45
+ NULL, NULL };
46
+
47
+/**
48
+ * Clean up the main thread.
49
+ *
50
+ * @param ptr thread data.
51
+ */
52
+static void mdflush_cleanup(void *ptr)
53
+{
54
+ ebpf_module_t *em = (ebpf_module_t *)ptr;
55
+ if (!em->enabled) {
56
+ return;
57
+ }
58
+
59
+ heartbeat_t hb;
60
+ heartbeat_init(&hb);
61
+ uint32_t tick = 1 * USEC_PER_MS;
62
+ while (!read_thread_closed) {
63
+ usec_t dt = heartbeat_next(&hb, tick);
64
+ UNUSED(dt);
65
+ }
66
+
67
+ freez(mdflush_ebpf_vals);
68
+ freez(mdflush_threads.thread);
69
+
70
+ if (probe_links) {
71
+ struct bpf_program *prog;
72
+ size_t i = 0 ;
73
+ bpf_object__for_each_program(prog, objects) {
74
+ bpf_link__destroy(probe_links[i]);
75
+ i++;
76
+ }
77
+ bpf_object__close(objects);
78
+ }
79
+}
80
+
81
+/**
82
+ * Compare mdflush values.
83
+ *
84
+ * @param a `netdata_mdflush_t *`.
85
+ * @param b `netdata_mdflush_t *`.
86
+ *
87
+ * @return 0 if a==b, 1 if a>b, -1 if a<b.
88
+*/
89
+static int mdflush_val_cmp(void *a, void *b)
90
+{
91
+ netdata_mdflush_t *ptr1 = a;
92
+ netdata_mdflush_t *ptr2 = b;
93
+
94
+ if (ptr1->unit > ptr2->unit) {
95
+ return 1;
96
+ }
97
+ else if (ptr1->unit < ptr2->unit) {
98
+ return -1;
99
+ }
100
+ else {
101
+ return 0;
102
+ }
103
+}
104
+
105
+static void mdflush_read_count_map()
106
+{
107
+ int mapfd = mdflush_maps[MDFLUSH_MAP_COUNT].map_fd;
108
+ mdflush_ebpf_key_t curr_key = (uint32_t)-1;
109
+ mdflush_ebpf_key_t key = (uint32_t)-1;
110
+ netdata_mdflush_t search_v;
111
+ netdata_mdflush_t *v = NULL;
112
+
113
+ while (bpf_map_get_next_key(mapfd, &curr_key, &key) == 0) {
114
+ curr_key = key;
115
+
116
+ // get val for this key.
117
+ int test = bpf_map_lookup_elem(mapfd, &key, mdflush_ebpf_vals);
118
+ if (unlikely(test < 0)) {
119
+ continue;
120
+ }
121
+
122
+ // is this record saved yet?
123
+ //
124
+ // if not, make a new one, mark it as unsaved for now, and continue; we
125
+ // will insert it at the end after all of its values are correctly set,
126
+ // so that we can safely publish it to the collector within a single,
127
+ // short locked operation.
128
+ //
129
+ // otherwise simply continue; we will only update the flush count,
130
+ // which can be republished safely without a lock.
131
+ //
132
+ // NOTE: lock isn't strictly necessary for this initial search, as only
133
+ // this thread does writing, but the AVL is using a read-write lock so
134
+ // there is no congestion.
135
+ bool v_is_new = false;
136
+ search_v.unit = key;
137
+ v = (netdata_mdflush_t *)avl_search_lock(
138
+ &mdflush_pub,
139
+ (avl_t *)&search_v
140
+ );
141
+ if (unlikely(v == NULL)) {
142
+ // flush count can only be added reliably at a later time.
143
+ // when they're added, only then will we AVL insert.
144
+ v = callocz(1, sizeof(netdata_mdflush_t));
145
+ v->unit = key;
146
+ sprintf(v->disk_name, "md%u", key);
147
+ v->dim_exists = false;
148
+
149
+ v_is_new = true;
150
+ }
151
+
152
+ // we must add up count value for this record across all CPUs.
153
+ uint64_t total_cnt = 0;
154
+ int i;
155
+ int end = (running_on_kernel < NETDATA_KERNEL_V4_15) ? 1 : ebpf_nprocs;
156
+ for (i = 0; i < end; i++) {
157
+ total_cnt += mdflush_ebpf_vals[i];
158
+ }
159
+
160
+ // can now safely publish count for existing records.
161
+ v->cnt = total_cnt;
162
+
163
+ // can now safely publish new record.
164
+ if (v_is_new) {
165
+ avl_t *check = avl_insert_lock(&mdflush_pub, (avl_t *)v);
166
+ if (check != (avl_t *)v) {
167
+ error("Internal error, cannot insert the AVL tree.");
168
+ }
169
+ }
170
+ }
171
+}
172
+
173
+/**
174
+ * Read eBPF maps for mdflush.
175
+ */
176
+static void *mdflush_reader(void *ptr)
177
+{
178
+ read_thread_closed = 0;
179
+
180
+ heartbeat_t hb;
181
+ heartbeat_init(&hb);
182
+
183
+ ebpf_module_t *em = (ebpf_module_t *)ptr;
184
+
185
+ usec_t step = NETDATA_MDFLUSH_SLEEP_MS * em->update_every;
186
+ while (!close_ebpf_plugin) {
187
+ usec_t dt = heartbeat_next(&hb, step);
188
+ UNUSED(dt);
189
+
190
+ mdflush_read_count_map();
191
+ }
192
+
193
+ read_thread_closed = 1;
194
+ return NULL;
195
+}
196
+
197
+static void mdflush_create_charts(int update_every)
198
+{
199
+ ebpf_create_chart(
200
+ "mdstat",
201
+ "mdstat_flush",
202
+ "MD flushes",
203
+ "flushes",
204
+ "flush (eBPF)",
205
+ "md.flush",
206
+ NETDATA_EBPF_CHART_TYPE_STACKED,
207
+ NETDATA_CHART_PRIO_MDSTAT_FLUSH,
208
+ NULL, NULL, 0, update_every,
209
+ NETDATA_EBPF_MODULE_NAME_MDFLUSH
210
+ );
211
+
212
+ fflush(stdout);
213
+}
214
+
215
+// callback for avl tree traversal on `mdflush_pub`.
216
+static int mdflush_write_dims(void *entry, void *data)
217
+{
218
+ UNUSED(data);
219
+
220
+ netdata_mdflush_t *v = entry;
221
+
222
+ // records get dynamically added in, so add the dim if we haven't yet.
223
+ if (!v->dim_exists) {
224
+ ebpf_write_global_dimension(
225
+ v->disk_name, v->disk_name,
226
+ ebpf_algorithms[NETDATA_EBPF_INCREMENTAL_IDX]
227
+ );
228
+ v->dim_exists = true;
229
+ }
230
+
231
+ write_chart_dimension(v->disk_name, v->cnt);
232
+
233
+ return 1;
234
+}
235
+
236
+/**
237
+* Main loop for this collector.
238
+*/
239
+static void mdflush_collector(ebpf_module_t *em)
240
+{
241
+ mdflush_ebpf_vals = callocz(ebpf_nprocs, sizeof(mdflush_ebpf_val_t));
242
+
243
+ avl_init_lock(&mdflush_pub, mdflush_val_cmp);
244
+
245
+ // create reader thread.
246
+ mdflush_threads.thread = mallocz(sizeof(netdata_thread_t));
247
+ mdflush_threads.start_routine = mdflush_reader;
248
+ netdata_thread_create(
249
+ mdflush_threads.thread,
250
+ mdflush_threads.name,
251
+ NETDATA_THREAD_OPTION_JOINABLE,
252
+ mdflush_reader,
253
+ em
254
+ );
255
+
256
+ // create chart and static dims.
257
+ pthread_mutex_lock(&lock);
258
+ mdflush_create_charts(em->update_every);
259
+ pthread_mutex_unlock(&lock);
260
+
261
+ // loop and read from published data until ebpf plugin is closed.
262
+ int update_every = em->update_every;
263
+ int counter = update_every - 1;
264
+ while (!close_ebpf_plugin) {
265
+ pthread_mutex_lock(&collect_data_mutex);
266
+ pthread_cond_wait(&collect_data_cond_var, &collect_data_mutex);
267
+
268
+ if (++counter == update_every) {
269
+ counter = 0;
270
+ pthread_mutex_lock(&lock);
271
+
272
+ // write dims now for all hitherto discovered devices.
273
+ write_begin_chart("mdstat", "mdstat_flush");
274
+ avl_traverse_lock(&mdflush_pub, mdflush_write_dims, NULL);
275
+ write_end_chart();
276
+
277
+ pthread_mutex_unlock(&lock);
278
+ }
279
+
280
+ pthread_mutex_unlock(&collect_data_mutex);
281
+ }
282
+}
283
+
284
+/**
285
+ * mdflush thread.
286
+ *
287
+ * @param ptr a `ebpf_module_t *`.
288
+ * @return always NULL.
289
+ */
290
+void *ebpf_mdflush_thread(void *ptr)
291
+{
292
+ netdata_thread_cleanup_push(mdflush_cleanup, ptr);
293
+
294
+ ebpf_module_t *em = (ebpf_module_t *)ptr;
295
+ em->maps = mdflush_maps;
296
+
297
+ if (!em->enabled) {
298
+ goto endmdflush;
299
+ }
300
+
301
+ probe_links = ebpf_load_program(ebpf_plugin_dir, em, kernel_string, &objects);
302
+ if (!probe_links) {
303
+ goto endmdflush;
304
+ }
305
+
306
+ mdflush_collector(em);
307
+
308
+endmdflush:
309
+ netdata_thread_cleanup_pop(1);
310
+
311
+ return NULL;
312
+}
collectors/ebpf.plugin/ebpf_mdflush.h
new
+42
@@ -0,0 +1,42 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_EBPF_MDFLUSH_H
4
+#define NETDATA_EBPF_MDFLUSH_H 1
5
+
6
+// Module name
7
+#define NETDATA_EBPF_MODULE_NAME_MDFLUSH "mdflush"
8
+
9
+#define NETDATA_MDFLUSH_SLEEP_MS 850000ULL
10
+
11
+// charts
12
+#define NETDATA_MDFLUSH_GLOBAL_CHART "mdflush"
13
+
14
+// configuration file
15
+#define NETDATA_DIRECTORY_MDFLUSH_CONFIG_FILE "mdflush.conf"
16
+
17
+// copy of mdflush types from kernel-collectors repo.
18
+typedef uint32_t mdflush_ebpf_key_t;
19
+typedef uint64_t mdflush_ebpf_val_t;
20
+
21
+typedef struct netdata_mdflush {
22
+ // must be at top for simplified AVL tree usage.
23
+ // if it's not at the top, we need to use `containerof` for almost all ops.
24
+ avl_t avl;
25
+
26
+ // key & name of device.
27
+ // the name is generated by the key, usually as `md<unit>`.
28
+ uint32_t unit;
29
+ char disk_name[32];
30
+
31
+ // have we defined the dimension for this device yet?
32
+ bool dim_exists;
33
+
34
+ // incremental flush count value.
35
+ uint64_t cnt;
36
+} netdata_mdflush_t;
37
+
38
+extern void *ebpf_mdflush_thread(void *ptr);
39
+
40
+extern struct config mdflush_config;
41
+
42
+#endif
packaging/ebpf.checksums
+3
-3
@@ -1,3 +1,3 @@
1
-ec330d7529b5d94e705dba88494d4721a59f9f7d8e4cadff59ede8489e1dd5c3 netdata-kernel-collector-glibc-v0.8.3.tar.xz
2
-c6dbf522ae1fc3930701db1567ac6abb9cc944b0d3f7dd5ab2a2edd511816a3f netdata-kernel-collector-musl-v0.8.3.tar.xz
3
-3d29ccd9690253dec8727fe94a2a04f64686a7fd3c93eb4f382445f56dc249c7 netdata-kernel-collector-static-v0.8.3.tar.xz
1
+e5a4e49fcfcb1602aec5c770de773e91918836b24ac7de2d817bc8a6d106dbcf netdata-kernel-collector-glibc-v0.8.4.tar.xz
2
+beb57f51c6c8178e9a16f7e8370c55d0f29f20f1d4e9546a5e097e647192514c netdata-kernel-collector-musl-v0.8.4.tar.xz
3
+9ee4ca483b7575f9e9c74dc61ec0ab7af3abf1a6404f191e0ac092500842b8a7 netdata-kernel-collector-static-v0.8.4.tar.xz
packaging/ebpf.version
+1
-1
@@ -1 +1 @@
1
-v0.8.3
1
+v0.8.4
web/gui/dashboard_info.js
+3
@@ -1606,6 +1606,9 @@ netdataDashboard.context = {
1606
'software issues should never cause such a mismatch. '+
1607
'For details, see <a href="https://man7.org/linux/man-pages/man4/md.4.html" target="_blank">md(4)</a>.'
1608
},
1609
+ 'md.flush': {
1610
+ info: 'Number of flush counts per MD array. Based on the eBPF <a href="https://github.com/iovisor/bcc/blob/master/tools/mdflush_example.txt" target="_blank">mdflush</a> from BCC tools.'
1611
+ },
1612
1613
// ------------------------------------------------------------------------
1614
// IP