ebpf_sync.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "ebpf.h"
  3. #include "ebpf_sync.h"
  4. static char *sync_counter_dimension_name[NETDATA_SYNC_IDX_END] = { "sync", "syncfs", "msync", "fsync", "fdatasync",
  5. "sync_file_range" };
  6. static netdata_syscall_stat_t sync_counter_aggregated_data[NETDATA_SYNC_IDX_END];
  7. static netdata_publish_syscall_t sync_counter_publish_aggregated[NETDATA_SYNC_IDX_END];
  8. static netdata_idx_t sync_hash_values[NETDATA_SYNC_IDX_END];
  9. ebpf_local_maps_t sync_maps[] = {{.name = "tbl_sync", .internal_input = NETDATA_SYNC_END,
  10. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  11. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  12. #ifdef LIBBPF_MAJOR_VERSION
  13. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  14. #endif
  15. },
  16. {.name = NULL, .internal_input = 0, .user_input = 0,
  17. .type = NETDATA_EBPF_MAP_CONTROLLER,
  18. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  19. #ifdef LIBBPF_MAJOR_VERSION
  20. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  21. #endif
  22. }};
  23. ebpf_local_maps_t syncfs_maps[] = {{.name = "tbl_syncfs", .internal_input = NETDATA_SYNC_END,
  24. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  25. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  26. #ifdef LIBBPF_MAJOR_VERSION
  27. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  28. #endif
  29. },
  30. {.name = NULL, .internal_input = 0, .user_input = 0,
  31. .type = NETDATA_EBPF_MAP_CONTROLLER,
  32. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  33. #ifdef LIBBPF_MAJOR_VERSION
  34. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  35. #endif
  36. }};
  37. ebpf_local_maps_t msync_maps[] = {{.name = "tbl_msync", .internal_input = NETDATA_SYNC_END,
  38. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  39. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  40. #ifdef LIBBPF_MAJOR_VERSION
  41. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  42. #endif
  43. },
  44. {.name = NULL, .internal_input = 0, .user_input = 0,
  45. .type = NETDATA_EBPF_MAP_CONTROLLER,
  46. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  47. #ifdef LIBBPF_MAJOR_VERSION
  48. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  49. #endif
  50. }};
  51. ebpf_local_maps_t fsync_maps[] = {{.name = "tbl_fsync", .internal_input = NETDATA_SYNC_END,
  52. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  53. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  54. #ifdef LIBBPF_MAJOR_VERSION
  55. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  56. #endif
  57. },
  58. {.name = NULL, .internal_input = 0, .user_input = 0,
  59. .type = NETDATA_EBPF_MAP_CONTROLLER,
  60. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  61. #ifdef LIBBPF_MAJOR_VERSION
  62. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  63. #endif
  64. }};
  65. ebpf_local_maps_t fdatasync_maps[] = {{.name = "tbl_fdatasync", .internal_input = NETDATA_SYNC_END,
  66. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  67. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  68. #ifdef LIBBPF_MAJOR_VERSION
  69. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  70. #endif
  71. },
  72. {.name = NULL, .internal_input = 0, .user_input = 0,
  73. .type = NETDATA_EBPF_MAP_CONTROLLER,
  74. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  75. #ifdef LIBBPF_MAJOR_VERSION
  76. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  77. #endif
  78. }};
  79. ebpf_local_maps_t sync_file_range_maps[] = {{.name = "tbl_syncfr", .internal_input = NETDATA_SYNC_END,
  80. .user_input = 0, .type = NETDATA_EBPF_MAP_STATIC,
  81. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  82. #ifdef LIBBPF_MAJOR_VERSION
  83. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  84. #endif
  85. },
  86. {.name = NULL, .internal_input = 0, .user_input = 0,
  87. .type = NETDATA_EBPF_MAP_CONTROLLER,
  88. .map_fd = ND_EBPF_MAP_FD_NOT_INITIALIZED,
  89. #ifdef LIBBPF_MAJOR_VERSION
  90. .map_type = BPF_MAP_TYPE_PERCPU_ARRAY
  91. #endif
  92. }};
  93. struct config sync_config = { .first_section = NULL,
  94. .last_section = NULL,
  95. .mutex = NETDATA_MUTEX_INITIALIZER,
  96. .index = { .avl_tree = { .root = NULL, .compar = appconfig_section_compare },
  97. .rwlock = AVL_LOCK_INITIALIZER } };
  98. netdata_ebpf_targets_t sync_targets[] = { {.name = NETDATA_SYSCALLS_SYNC, .mode = EBPF_LOAD_TRAMPOLINE},
  99. {.name = NETDATA_SYSCALLS_SYNCFS, .mode = EBPF_LOAD_TRAMPOLINE},
  100. {.name = NETDATA_SYSCALLS_MSYNC, .mode = EBPF_LOAD_TRAMPOLINE},
  101. {.name = NETDATA_SYSCALLS_FSYNC, .mode = EBPF_LOAD_TRAMPOLINE},
  102. {.name = NETDATA_SYSCALLS_FDATASYNC, .mode = EBPF_LOAD_TRAMPOLINE},
  103. {.name = NETDATA_SYSCALLS_SYNC_FILE_RANGE, .mode = EBPF_LOAD_TRAMPOLINE},
  104. {.name = NULL, .mode = EBPF_LOAD_TRAMPOLINE}};
  105. #ifdef LIBBPF_MAJOR_VERSION
  106. /*****************************************************************
  107. *
  108. * BTF FUNCTIONS
  109. *
  110. *****************************************************************/
  111. /**
  112. * Disable probe
  113. *
  114. * Disable kprobe to use another method.
  115. *
  116. * @param obj is the main structure for bpf objects.
  117. */
  118. static inline void ebpf_sync_disable_probe(struct sync_bpf *obj)
  119. {
  120. bpf_program__set_autoload(obj->progs.netdata_sync_kprobe, false);
  121. }
  122. /**
  123. * Disable trampoline
  124. *
  125. * Disable trampoline to use another method.
  126. *
  127. * @param obj is the main structure for bpf objects.
  128. */
  129. static inline void ebpf_sync_disable_trampoline(struct sync_bpf *obj)
  130. {
  131. bpf_program__set_autoload(obj->progs.netdata_sync_fentry, false);
  132. }
  133. /**
  134. * Disable tracepoint
  135. *
  136. * Disable tracepoints according information given.
  137. *
  138. * @param obj object loaded
  139. * @param idx Which syscall will not be disabled
  140. */
  141. void ebpf_sync_disable_tracepoints(struct sync_bpf *obj, sync_syscalls_index_t idx)
  142. {
  143. if (idx != NETDATA_SYNC_SYNC_IDX)
  144. bpf_program__set_autoload(obj->progs.netdata_sync_entry, false);
  145. if (idx != NETDATA_SYNC_SYNCFS_IDX)
  146. bpf_program__set_autoload(obj->progs.netdata_syncfs_entry, false);
  147. if (idx != NETDATA_SYNC_MSYNC_IDX)
  148. bpf_program__set_autoload(obj->progs.netdata_msync_entry, false);
  149. if (idx != NETDATA_SYNC_FSYNC_IDX)
  150. bpf_program__set_autoload(obj->progs.netdata_fsync_entry, false);
  151. if (idx != NETDATA_SYNC_FDATASYNC_IDX)
  152. bpf_program__set_autoload(obj->progs.netdata_fdatasync_entry, false);
  153. if (idx != NETDATA_SYNC_SYNC_FILE_RANGE_IDX)
  154. bpf_program__set_autoload(obj->progs.netdata_sync_file_range_entry, false);
  155. }
  156. /**
  157. * Set hash tables
  158. *
  159. * Set the values for maps according the value given by kernel.
  160. *
  161. * @param map the map loaded.
  162. * @param obj the main structure for bpf objects.
  163. */
  164. static void ebpf_sync_set_hash_tables(ebpf_local_maps_t *map, struct sync_bpf *obj)
  165. {
  166. map->map_fd = bpf_map__fd(obj->maps.tbl_sync);
  167. }
  168. /**
  169. * Load and attach
  170. *
  171. * Load and attach the eBPF code in kernel.
  172. *
  173. * @param obj is the main structure for bpf objects.
  174. * @param em the structure with configuration
  175. * @param target the syscall that we are attaching a tracer.
  176. * @param idx the index for the main structure
  177. *
  178. * @return it returns 0 on success and -1 otherwise
  179. */
  180. static inline int ebpf_sync_load_and_attach(struct sync_bpf *obj, ebpf_module_t *em, char *target,
  181. sync_syscalls_index_t idx)
  182. {
  183. netdata_ebpf_targets_t *synct = em->targets;
  184. netdata_ebpf_program_loaded_t test = synct[NETDATA_SYNC_SYNC_IDX].mode;
  185. if (test == EBPF_LOAD_TRAMPOLINE) {
  186. ebpf_sync_disable_probe(obj);
  187. ebpf_sync_disable_tracepoints(obj, NETDATA_SYNC_IDX_END);
  188. bpf_program__set_attach_target(obj->progs.netdata_sync_fentry, 0,
  189. target);
  190. } else if (test == EBPF_LOAD_PROBE ||
  191. test == EBPF_LOAD_RETPROBE) {
  192. ebpf_sync_disable_tracepoints(obj, NETDATA_SYNC_IDX_END);
  193. ebpf_sync_disable_trampoline(obj);
  194. } else {
  195. ebpf_sync_disable_probe(obj);
  196. ebpf_sync_disable_trampoline(obj);
  197. ebpf_sync_disable_tracepoints(obj, idx);
  198. }
  199. ebpf_update_map_type(obj->maps.tbl_sync, &em->maps[NETDATA_SYNC_GLOBAL_TABLE]);
  200. int ret = sync_bpf__load(obj);
  201. if (!ret) {
  202. if (test != EBPF_LOAD_PROBE && test != EBPF_LOAD_RETPROBE) {
  203. ret = sync_bpf__attach(obj);
  204. } else {
  205. obj->links.netdata_sync_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_sync_kprobe,
  206. false, target);
  207. ret = (int)libbpf_get_error(obj->links.netdata_sync_kprobe);
  208. }
  209. if (!ret)
  210. ebpf_sync_set_hash_tables(&em->maps[NETDATA_SYNC_GLOBAL_TABLE], obj);
  211. }
  212. return ret;
  213. }
  214. #endif
  215. /*****************************************************************
  216. *
  217. * CLEANUP THREAD
  218. *
  219. *****************************************************************/
  220. #ifdef LIBBPF_MAJOR_VERSION
  221. /**
  222. * Cleanup Objects
  223. *
  224. * Cleanup loaded objects when thread was initialized.
  225. */
  226. void ebpf_sync_cleanup_objects()
  227. {
  228. int i;
  229. for (i = 0; local_syscalls[i].syscall; i++) {
  230. ebpf_sync_syscalls_t *w = &local_syscalls[i];
  231. if (w->sync_obj)
  232. sync_bpf__destroy(w->sync_obj);
  233. }
  234. }
  235. #endif
  236. /**
  237. * Sync Free
  238. *
  239. * Cleanup variables after child threads to stop
  240. *
  241. * @param ptr thread data.
  242. */
  243. static void ebpf_sync_free(ebpf_module_t *em)
  244. {
  245. #ifdef LIBBPF_MAJOR_VERSION
  246. ebpf_sync_cleanup_objects();
  247. #endif
  248. pthread_mutex_lock(&ebpf_exit_cleanup);
  249. em->enabled = NETDATA_THREAD_EBPF_STOPPED;
  250. pthread_mutex_unlock(&ebpf_exit_cleanup);
  251. }
  252. /**
  253. * Exit
  254. *
  255. * Clean up the main thread.
  256. *
  257. * @param ptr thread data.
  258. */
  259. static void ebpf_sync_exit(void *ptr)
  260. {
  261. ebpf_module_t *em = (ebpf_module_t *)ptr;
  262. ebpf_sync_free(em);
  263. }
  264. /*****************************************************************
  265. *
  266. * INITIALIZE THREAD
  267. *
  268. *****************************************************************/
  269. /**
  270. * Load Legacy
  271. *
  272. * Load legacy code.
  273. *
  274. * @param w is the sync output structure with pointers to objects loaded.
  275. * @param em is structure with configuration
  276. *
  277. * @return 0 on success and -1 otherwise.
  278. */
  279. static int ebpf_sync_load_legacy(ebpf_sync_syscalls_t *w, ebpf_module_t *em)
  280. {
  281. em->thread_name = w->syscall;
  282. if (!w->probe_links) {
  283. w->probe_links = ebpf_load_program(ebpf_plugin_dir, em, running_on_kernel, isrh, &w->objects);
  284. if (!w->probe_links) {
  285. return -1;
  286. }
  287. }
  288. return 0;
  289. }
  290. /*
  291. * Initialize Syscalls
  292. *
  293. * Load the eBPF programs to monitor syscalls
  294. *
  295. * @return 0 on success and -1 otherwise.
  296. */
  297. static int ebpf_sync_initialize_syscall(ebpf_module_t *em)
  298. {
  299. #ifdef LIBBPF_MAJOR_VERSION
  300. ebpf_define_map_type(sync_maps, em->maps_per_core, running_on_kernel);
  301. ebpf_define_map_type(syncfs_maps, em->maps_per_core, running_on_kernel);
  302. ebpf_define_map_type(msync_maps, em->maps_per_core, running_on_kernel);
  303. ebpf_define_map_type(fsync_maps, em->maps_per_core, running_on_kernel);
  304. ebpf_define_map_type(fdatasync_maps, em->maps_per_core, running_on_kernel);
  305. ebpf_define_map_type(sync_file_range_maps, em->maps_per_core, running_on_kernel);
  306. #endif
  307. int i;
  308. const char *saved_name = em->thread_name;
  309. int errors = 0;
  310. for (i = 0; local_syscalls[i].syscall; i++) {
  311. ebpf_sync_syscalls_t *w = &local_syscalls[i];
  312. w->sync_maps = local_syscalls[i].sync_maps;
  313. em->maps = local_syscalls[i].sync_maps;
  314. if (w->enabled) {
  315. if (em->load & EBPF_LOAD_LEGACY) {
  316. if (ebpf_sync_load_legacy(w, em))
  317. errors++;
  318. em->thread_name = saved_name;
  319. }
  320. #ifdef LIBBPF_MAJOR_VERSION
  321. else {
  322. char syscall[NETDATA_EBPF_MAX_SYSCALL_LENGTH];
  323. ebpf_select_host_prefix(syscall, NETDATA_EBPF_MAX_SYSCALL_LENGTH, w->syscall, running_on_kernel);
  324. if (ebpf_is_function_inside_btf(default_btf, syscall)) {
  325. w->sync_obj = sync_bpf__open();
  326. if (!w->sync_obj) {
  327. w->enabled = false;
  328. errors++;
  329. } else {
  330. if (ebpf_sync_load_and_attach(w->sync_obj, em, syscall, i)) {
  331. w->enabled = false;
  332. errors++;
  333. }
  334. }
  335. } else {
  336. info("Cannot find syscall %s we are not going to monitor it.", syscall);
  337. w->enabled = false;
  338. }
  339. em->thread_name = saved_name;
  340. }
  341. #endif
  342. }
  343. }
  344. em->thread_name = saved_name;
  345. memset(sync_counter_aggregated_data, 0 , NETDATA_SYNC_IDX_END * sizeof(netdata_syscall_stat_t));
  346. memset(sync_counter_publish_aggregated, 0 , NETDATA_SYNC_IDX_END * sizeof(netdata_publish_syscall_t));
  347. memset(sync_hash_values, 0 , NETDATA_SYNC_IDX_END * sizeof(netdata_idx_t));
  348. return (errors) ? -1 : 0;
  349. }
  350. /*****************************************************************
  351. *
  352. * DATA THREAD
  353. *
  354. *****************************************************************/
  355. /**
  356. * Read global table
  357. *
  358. * Read the table with number of calls for all functions
  359. *
  360. * @param maps_per_core do I need to read all cores?
  361. */
  362. static void ebpf_sync_read_global_table(int maps_per_core)
  363. {
  364. netdata_idx_t stored[NETDATA_MAX_PROCESSOR];
  365. uint32_t idx = NETDATA_SYNC_CALL;
  366. int i;
  367. for (i = 0; local_syscalls[i].syscall; i++) {
  368. ebpf_sync_syscalls_t *w = &local_syscalls[i];
  369. if (w->enabled) {
  370. int fd = w->sync_maps[NETDATA_SYNC_GLOBAL_TABLE].map_fd;
  371. if (!bpf_map_lookup_elem(fd, &idx, &stored)) {
  372. int j, end = (maps_per_core) ? ebpf_nprocs : 1;
  373. netdata_idx_t total = 0;
  374. for (j = 0; j < end ;j++ )
  375. total += stored[j];
  376. sync_hash_values[i] = total;
  377. }
  378. }
  379. }
  380. }
  381. /**
  382. * Create Sync charts
  383. *
  384. * Create charts and dimensions according user input.
  385. *
  386. * @param id chart id
  387. * @param idx the first index with data.
  388. * @param end the last index with data.
  389. */
  390. static void ebpf_send_sync_chart(char *id,
  391. int idx,
  392. int end)
  393. {
  394. write_begin_chart(NETDATA_EBPF_MEMORY_GROUP, id);
  395. netdata_publish_syscall_t *move = &sync_counter_publish_aggregated[idx];
  396. while (move && idx <= end) {
  397. if (local_syscalls[idx].enabled)
  398. write_chart_dimension(move->name, (long long)sync_hash_values[idx]);
  399. move = move->next;
  400. idx++;
  401. }
  402. write_end_chart();
  403. }
  404. /**
  405. * Send data
  406. *
  407. * Send global charts to Netdata
  408. */
  409. static void sync_send_data()
  410. {
  411. if (local_syscalls[NETDATA_SYNC_FSYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_FDATASYNC_IDX].enabled) {
  412. ebpf_send_sync_chart(NETDATA_EBPF_FILE_SYNC_CHART, NETDATA_SYNC_FSYNC_IDX, NETDATA_SYNC_FDATASYNC_IDX);
  413. }
  414. if (local_syscalls[NETDATA_SYNC_MSYNC_IDX].enabled)
  415. ebpf_one_dimension_write_charts(NETDATA_EBPF_MEMORY_GROUP, NETDATA_EBPF_MSYNC_CHART,
  416. sync_counter_publish_aggregated[NETDATA_SYNC_MSYNC_IDX].dimension,
  417. sync_hash_values[NETDATA_SYNC_MSYNC_IDX]);
  418. if (local_syscalls[NETDATA_SYNC_SYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_SYNCFS_IDX].enabled) {
  419. ebpf_send_sync_chart(NETDATA_EBPF_SYNC_CHART, NETDATA_SYNC_SYNC_IDX, NETDATA_SYNC_SYNCFS_IDX);
  420. }
  421. if (local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].enabled)
  422. ebpf_one_dimension_write_charts(NETDATA_EBPF_MEMORY_GROUP, NETDATA_EBPF_FILE_SEGMENT_CHART,
  423. sync_counter_publish_aggregated[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].dimension,
  424. sync_hash_values[NETDATA_SYNC_SYNC_FILE_RANGE_IDX]);
  425. }
  426. /**
  427. * Main loop for this collector.
  428. */
  429. static void sync_collector(ebpf_module_t *em)
  430. {
  431. heartbeat_t hb;
  432. heartbeat_init(&hb);
  433. int update_every = em->update_every;
  434. int counter = update_every - 1;
  435. int maps_per_core = em->maps_per_core;
  436. while (!ebpf_exit_plugin) {
  437. (void)heartbeat_next(&hb, USEC_PER_SEC);
  438. if (ebpf_exit_plugin || ++counter != update_every)
  439. continue;
  440. counter = 0;
  441. ebpf_sync_read_global_table(maps_per_core);
  442. pthread_mutex_lock(&lock);
  443. sync_send_data();
  444. pthread_mutex_unlock(&lock);
  445. }
  446. }
  447. /*****************************************************************
  448. *
  449. * MAIN THREAD
  450. *
  451. *****************************************************************/
  452. /**
  453. * Create Sync charts
  454. *
  455. * Create charts and dimensions according user input.
  456. *
  457. * @param id chart id
  458. * @param title chart title
  459. * @param order order number of the specified chart
  460. * @param idx the first index with data.
  461. * @param end the last index with data.
  462. * @param update_every value to overwrite the update frequency set by the server.
  463. */
  464. static void ebpf_create_sync_chart(char *id,
  465. char *title,
  466. int order,
  467. int idx,
  468. int end,
  469. int update_every)
  470. {
  471. ebpf_write_chart_cmd(NETDATA_EBPF_MEMORY_GROUP, id, title, EBPF_COMMON_DIMENSION_CALL,
  472. NETDATA_EBPF_SYNC_SUBMENU, NETDATA_EBPF_CHART_TYPE_LINE, NULL, order,
  473. update_every,
  474. NETDATA_EBPF_MODULE_NAME_SYNC);
  475. netdata_publish_syscall_t *move = &sync_counter_publish_aggregated[idx];
  476. while (move && idx <= end) {
  477. if (local_syscalls[idx].enabled)
  478. ebpf_write_global_dimension(move->name, move->dimension, move->algorithm);
  479. move = move->next;
  480. idx++;
  481. }
  482. }
  483. /**
  484. * Create global charts
  485. *
  486. * Call ebpf_create_chart to create the charts for the collector.
  487. *
  488. * @param update_every value to overwrite the update frequency set by the server.
  489. */
  490. static void ebpf_create_sync_charts(int update_every)
  491. {
  492. if (local_syscalls[NETDATA_SYNC_FSYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_FDATASYNC_IDX].enabled)
  493. ebpf_create_sync_chart(NETDATA_EBPF_FILE_SYNC_CHART,
  494. "Monitor calls for <code>fsync(2)</code> and <code>fdatasync(2)</code>.", 21300,
  495. NETDATA_SYNC_FSYNC_IDX, NETDATA_SYNC_FDATASYNC_IDX, update_every);
  496. if (local_syscalls[NETDATA_SYNC_MSYNC_IDX].enabled)
  497. ebpf_create_sync_chart(NETDATA_EBPF_MSYNC_CHART,
  498. "Monitor calls for <code>msync(2)</code>.", 21301,
  499. NETDATA_SYNC_MSYNC_IDX, NETDATA_SYNC_MSYNC_IDX, update_every);
  500. if (local_syscalls[NETDATA_SYNC_SYNC_IDX].enabled && local_syscalls[NETDATA_SYNC_SYNCFS_IDX].enabled)
  501. ebpf_create_sync_chart(NETDATA_EBPF_SYNC_CHART,
  502. "Monitor calls for <code>sync(2)</code> and <code>syncfs(2)</code>.", 21302,
  503. NETDATA_SYNC_SYNC_IDX, NETDATA_SYNC_SYNCFS_IDX, update_every);
  504. if (local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].enabled)
  505. ebpf_create_sync_chart(NETDATA_EBPF_FILE_SEGMENT_CHART,
  506. "Monitor calls for <code>sync_file_range(2)</code>.", 21303,
  507. NETDATA_SYNC_SYNC_FILE_RANGE_IDX, NETDATA_SYNC_SYNC_FILE_RANGE_IDX, update_every);
  508. }
  509. /**
  510. * Parse Syscalls
  511. *
  512. * Parse syscall options available inside ebpf.d/sync.conf
  513. */
  514. static void ebpf_sync_parse_syscalls()
  515. {
  516. int i;
  517. for (i = 0; local_syscalls[i].syscall; i++) {
  518. local_syscalls[i].enabled = appconfig_get_boolean(&sync_config, NETDATA_SYNC_CONFIG_NAME,
  519. local_syscalls[i].syscall, CONFIG_BOOLEAN_YES);
  520. }
  521. }
  522. /**
  523. * Set sync maps
  524. *
  525. * When thread is initialized the variable sync_maps is set as null,
  526. * this function fills the variable before to use.
  527. */
  528. static void ebpf_set_sync_maps()
  529. {
  530. local_syscalls[NETDATA_SYNC_SYNC_IDX].sync_maps = sync_maps;
  531. local_syscalls[NETDATA_SYNC_SYNCFS_IDX].sync_maps = syncfs_maps;
  532. local_syscalls[NETDATA_SYNC_MSYNC_IDX].sync_maps = msync_maps;
  533. local_syscalls[NETDATA_SYNC_FSYNC_IDX].sync_maps = fsync_maps;
  534. local_syscalls[NETDATA_SYNC_FDATASYNC_IDX].sync_maps = fdatasync_maps;
  535. local_syscalls[NETDATA_SYNC_SYNC_FILE_RANGE_IDX].sync_maps = sync_file_range_maps;
  536. }
  537. /**
  538. * Sync thread
  539. *
  540. * Thread used to make sync thread
  541. *
  542. * @param ptr a pointer to `struct ebpf_module`
  543. *
  544. * @return It always return NULL
  545. */
  546. void *ebpf_sync_thread(void *ptr)
  547. {
  548. netdata_thread_cleanup_push(ebpf_sync_exit, ptr);
  549. ebpf_module_t *em = (ebpf_module_t *)ptr;
  550. ebpf_set_sync_maps();
  551. ebpf_sync_parse_syscalls();
  552. #ifdef LIBBPF_MAJOR_VERSION
  553. ebpf_adjust_thread_load(em, default_btf);
  554. #endif
  555. if (ebpf_sync_initialize_syscall(em)) {
  556. goto endsync;
  557. }
  558. int algorithms[NETDATA_SYNC_IDX_END] = { NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX,
  559. NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX,
  560. NETDATA_EBPF_INCREMENTAL_IDX, NETDATA_EBPF_INCREMENTAL_IDX };
  561. ebpf_global_labels(sync_counter_aggregated_data, sync_counter_publish_aggregated,
  562. sync_counter_dimension_name, sync_counter_dimension_name,
  563. algorithms, NETDATA_SYNC_IDX_END);
  564. pthread_mutex_lock(&lock);
  565. ebpf_create_sync_charts(em->update_every);
  566. ebpf_update_stats(&plugin_statistics, em);
  567. pthread_mutex_unlock(&lock);
  568. sync_collector(em);
  569. endsync:
  570. ebpf_update_disabled_plugin_stats(em);
  571. netdata_thread_cleanup_pop(1);
  572. return NULL;
  573. }