freebsd_getmntinfo.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "plugin_freebsd.h"
  3. #include <sys/mount.h>
  4. struct mount_point {
  5. char *name;
  6. uint32_t hash;
  7. size_t len;
  8. // flags
  9. int configured;
  10. int enabled;
  11. int updated;
  12. int do_space;
  13. int do_inodes;
  14. size_t collected; // the number of times this has been collected
  15. // charts and dimensions
  16. RRDSET *st_space;
  17. RRDDIM *rd_space_used;
  18. RRDDIM *rd_space_avail;
  19. RRDDIM *rd_space_reserved;
  20. RRDSET *st_inodes;
  21. RRDDIM *rd_inodes_used;
  22. RRDDIM *rd_inodes_avail;
  23. struct mount_point *next;
  24. };
  25. static struct mount_point *mount_points_root = NULL, *mount_points_last_used = NULL;
  26. static size_t mount_points_added = 0, mount_points_found = 0;
  27. static void mount_point_free(struct mount_point *m) {
  28. if (likely(m->st_space))
  29. rrdset_is_obsolete(m->st_space);
  30. if (likely(m->st_inodes))
  31. rrdset_is_obsolete(m->st_inodes);
  32. mount_points_added--;
  33. freez(m->name);
  34. freez(m);
  35. }
  36. static void mount_points_cleanup() {
  37. if (likely(mount_points_found == mount_points_added)) return;
  38. struct mount_point *m = mount_points_root, *last = NULL;
  39. while(m) {
  40. if (unlikely(!m->updated)) {
  41. // info("Removing mount point '%s', linked after '%s'", m->name, last?last->name:"ROOT");
  42. if (mount_points_last_used == m)
  43. mount_points_last_used = last;
  44. struct mount_point *t = m;
  45. if (m == mount_points_root || !last)
  46. mount_points_root = m = m->next;
  47. else
  48. last->next = m = m->next;
  49. t->next = NULL;
  50. mount_point_free(t);
  51. }
  52. else {
  53. last = m;
  54. m->updated = 0;
  55. m = m->next;
  56. }
  57. }
  58. }
  59. static struct mount_point *get_mount_point(const char *name) {
  60. struct mount_point *m;
  61. uint32_t hash = simple_hash(name);
  62. // search it, from the last position to the end
  63. for(m = mount_points_last_used ; m ; m = m->next) {
  64. if (unlikely(hash == m->hash && !strcmp(name, m->name))) {
  65. mount_points_last_used = m->next;
  66. return m;
  67. }
  68. }
  69. // search it from the beginning to the last position we used
  70. for(m = mount_points_root ; m != mount_points_last_used ; m = m->next) {
  71. if (unlikely(hash == m->hash && !strcmp(name, m->name))) {
  72. mount_points_last_used = m->next;
  73. return m;
  74. }
  75. }
  76. // create a new one
  77. m = callocz(1, sizeof(struct mount_point));
  78. m->name = strdupz(name);
  79. m->hash = simple_hash(m->name);
  80. m->len = strlen(m->name);
  81. mount_points_added++;
  82. // link it to the end
  83. if (mount_points_root) {
  84. struct mount_point *e;
  85. for(e = mount_points_root; e->next ; e = e->next) ;
  86. e->next = m;
  87. }
  88. else
  89. mount_points_root = m;
  90. return m;
  91. }
  92. // --------------------------------------------------------------------------------------------------------------------
  93. // getmntinfo
  94. int do_getmntinfo(int update_every, usec_t dt) {
  95. (void)dt;
  96. #define DEFAULT_EXCLUDED_PATHS "/proc/*"
  97. // taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
  98. #define DEFAULT_EXCLUDED_FILESYSTEMS "autofs procfs subfs devfs none"
  99. #define CONFIG_SECTION_GETMNTINFO "plugin:freebsd:getmntinfo"
  100. static int enable_new_mount_points = -1;
  101. static int do_space = -1, do_inodes = -1;
  102. static SIMPLE_PATTERN *excluded_mountpoints = NULL;
  103. static SIMPLE_PATTERN *excluded_filesystems = NULL;
  104. if (unlikely(enable_new_mount_points == -1)) {
  105. enable_new_mount_points = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO,
  106. "enable new mount points detected at runtime",
  107. CONFIG_BOOLEAN_AUTO);
  108. do_space = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "space usage for all disks", CONFIG_BOOLEAN_AUTO);
  109. do_inodes = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "inodes usage for all disks", CONFIG_BOOLEAN_AUTO);
  110. excluded_mountpoints = simple_pattern_create(
  111. config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on paths",
  112. DEFAULT_EXCLUDED_PATHS)
  113. , NULL
  114. , SIMPLE_PATTERN_EXACT
  115. );
  116. excluded_filesystems = simple_pattern_create(
  117. config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on filesystems",
  118. DEFAULT_EXCLUDED_FILESYSTEMS)
  119. , NULL
  120. , SIMPLE_PATTERN_EXACT
  121. );
  122. }
  123. if (likely(do_space || do_inodes)) {
  124. struct statfs *mntbuf;
  125. int mntsize;
  126. // there is no mount info in sysctl MIBs
  127. if (unlikely(!(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)))) {
  128. error("FREEBSD: getmntinfo() failed");
  129. do_space = 0;
  130. error("DISABLED: disk_space.* charts");
  131. do_inodes = 0;
  132. error("DISABLED: disk_inodes.* charts");
  133. error("DISABLED: getmntinfo module");
  134. return 1;
  135. } else {
  136. int i;
  137. mount_points_found = 0;
  138. for (i = 0; i < mntsize; i++) {
  139. char title[4096 + 1];
  140. struct mount_point *m = get_mount_point(mntbuf[i].f_mntonname);
  141. m->updated = 1;
  142. mount_points_found++;
  143. if (unlikely(!m->configured)) {
  144. char var_name[4096 + 1];
  145. // this is the first time we see this filesystem
  146. // remember we configured it
  147. m->configured = 1;
  148. m->enabled = enable_new_mount_points;
  149. if (likely(m->enabled))
  150. m->enabled = !(simple_pattern_matches(excluded_mountpoints, mntbuf[i].f_mntonname)
  151. || simple_pattern_matches(excluded_filesystems, mntbuf[i].f_fstypename));
  152. snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETMNTINFO, mntbuf[i].f_mntonname);
  153. m->enabled = config_get_boolean_ondemand(var_name, "enabled", m->enabled);
  154. if (unlikely(m->enabled == CONFIG_BOOLEAN_NO))
  155. continue;
  156. m->do_space = config_get_boolean_ondemand(var_name, "space usage", do_space);
  157. m->do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", do_inodes);
  158. }
  159. if (unlikely(!m->enabled))
  160. continue;
  161. if (unlikely(mntbuf[i].f_flags & MNT_RDONLY && !m->collected))
  162. continue;
  163. // --------------------------------------------------------------------------
  164. int rendered = 0;
  165. if (m->do_space == CONFIG_BOOLEAN_YES || (m->do_space == CONFIG_BOOLEAN_AUTO &&
  166. (mntbuf[i].f_blocks > 2 ||
  167. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  168. if (unlikely(!m->st_space)) {
  169. snprintfz(title, 4096, "Disk Space Usage for %s [%s]",
  170. mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
  171. m->st_space = rrdset_create_localhost("disk_space",
  172. mntbuf[i].f_mntonname,
  173. NULL,
  174. mntbuf[i].f_mntonname,
  175. "disk.space",
  176. title,
  177. "GiB",
  178. "freebsd.plugin",
  179. "getmntinfo",
  180. NETDATA_CHART_PRIO_DISKSPACE_SPACE,
  181. update_every,
  182. RRDSET_TYPE_STACKED
  183. );
  184. m->rd_space_avail = rrddim_add(m->st_space, "avail", NULL,
  185. mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
  186. m->rd_space_used = rrddim_add(m->st_space, "used", NULL,
  187. mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
  188. m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root",
  189. mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
  190. } else
  191. rrdset_next(m->st_space);
  192. rrddim_set_by_pointer(m->st_space, m->rd_space_avail, (collected_number) mntbuf[i].f_bavail);
  193. rrddim_set_by_pointer(m->st_space, m->rd_space_used, (collected_number) (mntbuf[i].f_blocks -
  194. mntbuf[i].f_bfree));
  195. rrddim_set_by_pointer(m->st_space, m->rd_space_reserved, (collected_number) (mntbuf[i].f_bfree -
  196. mntbuf[i].f_bavail));
  197. rrdset_done(m->st_space);
  198. rendered++;
  199. }
  200. // --------------------------------------------------------------------------
  201. if (m->do_inodes == CONFIG_BOOLEAN_YES || (m->do_inodes == CONFIG_BOOLEAN_AUTO &&
  202. (mntbuf[i].f_files > 1 ||
  203. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  204. if (unlikely(!m->st_inodes)) {
  205. snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]",
  206. mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
  207. m->st_inodes = rrdset_create_localhost("disk_inodes",
  208. mntbuf[i].f_mntonname,
  209. NULL,
  210. mntbuf[i].f_mntonname,
  211. "disk.inodes",
  212. title,
  213. "inodes",
  214. "freebsd.plugin",
  215. "getmntinfo",
  216. NETDATA_CHART_PRIO_DISKSPACE_INODES,
  217. update_every,
  218. RRDSET_TYPE_STACKED
  219. );
  220. m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  221. m->rd_inodes_used = rrddim_add(m->st_inodes, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  222. } else
  223. rrdset_next(m->st_inodes);
  224. rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_avail, (collected_number) mntbuf[i].f_ffree);
  225. rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_used, (collected_number) (mntbuf[i].f_files -
  226. mntbuf[i].f_ffree));
  227. rrdset_done(m->st_inodes);
  228. rendered++;
  229. }
  230. if (likely(rendered))
  231. m->collected++;
  232. }
  233. }
  234. } else {
  235. error("DISABLED: getmntinfo module");
  236. return 1;
  237. }
  238. mount_points_cleanup();
  239. return 0;
  240. }