ebpf_filesystem.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  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. static netdata_syscall_stat_t filesystem_aggregated_data[NETDATA_EBPF_HIST_MAX_BINS];
  30. static netdata_publish_syscall_t filesystem_publish_aggregated[NETDATA_EBPF_HIST_MAX_BINS];
  31. char **dimensions = NULL;
  32. static netdata_idx_t *filesystem_hash_values = NULL;
  33. /*****************************************************************
  34. *
  35. * COMMON FUNCTIONS
  36. *
  37. *****************************************************************/
  38. /**
  39. * Create Filesystem chart
  40. *
  41. * Create latency charts
  42. *
  43. * @param update_every value to overwrite the update frequency set by the server.
  44. */
  45. static void ebpf_obsolete_fs_charts(int update_every)
  46. {
  47. int i;
  48. uint32_t test = NETDATA_FILESYSTEM_FLAG_CHART_CREATED | NETDATA_FILESYSTEM_REMOVE_CHARTS;
  49. for (i = 0; localfs[i].filesystem; i++) {
  50. ebpf_filesystem_partitions_t *efp = &localfs[i];
  51. uint32_t flags = efp->flags;
  52. if ((flags & test) == test) {
  53. flags &= ~NETDATA_FILESYSTEM_FLAG_CHART_CREATED;
  54. ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hread.name,
  55. efp->hread.title,
  56. EBPF_COMMON_DIMENSION_CALL, efp->family_name,
  57. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hread.order, update_every);
  58. ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hwrite.name,
  59. efp->hwrite.title,
  60. EBPF_COMMON_DIMENSION_CALL, efp->family_name,
  61. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hwrite.order, update_every);
  62. ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hopen.name, efp->hopen.title,
  63. EBPF_COMMON_DIMENSION_CALL, efp->family_name,
  64. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hopen.order, update_every);
  65. ebpf_write_chart_obsolete(NETDATA_FILESYSTEM_FAMILY, efp->hadditional.name, efp->hadditional.title,
  66. EBPF_COMMON_DIMENSION_CALL, efp->family_name,
  67. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, efp->hadditional.order,
  68. update_every);
  69. }
  70. efp->flags = flags;
  71. }
  72. }
  73. /**
  74. * Create Filesystem chart
  75. *
  76. * Create latency charts
  77. *
  78. * @param update_every value to overwrite the update frequency set by the server.
  79. */
  80. static void ebpf_create_fs_charts(int update_every)
  81. {
  82. static int order = NETDATA_CHART_PRIO_EBPF_FILESYSTEM_CHARTS;
  83. char chart_name[64], title[256], family[64];
  84. int i;
  85. uint32_t test = NETDATA_FILESYSTEM_FLAG_CHART_CREATED|NETDATA_FILESYSTEM_REMOVE_CHARTS;
  86. for (i = 0; localfs[i].filesystem; i++) {
  87. ebpf_filesystem_partitions_t *efp = &localfs[i];
  88. uint32_t flags = efp->flags;
  89. if (flags & NETDATA_FILESYSTEM_FLAG_HAS_PARTITION && !(flags & test)) {
  90. snprintfz(title, 255, "%s latency for each read request.", efp->filesystem);
  91. snprintfz(family, 63, "%s_latency", efp->family);
  92. snprintfz(chart_name, 63, "%s_read_latency", efp->filesystem);
  93. efp->hread.name = strdupz(chart_name);
  94. efp->hread.title = strdupz(title);
  95. efp->hread.order = order;
  96. efp->family_name = strdupz(family);
  97. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hread.name,
  98. title,
  99. EBPF_COMMON_DIMENSION_CALL, family,
  100. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
  101. filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
  102. update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
  103. order++;
  104. snprintfz(title, 255, "%s latency for each write request.", efp->filesystem);
  105. snprintfz(chart_name, 63, "%s_write_latency", efp->filesystem);
  106. efp->hwrite.name = strdupz(chart_name);
  107. efp->hwrite.title = strdupz(title);
  108. efp->hwrite.order = order;
  109. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hwrite.name,
  110. title,
  111. EBPF_COMMON_DIMENSION_CALL, family,
  112. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
  113. filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
  114. update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
  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_EBPF_HIST_MAX_BINS,
  126. update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
  127. order++;
  128. char *type = (efp->flags & NETDATA_FILESYSTEM_ATTR_CHARTS) ? "attribute" : "sync";
  129. snprintfz(title, 255, "%s latency for each %s request.", efp->filesystem, type);
  130. snprintfz(chart_name, 63, "%s_%s_latency", efp->filesystem, type);
  131. efp->hadditional.name = strdupz(chart_name);
  132. efp->hadditional.title = strdupz(title);
  133. efp->hadditional.order = order;
  134. ebpf_create_chart(NETDATA_FILESYSTEM_FAMILY, efp->hadditional.name, title,
  135. EBPF_COMMON_DIMENSION_CALL, family,
  136. NULL, NETDATA_EBPF_CHART_TYPE_STACKED, order, ebpf_create_global_dimension,
  137. filesystem_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
  138. update_every, NETDATA_EBPF_MODULE_NAME_FILESYSTEM);
  139. order++;
  140. efp->flags |= NETDATA_FILESYSTEM_FLAG_CHART_CREATED;
  141. }
  142. }
  143. }
  144. /**
  145. * Initialize eBPF data
  146. *
  147. * @param em main thread structure.
  148. *
  149. * @return it returns 0 on success and -1 otherwise.
  150. */
  151. int ebpf_filesystem_initialize_ebpf_data(ebpf_module_t *em)
  152. {
  153. int i;
  154. const char *saved_name = em->thread_name;
  155. uint64_t kernels = em->kernels;
  156. for (i = 0; localfs[i].filesystem; i++) {
  157. ebpf_filesystem_partitions_t *efp = &localfs[i];
  158. if (!efp->probe_links && efp->flags & NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM) {
  159. em->thread_name = efp->filesystem;
  160. em->kernels = efp->kernels;
  161. efp->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &efp->objects);
  162. if (!efp->probe_links) {
  163. em->thread_name = saved_name;
  164. em->kernels = kernels;
  165. return -1;
  166. }
  167. efp->flags |= NETDATA_FILESYSTEM_FLAG_HAS_PARTITION;
  168. // Nedeed for filesystems like btrfs
  169. if ((efp->flags & NETDATA_FILESYSTEM_FILL_ADDRESS_TABLE) && (efp->addresses.function)) {
  170. ebpf_load_addresses(&efp->addresses, fs_maps[i + 1].map_fd);
  171. }
  172. }
  173. efp->flags &= ~NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM;
  174. }
  175. em->thread_name = saved_name;
  176. em->kernels = kernels;
  177. if (!dimensions) {
  178. dimensions = ebpf_fill_histogram_dimension(NETDATA_EBPF_HIST_MAX_BINS);
  179. memset(filesystem_aggregated_data, 0 , NETDATA_EBPF_HIST_MAX_BINS * sizeof(netdata_syscall_stat_t));
  180. memset(filesystem_publish_aggregated, 0 , NETDATA_EBPF_HIST_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. (w->optional_filesystem && !strcmp(fs, w->optional_filesystem)))) {
  218. localfs[i].flags |= NETDATA_FILESYSTEM_LOAD_EBPF_PROGRAM;
  219. localfs[i].flags &= ~NETDATA_FILESYSTEM_REMOVE_CHARTS;
  220. count++;
  221. break;
  222. }
  223. }
  224. }
  225. procfile_close(ff);
  226. return count;
  227. }
  228. /**
  229. * Update partition
  230. *
  231. * Update the partition structures before to plot
  232. *
  233. * @param em main thread structure
  234. *
  235. * @return 0 on success and -1 otherwise.
  236. */
  237. static int ebpf_update_partitions(ebpf_module_t *em)
  238. {
  239. static time_t update_every = 0;
  240. time_t curr = now_realtime_sec();
  241. if (curr < update_every)
  242. return 0;
  243. update_every = curr + 5 * em->update_every;
  244. if (!ebpf_read_local_partitions()) {
  245. em->optional = -1;
  246. return -1;
  247. }
  248. if (ebpf_filesystem_initialize_ebpf_data(em)) {
  249. return -1;
  250. }
  251. return 0;
  252. }
  253. /*****************************************************************
  254. *
  255. * CLEANUP FUNCTIONS
  256. *
  257. *****************************************************************/
  258. /*
  259. * Cleanup eBPF data
  260. */
  261. void ebpf_filesystem_cleanup_ebpf_data()
  262. {
  263. int i;
  264. for (i = 0; localfs[i].filesystem; i++) {
  265. ebpf_filesystem_partitions_t *efp = &localfs[i];
  266. if (efp->probe_links) {
  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->hadditional.name);
  275. freez(efp->hadditional.title);
  276. }
  277. }
  278. }
  279. /**
  280. * Filesystem Free
  281. *
  282. * Cleanup variables after child threads to stop
  283. *
  284. * @param ptr thread data.
  285. */
  286. static void ebpf_filesystem_free(ebpf_module_t *em)
  287. {
  288. pthread_mutex_lock(&ebpf_exit_cleanup);
  289. em->thread->enabled = NETDATA_THREAD_EBPF_STOPPING;
  290. pthread_mutex_unlock(&ebpf_exit_cleanup);
  291. ebpf_cleanup_publish_syscall(filesystem_publish_aggregated);
  292. ebpf_filesystem_cleanup_ebpf_data();
  293. if (dimensions)
  294. ebpf_histogram_dimension_cleanup(dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  295. freez(filesystem_hash_values);
  296. pthread_mutex_lock(&ebpf_exit_cleanup);
  297. em->thread->enabled = NETDATA_THREAD_EBPF_STOPPED;
  298. pthread_mutex_unlock(&ebpf_exit_cleanup);
  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. ebpf_filesystem_free(em);
  311. }
  312. /*****************************************************************
  313. *
  314. * MAIN THREAD
  315. *
  316. *****************************************************************/
  317. /**
  318. * Select hist
  319. *
  320. * Select a histogram to store data.
  321. *
  322. * @param efp pointer for the structure with pointers.
  323. * @param id histogram selector
  324. *
  325. * @return It returns a pointer for the histogram
  326. */
  327. static inline netdata_ebpf_histogram_t *select_hist(ebpf_filesystem_partitions_t *efp, uint32_t *idx, uint32_t id)
  328. {
  329. if (id < NETDATA_KEY_CALLS_READ) {
  330. *idx = id;
  331. return &efp->hread;
  332. } else if (id < NETDATA_KEY_CALLS_WRITE) {
  333. *idx = id - NETDATA_KEY_CALLS_READ;
  334. return &efp->hwrite;
  335. } else if (id < NETDATA_KEY_CALLS_OPEN) {
  336. *idx = id - NETDATA_KEY_CALLS_WRITE;
  337. return &efp->hopen;
  338. } else if (id < NETDATA_KEY_CALLS_SYNC ){
  339. *idx = id - NETDATA_KEY_CALLS_OPEN;
  340. return &efp->hadditional;
  341. }
  342. return NULL;
  343. }
  344. /**
  345. * Read hard disk table
  346. *
  347. * @param table index for the hash table
  348. *
  349. * Read the table with number of calls for all functions
  350. */
  351. static void read_filesystem_table(ebpf_filesystem_partitions_t *efp, int fd)
  352. {
  353. netdata_idx_t *values = filesystem_hash_values;
  354. uint32_t key;
  355. uint32_t idx;
  356. for (key = 0; key < NETDATA_KEY_CALLS_SYNC; key++) {
  357. netdata_ebpf_histogram_t *w = select_hist(efp, &idx, key);
  358. if (!w) {
  359. continue;
  360. }
  361. int test = bpf_map_lookup_elem(fd, &key, values);
  362. if (test < 0) {
  363. continue;
  364. }
  365. uint64_t total = 0;
  366. int i;
  367. int end = ebpf_nprocs;
  368. for (i = 0; i < end; i++) {
  369. total += values[i];
  370. }
  371. if (idx >= NETDATA_EBPF_HIST_MAX_BINS)
  372. idx = NETDATA_EBPF_HIST_MAX_BINS - 1;
  373. w->histogram[idx] = total;
  374. }
  375. }
  376. /**
  377. * Read hard disk table
  378. *
  379. * @param table index for the hash table
  380. *
  381. * Read the table with number of calls for all functions
  382. */
  383. static void read_filesystem_tables()
  384. {
  385. int i;
  386. for (i = 0; localfs[i].filesystem; i++) {
  387. ebpf_filesystem_partitions_t *efp = &localfs[i];
  388. if (efp->flags & NETDATA_FILESYSTEM_FLAG_HAS_PARTITION) {
  389. read_filesystem_table(efp, fs_maps[i].map_fd);
  390. }
  391. }
  392. }
  393. /**
  394. * Socket read hash
  395. *
  396. * This is the thread callback.
  397. * This thread is necessary, because we cannot freeze the whole plugin to read the data on very busy socket.
  398. *
  399. * @param ptr It is a NULL value for this thread.
  400. *
  401. * @return It always returns NULL.
  402. */
  403. void ebpf_filesystem_read_hash(ebpf_module_t *em)
  404. {
  405. ebpf_obsolete_fs_charts(em->update_every);
  406. (void) ebpf_update_partitions(em);
  407. if (em->optional)
  408. return;
  409. read_filesystem_tables();
  410. }
  411. /**
  412. * Send Hard disk data
  413. *
  414. * Send hard disk information to Netdata.
  415. */
  416. static void ebpf_histogram_send_data()
  417. {
  418. uint32_t i;
  419. uint32_t test = NETDATA_FILESYSTEM_FLAG_HAS_PARTITION | NETDATA_FILESYSTEM_REMOVE_CHARTS;
  420. for (i = 0; localfs[i].filesystem; i++) {
  421. ebpf_filesystem_partitions_t *efp = &localfs[i];
  422. if ((efp->flags & test) == NETDATA_FILESYSTEM_FLAG_HAS_PARTITION) {
  423. write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hread.name,
  424. efp->hread.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  425. write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hwrite.name,
  426. efp->hwrite.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  427. write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hopen.name,
  428. efp->hopen.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  429. write_histogram_chart(NETDATA_FILESYSTEM_FAMILY, efp->hadditional.name,
  430. efp->hadditional.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  431. }
  432. }
  433. }
  434. /**
  435. * Main loop for this collector.
  436. *
  437. * @param em main structure for this thread
  438. */
  439. static void filesystem_collector(ebpf_module_t *em)
  440. {
  441. int update_every = em->update_every;
  442. heartbeat_t hb;
  443. heartbeat_init(&hb);
  444. int counter = update_every - 1;
  445. while (!ebpf_exit_plugin) {
  446. (void)heartbeat_next(&hb, USEC_PER_SEC);
  447. if (ebpf_exit_plugin || ++counter != update_every)
  448. continue;
  449. counter = 0;
  450. ebpf_filesystem_read_hash(em);
  451. pthread_mutex_lock(&lock);
  452. ebpf_create_fs_charts(update_every);
  453. ebpf_histogram_send_data();
  454. pthread_mutex_unlock(&lock);
  455. }
  456. }
  457. /*****************************************************************
  458. *
  459. * ENTRY THREAD
  460. *
  461. *****************************************************************/
  462. /**
  463. * Update Filesystem
  464. *
  465. * Update file system structure using values read from configuration file.
  466. */
  467. static void ebpf_update_filesystem()
  468. {
  469. char dist[NETDATA_FS_MAX_DIST_NAME + 1];
  470. int i;
  471. for (i = 0; localfs[i].filesystem; i++) {
  472. snprintfz(dist, NETDATA_FS_MAX_DIST_NAME, "%sdist", localfs[i].filesystem);
  473. localfs[i].enabled = appconfig_get_boolean(&fs_config, NETDATA_FILESYSTEM_CONFIG_NAME, dist,
  474. CONFIG_BOOLEAN_YES);
  475. }
  476. }
  477. /**
  478. * Filesystem thread
  479. *
  480. * Thread used to generate socket charts.
  481. *
  482. * @param ptr a pointer to `struct ebpf_module`
  483. *
  484. * @return It always return NULL
  485. */
  486. void *ebpf_filesystem_thread(void *ptr)
  487. {
  488. netdata_thread_cleanup_push(ebpf_filesystem_exit, ptr);
  489. ebpf_module_t *em = (ebpf_module_t *)ptr;
  490. em->maps = fs_maps;
  491. ebpf_update_filesystem();
  492. // Initialize optional as zero, to identify when there are not partitions to monitor
  493. em->optional = 0;
  494. if (ebpf_update_partitions(em)) {
  495. if (em->optional)
  496. info("Netdata cannot monitor the filesystems used on this host.");
  497. em->thread->enabled = NETDATA_THREAD_EBPF_STOPPED;
  498. goto endfilesystem;
  499. }
  500. int algorithms[NETDATA_EBPF_HIST_MAX_BINS];
  501. ebpf_fill_algorithms(algorithms, NETDATA_EBPF_HIST_MAX_BINS, NETDATA_EBPF_INCREMENTAL_IDX);
  502. ebpf_global_labels(filesystem_aggregated_data, filesystem_publish_aggregated, dimensions, dimensions,
  503. algorithms, NETDATA_EBPF_HIST_MAX_BINS);
  504. pthread_mutex_lock(&lock);
  505. ebpf_create_fs_charts(em->update_every);
  506. ebpf_update_stats(&plugin_statistics, em);
  507. pthread_mutex_unlock(&lock);
  508. filesystem_collector(em);
  509. endfilesystem:
  510. ebpf_update_disabled_plugin_stats(em);
  511. netdata_thread_cleanup_pop(1);
  512. return NULL;
  513. }