ebpf_filesystem.c 23 KB

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