ebpf_filesystem.c 20 KB

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