ebpf_filesystem.c 26 KB

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