sys_fs_btrfs.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "plugin_proc.h"
  3. #define PLUGIN_PROC_MODULE_BTRFS_NAME "/sys/fs/btrfs"
  4. typedef struct btrfs_disk {
  5. char *name;
  6. uint32_t hash;
  7. int exists;
  8. char *size_filename;
  9. char *hw_sector_size_filename;
  10. unsigned long long size;
  11. unsigned long long hw_sector_size;
  12. struct btrfs_disk *next;
  13. } BTRFS_DISK;
  14. typedef struct btrfs_node {
  15. int exists;
  16. int logged_error;
  17. char *id;
  18. uint32_t hash;
  19. char *label;
  20. // unsigned long long int sectorsize;
  21. // unsigned long long int nodesize;
  22. // unsigned long long int quota_override;
  23. #define declare_btrfs_allocation_section_field(SECTION, FIELD) \
  24. char *allocation_ ## SECTION ## _ ## FIELD ## _filename; \
  25. unsigned long long int allocation_ ## SECTION ## _ ## FIELD;
  26. #define declare_btrfs_allocation_field(FIELD) \
  27. char *allocation_ ## FIELD ## _filename; \
  28. unsigned long long int allocation_ ## FIELD;
  29. RRDSET *st_allocation_disks;
  30. RRDDIM *rd_allocation_disks_unallocated;
  31. RRDDIM *rd_allocation_disks_data_used;
  32. RRDDIM *rd_allocation_disks_data_free;
  33. RRDDIM *rd_allocation_disks_metadata_used;
  34. RRDDIM *rd_allocation_disks_metadata_free;
  35. RRDDIM *rd_allocation_disks_system_used;
  36. RRDDIM *rd_allocation_disks_system_free;
  37. unsigned long long all_disks_total;
  38. RRDSET *st_allocation_data;
  39. RRDDIM *rd_allocation_data_free;
  40. RRDDIM *rd_allocation_data_used;
  41. declare_btrfs_allocation_section_field(data, total_bytes)
  42. declare_btrfs_allocation_section_field(data, bytes_used)
  43. declare_btrfs_allocation_section_field(data, disk_total)
  44. declare_btrfs_allocation_section_field(data, disk_used)
  45. RRDSET *st_allocation_metadata;
  46. RRDDIM *rd_allocation_metadata_free;
  47. RRDDIM *rd_allocation_metadata_used;
  48. RRDDIM *rd_allocation_metadata_reserved;
  49. declare_btrfs_allocation_section_field(metadata, total_bytes)
  50. declare_btrfs_allocation_section_field(metadata, bytes_used)
  51. declare_btrfs_allocation_section_field(metadata, disk_total)
  52. declare_btrfs_allocation_section_field(metadata, disk_used)
  53. //declare_btrfs_allocation_field(global_rsv_reserved)
  54. declare_btrfs_allocation_field(global_rsv_size)
  55. RRDSET *st_allocation_system;
  56. RRDDIM *rd_allocation_system_free;
  57. RRDDIM *rd_allocation_system_used;
  58. declare_btrfs_allocation_section_field(system, total_bytes)
  59. declare_btrfs_allocation_section_field(system, bytes_used)
  60. declare_btrfs_allocation_section_field(system, disk_total)
  61. declare_btrfs_allocation_section_field(system, disk_used)
  62. BTRFS_DISK *disks;
  63. struct btrfs_node *next;
  64. } BTRFS_NODE;
  65. static BTRFS_NODE *nodes = NULL;
  66. static inline void btrfs_free_disk(BTRFS_DISK *d) {
  67. freez(d->name);
  68. freez(d->size_filename);
  69. freez(d->hw_sector_size_filename);
  70. freez(d);
  71. }
  72. static inline void btrfs_free_node(BTRFS_NODE *node) {
  73. // info("BTRFS: destroying '%s'", node->id);
  74. if(node->st_allocation_disks)
  75. rrdset_is_obsolete(node->st_allocation_disks);
  76. if(node->st_allocation_data)
  77. rrdset_is_obsolete(node->st_allocation_data);
  78. if(node->st_allocation_metadata)
  79. rrdset_is_obsolete(node->st_allocation_metadata);
  80. if(node->st_allocation_system)
  81. rrdset_is_obsolete(node->st_allocation_system);
  82. freez(node->allocation_data_bytes_used_filename);
  83. freez(node->allocation_data_total_bytes_filename);
  84. freez(node->allocation_metadata_bytes_used_filename);
  85. freez(node->allocation_metadata_total_bytes_filename);
  86. freez(node->allocation_system_bytes_used_filename);
  87. freez(node->allocation_system_total_bytes_filename);
  88. while(node->disks) {
  89. BTRFS_DISK *d = node->disks;
  90. node->disks = node->disks->next;
  91. btrfs_free_disk(d);
  92. }
  93. freez(node->label);
  94. freez(node->id);
  95. freez(node);
  96. }
  97. static inline int find_btrfs_disks(BTRFS_NODE *node, const char *path) {
  98. char filename[FILENAME_MAX + 1];
  99. node->all_disks_total = 0;
  100. BTRFS_DISK *d;
  101. for(d = node->disks ; d ; d = d->next)
  102. d->exists = 0;
  103. DIR *dir = opendir(path);
  104. if (!dir) {
  105. if(!node->logged_error) {
  106. error("BTRFS: Cannot open directory '%s'.", path);
  107. node->logged_error = 1;
  108. }
  109. return 1;
  110. }
  111. node->logged_error = 0;
  112. struct dirent *de = NULL;
  113. while ((de = readdir(dir))) {
  114. if (de->d_type != DT_LNK
  115. || !strcmp(de->d_name, ".")
  116. || !strcmp(de->d_name, "..")
  117. ) {
  118. // info("BTRFS: ignoring '%s'", de->d_name);
  119. continue;
  120. }
  121. uint32_t hash = simple_hash(de->d_name);
  122. // --------------------------------------------------------------------
  123. // search for it
  124. for(d = node->disks ; d ; d = d->next) {
  125. if(hash == d->hash && !strcmp(de->d_name, d->name))
  126. break;
  127. }
  128. // --------------------------------------------------------------------
  129. // did we find it?
  130. if(!d) {
  131. d = callocz(sizeof(BTRFS_DISK), 1);
  132. d->name = strdupz(de->d_name);
  133. d->hash = simple_hash(d->name);
  134. snprintfz(filename, FILENAME_MAX, "%s/%s/size", path, de->d_name);
  135. d->size_filename = strdupz(filename);
  136. // for bcache
  137. snprintfz(filename, FILENAME_MAX, "%s/%s/bcache/../queue/hw_sector_size", path, de->d_name);
  138. struct stat sb;
  139. if(stat(filename, &sb) == -1) {
  140. // for disks
  141. snprintfz(filename, FILENAME_MAX, "%s/%s/queue/hw_sector_size", path, de->d_name);
  142. if(stat(filename, &sb) == -1)
  143. // for partitions
  144. snprintfz(filename, FILENAME_MAX, "%s/%s/../queue/hw_sector_size", path, de->d_name);
  145. }
  146. d->hw_sector_size_filename = strdupz(filename);
  147. // link it
  148. d->next = node->disks;
  149. node->disks = d;
  150. }
  151. d->exists = 1;
  152. // --------------------------------------------------------------------
  153. // update the values
  154. if(read_single_number_file(d->size_filename, &d->size) != 0) {
  155. error("BTRFS: failed to read '%s'", d->size_filename);
  156. d->exists = 0;
  157. continue;
  158. }
  159. if(read_single_number_file(d->hw_sector_size_filename, &d->hw_sector_size) != 0) {
  160. error("BTRFS: failed to read '%s'", d->hw_sector_size_filename);
  161. d->exists = 0;
  162. continue;
  163. }
  164. node->all_disks_total += d->size * d->hw_sector_size;
  165. }
  166. closedir(dir);
  167. // ------------------------------------------------------------------------
  168. // cleanup
  169. BTRFS_DISK *last = NULL;
  170. d = node->disks;
  171. while(d) {
  172. if(unlikely(!d->exists)) {
  173. if(unlikely(node->disks == d)) {
  174. node->disks = d->next;
  175. btrfs_free_disk(d);
  176. d = node->disks;
  177. last = NULL;
  178. }
  179. else {
  180. last->next = d->next;
  181. btrfs_free_disk(d);
  182. d = last->next;
  183. }
  184. continue;
  185. }
  186. last = d;
  187. d = d->next;
  188. }
  189. return 0;
  190. }
  191. static inline int find_all_btrfs_pools(const char *path) {
  192. static int logged_error = 0;
  193. char filename[FILENAME_MAX + 1];
  194. BTRFS_NODE *node;
  195. for(node = nodes ; node ; node = node->next)
  196. node->exists = 0;
  197. DIR *dir = opendir(path);
  198. if (!dir) {
  199. if(!logged_error) {
  200. error("BTRFS: Cannot open directory '%s'.", path);
  201. logged_error = 1;
  202. }
  203. return 1;
  204. }
  205. logged_error = 0;
  206. struct dirent *de = NULL;
  207. while ((de = readdir(dir))) {
  208. if(de->d_type != DT_DIR
  209. || !strcmp(de->d_name, ".")
  210. || !strcmp(de->d_name, "..")
  211. || !strcmp(de->d_name, "features")
  212. ) {
  213. // info("BTRFS: ignoring '%s'", de->d_name);
  214. continue;
  215. }
  216. uint32_t hash = simple_hash(de->d_name);
  217. // search for it
  218. for(node = nodes ; node ; node = node->next) {
  219. if(hash == node->hash && !strcmp(de->d_name, node->id))
  220. break;
  221. }
  222. // did we find it?
  223. if(node) {
  224. // info("BTRFS: already exists '%s'", de->d_name);
  225. node->exists = 1;
  226. // update the disk sizes
  227. snprintfz(filename, FILENAME_MAX, "%s/%s/devices", path, de->d_name);
  228. find_btrfs_disks(node, filename);
  229. continue;
  230. }
  231. // info("BTRFS: adding '%s'", de->d_name);
  232. // not found, create it
  233. node = callocz(sizeof(BTRFS_NODE), 1);
  234. node->id = strdupz(de->d_name);
  235. node->hash = simple_hash(node->id);
  236. node->exists = 1;
  237. {
  238. char label[FILENAME_MAX + 1] = "";
  239. snprintfz(filename, FILENAME_MAX, "%s/%s/label", path, de->d_name);
  240. if(read_file(filename, label, FILENAME_MAX) != 0) {
  241. error("BTRFS: failed to read '%s'", filename);
  242. btrfs_free_node(node);
  243. continue;
  244. }
  245. char *s = label;
  246. if (s[0])
  247. s = trim(label);
  248. if(s && s[0])
  249. node->label = strdupz(s);
  250. else
  251. node->label = strdupz(node->id);
  252. }
  253. //snprintfz(filename, FILENAME_MAX, "%s/%s/sectorsize", path, de->d_name);
  254. //if(read_single_number_file(filename, &node->sectorsize) != 0) {
  255. // error("BTRFS: failed to read '%s'", filename);
  256. // btrfs_free_node(node);
  257. // continue;
  258. //}
  259. //snprintfz(filename, FILENAME_MAX, "%s/%s/nodesize", path, de->d_name);
  260. //if(read_single_number_file(filename, &node->nodesize) != 0) {
  261. // error("BTRFS: failed to read '%s'", filename);
  262. // btrfs_free_node(node);
  263. // continue;
  264. //}
  265. //snprintfz(filename, FILENAME_MAX, "%s/%s/quota_override", path, de->d_name);
  266. //if(read_single_number_file(filename, &node->quota_override) != 0) {
  267. // error("BTRFS: failed to read '%s'", filename);
  268. // btrfs_free_node(node);
  269. // continue;
  270. //}
  271. // --------------------------------------------------------------------
  272. // macros to simplify our life
  273. #define init_btrfs_allocation_field(FIELD) {\
  274. snprintfz(filename, FILENAME_MAX, "%s/%s/allocation/" #FIELD, path, de->d_name); \
  275. if(read_single_number_file(filename, &node->allocation_ ## FIELD) != 0) {\
  276. error("BTRFS: failed to read '%s'", filename);\
  277. btrfs_free_node(node);\
  278. continue;\
  279. }\
  280. if(!node->allocation_ ## FIELD ## _filename)\
  281. node->allocation_ ## FIELD ## _filename = strdupz(filename);\
  282. }
  283. #define init_btrfs_allocation_section_field(SECTION, FIELD) {\
  284. snprintfz(filename, FILENAME_MAX, "%s/%s/allocation/" #SECTION "/" #FIELD, path, de->d_name); \
  285. if(read_single_number_file(filename, &node->allocation_ ## SECTION ## _ ## FIELD) != 0) {\
  286. error("BTRFS: failed to read '%s'", filename);\
  287. btrfs_free_node(node);\
  288. continue;\
  289. }\
  290. if(!node->allocation_ ## SECTION ## _ ## FIELD ## _filename)\
  291. node->allocation_ ## SECTION ## _ ## FIELD ## _filename = strdupz(filename);\
  292. }
  293. // --------------------------------------------------------------------
  294. // allocation/data
  295. init_btrfs_allocation_section_field(data, total_bytes);
  296. init_btrfs_allocation_section_field(data, bytes_used);
  297. init_btrfs_allocation_section_field(data, disk_total);
  298. init_btrfs_allocation_section_field(data, disk_used);
  299. // --------------------------------------------------------------------
  300. // allocation/metadata
  301. init_btrfs_allocation_section_field(metadata, total_bytes);
  302. init_btrfs_allocation_section_field(metadata, bytes_used);
  303. init_btrfs_allocation_section_field(metadata, disk_total);
  304. init_btrfs_allocation_section_field(metadata, disk_used);
  305. init_btrfs_allocation_field(global_rsv_size);
  306. // init_btrfs_allocation_field(global_rsv_reserved);
  307. // --------------------------------------------------------------------
  308. // allocation/system
  309. init_btrfs_allocation_section_field(system, total_bytes);
  310. init_btrfs_allocation_section_field(system, bytes_used);
  311. init_btrfs_allocation_section_field(system, disk_total);
  312. init_btrfs_allocation_section_field(system, disk_used);
  313. // --------------------------------------------------------------------
  314. // find all disks related to this node
  315. // and collect their sizes
  316. snprintfz(filename, FILENAME_MAX, "%s/%s/devices", path, de->d_name);
  317. find_btrfs_disks(node, filename);
  318. // --------------------------------------------------------------------
  319. // link it
  320. // info("BTRFS: linking '%s'", node->id);
  321. node->next = nodes;
  322. nodes = node;
  323. }
  324. closedir(dir);
  325. // ------------------------------------------------------------------------
  326. // cleanup
  327. BTRFS_NODE *last = NULL;
  328. node = nodes;
  329. while(node) {
  330. if(unlikely(!node->exists)) {
  331. if(unlikely(nodes == node)) {
  332. nodes = node->next;
  333. btrfs_free_node(node);
  334. node = nodes;
  335. last = NULL;
  336. }
  337. else {
  338. last->next = node->next;
  339. btrfs_free_node(node);
  340. node = last->next;
  341. }
  342. continue;
  343. }
  344. last = node;
  345. node = node->next;
  346. }
  347. return 0;
  348. }
  349. static void add_labels_to_btrfs(BTRFS_NODE *n, RRDSET *st) {
  350. rrdlabels_add(st->state->chart_labels, "device", n->id, RRDLABEL_SRC_AUTO);
  351. rrdlabels_add(st->state->chart_labels, "device_label", n->label, RRDLABEL_SRC_AUTO);
  352. }
  353. int do_sys_fs_btrfs(int update_every, usec_t dt) {
  354. static int initialized = 0
  355. , do_allocation_disks = CONFIG_BOOLEAN_AUTO
  356. , do_allocation_system = CONFIG_BOOLEAN_AUTO
  357. , do_allocation_data = CONFIG_BOOLEAN_AUTO
  358. , do_allocation_metadata = CONFIG_BOOLEAN_AUTO;
  359. static usec_t refresh_delta = 0, refresh_every = 60 * USEC_PER_SEC;
  360. static char *btrfs_path = NULL;
  361. (void)dt;
  362. if(unlikely(!initialized)) {
  363. initialized = 1;
  364. char filename[FILENAME_MAX + 1];
  365. snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/fs/btrfs");
  366. btrfs_path = config_get("plugin:proc:/sys/fs/btrfs", "path to monitor", filename);
  367. refresh_every = config_get_number("plugin:proc:/sys/fs/btrfs", "check for btrfs changes every", refresh_every / USEC_PER_SEC) * USEC_PER_SEC;
  368. refresh_delta = refresh_every;
  369. do_allocation_disks = config_get_boolean_ondemand("plugin:proc:/sys/fs/btrfs", "physical disks allocation", do_allocation_disks);
  370. do_allocation_data = config_get_boolean_ondemand("plugin:proc:/sys/fs/btrfs", "data allocation", do_allocation_data);
  371. do_allocation_metadata = config_get_boolean_ondemand("plugin:proc:/sys/fs/btrfs", "metadata allocation", do_allocation_metadata);
  372. do_allocation_system = config_get_boolean_ondemand("plugin:proc:/sys/fs/btrfs", "system allocation", do_allocation_system);
  373. }
  374. refresh_delta += dt;
  375. if(refresh_delta >= refresh_every) {
  376. refresh_delta = 0;
  377. find_all_btrfs_pools(btrfs_path);
  378. }
  379. BTRFS_NODE *node;
  380. for(node = nodes; node ; node = node->next) {
  381. // --------------------------------------------------------------------
  382. // allocation/system
  383. #define collect_btrfs_allocation_field(FIELD) \
  384. read_single_number_file(node->allocation_ ## FIELD ## _filename, &node->allocation_ ## FIELD)
  385. #define collect_btrfs_allocation_section_field(SECTION, FIELD) \
  386. read_single_number_file(node->allocation_ ## SECTION ## _ ## FIELD ## _filename, &node->allocation_ ## SECTION ## _ ## FIELD)
  387. if(do_allocation_disks != CONFIG_BOOLEAN_NO) {
  388. if( collect_btrfs_allocation_section_field(data, disk_total) != 0
  389. || collect_btrfs_allocation_section_field(data, disk_used) != 0
  390. || collect_btrfs_allocation_section_field(metadata, disk_total) != 0
  391. || collect_btrfs_allocation_section_field(metadata, disk_used) != 0
  392. || collect_btrfs_allocation_section_field(system, disk_total) != 0
  393. || collect_btrfs_allocation_section_field(system, disk_used) != 0) {
  394. error("BTRFS: failed to collect physical disks allocation for '%s'", node->id);
  395. // make it refresh btrfs at the next iteration
  396. refresh_delta = refresh_every;
  397. continue;
  398. }
  399. }
  400. if(do_allocation_data != CONFIG_BOOLEAN_NO) {
  401. if (collect_btrfs_allocation_section_field(data, total_bytes) != 0
  402. || collect_btrfs_allocation_section_field(data, bytes_used) != 0) {
  403. error("BTRFS: failed to collect allocation/data for '%s'", node->id);
  404. // make it refresh btrfs at the next iteration
  405. refresh_delta = refresh_every;
  406. continue;
  407. }
  408. }
  409. if(do_allocation_metadata != CONFIG_BOOLEAN_NO) {
  410. if (collect_btrfs_allocation_section_field(metadata, total_bytes) != 0
  411. || collect_btrfs_allocation_section_field(metadata, bytes_used) != 0
  412. || collect_btrfs_allocation_field(global_rsv_size) != 0
  413. ) {
  414. error("BTRFS: failed to collect allocation/metadata for '%s'", node->id);
  415. // make it refresh btrfs at the next iteration
  416. refresh_delta = refresh_every;
  417. continue;
  418. }
  419. }
  420. if(do_allocation_system != CONFIG_BOOLEAN_NO) {
  421. if (collect_btrfs_allocation_section_field(system, total_bytes) != 0
  422. || collect_btrfs_allocation_section_field(system, bytes_used) != 0) {
  423. error("BTRFS: failed to collect allocation/system for '%s'", node->id);
  424. // make it refresh btrfs at the next iteration
  425. refresh_delta = refresh_every;
  426. continue;
  427. }
  428. }
  429. // --------------------------------------------------------------------
  430. // allocation/disks
  431. if(do_allocation_disks == CONFIG_BOOLEAN_YES || (do_allocation_disks == CONFIG_BOOLEAN_AUTO &&
  432. ((node->all_disks_total && node->allocation_data_disk_total) ||
  433. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  434. do_allocation_disks = CONFIG_BOOLEAN_YES;
  435. if(unlikely(!node->st_allocation_disks)) {
  436. char id[RRD_ID_LENGTH_MAX + 1], name[RRD_ID_LENGTH_MAX + 1], title[200 + 1];
  437. snprintf(id, RRD_ID_LENGTH_MAX, "disk_%s", node->id);
  438. snprintf(name, RRD_ID_LENGTH_MAX, "disk_%s", node->label);
  439. snprintf(title, 200, "BTRFS Physical Disk Allocation");
  440. netdata_fix_chart_id(id);
  441. netdata_fix_chart_name(name);
  442. node->st_allocation_disks = rrdset_create_localhost(
  443. "btrfs"
  444. , id
  445. , name
  446. , node->label
  447. , "btrfs.disk"
  448. , title
  449. , "MiB"
  450. , PLUGIN_PROC_NAME
  451. , PLUGIN_PROC_MODULE_BTRFS_NAME
  452. , NETDATA_CHART_PRIO_BTRFS_DISK
  453. , update_every
  454. , RRDSET_TYPE_STACKED
  455. );
  456. node->rd_allocation_disks_unallocated = rrddim_add(node->st_allocation_disks, "unallocated", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  457. node->rd_allocation_disks_data_free = rrddim_add(node->st_allocation_disks, "data_free", "data free", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  458. node->rd_allocation_disks_data_used = rrddim_add(node->st_allocation_disks, "data_used", "data used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  459. node->rd_allocation_disks_metadata_free = rrddim_add(node->st_allocation_disks, "meta_free", "meta free", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  460. node->rd_allocation_disks_metadata_used = rrddim_add(node->st_allocation_disks, "meta_used", "meta used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  461. node->rd_allocation_disks_system_free = rrddim_add(node->st_allocation_disks, "sys_free", "sys free", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  462. node->rd_allocation_disks_system_used = rrddim_add(node->st_allocation_disks, "sys_used", "sys used", 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  463. add_labels_to_btrfs(node, node->st_allocation_disks);
  464. }
  465. else rrdset_next(node->st_allocation_disks);
  466. // unsigned long long disk_used = node->allocation_data_disk_used + node->allocation_metadata_disk_used + node->allocation_system_disk_used;
  467. unsigned long long disk_total = node->allocation_data_disk_total + node->allocation_metadata_disk_total + node->allocation_system_disk_total;
  468. unsigned long long disk_unallocated = node->all_disks_total - disk_total;
  469. rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_unallocated, disk_unallocated);
  470. rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_data_used, node->allocation_data_disk_used);
  471. rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_data_free, node->allocation_data_disk_total - node->allocation_data_disk_used);
  472. rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_metadata_used, node->allocation_metadata_disk_used);
  473. rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_metadata_free, node->allocation_metadata_disk_total - node->allocation_metadata_disk_used);
  474. rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_system_used, node->allocation_system_disk_used);
  475. rrddim_set_by_pointer(node->st_allocation_disks, node->rd_allocation_disks_system_free, node->allocation_system_disk_total - node->allocation_system_disk_used);
  476. rrdset_done(node->st_allocation_disks);
  477. }
  478. // --------------------------------------------------------------------
  479. // allocation/data
  480. if(do_allocation_data == CONFIG_BOOLEAN_YES || (do_allocation_data == CONFIG_BOOLEAN_AUTO &&
  481. (node->allocation_data_total_bytes ||
  482. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  483. do_allocation_data = CONFIG_BOOLEAN_YES;
  484. if(unlikely(!node->st_allocation_data)) {
  485. char id[RRD_ID_LENGTH_MAX + 1], name[RRD_ID_LENGTH_MAX + 1], title[200 + 1];
  486. snprintf(id, RRD_ID_LENGTH_MAX, "data_%s", node->id);
  487. snprintf(name, RRD_ID_LENGTH_MAX, "data_%s", node->label);
  488. snprintf(title, 200, "BTRFS Data Allocation");
  489. netdata_fix_chart_id(id);
  490. netdata_fix_chart_name(name);
  491. node->st_allocation_data = rrdset_create_localhost(
  492. "btrfs"
  493. , id
  494. , name
  495. , node->label
  496. , "btrfs.data"
  497. , title
  498. , "MiB"
  499. , PLUGIN_PROC_NAME
  500. , PLUGIN_PROC_MODULE_BTRFS_NAME
  501. , NETDATA_CHART_PRIO_BTRFS_DATA
  502. , update_every
  503. , RRDSET_TYPE_STACKED
  504. );
  505. node->rd_allocation_data_free = rrddim_add(node->st_allocation_data, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  506. node->rd_allocation_data_used = rrddim_add(node->st_allocation_data, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  507. add_labels_to_btrfs(node, node->st_allocation_data);
  508. }
  509. else rrdset_next(node->st_allocation_data);
  510. rrddim_set_by_pointer(node->st_allocation_data, node->rd_allocation_data_free, node->allocation_data_total_bytes - node->allocation_data_bytes_used);
  511. rrddim_set_by_pointer(node->st_allocation_data, node->rd_allocation_data_used, node->allocation_data_bytes_used);
  512. rrdset_done(node->st_allocation_data);
  513. }
  514. // --------------------------------------------------------------------
  515. // allocation/metadata
  516. if(do_allocation_metadata == CONFIG_BOOLEAN_YES || (do_allocation_metadata == CONFIG_BOOLEAN_AUTO &&
  517. (node->allocation_metadata_total_bytes ||
  518. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  519. do_allocation_metadata = CONFIG_BOOLEAN_YES;
  520. if(unlikely(!node->st_allocation_metadata)) {
  521. char id[RRD_ID_LENGTH_MAX + 1], name[RRD_ID_LENGTH_MAX + 1], title[200 + 1];
  522. snprintf(id, RRD_ID_LENGTH_MAX, "metadata_%s", node->id);
  523. snprintf(name, RRD_ID_LENGTH_MAX, "metadata_%s", node->label);
  524. snprintf(title, 200, "BTRFS Metadata Allocation");
  525. netdata_fix_chart_id(id);
  526. netdata_fix_chart_name(name);
  527. node->st_allocation_metadata = rrdset_create_localhost(
  528. "btrfs"
  529. , id
  530. , name
  531. , node->label
  532. , "btrfs.metadata"
  533. , title
  534. , "MiB"
  535. , PLUGIN_PROC_NAME
  536. , PLUGIN_PROC_MODULE_BTRFS_NAME
  537. , NETDATA_CHART_PRIO_BTRFS_METADATA
  538. , update_every
  539. , RRDSET_TYPE_STACKED
  540. );
  541. node->rd_allocation_metadata_free = rrddim_add(node->st_allocation_metadata, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  542. node->rd_allocation_metadata_used = rrddim_add(node->st_allocation_metadata, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  543. node->rd_allocation_metadata_reserved = rrddim_add(node->st_allocation_metadata, "reserved", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  544. add_labels_to_btrfs(node, node->st_allocation_metadata);
  545. }
  546. else rrdset_next(node->st_allocation_metadata);
  547. rrddim_set_by_pointer(node->st_allocation_metadata, node->rd_allocation_metadata_free, node->allocation_metadata_total_bytes - node->allocation_metadata_bytes_used - node->allocation_global_rsv_size);
  548. rrddim_set_by_pointer(node->st_allocation_metadata, node->rd_allocation_metadata_used, node->allocation_metadata_bytes_used);
  549. rrddim_set_by_pointer(node->st_allocation_metadata, node->rd_allocation_metadata_reserved, node->allocation_global_rsv_size);
  550. rrdset_done(node->st_allocation_metadata);
  551. }
  552. // --------------------------------------------------------------------
  553. // allocation/system
  554. if(do_allocation_system == CONFIG_BOOLEAN_YES || (do_allocation_system == CONFIG_BOOLEAN_AUTO &&
  555. (node->allocation_system_total_bytes ||
  556. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  557. do_allocation_system = CONFIG_BOOLEAN_YES;
  558. if(unlikely(!node->st_allocation_system)) {
  559. char id[RRD_ID_LENGTH_MAX + 1], name[RRD_ID_LENGTH_MAX + 1], title[200 + 1];
  560. snprintf(id, RRD_ID_LENGTH_MAX, "system_%s", node->id);
  561. snprintf(name, RRD_ID_LENGTH_MAX, "system_%s", node->label);
  562. snprintf(title, 200, "BTRFS System Allocation");
  563. netdata_fix_chart_id(id);
  564. netdata_fix_chart_name(name);
  565. node->st_allocation_system = rrdset_create_localhost(
  566. "btrfs"
  567. , id
  568. , name
  569. , node->label
  570. , "btrfs.system"
  571. , title
  572. , "MiB"
  573. , PLUGIN_PROC_NAME
  574. , PLUGIN_PROC_MODULE_BTRFS_NAME
  575. , NETDATA_CHART_PRIO_BTRFS_SYSTEM
  576. , update_every
  577. , RRDSET_TYPE_STACKED
  578. );
  579. node->rd_allocation_system_free = rrddim_add(node->st_allocation_system, "free", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  580. node->rd_allocation_system_used = rrddim_add(node->st_allocation_system, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
  581. add_labels_to_btrfs(node, node->st_allocation_system);
  582. }
  583. else rrdset_next(node->st_allocation_system);
  584. rrddim_set_by_pointer(node->st_allocation_system, node->rd_allocation_system_free, node->allocation_system_total_bytes - node->allocation_system_bytes_used);
  585. rrddim_set_by_pointer(node->st_allocation_system, node->rd_allocation_system_used, node->allocation_system_bytes_used);
  586. rrdset_done(node->st_allocation_system);
  587. }
  588. }
  589. return 0;
  590. }