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