Self-cleaning obsolete filesystems in FreeBSD plugin
Vladimir Kobal committed
Mar 30, 2017 at 14:12 UTC
e583f02cae81958293ff716fb5c1a86ec7d0fe69
4 files changed
+301
-212
src/Makefile.am
+1
@@ -146,6 +146,7 @@ netdata_SOURCES += \
146
plugin_freebsd.c \
147
plugin_freebsd.h \
148
freebsd_sysctl.c \
149
+ freebsd_getmntinfo.c \
150
$(NULL)
151
else
152
if MACOS
src/freebsd_getmntinfo.c
new
+294
@@ -0,0 +1,294 @@
1
+#include "common.h"
2
+
3
+#include <sys/mount.h>
4
+
5
+struct mount_point {
6
+ char *name;
7
+ uint32_t hash;
8
+ size_t len;
9
+
10
+ // flags
11
+ int configured;
12
+ int enabled;
13
+ int updated;
14
+
15
+ int do_space;
16
+ int do_inodes;
17
+
18
+ size_t collected; // the number of times this has been collected
19
+
20
+ // charts and dimensions
21
+
22
+ RRDSET *st_space;
23
+ RRDDIM *rd_space_used;
24
+ RRDDIM *rd_space_avail;
25
+ RRDDIM *rd_space_reserved;
26
+
27
+ RRDSET *st_inodes;
28
+ RRDDIM *rd_inodes_used;
29
+ RRDDIM *rd_inodes_avail;
30
+
31
+ struct mount_point *next;
32
+};
33
+
34
+static struct mount_point *mount_points_root = NULL, *mount_points_last_used = NULL;
35
+
36
+static size_t mount_points_added = 0, mount_points_found = 0;
37
+
38
+static void mount_point_free(struct mount_point *m) {
39
+ if (likely(m->st_space))
40
+ rrdset_flag_set(m->st_space, RRDSET_FLAG_OBSOLETE);
41
+ if (likely(m->st_inodes))
42
+ rrdset_flag_set(m->st_inodes, RRDSET_FLAG_OBSOLETE);
43
+
44
+ mount_points_added--;
45
+ freez(m->name);
46
+ freez(m);
47
+}
48
+
49
+static void mount_points_cleanup() {
50
+ if (likely(mount_points_found == mount_points_added)) return;
51
+
52
+ struct mount_point *m = mount_points_root, *last = NULL;
53
+ while(m) {
54
+ if (unlikely(!m->updated)) {
55
+ // info("Removing mount point '%s', linked after '%s'", m->name, last?last->name:"ROOT");
56
+
57
+ if (mount_points_last_used == m)
58
+ mount_points_last_used = last;
59
+
60
+ struct mount_point *t = m;
61
+
62
+ if (m == mount_points_root || !last)
63
+ mount_points_root = m = m->next;
64
+
65
+ else
66
+ last->next = m = m->next;
67
+
68
+ t->next = NULL;
69
+ mount_point_free(t);
70
+ }
71
+ else {
72
+ last = m;
73
+ m->updated = 0;
74
+ m = m->next;
75
+ }
76
+ }
77
+}
78
+
79
+static struct mount_point *get_mount_point(const char *name) {
80
+ struct mount_point *m;
81
+
82
+ uint32_t hash = simple_hash(name);
83
+
84
+ // search it, from the last position to the end
85
+ for(m = mount_points_last_used ; m ; m = m->next) {
86
+ if (unlikely(hash == m->hash && !strcmp(name, m->name))) {
87
+ mount_points_last_used = m->next;
88
+ return m;
89
+ }
90
+ }
91
+
92
+ // search it from the beginning to the last position we used
93
+ for(m = mount_points_root ; m != mount_points_last_used ; m = m->next) {
94
+ if (unlikely(hash == m->hash && !strcmp(name, m->name))) {
95
+ mount_points_last_used = m->next;
96
+ return m;
97
+ }
98
+ }
99
+
100
+ // create a new one
101
+ m = callocz(1, sizeof(struct mount_point));
102
+ m->name = strdupz(name);
103
+ m->hash = simple_hash(m->name);
104
+ m->len = strlen(m->name);
105
+ mount_points_added++;
106
+
107
+ // link it to the end
108
+ if (mount_points_root) {
109
+ struct mount_point *e;
110
+ for(e = mount_points_root; e->next ; e = e->next) ;
111
+ e->next = m;
112
+ }
113
+ else
114
+ mount_points_root = m;
115
+
116
+ return m;
117
+}
118
+
119
+// --------------------------------------------------------------------------------------------------------------------
120
+// getmntinfo
121
+
122
+int do_getmntinfo(int update_every, usec_t dt) {
123
+ (void)dt;
124
+
125
+#define DELAULT_EXLUDED_PATHS "/proc/*"
126
+// taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
127
+#define DEFAULT_EXCLUDED_FILESYSTEMS "autofs procfs subfs devfs none"
128
+#define CONFIG_SECTION_GETMNTINFO "plugin:freebsd:getmntinfo"
129
+
130
+ static int enable_new_mount_points = -1;
131
+ static int do_space = -1, do_inodes = -1;
132
+ static SIMPLE_PATTERN *excluded_mountpoints = NULL;
133
+ static SIMPLE_PATTERN *excluded_filesystems = NULL;
134
+
135
+ if (unlikely(enable_new_mount_points == -1)) {
136
+ enable_new_mount_points = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO,
137
+ "enable new mount points detected at runtime",
138
+ CONFIG_BOOLEAN_AUTO);
139
+
140
+ do_space = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "space usage for all disks", CONFIG_BOOLEAN_AUTO);
141
+ do_inodes = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "inodes usage for all disks", CONFIG_BOOLEAN_AUTO);
142
+
143
+ excluded_mountpoints = simple_pattern_create(
144
+ config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on paths",
145
+ DELAULT_EXLUDED_PATHS),
146
+ SIMPLE_PATTERN_EXACT
147
+ );
148
+
149
+ excluded_filesystems = simple_pattern_create(
150
+ config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on filesystems",
151
+ DEFAULT_EXCLUDED_FILESYSTEMS),
152
+ SIMPLE_PATTERN_EXACT
153
+ );
154
+ }
155
+
156
+ if (likely(do_space || do_inodes)) {
157
+ struct statfs *mntbuf;
158
+ int mntsize;
159
+
160
+ // there is no mount info in sysctl MIBs
161
+ if (unlikely(!(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)))) {
162
+ error("FREEBSD: getmntinfo() failed");
163
+ do_space = 0;
164
+ error("DISABLED: disk_space.* charts");
165
+ do_inodes = 0;
166
+ error("DISABLED: disk_inodes.* charts");
167
+ error("DISABLED: getmntinfo module");
168
+ return 1;
169
+ } else {
170
+ int i;
171
+
172
+ mount_points_found = 0;
173
+
174
+ for (i = 0; i < mntsize; i++) {
175
+ char title[4096 + 1];
176
+
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 = config_get_boolean_ondemand(var_name, "enabled", m->enabled);
197
+
198
+ if (unlikely(m->enabled == CONFIG_BOOLEAN_NO))
199
+ continue;
200
+
201
+ m->do_space = config_get_boolean_ondemand(var_name, "space usage", do_space);
202
+ m->do_inodes = config_get_boolean_ondemand(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
+ // --------------------------------------------------------------------------
212
+
213
+ int rendered = 0;
214
+
215
+ if (m->do_space == CONFIG_BOOLEAN_YES || (m->do_space == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_blocks > 2))) {
216
+ if (unlikely(!m->st_space)) {
217
+ snprintfz(title, 4096, "Disk Space Usage for %s [%s]",
218
+ mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
219
+ m->st_space = rrdset_create_localhost("disk_space",
220
+ mntbuf[i].f_mntonname,
221
+ NULL,
222
+ mntbuf[i].f_mntonname,
223
+ "disk.space",
224
+ title,
225
+ "GB",
226
+ 2023,
227
+ update_every,
228
+ RRDSET_TYPE_STACKED
229
+ );
230
+
231
+ m->rd_space_avail = rrddim_add(m->st_space, "avail", NULL,
232
+ mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
233
+ m->rd_space_used = rrddim_add(m->st_space, "used", NULL,
234
+ mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
235
+ m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root",
236
+ mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
237
+ } else
238
+ rrdset_next(m->st_space);
239
+
240
+ rrddim_set_by_pointer(m->st_space, m->rd_space_avail, (collected_number) mntbuf[i].f_bavail);
241
+ rrddim_set_by_pointer(m->st_space, m->rd_space_used, (collected_number) (mntbuf[i].f_blocks -
242
+ mntbuf[i].f_bfree));
243
+ rrddim_set_by_pointer(m->st_space, m->rd_space_reserved, (collected_number) (mntbuf[i].f_bfree -
244
+ mntbuf[i].f_bavail));
245
+ rrdset_done(m->st_space);
246
+
247
+ rendered++;
248
+ }
249
+
250
+ // --------------------------------------------------------------------------
251
+
252
+ if (m->do_inodes == CONFIG_BOOLEAN_YES || (m->do_inodes == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_files > 1))) {
253
+ if (unlikely(!m->st_inodes)) {
254
+ snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]",
255
+ mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
256
+ m->st_inodes = rrdset_create_localhost("disk_inodes",
257
+ mntbuf[i].f_mntonname,
258
+ NULL,
259
+ mntbuf[i].f_mntonname,
260
+ "disk.inodes",
261
+ title,
262
+ "Inodes",
263
+ 2024,
264
+ update_every,
265
+ RRDSET_TYPE_STACKED
266
+ );
267
+
268
+ m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
269
+ m->rd_inodes_used = rrddim_add(m->st_inodes, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
270
+ } else
271
+ rrdset_next(m->st_inodes);
272
+
273
+ rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_avail, (collected_number) mntbuf[i].f_ffree);
274
+ rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_used, (collected_number) (mntbuf[i].f_files -
275
+ mntbuf[i].f_ffree));
276
+ rrdset_done(m->st_inodes);
277
+
278
+ rendered++;
279
+ }
280
+
281
+ if (likely(rendered))
282
+ m->collected++;
283
+ }
284
+ }
285
+ } else {
286
+ error("DISABLED: getmntinfo module");
287
+ return 1;
288
+ }
289
+
290
+ mount_points_cleanup();
291
+
292
+ return 0;
293
+}
294
+
src/freebsd_sysctl.c
-212
@@ -29,12 +29,6 @@
29
// --------------------------------------------------------------------------------------------------------------------
30
// common definitions and variables
31
32
-#define KILO_FACTOR 1024
33
-#define MEGA_FACTOR 1048576 // 1024 * 1024
34
-#define GIGA_FACTOR 1073741824 // 1024 * 1024 * 1024
35
-
36
-#define MAX_INT_DIGITS 10 // maximum number of digits for int
37
-
32
int system_pagesize = PAGE_SIZE;
33
int number_of_cpus = 1;
34
@@ -2784,212 +2778,6 @@ int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
2778
return 0;
2779
}
2780
2787
-// --------------------------------------------------------------------------------------------------------------------
2788
-// getmntinfo
2789
-
2790
-int do_getmntinfo(int update_every, usec_t dt) {
2791
- (void)dt;
2792
-
2793
-#define DELAULT_EXLUDED_PATHS "/proc/*"
2794
-// taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
2795
-#define DEFAULT_EXCLUDED_FILESYSTEMS "autofs procfs subfs devfs none"
2796
-#define CONFIG_SECTION_GETMNTINFO "plugin:freebsd:getmntinfo"
2797
-
2798
- static int do_space = -1, do_inodes = -1;
2799
-
2800
- if (unlikely(do_space == -1)) {
2801
- do_space = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "space usage for all disks", CONFIG_BOOLEAN_AUTO);
2802
- do_inodes = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "inodes usage for all disks", CONFIG_BOOLEAN_AUTO);
2803
- }
2804
-
2805
- if (likely(do_space || do_inodes)) {
2806
- struct statfs *mntbuf;
2807
- int mntsize;
2808
-
2809
- // there is no mount info in sysctl MIBs
2810
- if (unlikely(!(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)))) {
2811
- error("FREEBSD: getmntinfo() failed");
2812
- do_space = 0;
2813
- error("DISABLED: disk_space.* charts");
2814
- do_inodes = 0;
2815
- error("DISABLED: disk_inodes.* charts");
2816
- error("DISABLED: getmntinfo module");
2817
- return 1;
2818
- } else {
2819
- // Data to be stored in DICTIONARY mount_points.
2820
- // This DICTIONARY is used to lookup the settings of the mount point on each iteration.
2821
- struct mount_point_metadata {
2822
- int do_space;
2823
- int do_inodes;
2824
-
2825
- size_t collected; // the number of times this has been collected
2826
-
2827
- // charts and dimensions
2828
-
2829
- RRDSET *st_space;
2830
- RRDDIM *rd_space_used;
2831
- RRDDIM *rd_space_avail;
2832
- RRDDIM *rd_space_reserved;
2833
-
2834
- RRDSET *st_inodes;
2835
- RRDDIM *rd_inodes_used;
2836
- RRDDIM *rd_inodes_avail;
2837
- };
2838
- static DICTIONARY *mount_points = NULL;
2839
- static SIMPLE_PATTERN *excluded_mountpoints = NULL;
2840
- static SIMPLE_PATTERN *excluded_filesystems = NULL;
2841
- int i;
2842
-
2843
- if(unlikely(!mount_points)) {
2844
-
2845
- excluded_mountpoints = simple_pattern_create(
2846
- config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on paths",
2847
- DELAULT_EXLUDED_PATHS),
2848
- SIMPLE_PATTERN_EXACT
2849
- );
2850
-
2851
- excluded_filesystems = simple_pattern_create(
2852
- config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on filesystems",
2853
- DEFAULT_EXCLUDED_FILESYSTEMS),
2854
- SIMPLE_PATTERN_EXACT
2855
- );
2856
-
2857
- mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
2858
- }
2859
-
2860
- for (i = 0; i < mntsize; i++) {
2861
-
2862
- char title[4096 + 1];
2863
- int def_space, def_inodes, iter_space, iter_inodes;
2864
-
2865
- struct mount_point_metadata *m = dictionary_get(mount_points, mntbuf[i].f_mntonname);
2866
- if(unlikely(!m)) {
2867
- char var_name[4096 + 1];
2868
- snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETMNTINFO, mntbuf[i].f_mntonname);
2869
-
2870
- def_space = do_space;
2871
- def_inodes = do_space;
2872
-
2873
- if(unlikely(simple_pattern_matches(excluded_mountpoints, mntbuf[i].f_mntonname))) {
2874
- def_space = CONFIG_BOOLEAN_NO;
2875
- def_inodes = CONFIG_BOOLEAN_NO;
2876
- }
2877
-
2878
- if(unlikely(simple_pattern_matches(excluded_filesystems, mntbuf[i].f_fstypename))) {
2879
- def_space = CONFIG_BOOLEAN_NO;
2880
- def_inodes = CONFIG_BOOLEAN_NO;
2881
- }
2882
-
2883
- iter_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
2884
- iter_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
2885
-
2886
- struct mount_point_metadata mp = {
2887
- .do_space = iter_space,
2888
- .do_inodes = iter_inodes,
2889
-
2890
- .collected = 0,
2891
-
2892
- .st_space = NULL,
2893
- .rd_space_avail = NULL,
2894
- .rd_space_used = NULL,
2895
- .rd_space_reserved = NULL,
2896
-
2897
- .st_inodes = NULL,
2898
- .rd_inodes_avail = NULL,
2899
- .rd_inodes_used = NULL,
2900
- };
2901
-
2902
- m = dictionary_set(mount_points, mntbuf[i].f_mntonname, &mp, sizeof(struct mount_point_metadata));
2903
- }
2904
-
2905
- if(unlikely(m->do_space == CONFIG_BOOLEAN_NO && m->do_inodes == CONFIG_BOOLEAN_NO))
2906
- continue;
2907
-
2908
- if(unlikely(mntbuf[i].f_flags & MNT_RDONLY && !m->collected))
2909
- continue;
2910
-
2911
- // --------------------------------------------------------------------------
2912
-
2913
- int rendered = 0;
2914
-
2915
- if (m->do_space == CONFIG_BOOLEAN_YES || (m->do_space == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_blocks > 2))) {
2916
- if (unlikely(!m->st_space)) {
2917
- snprintfz(title, 4096, "Disk Space Usage for %s [%s]",
2918
- mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
2919
- m->st_space = rrdset_create_localhost("disk_space",
2920
- mntbuf[i].f_mntonname,
2921
- NULL,
2922
- mntbuf[i].f_mntonname,
2923
- "disk.space",
2924
- title,
2925
- "GB",
2926
- 2023,
2927
- update_every,
2928
- RRDSET_TYPE_STACKED
2929
- );
2930
-
2931
- m->rd_space_avail = rrddim_add(m->st_space, "avail", NULL,
2932
- mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
2933
- m->rd_space_used = rrddim_add(m->st_space, "used", NULL,
2934
- mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
2935
- m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root",
2936
- mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
2937
- } else
2938
- rrdset_next(m->st_space);
2939
-
2940
- rrddim_set_by_pointer(m->st_space, m->rd_space_avail, (collected_number) mntbuf[i].f_bavail);
2941
- rrddim_set_by_pointer(m->st_space, m->rd_space_used, (collected_number) (mntbuf[i].f_blocks -
2942
- mntbuf[i].f_bfree));
2943
- rrddim_set_by_pointer(m->st_space, m->rd_space_reserved, (collected_number) (mntbuf[i].f_bfree -
2944
- mntbuf[i].f_bavail));
2945
- rrdset_done(m->st_space);
2946
-
2947
- rendered++;
2948
- }
2949
-
2950
- // --------------------------------------------------------------------------
2951
-
2952
- if (m->do_inodes == CONFIG_BOOLEAN_YES || (m->do_inodes == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_files > 1))) {
2953
- if (unlikely(!m->st_inodes)) {
2954
- snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]",
2955
- mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
2956
- m->st_inodes = rrdset_create_localhost("disk_inodes",
2957
- mntbuf[i].f_mntonname,
2958
- NULL,
2959
- mntbuf[i].f_mntonname,
2960
- "disk.inodes",
2961
- title,
2962
- "Inodes",
2963
- 2024,
2964
- update_every,
2965
- RRDSET_TYPE_STACKED
2966
- );
2967
-
2968
- m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2969
- m->rd_inodes_used = rrddim_add(m->st_inodes, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
2970
- } else
2971
- rrdset_next(m->st_inodes);
2972
-
2973
- rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_avail, (collected_number) mntbuf[i].f_ffree);
2974
- rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_used, (collected_number) (mntbuf[i].f_files -
2975
- mntbuf[i].f_ffree));
2976
- rrdset_done(m->st_inodes);
2977
-
2978
- rendered++;
2979
- }
2980
-
2981
- if(likely(rendered))
2982
- m->collected++;
2983
- }
2984
- }
2985
- } else {
2986
- error("DISABLED: getmntinfo module");
2987
- return 1;
2988
- }
2989
-
2990
- return 0;
2991
-}
2992
-
2781
// --------------------------------------------------------------------------------------------------------------------
2782
// getifaddrs
2783
src/plugin_freebsd.h
+6
@@ -3,6 +3,12 @@
3
4
#include <sys/sysctl.h>
5
6
+#define KILO_FACTOR 1024
7
+#define MEGA_FACTOR 1048576 // 1024 * 1024
8
+#define GIGA_FACTOR 1073741824 // 1024 * 1024 * 1024
9
+
10
+#define MAX_INT_DIGITS 10 // maximum number of digits for int
11
+
12
void *freebsd_main(void *ptr);
13
14
extern int freebsd_plugin_init();