ebpf_disk.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include <sys/resource.h>
  3. #include <stdlib.h>
  4. #include "ebpf.h"
  5. #include "ebpf_disk.h"
  6. struct config disk_config = { .first_section = NULL,
  7. .last_section = NULL,
  8. .mutex = NETDATA_MUTEX_INITIALIZER,
  9. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  10. .rwlock = AVL_LOCK_INITIALIZER } };
  11. static ebpf_local_maps_t disk_maps[] = {{.name = "tbl_disk_iocall", .internal_input = NETDATA_DISK_HISTOGRAM_LENGTH,
  12. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  13. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED},
  14. {.name = NULL, .internal_input = 0, .user_input = 0,
  15. .type = NETDATA_EBPF_MAP_CONTROLLER,
  16. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED}};
  17. static avl_tree_lock disk_tree;
  18. netdata_ebpf_disks_t *disk_list = NULL;
  19. char *tracepoint_block_type = { "block"} ;
  20. char *tracepoint_block_issue = { "block_rq_issue" };
  21. char *tracepoint_block_rq_complete = { "block_rq_complete" };
  22. static int was_block_issue_enabled = 0;
  23. static int was_block_rq_complete_enabled = 0;
  24. static char **dimensions = NULL;
  25. static netdata_syscall_stat_t disk_aggregated_data[NETDATA_EBPF_HIST_MAX_BINS];
  26. static netdata_publish_syscall_t disk_publish_aggregated[NETDATA_EBPF_HIST_MAX_BINS];
  27. static netdata_idx_t *disk_hash_values = NULL;
  28. ebpf_publish_disk_t *plot_disks = NULL;
  29. pthread_mutex_t plot_mutex;
  30. /*****************************************************************
  31. *
  32. * FUNCTIONS TO MANIPULATE HARD DISKS
  33. *
  34. *****************************************************************/
  35. /**
  36. * Parse start
  37. *
  38. * Parse start address of disk
  39. *
  40. * @param w structure where data is stored
  41. * @param filename variable used to store value
  42. *
  43. * @return It returns 0 on success and -1 otherwise
  44. */
  45. static inline int ebpf_disk_parse_start(netdata_ebpf_disks_t *w, char *filename)
  46. {
  47. char content[FILENAME_MAX + 1];
  48. int fd = open(filename, O_RDONLY, 0);
  49. if (fd < 0) {
  50. return -1;
  51. }
  52. ssize_t file_length = read(fd, content, 4095);
  53. if (file_length > 0) {
  54. if (file_length > FILENAME_MAX)
  55. file_length = FILENAME_MAX;
  56. content[file_length] = '\0';
  57. w->start = strtoul(content, NULL, 10);
  58. }
  59. close(fd);
  60. return 0;
  61. }
  62. /**
  63. * Parse uevent
  64. *
  65. * Parse uevent file
  66. *
  67. * @param w structure where data is stored
  68. * @param filename variable used to store value
  69. *
  70. * @return It returns 0 on success and -1 otherwise
  71. */
  72. static inline int ebpf_parse_uevent(netdata_ebpf_disks_t *w, char *filename)
  73. {
  74. char content[FILENAME_MAX + 1];
  75. int fd = open(filename, O_RDONLY, 0);
  76. if (fd < 0) {
  77. return -1;
  78. }
  79. ssize_t file_length = read(fd, content, FILENAME_MAX);
  80. if (file_length > 0) {
  81. if (file_length > FILENAME_MAX)
  82. file_length = FILENAME_MAX;
  83. content[file_length] = '\0';
  84. char *s = strstr(content, "PARTNAME=EFI");
  85. if (s) {
  86. w->main->boot_partition = w;
  87. w->flags |= NETDATA_DISK_HAS_EFI;
  88. w->boot_chart = strdupz("disk_bootsector");
  89. }
  90. }
  91. close(fd);
  92. return 0;
  93. }
  94. /**
  95. * Parse Size
  96. *
  97. * @param w structure where data is stored
  98. * @param filename variable used to store value
  99. *
  100. * @return It returns 0 on success and -1 otherwise
  101. */
  102. static inline int ebpf_parse_size(netdata_ebpf_disks_t *w, char *filename)
  103. {
  104. char content[FILENAME_MAX + 1];
  105. int fd = open(filename, O_RDONLY, 0);
  106. if (fd < 0) {
  107. return -1;
  108. }
  109. ssize_t file_length = read(fd, content, FILENAME_MAX);
  110. if (file_length > 0) {
  111. if (file_length > FILENAME_MAX)
  112. file_length = FILENAME_MAX;
  113. content[file_length] = '\0';
  114. w->end = w->start + strtoul(content, NULL, 10) -1;
  115. }
  116. close(fd);
  117. return 0;
  118. }
  119. /**
  120. * Read Disk information
  121. *
  122. * Read disk information from /sys/block
  123. *
  124. * @param w structure where data is stored
  125. * @param name disk name
  126. */
  127. static void ebpf_read_disk_info(netdata_ebpf_disks_t *w, char *name)
  128. {
  129. static netdata_ebpf_disks_t *main_disk = NULL;
  130. static uint32_t key = 0;
  131. char *path = { "/sys/block" };
  132. char disk[NETDATA_DISK_NAME_LEN + 1];
  133. char filename[FILENAME_MAX + 1];
  134. snprintfz(disk, NETDATA_DISK_NAME_LEN, "%s", name);
  135. size_t length = strlen(disk);
  136. if (!length) {
  137. return;
  138. }
  139. length--;
  140. size_t curr = length;
  141. while (isdigit((int)disk[length])) {
  142. disk[length--] = '\0';
  143. }
  144. // We are looking for partition information, if it is a device we will ignore it.
  145. if (curr == length) {
  146. main_disk = w;
  147. key = MKDEV(w->major, w->minor);
  148. w->bootsector_key = key;
  149. return;
  150. }
  151. w->bootsector_key = key;
  152. w->main = main_disk;
  153. snprintfz(filename, FILENAME_MAX, "%s/%s/%s/uevent", path, disk, name);
  154. if (ebpf_parse_uevent(w, filename))
  155. return;
  156. snprintfz(filename, FILENAME_MAX, "%s/%s/%s/start", path, disk, name);
  157. if (ebpf_disk_parse_start(w, filename))
  158. return;
  159. snprintfz(filename, FILENAME_MAX, "%s/%s/%s/size", path, disk, name);
  160. ebpf_parse_size(w, filename);
  161. }
  162. /**
  163. * New encode dev
  164. *
  165. * New encode algorithm extracted from https://elixir.bootlin.com/linux/v5.10.8/source/include/linux/kdev_t.h#L39
  166. *
  167. * @param major driver major number
  168. * @param minor driver minor number
  169. *
  170. * @return
  171. */
  172. static inline uint32_t netdata_new_encode_dev(uint32_t major, uint32_t minor) {
  173. return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
  174. }
  175. /**
  176. * Compare disks
  177. *
  178. * Compare major and minor values to add disks to tree.
  179. *
  180. * @param a pointer to netdata_ebpf_disks
  181. * @param b pointer to netdata_ebpf_disks
  182. *
  183. * @return It returns 0 case the values are equal, 1 case a is bigger than b and -1 case a is smaller than b.
  184. */
  185. static int ebpf_compare_disks(void *a, void *b)
  186. {
  187. netdata_ebpf_disks_t *ptr1 = a;
  188. netdata_ebpf_disks_t *ptr2 = b;
  189. if (ptr1->dev > ptr2->dev)
  190. return 1;
  191. if (ptr1->dev < ptr2->dev)
  192. return -1;
  193. return 0;
  194. }
  195. /**
  196. * Update listen table
  197. *
  198. * Update link list when it is necessary.
  199. *
  200. * @param name disk name
  201. * @param major major disk identifier
  202. * @param minor minor disk identifier
  203. * @param current_time current timestamp
  204. */
  205. static void update_disk_table(char *name, int major, int minor, time_t current_time)
  206. {
  207. netdata_ebpf_disks_t find;
  208. netdata_ebpf_disks_t *w;
  209. size_t length;
  210. uint32_t dev = netdata_new_encode_dev(major, minor);
  211. find.dev = dev;
  212. netdata_ebpf_disks_t *ret = (netdata_ebpf_disks_t *) avl_search_lock(&disk_tree, (avl_t *)&find);
  213. if (ret) { // Disk is already present
  214. ret->flags |= NETDATA_DISK_IS_HERE;
  215. ret->last_update = current_time;
  216. return;
  217. }
  218. netdata_ebpf_disks_t *update_next = disk_list;
  219. if (likely(disk_list)) {
  220. netdata_ebpf_disks_t *move = disk_list;
  221. while (move) {
  222. if (dev == move->dev)
  223. return;
  224. update_next = move;
  225. move = move->next;
  226. }
  227. w = callocz(1, sizeof(netdata_ebpf_disks_t));
  228. length = strlen(name);
  229. if (length >= NETDATA_DISK_NAME_LEN)
  230. length = NETDATA_DISK_NAME_LEN;
  231. memcpy(w->family, name, length);
  232. w->family[length] = '\0';
  233. w->major = major;
  234. w->minor = minor;
  235. w->dev = netdata_new_encode_dev(major, minor);
  236. update_next->next = w;
  237. } else {
  238. disk_list = callocz(1, sizeof(netdata_ebpf_disks_t));
  239. length = strlen(name);
  240. if (length >= NETDATA_DISK_NAME_LEN)
  241. length = NETDATA_DISK_NAME_LEN;
  242. memcpy(disk_list->family, name, length);
  243. disk_list->family[length] = '\0';
  244. disk_list->major = major;
  245. disk_list->minor = minor;
  246. disk_list->dev = netdata_new_encode_dev(major, minor);
  247. w = disk_list;
  248. }
  249. ebpf_read_disk_info(w, name);
  250. netdata_ebpf_disks_t *check;
  251. check = (netdata_ebpf_disks_t *) avl_insert_lock(&disk_tree, (avl_t *)w);
  252. if (check != w)
  253. error("Internal error, cannot insert the AVL tree.");
  254. #ifdef NETDATA_INTERNAL_CHECKS
  255. info("The Latency is monitoring the hard disk %s (Major = %d, Minor = %d, Device = %u)", name, major, minor,w->dev);
  256. #endif
  257. w->flags |= NETDATA_DISK_IS_HERE;
  258. }
  259. /**
  260. * Read Local Disks
  261. *
  262. * Parse /proc/partitions to get block disks used to measure latency.
  263. *
  264. * @return It returns 0 on success and -1 otherwise
  265. */
  266. static int read_local_disks()
  267. {
  268. char filename[FILENAME_MAX + 1];
  269. snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, NETDATA_EBPF_PROC_PARTITIONS);
  270. procfile *ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
  271. if (!ff)
  272. return -1;
  273. ff = procfile_readall(ff);
  274. if (!ff)
  275. return -1;
  276. size_t lines = procfile_lines(ff), l;
  277. time_t current_time = now_realtime_sec();
  278. for(l = 2; l < lines ;l++) {
  279. size_t words = procfile_linewords(ff, l);
  280. // This is header or end of file
  281. if (unlikely(words < 4))
  282. continue;
  283. int major = (int)strtol(procfile_lineword(ff, l, 0), NULL, 10);
  284. // The main goal of this thread is to measure block devices, so any block device with major number
  285. // smaller than 7 according /proc/devices is not "important".
  286. if (major > 7) {
  287. int minor = (int)strtol(procfile_lineword(ff, l, 1), NULL, 10);
  288. update_disk_table(procfile_lineword(ff, l, 3), major, minor, current_time);
  289. }
  290. }
  291. procfile_close(ff);
  292. return 0;
  293. }
  294. /**
  295. * Update disks
  296. *
  297. * @param em main thread structure
  298. */
  299. void ebpf_update_disks(ebpf_module_t *em)
  300. {
  301. static time_t update_every = 0;
  302. time_t curr = now_realtime_sec();
  303. if (curr < update_every)
  304. return;
  305. update_every = curr + 5 * em->update_every;
  306. (void)read_local_disks();
  307. }
  308. /*****************************************************************
  309. *
  310. * FUNCTIONS TO CLOSE THE THREAD
  311. *
  312. *****************************************************************/
  313. /**
  314. * Disk disable tracepoints
  315. *
  316. * Disable tracepoints when the plugin was responsible to enable it.
  317. */
  318. static void ebpf_disk_disable_tracepoints()
  319. {
  320. char *default_message = { "Cannot disable the tracepoint" };
  321. if (!was_block_issue_enabled) {
  322. if (ebpf_disable_tracing_values(tracepoint_block_type, tracepoint_block_issue))
  323. error("%s %s/%s.", default_message, tracepoint_block_type, tracepoint_block_issue);
  324. }
  325. if (!was_block_rq_complete_enabled) {
  326. if (ebpf_disable_tracing_values(tracepoint_block_type, tracepoint_block_rq_complete))
  327. error("%s %s/%s.", default_message, tracepoint_block_type, tracepoint_block_rq_complete);
  328. }
  329. }
  330. /**
  331. * Cleanup plot disks
  332. *
  333. * Clean disk list
  334. */
  335. static void ebpf_cleanup_plot_disks()
  336. {
  337. ebpf_publish_disk_t *move = plot_disks, *next;
  338. while (move) {
  339. next = move->next;
  340. freez(move);
  341. move = next;
  342. }
  343. }
  344. /**
  345. * Cleanup Disk List
  346. */
  347. static void ebpf_cleanup_disk_list()
  348. {
  349. netdata_ebpf_disks_t *move = disk_list;
  350. while (move) {
  351. netdata_ebpf_disks_t *next = move->next;
  352. freez(move->histogram.name);
  353. freez(move->boot_chart);
  354. freez(move);
  355. move = next;
  356. }
  357. }
  358. /**
  359. * DISK Free
  360. *
  361. * Cleanup variables after child threads to stop
  362. *
  363. * @param ptr thread data.
  364. */
  365. static void ebpf_disk_free(ebpf_module_t *em)
  366. {
  367. pthread_mutex_lock(&ebpf_exit_cleanup);
  368. em->enabled = NETDATA_THREAD_EBPF_STOPPING;
  369. pthread_mutex_unlock(&ebpf_exit_cleanup);
  370. ebpf_disk_disable_tracepoints();
  371. if (dimensions)
  372. ebpf_histogram_dimension_cleanup(dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  373. freez(disk_hash_values);
  374. pthread_mutex_destroy(&plot_mutex);
  375. ebpf_cleanup_plot_disks();
  376. ebpf_cleanup_disk_list();
  377. pthread_mutex_lock(&ebpf_exit_cleanup);
  378. em->enabled = NETDATA_THREAD_EBPF_STOPPED;
  379. pthread_mutex_unlock(&ebpf_exit_cleanup);
  380. }
  381. /**
  382. * Disk exit.
  383. *
  384. * Cancel child and exit.
  385. *
  386. * @param ptr thread data.
  387. */
  388. static void ebpf_disk_exit(void *ptr)
  389. {
  390. ebpf_module_t *em = (ebpf_module_t *)ptr;
  391. ebpf_disk_free(em);
  392. }
  393. /*****************************************************************
  394. *
  395. * MAIN LOOP
  396. *
  397. *****************************************************************/
  398. /**
  399. * Fill Plot list
  400. *
  401. * @param ptr a pointer for current disk
  402. */
  403. static void ebpf_fill_plot_disks(netdata_ebpf_disks_t *ptr)
  404. {
  405. pthread_mutex_lock(&plot_mutex);
  406. ebpf_publish_disk_t *w;
  407. if (likely(plot_disks)) {
  408. ebpf_publish_disk_t *move = plot_disks, *store = plot_disks;
  409. while (move) {
  410. if (move->plot == ptr) {
  411. pthread_mutex_unlock(&plot_mutex);
  412. return;
  413. }
  414. store = move;
  415. move = move->next;
  416. }
  417. w = callocz(1, sizeof(ebpf_publish_disk_t));
  418. w->plot = ptr;
  419. store->next = w;
  420. } else {
  421. plot_disks = callocz(1, sizeof(ebpf_publish_disk_t));
  422. plot_disks->plot = ptr;
  423. }
  424. pthread_mutex_unlock(&plot_mutex);
  425. ptr->flags |= NETDATA_DISK_ADDED_TO_PLOT_LIST;
  426. }
  427. /**
  428. * Read hard disk table
  429. *
  430. * @param table file descriptor for table
  431. *
  432. * Read the table with number of calls for all functions
  433. */
  434. static void read_hard_disk_tables(int table)
  435. {
  436. netdata_idx_t *values = disk_hash_values;
  437. block_key_t key = {};
  438. block_key_t next_key = {};
  439. netdata_ebpf_disks_t *ret = NULL;
  440. while (bpf_map_get_next_key(table, &key, &next_key) == 0) {
  441. int test = bpf_map_lookup_elem(table, &key, values);
  442. if (test < 0) {
  443. key = next_key;
  444. continue;
  445. }
  446. netdata_ebpf_disks_t find;
  447. find.dev = key.dev;
  448. if (likely(ret)) {
  449. if (find.dev != ret->dev)
  450. ret = (netdata_ebpf_disks_t *)avl_search_lock(&disk_tree, (avl_t *)&find);
  451. } else
  452. ret = (netdata_ebpf_disks_t *)avl_search_lock(&disk_tree, (avl_t *)&find);
  453. // Disk was inserted after we parse /proc/partitions
  454. if (!ret) {
  455. if (read_local_disks()) {
  456. key = next_key;
  457. continue;
  458. }
  459. ret = (netdata_ebpf_disks_t *)avl_search_lock(&disk_tree, (avl_t *)&find);
  460. if (!ret) {
  461. // We should never reach this point, but we are adding it to keep a safe code
  462. key = next_key;
  463. continue;
  464. }
  465. }
  466. uint64_t total = 0;
  467. int i;
  468. int end = (running_on_kernel < NETDATA_KERNEL_V4_15) ? 1 : ebpf_nprocs;
  469. for (i = 0; i < end; i++) {
  470. total += values[i];
  471. }
  472. ret->histogram.histogram[key.bin] = total;
  473. if (!(ret->flags & NETDATA_DISK_ADDED_TO_PLOT_LIST))
  474. ebpf_fill_plot_disks(ret);
  475. key = next_key;
  476. }
  477. }
  478. /**
  479. * Obsolete Hard Disk charts
  480. *
  481. * Make Hard disk charts and fill chart name
  482. *
  483. * @param w the structure with necessary information to create the chart
  484. * @param update_every value to overwrite the update frequency set by the server.
  485. */
  486. static void ebpf_obsolete_hd_charts(netdata_ebpf_disks_t *w, int update_every)
  487. {
  488. ebpf_write_chart_obsolete(w->histogram.name, w->family, w->histogram.title, EBPF_COMMON_DIMENSION_CALL,
  489. w->family, NETDATA_EBPF_CHART_TYPE_STACKED, "disk.latency_io",
  490. w->histogram.order, update_every);
  491. w->flags = 0;
  492. }
  493. /**
  494. * Create Hard Disk charts
  495. *
  496. * Make Hard disk charts and fill chart name
  497. *
  498. * @param w the structure with necessary information to create the chart
  499. * @param update_every value to overwrite the update frequency set by the server.
  500. */
  501. static void ebpf_create_hd_charts(netdata_ebpf_disks_t *w, int update_every)
  502. {
  503. int order = NETDATA_CHART_PRIO_DISK_LATENCY;
  504. char *family = w->family;
  505. w->histogram.name = strdupz("disk_latency_io");
  506. w->histogram.title = NULL;
  507. w->histogram.order = order;
  508. ebpf_create_chart(w->histogram.name, family, "Disk latency", EBPF_COMMON_DIMENSION_CALL,
  509. family, "disk.latency_io", NETDATA_EBPF_CHART_TYPE_STACKED, order,
  510. ebpf_create_global_dimension, disk_publish_aggregated, NETDATA_EBPF_HIST_MAX_BINS,
  511. update_every, NETDATA_EBPF_MODULE_NAME_DISK);
  512. order++;
  513. w->flags |= NETDATA_DISK_CHART_CREATED;
  514. }
  515. /**
  516. * Remove pointer from plot
  517. *
  518. * Remove pointer from plot list when the disk is not present.
  519. */
  520. static void ebpf_remove_pointer_from_plot_disk(ebpf_module_t *em)
  521. {
  522. time_t current_time = now_realtime_sec();
  523. time_t limit = 10 * em->update_every;
  524. pthread_mutex_lock(&plot_mutex);
  525. ebpf_publish_disk_t *move = plot_disks, *prev = plot_disks;
  526. int update_every = em->update_every;
  527. while (move) {
  528. netdata_ebpf_disks_t *ned = move->plot;
  529. uint32_t flags = ned->flags;
  530. if (!(flags & NETDATA_DISK_IS_HERE) && ((current_time - ned->last_update) > limit)) {
  531. ebpf_obsolete_hd_charts(ned, update_every);
  532. avl_t *ret = (avl_t *)avl_remove_lock(&disk_tree, (avl_t *)ned);
  533. UNUSED(ret);
  534. if (move == plot_disks) {
  535. freez(move);
  536. plot_disks = NULL;
  537. break;
  538. } else {
  539. prev->next = move->next;
  540. ebpf_publish_disk_t *clean = move;
  541. move = move->next;
  542. freez(clean);
  543. continue;
  544. }
  545. }
  546. prev = move;
  547. move = move->next;
  548. }
  549. pthread_mutex_unlock(&plot_mutex);
  550. }
  551. /**
  552. * Send Hard disk data
  553. *
  554. * Send hard disk information to Netdata.
  555. *
  556. * @param update_every value to overwrite the update frequency set by the server.
  557. */
  558. static void ebpf_latency_send_hd_data(int update_every)
  559. {
  560. pthread_mutex_lock(&plot_mutex);
  561. if (!plot_disks) {
  562. pthread_mutex_unlock(&plot_mutex);
  563. return;
  564. }
  565. ebpf_publish_disk_t *move = plot_disks;
  566. while (move) {
  567. netdata_ebpf_disks_t *ned = move->plot;
  568. uint32_t flags = ned->flags;
  569. if (!(flags & NETDATA_DISK_CHART_CREATED)) {
  570. ebpf_create_hd_charts(ned, update_every);
  571. }
  572. if ((flags & NETDATA_DISK_CHART_CREATED)) {
  573. write_histogram_chart(ned->histogram.name, ned->family,
  574. ned->histogram.histogram, dimensions, NETDATA_EBPF_HIST_MAX_BINS);
  575. }
  576. ned->flags &= ~NETDATA_DISK_IS_HERE;
  577. move = move->next;
  578. }
  579. pthread_mutex_unlock(&plot_mutex);
  580. }
  581. /**
  582. * Main loop for this collector.
  583. */
  584. static void disk_collector(ebpf_module_t *em)
  585. {
  586. disk_hash_values = callocz(ebpf_nprocs, sizeof(netdata_idx_t));
  587. int update_every = em->update_every;
  588. heartbeat_t hb;
  589. heartbeat_init(&hb);
  590. int counter = update_every - 1;
  591. while (!ebpf_exit_plugin) {
  592. (void)heartbeat_next(&hb, USEC_PER_SEC);
  593. if (ebpf_exit_plugin || ++counter != update_every)
  594. continue;
  595. counter = 0;
  596. read_hard_disk_tables(disk_maps[NETDATA_DISK_READ].map_fd);
  597. pthread_mutex_lock(&lock);
  598. ebpf_remove_pointer_from_plot_disk(em);
  599. ebpf_latency_send_hd_data(update_every);
  600. pthread_mutex_unlock(&lock);
  601. ebpf_update_disks(em);
  602. }
  603. }
  604. /*****************************************************************
  605. *
  606. * EBPF DISK THREAD
  607. *
  608. *****************************************************************/
  609. /**
  610. * Enable tracepoints
  611. *
  612. * Enable necessary tracepoints for thread.
  613. *
  614. * @return It returns 0 on success and -1 otherwise
  615. */
  616. static int ebpf_disk_enable_tracepoints()
  617. {
  618. int test = ebpf_is_tracepoint_enabled(tracepoint_block_type, tracepoint_block_issue);
  619. if (test == -1)
  620. return -1;
  621. else if (!test) {
  622. if (ebpf_enable_tracing_values(tracepoint_block_type, tracepoint_block_issue))
  623. return -1;
  624. }
  625. was_block_issue_enabled = test;
  626. test = ebpf_is_tracepoint_enabled(tracepoint_block_type, tracepoint_block_rq_complete);
  627. if (test == -1)
  628. return -1;
  629. else if (!test) {
  630. if (ebpf_enable_tracing_values(tracepoint_block_type, tracepoint_block_rq_complete))
  631. return -1;
  632. }
  633. was_block_rq_complete_enabled = test;
  634. return 0;
  635. }
  636. /**
  637. * Disk thread
  638. *
  639. * Thread used to generate disk charts.
  640. *
  641. * @param ptr a pointer to `struct ebpf_module`
  642. *
  643. * @return It always return NULL
  644. */
  645. void *ebpf_disk_thread(void *ptr)
  646. {
  647. netdata_thread_cleanup_push(ebpf_disk_exit, ptr);
  648. ebpf_module_t *em = (ebpf_module_t *)ptr;
  649. em->maps = disk_maps;
  650. if (ebpf_disk_enable_tracepoints()) {
  651. goto enddisk;
  652. }
  653. avl_init_lock(&disk_tree, ebpf_compare_disks);
  654. if (read_local_disks()) {
  655. goto enddisk;
  656. }
  657. if (pthread_mutex_init(&plot_mutex, NULL)) {
  658. error("Cannot initialize local mutex");
  659. goto enddisk;
  660. }
  661. em->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &em->objects);
  662. if (!em->probe_links) {
  663. goto enddisk;
  664. }
  665. int algorithms[NETDATA_EBPF_HIST_MAX_BINS];
  666. ebpf_fill_algorithms(algorithms, NETDATA_EBPF_HIST_MAX_BINS, NETDATA_EBPF_INCREMENTAL_IDX);
  667. dimensions = ebpf_fill_histogram_dimension(NETDATA_EBPF_HIST_MAX_BINS);
  668. ebpf_global_labels(disk_aggregated_data, disk_publish_aggregated, dimensions, dimensions, algorithms,
  669. NETDATA_EBPF_HIST_MAX_BINS);
  670. pthread_mutex_lock(&lock);
  671. ebpf_update_stats(&plugin_statistics, em);
  672. ebpf_update_kernel_memory_with_vector(&plugin_statistics, disk_maps);
  673. pthread_mutex_unlock(&lock);
  674. disk_collector(em);
  675. enddisk:
  676. ebpf_update_disabled_plugin_stats(em);
  677. netdata_thread_cleanup_pop(1);
  678. return NULL;
  679. }