@cryptotaxi247 / netdata-1 / commits / e583f02ca

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();