ebpf_filesystem.c 22 KB

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