ebpf_filesystem.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "ebpf_filesystem.h"
  3. struct config fs_config = { .first_section = NULL,
  4. .last_section = NULL,
  5. .mutex = NETDATA_MUTEX_INITIALIZER,
  6. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  7. .rwlock = AVL_LOCK_INITIALIZER } };
  8. static ebpf_local_maps_t fs_maps[] = {{.name = "tbl_ext4", .internal_input = NETDATA_KEY_CALLS_SYNC,
  9. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  10. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  11. {.name = "tbl_xfs", .internal_input = NETDATA_KEY_CALLS_SYNC,
  12. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  13. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  14. {.name = "tbl_nfs", .internal_input = NETDATA_KEY_CALLS_SYNC,
  15. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  16. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  17. {.name = "tbl_zfs", .internal_input = NETDATA_KEY_CALLS_SYNC,
  18. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  19. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  20. {.name = "tbl_btrfs", .internal_input = NETDATA_KEY_CALLS_SYNC,
  21. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  22. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  23. {.name = "tbl_ext_addr", .internal_input = 1,
  24. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  25. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  26. {.name = NULL, .internal_input = 0, .user_input = 0,
  27. .type = NETDATA_EBPF_MAP_CONTROLLER,
  28. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED}};
  29. struct netdata_static_thread filesystem_threads = {
  30. .name = "EBPF FS READ",
  31. .config_section = NULL,
  32. .config_name = NULL,
  33. .env_name = NULL,
  34. .enabled = 1,
  35. .thread = NULL,
  36. .init_routine = NULL,
  37. .start_routine = NULL
  38. };
  39. static enum ebpf_threads_status ebpf_fs_exited = NETDATA_THREAD_EBPF_RUNNING;
  40. static netdata_syscall_stat_t filesystem_aggregated_data[NETDATA_EBPF_HIST_MAX_BINS];
  41. static netdata_publish_syscall_t filesystem_publish_aggregated[NETDATA_EBPF_HIST_MAX_BINS];
  42. char **dimensions = NULL;
  43. static netdata_idx_t *filesystem_hash_values = NULL;
  44. /*****************************************************************
  45. *
  46. * COMMON FUNCTIONS
  47. *
  48. *****************************************************************/
  49. /**
  50. * Create Filesystem chart
  51. *
  52. * Create latency charts
  53. *
  54. * @param update_every value to overwrite the update frequency set by the server.
  55. */
  56. static void ebpf_obsolete_fs_charts(int update_every)
  57. {
  58. int i;
  59. uint32_t test = NETDATA_FILESYSTEM_FLAG_CHART_CREATED | NETDATA_FILESYSTEM_REMOVE_CHARTS;
  60. for (i = 0; localfs[i].filesystem; i++) {
  61. ebpf_filesystem_partitions_t *efp = &localfs[i];
  62. uint32_t flags = efp->flags;
  63. if ((flags & test) == test) {
  64. flags &= ~NETDATA_FILESYSTEM_FLAG_CHART_CREATED;
  65. ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hread.name,
  66. efp->hread.title,
  67. EBPF_COMMON_DIMENSION_CALL, efp->family_name,
  68. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hread.order, update_every);
  69. ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hwrite.name,
  70. efp->hwrite.title,
  71. EBPF_COMMON_DIMENSION_CALL, efp->family_name,
  72. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hwrite.order, update_every);
  73. ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hopen.name, efp->hopen.title,
  74. EBPF_COMMON_DIMENSION_CALL, efp->family_name,
  75. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hopen.order, update_every);
  76. ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hadditional.name, efp->hadditional.title,
  77. EBPF_COMMON_DIMENSION_CALL, efp->family_name,
  78. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hadditional.order,
  79. update_every);
  80. }
  81. efp->flags = flags;
  82. }
  83. }
  84. /**
  85. * Create Filesystem chart
  86. *
  87. * Create latency charts
  88. *
  89. * @param update_every value to overwrite the update frequency set by the server.
  90. */
  91. static void ebpf_create_fs_charts(int update_every)
  92. {
  93. static int order = NETDATA_CHART_PRIO_EBPF_FILESYSTEM_CHARTS;
  94. char chart_name[64], title[256], family[64];
  95. int i;
  96. uint32_t test = NETDATA_FILESYSTEM_FLAG_CHART_CREATED|NETDATA_FILESYSTEM_REMOVE_CHARTS;
  97. for (i = 0; localfs[i].filesystem; i++) {
  98. ebpf_filesystem_partitions_t *efp = &localfs[i];
  99. uint32_t flags = efp->flags;
  100. if (flags & NETDATA_FILESYSTEM_FLAG_HAS_PARTITION && !(flags & test)) {
  101. snprintfz(title, 255, "%s latency for each read request.", efp->filesystem);
  102. snprintfz(family, 63, "%s_latency", efp->family);
  103. snprintfz(chart_name, 63, "%s_read_latency", efp->filesystem);
  104. efp->hread.name = strdupz(chart_name);
  105. efp->hread.title = strdupz(title);
  106. efp->hread.order = order;
  107. efp->family_name = strdupz(family);
  108. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hread.name,
  109. title,
  110. EBPF_COMMON_DIMENSION_CALL, family,
  111. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
  112. filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
  113. update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
  114. order++;
  115. snprintfz(title, 255, "%s latency for each write request.", efp->filesystem);
  116. snprintfz(chart_name, 63, "%s_write_latency", efp->filesystem);
  117. efp->hwrite.name = strdupz(chart_name);
  118. efp->hwrite.title = strdupz(title);
  119. efp->hwrite.order = order;
  120. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hwrite.name,
  121. title,
  122. EBPF_COMMON_DIMENSION_CALL, family,
  123. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
  124. filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
  125. update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
  126. order++;
  127. snprintfz(title, 255, "%s latency for each open request.", efp->filesystem);
  128. snprintfz(chart_name, 63, "%s_open_latency", efp->filesystem);
  129. efp->hopen.name = strdupz(chart_name);
  130. efp->hopen.title = strdupz(title);
  131. efp->hopen.order = order;
  132. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hopen.name,
  133. title,
  134. EBPF_COMMON_DIMENSION_CALL, family,
  135. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
  136. filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
  137. update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
  138. order++;
  139. char *type = (efp->flags & NETDATA_FILESYSTEM_ATTR_CHARTS) ? "attribute" : "sync";
  140. snprintfz(title, 255, "%s latency for each %s request.", efp->filesystem, type);
  141. snprintfz(chart_name, 63, "%s_%s_latency", efp->filesystem, type);
  142. efp->hadditional.name = strdupz(chart_name);
  143. efp->hadditional.title = strdupz(title);
  144. efp->hadditional.order = order;
  145. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hadditional.name, title,
  146. EBPF_COMMON_DIMENSION_CALL, family,
  147. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
  148. filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
  149. update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
  150. order++;
  151. efp->flags |= NETDATA_FILESYSTEM_FLAG_CHART_CREATED;
  152. }
  153. }
  154. }
  155. /**
  156. * Initialize eBPF data
  157. *
  158. * @param em main thread structure.
  159. *
  160. * @return it returns 0 on success and -1 otherwise.
  161. */
  162. int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
  163. {
  164. int i;
  165. const char *saved_name = em->thread_name;
  166. uint64_t kernels = em->kernels;
  167. for (i = 0; localfs[i].filesystem; i++) {
  168. ebpf_filesystem_partitions_t *efp = &localfs[i];
  169. if (!efp->probe_links && efp->flags & NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM) {
  170. em->thread_name = efp->filesystem;
  171. em->kernels = efp->kernels;
  172. efp->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &efp->objects);
  173. if (!efp->probe_links) {
  174. em->thread_name = saved_name;
  175. em->kernels = kernels;
  176. return -1;
  177. }
  178. efp->flags |= NETDATA_FILESYSTEM_FLAG_HAS_PARTITION;
  179. // Nedeed for filesystems like btrfs
  180. if ((efp->flags & NETDATA_FILESYSTEM_FILL_ADDRESS_TABLE) && (efp->addresses.function)) {
  181. ebpf_load_addresses(&efp->addresses, fs_maps[i + 1].map_fd);
  182. }
  183. }
  184. efp->flags &= ~NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM;
  185. }
  186. em->thread_name = saved_name;
  187. em->kernels = kernels;
  188. if (!dimensions) {
  189. dimensions = ebpf_fill_histogram_dimension(NETDATA_EBPF_HIST_MAX_BINS);
  190. memset(filesystem_aggregated_data, 0 , NETDATA_EBPF_HIST_MAX_BINS * sizeof(netdata_syscall_stat_t));
  191. memset(filesystem_publish_aggregated, 0 , NETDATA_EBPF_HIST_MAX_BINS * sizeof(netdata_publish_syscall_t));
  192. filesystem_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
  193. }
  194. return 0;
  195. }
  196. /**
  197. * Read Local partitions
  198. *
  199. * @return the total of partitions that will be monitored
  200. */
  201. static int ebpf_read_local_partitions()
  202. {
  203. char filename[FILENAME_MAX + 1];
  204. snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", netdata_configured_host_prefix);
  205. procfile *ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
  206. if(unlikely(!ff)) {
  207. snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", netdata_configured_host_prefix);
  208. ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
  209. if(unlikely(!ff)) return 0;
  210. }
  211. ff = procfile_readall(ff);
  212. if(unlikely(!ff))
  213. return 0;
  214. int count = 0;
  215. unsigned long l, i, lines = procfile_lines(ff);
  216. for (i = 0; localfs[i].filesystem; i++) {
  217. localfs[i].flags |= NETDATA_FILESYSTEM_REMOVE_CHARTS;
  218. }
  219. for(l = 0; l < lines ; l++) {
  220. // In "normal" situation the expected value is at column 7
  221. // When `shared` options is added to mount information, the filesystem is at column 8
  222. // Finally when we have systemd starting netdata, it will be at column 9
  223. unsigned long index = procfile_linewords(ff, l) - 3;
  224. char *fs = procfile_lineword(ff, l, index);
  225. for (i = 0; localfs[i].filesystem; i++) {
  226. ebpf_filesystem_partitions_t *w = &localfs[i];
  227. if (w->enabled && (!strcmp(fs, w->filesystem) ||
  228. (w->optional_filesystem && !strcmp(fs, w->optional_filesystem)))) {
  229. localfs[i].flags |= NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM;
  230. localfs[i].flags &= ~NETDATA_FILESYSTEM_REMOVE_CHARTS;
  231. count++;
  232. break;
  233. }
  234. }
  235. }
  236. procfile_close(ff);
  237. return count;
  238. }
  239. /**
  240. * Update partition
  241. *
  242. * Update the partition structures before to plot
  243. *
  244. * @param em main thread structure
  245. *
  246. * @return 0 on success and -1 otherwise.
  247. */
  248. static int ebpf_update_partitions(ebpf_module_t *em)
  249. {
  250. static time_t update_every = 0;
  251. time_t curr = now_realtime_sec();
  252. if (curr < update_every)
  253. return 0;
  254. update_every = curr + 5 * em->update_every;
  255. if (!ebpf_read_local_partitions()) {
  256. em->optional = -1;
  257. return -1;
  258. }
  259. if (ebpf_filesystem_initialize_ebpf_data(em)) {
  260. return -1;
  261. }
  262. return 0;
  263. }
  264. /*****************************************************************
  265. *
  266. * CLEANUP FUNCTIONS
  267. *
  268. *****************************************************************/
  269. /*
  270. * Cleanup eBPF data
  271. */
  272. void ebpf_filesystem_cleanup_ebpf_data()
  273. {
  274. int i;
  275. for (i = 0; localfs[i].filesystem; i++) {
  276. ebpf_filesystem_partitions_t *efp = &localfs[i];
  277. if (efp->probe_links) {
  278. freez(efp->family_name);
  279. freez(efp->hread.name);
  280. freez(efp->hread.title);
  281. freez(efp->hwrite.name);
  282. freez(efp->hwrite.title);
  283. freez(efp->hopen.name);
  284. freez(efp->hopen.title);
  285. freez(efp->hadditional.name);
  286. freez(efp->hadditional.title);
  287. struct bpf_link **probe_links = efp->probe_links;
  288. size_t j = 0 ;
  289. struct bpf_program *prog;
  290. bpf_object__for_each_program(prog, efp->objects) {
  291. bpf_link__destroy(probe_links[j]);
  292. j++;
  293. }
  294. freez(probe_links);
  295. if (efp->objects)
  296. bpf_object__close(efp->objects);
  297. }
  298. }
  299. }
  300. /**
  301. * Filesystem exit
  302. *
  303. * Cancel child thread.
  304. *
  305. * @param ptr thread data.
  306. */
  307. static void ebpf_filesystem_exit(void *ptr)
  308. {
  309. ebpf_module_t *em = (ebpf_module_t *)ptr;
  310. if (!em->enabled) {
  311. em->enabled = NETDATA_MAIN_THREAD_EXITED;
  312. return;
  313. }
  314. ebpf_fs_exited = NETDATA_THREAD_EBPF_STOPPING;
  315. }
  316. /**
  317. * File system cleanup
  318. *
  319. * Clean up allocated thread.
  320. *
  321. * @param ptr thread data.
  322. */
  323. static void ebpf_filesystem_cleanup(void *ptr)
  324. {
  325. ebpf_module_t *em = (ebpf_module_t *)ptr;
  326. if (ebpf_fs_exited != NETDATA_THREAD_EBPF_STOPPED)
  327. return;
  328. freez(filesystem_threads.thread);
  329. ebpf_cleanup_publish_syscall(filesystem_publish_aggregated);
  330. ebpf_filesystem_cleanup_ebpf_data();
  331. if (dimensions)
  332. ebpf_histogram_dimension_cleanup(dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  333. freez(filesystem_hash_values);
  334. filesystem_threads.enabled = NETDATA_MAIN_THREAD_EXITED;
  335. em->enabled = NETDATA_MAIN_THREAD_EXITED;
  336. }
  337. /*****************************************************************
  338. *
  339. * MAIN THREAD
  340. *
  341. *****************************************************************/
  342. /**
  343. * Select hist
  344. *
  345. * Select a histogram to store data.
  346. *
  347. * @param efp pointer for the structure with pointers.
  348. * @param id histogram selector
  349. *
  350. * @return It returns a pointer for the histogram
  351. */
  352. static inline netdata_ebpf_histogram_t *select_hist(ebpf_filesystem_partitions_t *efp, uint32_t *idx, uint32_t id)
  353. {
  354. if (id < NETDATA_KEY_CALLS_READ) {
  355. *idx = id;
  356. return &efp->hread;
  357. } else if (id < NETDATA_KEY_CALLS_WRITE) {
  358. *idx = id - NETDATA_KEY_CALLS_READ;
  359. return &efp->hwrite;
  360. } else if (id < NETDATA_KEY_CALLS_OPEN) {
  361. *idx = id - NETDATA_KEY_CALLS_WRITE;
  362. return &efp->hopen;
  363. } else if (id < NETDATA_KEY_CALLS_SYNC ){
  364. *idx = id - NETDATA_KEY_CALLS_OPEN;
  365. return &efp->hadditional;
  366. }
  367. return NULL;
  368. }
  369. /**
  370. * Read hard disk table
  371. *
  372. * @param table index for the hash table
  373. *
  374. * Read the table with number of calls for all functions
  375. */
  376. static void read_filesystem_table(ebpf_filesystem_partitions_t *efp, int fd)
  377. {
  378. netdata_idx_t *values = filesystem_hash_values;
  379. uint32_t key;
  380. uint32_t idx;
  381. for (key = 0; key < NETDATA_KEY_CALLS_SYNC; key++) {
  382. netdata_ebpf_histogram_t *w = select_hist(efp, &idx, key);
  383. if (!w) {
  384. continue;
  385. }
  386. int test = bpf_map_lookup_elem(fd, &key, values);
  387. if (test < 0) {
  388. continue;
  389. }
  390. uint64_t total = 0;
  391. int i;
  392. int end = ebpf_nprocs;
  393. for (i = 0; i < end; i++) {
  394. total += values[i];
  395. }
  396. if (idx >= NETDATA_EBPF_HIST_MAX_BINS)
  397. idx = NETDATA_EBPF_HIST_MAX_BINS - 1;
  398. w->histogram[idx] = total;
  399. }
  400. }
  401. /**
  402. * Read hard disk table
  403. *
  404. * @param table index for the hash table
  405. *
  406. * Read the table with number of calls for all functions
  407. */
  408. static void read_filesystem_tables()
  409. {
  410. int i;
  411. for (i = 0; localfs[i].filesystem; i++) {
  412. ebpf_filesystem_partitions_t *efp = &localfs[i];
  413. if (efp->flags & NETDATA_FILESYSTEM_FLAG_HAS_PARTITION) {
  414. read_filesystem_table(efp, fs_maps[i].map_fd);
  415. }
  416. }
  417. }
  418. /**
  419. * Socket read hash
  420. *
  421. * This is the thread callback.
  422. * This thread is necessary, because we cannot freeze the whole plugin to read the data on very busy socket.
  423. *
  424. * @param ptr It is a NULL value for this thread.
  425. *
  426. * @return It always returns NULL.
  427. */
  428. void *ebpf_filesystem_read_hash(void *ptr)
  429. {
  430. netdata_thread_cleanup_push(ebpf_filesystem_cleanup, ptr);
  431. ebpf_module_t *em = (ebpf_module_t *)ptr;
  432. heartbeat_t hb;
  433. heartbeat_init(&hb);
  434. usec_t step = NETDATA_FILESYSTEM_READ_SLEEP_MS * em->update_every;
  435. int update_every = em->update_every;
  436. while (ebpf_fs_exited == NETDATA_THREAD_EBPF_RUNNING) {
  437. usec_t dt = heartbeat_next(&hb, step);
  438. (void)dt;
  439. if (ebpf_fs_exited == NETDATA_THREAD_EBPF_STOPPING)
  440. break;
  441. (void) ebpf_update_partitions(em);
  442. ebpf_obsolete_fs_charts(update_every);
  443. // No more partitions, it is not necessary to read tables
  444. if (em->optional)
  445. continue;
  446. read_filesystem_tables();
  447. }
  448. ebpf_fs_exited = NETDATA_THREAD_EBPF_STOPPED;
  449. netdata_thread_cleanup_pop(1);
  450. return NULL;
  451. }
  452. /**
  453. * Send Hard disk data
  454. *
  455. * Send hard disk information to Netdata.
  456. */
  457. static void ebpf_histogram_send_data()
  458. {
  459. uint32_t i;
  460. uint32_t test = NETDATA_FILESYSTEM_FLAG_HAS_PARTITION | NETDATA_FILESYSTEM_REMOVE_CHARTS;
  461. for (i = 0; localfs[i].filesystem; i++) {
  462. ebpf_filesystem_partitions_t *efp = &localfs[i];
  463. if ((efp->flags & test) == NETDATA_FILESYSTEM_FLAG_HAS_PARTITION) {
  464. write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hread.name,
  465. efp->hread.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  466. write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hwrite.name,
  467. efp->hwrite.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  468. write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hopen.name,
  469. efp->hopen.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  470. write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hadditional.name,
  471. efp->hadditional.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  472. }
  473. }
  474. }
  475. /**
  476. * Main loop for this collector.
  477. *
  478. * @param em main structure for this thread
  479. */
  480. static void filesystem_collector(ebpf_module_t *em)
  481. {
  482. filesystem_threads.thread = mallocz(sizeof(netdata_thread_t));
  483. filesystem_threads.start_routine = ebpf_filesystem_read_hash;
  484. netdata_thread_create(filesystem_threads.thread, filesystem_threads.name,
  485. NETDATA_THREAD_OPTION_DEFAULT, ebpf_filesystem_read_hash, em);
  486. int update_every = em->update_every;
  487. heartbeat_t hb;
  488. heartbeat_init(&hb);
  489. usec_t step = update_every * USEC_PER_SEC;
  490. while (!ebpf_exit_plugin) {
  491. (void)heartbeat_next(&hb, step);
  492. if (ebpf_exit_plugin)
  493. break;
  494. pthread_mutex_lock(&lock);
  495. ebpf_create_fs_charts(update_every);
  496. ebpf_histogram_send_data();
  497. pthread_mutex_unlock(&lock);
  498. }
  499. }
  500. /*****************************************************************
  501. *
  502. * ENTRY THREAD
  503. *
  504. *****************************************************************/
  505. /**
  506. * Update Filesystem
  507. *
  508. * Update file system structure using values read from configuration file.
  509. */
  510. static void ebpf_update_filesystem()
  511. {
  512. char dist[NETDATA_FS_MAX_DIST_NAME + 1];
  513. int i;
  514. for (i = 0; localfs[i].filesystem; i++) {
  515. snprintfz(dist, NETDATA_FS_MAX_DIST_NAME, "%sdist", localfs[i].filesystem);
  516. localfs[i].enabled = appconfig_get_boolean(&fs_config, NETDATA_FILESYSTEM_CONFIG_NAME, dist,
  517. CONFIG_BOOLEAN_YES);
  518. }
  519. }
  520. /**
  521. * Filesystem thread
  522. *
  523. * Thread used to generate socket charts.
  524. *
  525. * @param ptr a pointer to `struct ebpf_module`
  526. *
  527. * @return It always return NULL
  528. */
  529. void *ebpf_filesystem_thread(void *ptr)
  530. {
  531. netdata_thread_cleanup_push(ebpf_filesystem_exit, ptr);
  532. ebpf_module_t *em = (ebpf_module_t *)ptr;
  533. em->maps = fs_maps;
  534. ebpf_update_filesystem();
  535. if (!em->enabled)
  536. goto endfilesystem;
  537. // Initialize optional as zero, to identify when there are not partitions to monitor
  538. em->optional = 0;
  539. if (ebpf_update_partitions(em)) {
  540. if (em->optional)
  541. info("Netdata cannot monitor the filesystems used on this host.");
  542. em->enabled = CONFIG_BOOLEAN_NO;
  543. goto endfilesystem;
  544. }
  545. int algorithms[NETDATA_EBPF_HIST_MAX_BINS];
  546. ebpf_fill_algorithms(algorithms, NETDATA_EBPF_HIST_MAX_BINS, NETDATA_EBPF_INCREMENTAL_IDX);
  547. ebpf_global_labels(filesystem_aggregated_data, filesystem_publish_aggregated, dimensions, dimensions,
  548. algorithms, NETDATA_EBPF_HIST_MAX_BINS);
  549. pthread_mutex_lock(&lock);
  550. ebpf_create_fs_charts(em->update_every);
  551. ebpf_update_stats(&plugin_statistics, em);
  552. pthread_mutex_unlock(&lock);
  553. filesystem_collector(em);
  554. endfilesystem:
  555. if (!em->enabled)
  556. ebpf_update_disabled_plugin_stats(em);
  557. netdata_thread_cleanup_pop(1);
  558. return NULL;
  559. }