master
c 626 lines 24.1 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "plugin_proc.h"
4
5 #define PLUGIN_PROC_MODULE_MDSTAT_NAME "/proc/mdstat"
6
7 struct raid {
8 int redundant;
9 char *name;
10 uint32_t hash;
11 char *level;
12
13 RRDDIM *rd_health;
14 unsigned long long failed_disks;
15
16 RRDSET *st_disks;
17 RRDDIM *rd_down;
18 RRDDIM *rd_inuse;
19 unsigned long long total_disks;
20 unsigned long long inuse_disks;
21
22 RRDSET *st_operation;
23 RRDDIM *rd_check;
24 RRDDIM *rd_resync;
25 RRDDIM *rd_recovery;
26 RRDDIM *rd_reshape;
27 unsigned long long check;
28 unsigned long long resync;
29 unsigned long long recovery;
30 unsigned long long reshape;
31
32 RRDSET *st_finish;
33 RRDDIM *rd_finish_in;
34 unsigned long long finish_in;
35
36 RRDSET *st_speed;
37 RRDDIM *rd_speed;
38 unsigned long long speed;
39
40 char *mismatch_cnt_filename;
41 RRDSET *st_mismatch_cnt;
42 RRDDIM *rd_mismatch_cnt;
43 unsigned long long mismatch_cnt;
44
45 RRDSET *st_nonredundant;
46 RRDDIM *rd_nonredundant;
47 };
48
49 struct old_raid {
50 int redundant;
51 char *name;
52 uint32_t hash;
53 int found;
54 };
55
56 static inline char *remove_trailing_chars(char *s, char c)
57 {
58 while (*s) {
59 if (unlikely(*s == c)) {
60 *s = '\0';
61 }
62 s++;
63 }
64 return s;
65 }
66
67 static inline void make_chart_obsolete(char *name, const char *id_modifier)
68 {
69 char id[50 + 1];
70 RRDSET *st = NULL;
71
72 if (likely(name && id_modifier)) {
73 snprintfz(id, sizeof(id) - 1, "%s_%s", name, id_modifier);
74 st = rrdset_find_active_bytype_localhost("mdstat", id);
75 if (likely(st))
76 rrdset_is_obsolete___safe_from_collector_thread(st);
77 }
78 }
79
80 static void add_labels_to_mdstat(struct raid *raid, RRDSET *st) {
81 rrdlabels_add(st->rrdlabels, "device", raid->name, RRDLABEL_SRC_AUTO);
82 rrdlabels_add(st->rrdlabels, "raid_level", raid->level, RRDLABEL_SRC_AUTO);
83 }
84
85 int do_proc_mdstat(int update_every, usec_t dt)
86 {
87 (void)dt;
88 static procfile *ff = NULL;
89 static int do_health = -1, do_nonredundant = -1, do_disks = -1, do_operations = -1, do_mismatch = -1,
90 do_mismatch_config = -1;
91 static int make_charts_obsolete = -1;
92 static const char *mdstat_filename = NULL, *mismatch_cnt_filename = NULL;
93 static struct raid *raids = NULL;
94 static size_t raids_allocated = 0;
95 size_t raids_num = 0, raid_idx = 0, redundant_num = 0;
96 static struct old_raid *old_raids = NULL;
97 static size_t old_raids_allocated = 0;
98 size_t old_raid_idx = 0;
99
100 if (unlikely(do_health == -1)) {
101 do_health =
102 inicfg_get_boolean(&netdata_config, "plugin:proc:/proc/mdstat", "faulty devices", CONFIG_BOOLEAN_YES);
103 do_nonredundant =
104 inicfg_get_boolean(&netdata_config, "plugin:proc:/proc/mdstat", "nonredundant arrays availability", CONFIG_BOOLEAN_YES);
105 do_mismatch_config =
106 inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/mdstat", "mismatch count", CONFIG_BOOLEAN_AUTO);
107 do_disks =
108 inicfg_get_boolean(&netdata_config, "plugin:proc:/proc/mdstat", "disk stats", CONFIG_BOOLEAN_YES);
109 do_operations =
110 inicfg_get_boolean(&netdata_config, "plugin:proc:/proc/mdstat", "operation status", CONFIG_BOOLEAN_YES);
111
112 make_charts_obsolete =
113 inicfg_get_boolean(&netdata_config, "plugin:proc:/proc/mdstat", "make charts obsolete", CONFIG_BOOLEAN_YES);
114
115 char filename[FILENAME_MAX + 1];
116
117 snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/mdstat");
118 mdstat_filename = inicfg_get(&netdata_config, "plugin:proc:/proc/mdstat", "filename to monitor", filename);
119
120 snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/md/mismatch_cnt");
121 mismatch_cnt_filename = inicfg_get(&netdata_config, "plugin:proc:/proc/mdstat", "mismatch_cnt filename to monitor", filename);
122 }
123
124 if (unlikely(!ff)) {
125 ff = procfile_open(mdstat_filename, " \t:", PROCFILE_FLAG_DEFAULT);
126 if (unlikely(!ff))
127 return 1;
128 }
129
130 ff = procfile_readall(ff);
131 if (unlikely(!ff))
132 return 0; // we return 0, so that we will retry opening it next time
133
134 size_t lines = procfile_lines(ff);
135 size_t words = 0;
136
137 if (unlikely(lines < 2)) {
138 collector_error("Cannot read /proc/mdstat. Expected 2 or more lines, read %zu.", lines);
139 return 1;
140 }
141
142 // find how many raids are there
143 size_t l;
144 raids_num = 0;
145 for (l = 1; l < lines - 2; l++) {
146 if (unlikely(procfile_lineword(ff, l, 1)[0] == 'a')) // check if the raid is active
147 raids_num++;
148 }
149
150 if (unlikely(!raids_num && !old_raids_allocated))
151 return 0; // we return 0, so that we will retry searching for raids next time
152
153 // allocate the memory we need;
154 if (unlikely(raids_num != raids_allocated)) {
155 for (raid_idx = 0; raid_idx < raids_allocated; raid_idx++) {
156 struct raid *raid = &raids[raid_idx];
157 freez(raid->name);
158 freez(raid->level);
159 freez(raid->mismatch_cnt_filename);
160 }
161 if (raids_num) {
162 raids = (struct raid *)reallocz(raids, raids_num * sizeof(struct raid));
163 memset(raids, 0, raids_num * sizeof(struct raid));
164 } else {
165 freez(raids);
166 raids = NULL;
167 }
168 raids_allocated = raids_num;
169 }
170
171 // loop through all lines except the first and the last ones
172 for (l = 1, raid_idx = 0; l < (lines - 2) && raid_idx < raids_num; l++) {
173 struct raid *raid = &raids[raid_idx];
174 raid->redundant = 0;
175
176 words = procfile_linewords(ff, l);
177
178 if (unlikely(words < 3))
179 continue;
180
181 if (unlikely(procfile_lineword(ff, l, 1)[0] != 'a'))
182 continue;
183
184 if (unlikely(!raid->name)) {
185 raid->name = strdupz(procfile_lineword(ff, l, 0));
186 raid->hash = simple_hash(raid->name);
187 raid->level = strdupz(procfile_lineword(ff, l, 2));
188 } else if (unlikely(strcmp(raid->name, procfile_lineword(ff, l, 0)))) {
189 freez(raid->name);
190 freez(raid->mismatch_cnt_filename);
191 freez(raid->level);
192 memset(raid, 0, sizeof(struct raid));
193 raid->name = strdupz(procfile_lineword(ff, l, 0));
194 raid->hash = simple_hash(raid->name);
195 raid->level = strdupz(procfile_lineword(ff, l, 2));
196 }
197
198 if (unlikely(!raid->name || !raid->name[0]))
199 continue;
200
201 raid_idx++;
202
203 // check if raid has disk status
204 l++;
205 words = procfile_linewords(ff, l);
206 if (words < 2 || procfile_lineword(ff, l, words - 1)[0] != '[')
207 continue;
208
209 // split inuse and total number of disks
210 if (likely(do_health || do_disks)) {
211 char *s = NULL, *str_total = NULL, *str_inuse = NULL;
212
213 s = procfile_lineword(ff, l, words - 2);
214 if (unlikely(s[0] != '[')) {
215 collector_error("Cannot read /proc/mdstat raid health status. Unexpected format: missing opening bracket.");
216 continue;
217 }
218 str_total = ++s;
219 while (*s) {
220 if (unlikely(*s == '/')) {
221 *s = '\0';
222 str_inuse = s + 1;
223 } else if (unlikely(*s == ']')) {
224 *s = '\0';
225 break;
226 }
227 s++;
228 }
229 if (unlikely(str_total[0] == '\0' || !str_inuse || str_inuse[0] == '\0')) {
230 collector_error("Cannot read /proc/mdstat raid health status. Unexpected format.");
231 continue;
232 }
233
234 raid->inuse_disks = str2ull(str_inuse, NULL);
235 raid->total_disks = str2ull(str_total, NULL);
236 raid->failed_disks = raid->total_disks - raid->inuse_disks;
237 }
238
239 raid->redundant = 1;
240 redundant_num++;
241 l++;
242
243 // check if any operation is performed on the raid
244 if (likely(do_operations)) {
245 char *s = NULL;
246
247 raid->check = 0;
248 raid->resync = 0;
249 raid->recovery = 0;
250 raid->reshape = 0;
251 raid->finish_in = 0;
252 raid->speed = 0;
253
254 words = procfile_linewords(ff, l);
255
256 if (likely(words < 2))
257 continue;
258
259 if (unlikely(procfile_lineword(ff, l, 0)[0] != '['))
260 continue;
261
262 if (unlikely(words < 7)) {
263 collector_error("Cannot read /proc/mdstat line. Expected 7 params, read %zu.", words);
264 continue;
265 }
266
267 char *word;
268 word = procfile_lineword(ff, l, 3);
269 remove_trailing_chars(word, '%');
270
271 unsigned long long percentage = (unsigned long long)(str2ndd(word, NULL) * 100);
272 // possible operations: check, resync, recovery, reshape
273 // 4-th character is unique for each operation so it is checked
274 switch (procfile_lineword(ff, l, 1)[3]) {
275 case 'c': // check
276 raid->check = percentage;
277 break;
278 case 'y': // resync
279 raid->resync = percentage;
280 break;
281 case 'o': // recovery
282 raid->recovery = percentage;
283 break;
284 case 'h': // reshape
285 raid->reshape = percentage;
286 break;
287 }
288
289 word = procfile_lineword(ff, l, 5);
290 s = remove_trailing_chars(word, 'm'); // remove trailing "min"
291
292 word += 7; // skip leading "finish="
293
294 if (likely(s > word))
295 raid->finish_in = (unsigned long long)(str2ndd(word, NULL) * 60);
296
297 word = procfile_lineword(ff, l, 6);
298 s = remove_trailing_chars(word, 'K'); // remove trailing "K/sec"
299
300 word += 6; // skip leading "speed="
301
302 if (likely(s > word))
303 raid->speed = str2ull(word, NULL);
304 }
305 }
306
307 // read mismatch_cnt files
308 if (do_mismatch == -1) {
309 if (do_mismatch_config == CONFIG_BOOLEAN_AUTO) {
310 if (raids_num > 50)
311 do_mismatch = CONFIG_BOOLEAN_NO;
312 else
313 do_mismatch = CONFIG_BOOLEAN_YES;
314 } else
315 do_mismatch = do_mismatch_config;
316 }
317
318 if (likely(do_mismatch)) {
319 for (raid_idx = 0; raid_idx < raids_num; raid_idx++) {
320 char filename[FILENAME_MAX + 1];
321 struct raid *raid = &raids[raid_idx];
322
323 if (likely(raid->redundant)) {
324 if (unlikely(!raid->mismatch_cnt_filename)) {
325 snprintfz(filename, FILENAME_MAX, mismatch_cnt_filename, raid->name);
326 raid->mismatch_cnt_filename = strdupz(filename);
327 }
328 if (unlikely(read_single_number_file(raid->mismatch_cnt_filename, &raid->mismatch_cnt))) {
329 collector_error("Cannot read file '%s'", raid->mismatch_cnt_filename);
330 do_mismatch = CONFIG_BOOLEAN_NO;
331 collector_error("Monitoring for mismatch count has been disabled");
332 break;
333 }
334 }
335 }
336 }
337
338 // check for disappeared raids
339 for (old_raid_idx = 0; old_raid_idx < old_raids_allocated; old_raid_idx++) {
340 struct old_raid *old_raid = &old_raids[old_raid_idx];
341 int found = 0;
342
343 for (raid_idx = 0; raid_idx < raids_num; raid_idx++) {
344 struct raid *raid = &raids[raid_idx];
345
346 if (unlikely(
347 raid->hash == old_raid->hash && !strcmp(raid->name, old_raid->name) &&
348 raid->redundant == old_raid->redundant))
349 found = 1;
350 }
351
352 old_raid->found = found;
353 }
354
355 int raid_disappeared = 0;
356 for (old_raid_idx = 0; old_raid_idx < old_raids_allocated; old_raid_idx++) {
357 struct old_raid *old_raid = &old_raids[old_raid_idx];
358
359 if (unlikely(!old_raid->found)) {
360 if (likely(make_charts_obsolete)) {
361 make_chart_obsolete(old_raid->name, "disks");
362 make_chart_obsolete(old_raid->name, "mismatch");
363 make_chart_obsolete(old_raid->name, "operation");
364 make_chart_obsolete(old_raid->name, "finish");
365 make_chart_obsolete(old_raid->name, "speed");
366 make_chart_obsolete(old_raid->name, "availability");
367 }
368 raid_disappeared = 1;
369 }
370 }
371
372 // allocate memory for nonredundant arrays
373 if (unlikely(raid_disappeared || old_raids_allocated != raids_num)) {
374 for (old_raid_idx = 0; old_raid_idx < old_raids_allocated; old_raid_idx++) {
375 freez(old_raids[old_raid_idx].name);
376 }
377 if (likely(raids_num)) {
378 old_raids = reallocz(old_raids, sizeof(struct old_raid) * raids_num);
379 memset(old_raids, 0, sizeof(struct old_raid) * raids_num);
380 } else {
381 freez(old_raids);
382 old_raids = NULL;
383 }
384 old_raids_allocated = raids_num;
385 for (old_raid_idx = 0; old_raid_idx < old_raids_allocated; old_raid_idx++) {
386 struct old_raid *old_raid = &old_raids[old_raid_idx];
387 struct raid *raid = &raids[old_raid_idx];
388
389 old_raid->name = strdupz(raid->name);
390 old_raid->hash = raid->hash;
391 old_raid->redundant = raid->redundant;
392 }
393 }
394
395 if (likely(do_health && redundant_num)) {
396 static RRDSET *st_mdstat_health = NULL;
397 if (unlikely(!st_mdstat_health)) {
398 st_mdstat_health = rrdset_create_localhost(
399 "mdstat",
400 "mdstat_health",
401 NULL,
402 "health",
403 "md.health",
404 "Faulty Devices In MD",
405 "failed disks",
406 PLUGIN_PROC_NAME,
407 PLUGIN_PROC_MODULE_MDSTAT_NAME,
408 NETDATA_CHART_PRIO_MDSTAT_HEALTH,
409 update_every,
410 RRDSET_TYPE_LINE);
411 }
412
413 if (!redundant_num) {
414 if (likely(make_charts_obsolete))
415 make_chart_obsolete("mdstat", "health");
416 } else {
417 for (raid_idx = 0; raid_idx < raids_num; raid_idx++) {
418 struct raid *raid = &raids[raid_idx];
419
420 if (likely(raid->redundant)) {
421 if (unlikely(!raid->rd_health && !(raid->rd_health = rrddim_find_active(st_mdstat_health, raid->name))))
422 raid->rd_health = rrddim_add(st_mdstat_health, raid->name, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
423
424 rrddim_set_by_pointer(st_mdstat_health, raid->rd_health, raid->failed_disks);
425 }
426 }
427
428 rrdset_done(st_mdstat_health);
429 }
430 }
431
432 for (raid_idx = 0; raid_idx < raids_num; raid_idx++) {
433 struct raid *raid = &raids[raid_idx];
434 char id[50 + 1];
435 char family[50 + 1];
436
437 if (likely(raid->redundant)) {
438 if (likely(do_disks)) {
439 snprintfz(id, sizeof(id) - 1, "%s_disks", raid->name);
440
441 if (unlikely(!raid->st_disks && !(raid->st_disks = rrdset_find_active_byname_localhost(id)))) {
442 snprintfz(family, sizeof(family) - 1, "%s (%s)", raid->name, raid->level);
443
444 raid->st_disks = rrdset_create_localhost(
445 "mdstat",
446 id,
447 NULL,
448 family,
449 "md.disks",
450 "Disks Stats",
451 "disks",
452 PLUGIN_PROC_NAME,
453 PLUGIN_PROC_MODULE_MDSTAT_NAME,
454 NETDATA_CHART_PRIO_MDSTAT_DISKS + raid_idx * 10,
455 update_every,
456 RRDSET_TYPE_STACKED);
457
458 add_labels_to_mdstat(raid, raid->st_disks);
459 }
460
461 if (unlikely(!raid->rd_inuse && !(raid->rd_inuse = rrddim_find_active(raid->st_disks, "inuse"))))
462 raid->rd_inuse = rrddim_add(raid->st_disks, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
463 if (unlikely(!raid->rd_down && !(raid->rd_down = rrddim_find_active(raid->st_disks, "down"))))
464 raid->rd_down = rrddim_add(raid->st_disks, "down", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
465
466 rrddim_set_by_pointer(raid->st_disks, raid->rd_inuse, raid->inuse_disks);
467 rrddim_set_by_pointer(raid->st_disks, raid->rd_down, raid->failed_disks);
468 rrdset_done(raid->st_disks);
469 }
470
471 if (likely(do_mismatch)) {
472 snprintfz(id, sizeof(id) - 1, "%s_mismatch", raid->name);
473
474 if (unlikely(!raid->st_mismatch_cnt && !(raid->st_mismatch_cnt = rrdset_find_active_byname_localhost(id)))) {
475 snprintfz(family, sizeof(family) - 1, "%s (%s)", raid->name, raid->level);
476
477 raid->st_mismatch_cnt = rrdset_create_localhost(
478 "mdstat",
479 id,
480 NULL,
481 family,
482 "md.mismatch_cnt",
483 "Mismatch Count",
484 "unsynchronized blocks",
485 PLUGIN_PROC_NAME,
486 PLUGIN_PROC_MODULE_MDSTAT_NAME,
487 NETDATA_CHART_PRIO_MDSTAT_MISMATCH + raid_idx * 10,
488 update_every,
489 RRDSET_TYPE_LINE);
490
491 add_labels_to_mdstat(raid, raid->st_mismatch_cnt);
492 }
493
494 if (unlikely(!raid->rd_mismatch_cnt && !(raid->rd_mismatch_cnt = rrddim_find_active(raid->st_mismatch_cnt, "count"))))
495 raid->rd_mismatch_cnt = rrddim_add(raid->st_mismatch_cnt, "count", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
496
497 rrddim_set_by_pointer(raid->st_mismatch_cnt, raid->rd_mismatch_cnt, raid->mismatch_cnt);
498 rrdset_done(raid->st_mismatch_cnt);
499 }
500
501 if (likely(do_operations)) {
502 snprintfz(id, sizeof(id) - 1, "%s_operation", raid->name);
503
504 if (unlikely(!raid->st_operation && !(raid->st_operation = rrdset_find_active_byname_localhost(id)))) {
505 snprintfz(family, sizeof(family) - 1, "%s (%s)", raid->name, raid->level);
506
507 raid->st_operation = rrdset_create_localhost(
508 "mdstat",
509 id,
510 NULL,
511 family,
512 "md.status",
513 "Current Status",
514 "percent",
515 PLUGIN_PROC_NAME,
516 PLUGIN_PROC_MODULE_MDSTAT_NAME,
517 NETDATA_CHART_PRIO_MDSTAT_OPERATION + raid_idx * 10,
518 update_every,
519 RRDSET_TYPE_LINE);
520
521 add_labels_to_mdstat(raid, raid->st_operation);
522 }
523
524 if(unlikely(!raid->rd_check && !(raid->rd_check = rrddim_find_active(raid->st_operation, "check"))))
525 raid->rd_check = rrddim_add(raid->st_operation, "check", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
526 if(unlikely(!raid->rd_resync && !(raid->rd_resync = rrddim_find_active(raid->st_operation, "resync"))))
527 raid->rd_resync = rrddim_add(raid->st_operation, "resync", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
528 if(unlikely(!raid->rd_recovery && !(raid->rd_recovery = rrddim_find_active(raid->st_operation, "recovery"))))
529 raid->rd_recovery = rrddim_add(raid->st_operation, "recovery", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
530 if(unlikely(!raid->rd_reshape && !(raid->rd_reshape = rrddim_find_active(raid->st_operation, "reshape"))))
531 raid->rd_reshape = rrddim_add(raid->st_operation, "reshape", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
532
533 rrddim_set_by_pointer(raid->st_operation, raid->rd_check, raid->check);
534 rrddim_set_by_pointer(raid->st_operation, raid->rd_resync, raid->resync);
535 rrddim_set_by_pointer(raid->st_operation, raid->rd_recovery, raid->recovery);
536 rrddim_set_by_pointer(raid->st_operation, raid->rd_reshape, raid->reshape);
537 rrdset_done(raid->st_operation);
538
539 snprintfz(id, sizeof(id) - 1, "%s_finish", raid->name);
540 if (unlikely(!raid->st_finish && !(raid->st_finish = rrdset_find_active_byname_localhost(id)))) {
541 snprintfz(family, sizeof(family) - 1, "%s (%s)", raid->name, raid->level);
542
543 raid->st_finish = rrdset_create_localhost(
544 "mdstat",
545 id,
546 NULL,
547 family,
548 "md.expected_time_until_operation_finish",
549 "Approximate Time Until Finish",
550 "seconds",
551 PLUGIN_PROC_NAME,
552 PLUGIN_PROC_MODULE_MDSTAT_NAME,
553 NETDATA_CHART_PRIO_MDSTAT_FINISH + raid_idx * 10,
554 update_every, RRDSET_TYPE_LINE);
555
556 add_labels_to_mdstat(raid, raid->st_finish);
557 }
558
559 if(unlikely(!raid->rd_finish_in && !(raid->rd_finish_in = rrddim_find_active(raid->st_finish, "finish_in"))))
560 raid->rd_finish_in = rrddim_add(raid->st_finish, "finish_in", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
561
562 rrddim_set_by_pointer(raid->st_finish, raid->rd_finish_in, raid->finish_in);
563 rrdset_done(raid->st_finish);
564
565 snprintfz(id, sizeof(id) - 1, "%s_speed", raid->name);
566 if (unlikely(!raid->st_speed && !(raid->st_speed = rrdset_find_active_byname_localhost(id)))) {
567 snprintfz(family, sizeof(family) - 1, "%s (%s)", raid->name, raid->level);
568
569 raid->st_speed = rrdset_create_localhost(
570 "mdstat",
571 id,
572 NULL,
573 family,
574 "md.operation_speed",
575 "Operation Speed",
576 "KiB/s",
577 PLUGIN_PROC_NAME,
578 PLUGIN_PROC_MODULE_MDSTAT_NAME,
579 NETDATA_CHART_PRIO_MDSTAT_SPEED + raid_idx * 10,
580 update_every,
581 RRDSET_TYPE_LINE);
582
583 add_labels_to_mdstat(raid, raid->st_speed);
584 }
585
586 if (unlikely(!raid->rd_speed && !(raid->rd_speed = rrddim_find_active(raid->st_speed, "speed"))))
587 raid->rd_speed = rrddim_add(raid->st_speed, "speed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
588
589 rrddim_set_by_pointer(raid->st_speed, raid->rd_speed, raid->speed);
590 rrdset_done(raid->st_speed);
591 }
592 } else {
593 if (likely(do_nonredundant)) {
594 snprintfz(id, sizeof(id) - 1, "%s_availability", raid->name);
595
596 if (unlikely(!raid->st_nonredundant && !(raid->st_nonredundant = rrdset_find_active_localhost(id)))) {
597 snprintfz(family, sizeof(family) - 1, "%s (%s)", raid->name, raid->level);
598
599 raid->st_nonredundant = rrdset_create_localhost(
600 "mdstat",
601 id,
602 NULL,
603 family,
604 "md.nonredundant",
605 "Nonredundant Array Availability",
606 "boolean",
607 PLUGIN_PROC_NAME,
608 PLUGIN_PROC_MODULE_MDSTAT_NAME,
609 NETDATA_CHART_PRIO_MDSTAT_NONREDUNDANT + raid_idx * 10,
610 update_every,
611 RRDSET_TYPE_LINE);
612
613 add_labels_to_mdstat(raid, raid->st_nonredundant);
614 }
615
616 if (unlikely(!raid->rd_nonredundant && !(raid->rd_nonredundant = rrddim_find_active(raid->st_nonredundant, "available"))))
617 raid->rd_nonredundant = rrddim_add(raid->st_nonredundant, "available", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
618
619 rrddim_set_by_pointer(raid->st_nonredundant, raid->rd_nonredundant, 1);
620 rrdset_done(raid->st_nonredundant);
621 }
622 }
623 }
624
625 return 0;
626 }