ebpf_filesystem.c 24 KB

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