@cryptotaxi247 / netdata-1 / commits / 25ffc0150

collect disk space utilization from all mounted disks; fixes #747; possibly fixes #605

Costa Tsaousis (ktsaou) committed Oct 23, 2016 at 02:08 UTC 25ffc015051f98268d4cd406dea3b1f7d6ec4160
4 files changed +328 -99
src/common.h
+1
@@ -64,6 +64,7 @@
64 #include <time.h>
65 #include <unistd.h>
66 #include <uuid/uuid.h>
67 +#include <mntent.h>
68
69 #ifdef STORAGE_WITH_MATH
70 #include <math.h>
src/proc_diskstats.c
+161 -85
@@ -6,13 +6,19 @@
6 #define DISK_TYPE_PARTITION 2
7 #define DISK_TYPE_CONTAINER 3
8
9 +#ifndef NETDATA_RELOAD_MOUNTINFO_EVERY
10 +#define NETDATA_RELOAD_MOUNTINFO_EVERY 10
11 +#endif
12 +
13 static struct disk {
14 char *disk; // the name of the disk (sda, sdb, etc)
15 unsigned long major;
16 unsigned long minor;
17 int sector_size;
18 int type;
19 +
20 char *mount_point;
21 + uint32_t mount_point_hash;
22
23 // disk options caching
24 int configured;
@@ -29,109 +35,148 @@ static struct disk {
35 struct disk *next;
36 } *disk_root = NULL;
37
32 -/* Return true if N is a known integer value. On many file systems,
33 - UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
34 - represents unknown. Use a rule that works on AIX file systems, and
35 - that almost-always works on other types. */
36 -static inline int known_value (uintmax_t n) { return n < UINTMAX_MAX - 1; }
38 +static struct mountinfo *disk_mountinfo_root = NULL;
39 +
40 +static inline void mountinfo_reload(int force) {
41 + static time_t last_loaded = 0;
42 + time_t now = time(NULL);
43 +
44 + if(force || now - last_loaded >= NETDATA_RELOAD_MOUNTINFO_EVERY) {
45 +//#ifdef NETDATA_INTERNAL_CHECKS
46 +// info("Reloading mountinfo");
47 +//#endif
48 +
49 + // mountinfo_free() can be called with NULL disk_mountinfo_root
50 + mountinfo_free(disk_mountinfo_root);
51 +
52 + // re-read mountinfo in case something changed
53 + disk_mountinfo_root = mountinfo_read();
54 +
55 + last_loaded = now;
56 + }
57 +}
58
38 -static inline void disk_space_stats(struct disk *d, const char *disk, const char *family, int update_every, unsigned long long dt) {
59 +static inline void do_disk_space_stats(struct disk *d, const char *mount_point, const char *mount_source, const char *disk, const char *family, int update_every, unsigned long long dt) {
60 struct statvfs buff_statvfs;
40 - RRDSET *st;
61 + if (statvfs(mount_point, &buff_statvfs) < 0) {
62 + error("Failed statvfs() for '%s' (disk '%s')", mount_point, disk);
63 + return;
64 + }
65
42 - if (statvfs(d->mount_point, &buff_statvfs) < 0)
43 - error("Failed statvfs() for '%s' (disk '%s')", d->mount_point, d->disk);
44 - else {
45 - struct stat buff_stat;
66 + int do_space, do_inodes;
67
68 + if(d) {
69 // verify we collected the metrics for the right disk.
70 // if not the mountpoint has changed.
71
50 - if(stat(d->mount_point, &buff_stat) == -1)
51 - error("Failed to stat() for '%s' (disk '%s')", d->mount_point, d->disk);
52 - else {
53 - if(major(buff_stat.st_dev) == d->major && minor(buff_stat.st_dev) == d->minor) {
54 -
55 - // http://stackoverflow.com/a/4965511
56 - // taken from get_fs_usage() found in coreutils
57 - unsigned long bsize = (buff_statvfs.f_frsize) ? buff_statvfs.f_frsize : buff_statvfs.f_bsize;
58 -
59 - fsblkcnt_t bavail = buff_statvfs.f_bavail;
60 - fsblkcnt_t btotal = buff_statvfs.f_blocks;
61 - fsblkcnt_t bavail_root = buff_statvfs.f_bfree;
62 - fsblkcnt_t breserved_root = bavail_root - bavail;
63 - fsblkcnt_t bused;
64 - if(likely(btotal >= bavail_root))
65 - bused = btotal - bavail_root;
66 - else
67 - bused = bavail_root - btotal;
72 + struct stat buff_stat;
73 + if(stat(mount_point, &buff_stat) == -1) {
74 + error("Failed to stat() for '%s' (disk '%s')", mount_point, disk);
75 + return;
76 + }
77 + else if(major(buff_stat.st_dev) != d->major || minor(buff_stat.st_dev) != d->minor) {
78 + error("Disk '%s' (disk '%s') switched major:minor", mount_point, disk);
79 + freez(d->mount_point);
80 + d->mount_point = NULL;
81 + d->mount_point_hash = 0;
82 + return;
83 + }
84 +
85 + do_space = d->do_space;
86 + do_inodes = d->do_inodes;
87 + }
88 + else {
89 + char var_name[4096 + 1];
90 + snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", mount_point);
91 +
92 + int def_space = CONFIG_ONDEMAND_ONDEMAND;
93 +
94 + // check the user configuration (this will also show our 'on demand' decision)
95 + def_space = config_get_boolean_ondemand(var_name, "enable space metrics", def_space);
96 +
97 + int ddo_space = def_space,
98 + ddo_inodes = def_space;
99 +
100 + do_space = config_get_boolean_ondemand(var_name, "space usage", ddo_space);
101 + do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", ddo_inodes);
102 + }
103 +
104 + // taken from get_fs_usage() found in coreutils
105 + unsigned long bsize = (buff_statvfs.f_frsize) ? buff_statvfs.f_frsize : buff_statvfs.f_bsize;
106 +
107 + fsblkcnt_t bavail = buff_statvfs.f_bavail;
108 + fsblkcnt_t btotal = buff_statvfs.f_blocks;
109 + fsblkcnt_t bavail_root = buff_statvfs.f_bfree;
110 + fsblkcnt_t breserved_root = bavail_root - bavail;
111 + fsblkcnt_t bused;
112 + if(likely(btotal >= bavail_root))
113 + bused = btotal - bavail_root;
114 + else
115 + bused = bavail_root - btotal;
116
117 #ifdef NETDATA_INTERNAL_CHECKS
70 - if(unlikely(btotal != bavail + breserved_root + bused))
71 - error("Disk block statistics for '%s' (disk '%s') do not sum up: total = %llu, available = %llu, reserved = %llu, used = %llu", d->mount_point, d->disk, (unsigned long long)btotal, (unsigned long long)bavail, (unsigned long long)breserved_root, (unsigned long long)bused);
118 + if(unlikely(btotal != bavail + breserved_root + bused))
119 + error("Disk block statistics for '%s' (disk '%s') do not sum up: total = %llu, available = %llu, reserved = %llu, used = %llu", mount_point, disk, (unsigned long long)btotal, (unsigned long long)bavail, (unsigned long long)breserved_root, (unsigned long long)bused);
120 #endif
121
74 - // --------------------------------------------------------------------------
122 + // --------------------------------------------------------------------------
123
76 - fsfilcnt_t favail = buff_statvfs.f_favail;
77 - fsfilcnt_t ftotal = buff_statvfs.f_files;
78 - fsfilcnt_t favail_root = buff_statvfs.f_ffree;
79 - fsfilcnt_t freserved_root = favail_root - favail;
80 - fsfilcnt_t fused = ftotal - favail_root;
124 + fsfilcnt_t favail = buff_statvfs.f_favail;
125 + fsfilcnt_t ftotal = buff_statvfs.f_files;
126 + fsfilcnt_t favail_root = buff_statvfs.f_ffree;
127 + fsfilcnt_t freserved_root = favail_root - favail;
128 + fsfilcnt_t fused = ftotal - favail_root;
129
130 #ifdef NETDATA_INTERNAL_CHECKS
83 - if(unlikely(btotal != bavail + breserved_root + bused))
84 - error("Disk inode statistics for '%s' (disk '%s') do not sum up: total = %llu, available = %llu, reserved = %llu, used = %llu", d->mount_point, d->disk, (unsigned long long)ftotal, (unsigned long long)favail, (unsigned long long)freserved_root, (unsigned long long)fused);
131 + if(unlikely(btotal != bavail + breserved_root + bused))
132 + error("Disk inode statistics for '%s' (disk '%s') do not sum up: total = %llu, available = %llu, reserved = %llu, used = %llu", mount_point, disk, (unsigned long long)ftotal, (unsigned long long)favail, (unsigned long long)freserved_root, (unsigned long long)fused);
133 #endif
134
87 - // --------------------------------------------------------------------------
88 -
89 - if(d->do_space == CONFIG_ONDEMAND_YES || (d->do_space == CONFIG_ONDEMAND_ONDEMAND && (bavail || breserved_root || bused))) {
90 - d->do_space = CONFIG_ONDEMAND_YES;
135 + // --------------------------------------------------------------------------
136
92 - st = rrdset_find_bytype("disk_space", disk);
93 - if(!st) {
94 - st = rrdset_create("disk_space", disk, NULL, family, "disk.space", "Disk Space Usage", "GB", 2023, update_every, RRDSET_TYPE_STACKED);
95 - st->isdetail = 1;
137 + RRDSET *st;
138
97 - rrddim_add(st, "avail", NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
98 - rrddim_add(st, "used" , NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
99 - rrddim_add(st, "reserved_for_root", "reserved for root", bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
100 - }
101 - else rrdset_next_usec(st, dt);
139 + if(do_space == CONFIG_ONDEMAND_YES || (do_space == CONFIG_ONDEMAND_ONDEMAND && (bavail || breserved_root || bused))) {
140 + st = rrdset_find_bytype("disk_space", disk);
141 + if(!st) {
142 + char title[4096 + 1];
143 + snprintfz(title, 4096, "Disk Space Usage for %s [%s]", family, mount_source);
144 + st = rrdset_create("disk_space", disk, NULL, family, "disk.space", title, "GB", 2023, update_every, RRDSET_TYPE_STACKED);
145
103 - rrddim_set(st, "avail", bavail);
104 - rrddim_set(st, "used", bused);
105 - rrddim_set(st, "reserved_for_root", breserved_root);
106 - rrdset_done(st);
107 - }
146 + rrddim_add(st, "avail", NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
147 + rrddim_add(st, "used" , NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
148 + rrddim_add(st, "reserved_for_root", "reserved for root", bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
149 + }
150 + else rrdset_next_usec(st, dt);
151
109 - // --------------------------------------------------------------------------
152 + rrddim_set(st, "avail", bavail);
153 + rrddim_set(st, "used", bused);
154 + rrddim_set(st, "reserved_for_root", breserved_root);
155 + rrdset_done(st);
156 + }
157
111 - if(d->do_inodes == CONFIG_ONDEMAND_YES || (d->do_inodes == CONFIG_ONDEMAND_ONDEMAND && (favail || freserved_root || fused))) {
112 - st = rrdset_find_bytype("disk_inodes", disk);
113 - if(!st) {
114 - st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", "Disk Inodes Usage", "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
115 - st->isdetail = 1;
158 + // --------------------------------------------------------------------------
159
117 - rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
118 - rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
119 - rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
120 - }
121 - else rrdset_next_usec(st, dt);
160 + if(do_inodes == CONFIG_ONDEMAND_YES || (do_inodes == CONFIG_ONDEMAND_ONDEMAND && (favail || freserved_root || fused))) {
161 + st = rrdset_find_bytype("disk_inodes", disk);
162 + if(!st) {
163 + char title[4096 + 1];
164 + snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", family, mount_source);
165 + st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", title, "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
166
123 - rrddim_set(st, "avail", favail);
124 - rrddim_set(st, "used", fused);
125 - rrddim_set(st, "reserved_for_root", freserved_root);
126 - rrdset_done(st);
127 - }
128 - }
167 + rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
168 + rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
169 + rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
170 }
171 + else rrdset_next_usec(st, dt);
172 +
173 + rrddim_set(st, "avail", favail);
174 + rrddim_set(st, "used", fused);
175 + rrddim_set(st, "reserved_for_root", freserved_root);
176 + rrdset_done(st);
177 }
178 }
179
133 -static struct mountinfo *disk_mountinfo_root = NULL;
134 -
180 static struct disk *get_disk(unsigned long major, unsigned long minor, char *disk) {
181 static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
182 static char path_to_get_hw_sector_size_partitions[FILENAME_MAX + 1] = "";
@@ -216,21 +261,20 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
261 // mountinfo_find() can be called with NULL disk_mountinfo_root
262 struct mountinfo *mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
263 if(unlikely(!mi)) {
219 - // mountinfo_free() can be called with NULL disk_mountinfo_root
220 - mountinfo_free(disk_mountinfo_root);
221 -
222 - // re-read mountinfo in case something changed
223 - disk_mountinfo_root = mountinfo_read();
264 + mountinfo_reload(1);
265
266 // search again for this disk
267 mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
268 }
269
229 - if(mi)
270 + if(mi) {
271 d->mount_point = strdupz(mi->mount_point);
231 - // no need to check for NULL
232 - else
272 + d->mount_point_hash = mi->mount_point_hash;
273 + }
274 + else {
275 d->mount_point = NULL;
276 + d->mount_point_hash = 0;
277 + }
278
279 // ------------------------------------------------------------------------
280 // find the disk sector size
@@ -344,6 +388,9 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
388 uint32_t lines = procfile_lines(ff), l;
389 uint32_t words;
390
391 + // this is smart enough not to reload it every time
392 + mountinfo_reload(0);
393 +
394 for(l = 0; l < lines ;l++) {
395 // --------------------------------------------------------------------------
396 // Read parameters
@@ -723,12 +770,41 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
770 }
771 }
772
773 + /*
774 // --------------------------------------------------------------------------
775 // space metrics
776
777 if(d->mount_point && (d->do_space || d->do_inodes) ) {
730 - disk_space_stats(d, disk, family, update_every, dt);
778 + do_disk_space_stats(d, d->mount_point, disk, disk, family, update_every, dt);
779 }
780 + */
781 + }
782 +
783 + // --------------------------------------------------------------------------
784 + // space metrics for non-block devices
785 +
786 + struct mountinfo *mi;
787 + for(mi = disk_mountinfo_root; mi ;mi = mi->next) {
788 + if(unlikely(mi->flags & MOUNTINFO_IS_DUMMY || mi->flags & MOUNTINFO_IS_BIND || mi->flags & MOUNTINFO_IS_SAME_DEV || mi->flags & MOUNTINFO_NO_STAT || mi->flags & MOUNTINFO_NO_SIZE))
789 + continue;
790 +
791 + /*
792 + // skip the ones with block devices
793 + int skip = 0;
794 + struct disk *d;
795 + for(d = disk_root; d ;d = d->next) {
796 + if(unlikely(d->mount_point && mi->mount_point_hash == d->mount_point_hash && strcmp(mi->mount_point, d->mount_point))) {
797 + skip = 1;
798 + break;
799 + }
800 + }
801 +
802 + if(unlikely(skip))
803 + continue;
804 + */
805 +
806 + // fprintf(stderr, "Will process mount point '%s', source '%s', filesystem '%s'\n", mi->mount_point, mi->mount_source, mi->filesystem);
807 + do_disk_space_stats(NULL, mi->mount_point, mi->mount_source, mi->persistent_id, mi->mount_point , update_every, dt);
808 }
809
810 return 0;
src/proc_self_mountinfo.c
+152 -14
@@ -1,5 +1,48 @@
1 #include "common.h"
2
3 +// ----------------------------------------------------------------------------
4 +// taken from gnulib/mountlist.c
5 +
6 +#ifndef ME_REMOTE
7 +/* A file system is "remote" if its Fs_name contains a ':'
8 + or if (it is of type (smbfs or cifs) and its Fs_name starts with '//')
9 + or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). */
10 +# define ME_REMOTE(Fs_name, Fs_type) \
11 + (strchr (Fs_name, ':') != NULL \
12 + || ((Fs_name)[0] == '/' \
13 + && (Fs_name)[1] == '/' \
14 + && (strcmp (Fs_type, "smbfs") == 0 \
15 + || strcmp (Fs_type, "cifs") == 0)) \
16 + || (strcmp("-hosts", Fs_name) == 0))
17 +#endif
18 +
19 +#define ME_DUMMY_0(Fs_name, Fs_type) \
20 + (strcmp (Fs_type, "autofs") == 0 \
21 + || strcmp (Fs_type, "proc") == 0 \
22 + || strcmp (Fs_type, "subfs") == 0 \
23 + /* for Linux 2.6/3.x */ \
24 + || strcmp (Fs_type, "debugfs") == 0 \
25 + || strcmp (Fs_type, "devpts") == 0 \
26 + || strcmp (Fs_type, "fusectl") == 0 \
27 + || strcmp (Fs_type, "mqueue") == 0 \
28 + || strcmp (Fs_type, "rpc_pipefs") == 0 \
29 + || strcmp (Fs_type, "sysfs") == 0 \
30 + /* FreeBSD, Linux 2.4 */ \
31 + || strcmp (Fs_type, "devfs") == 0 \
32 + /* for NetBSD 3.0 */ \
33 + || strcmp (Fs_type, "kernfs") == 0 \
34 + /* for Irix 6.5 */ \
35 + || strcmp (Fs_type, "ignore") == 0)
36 +
37 +/* Historically, we have marked as "dummy" any file system of type "none",
38 + but now that programs like du need to know about bind-mounted directories,
39 + we grant an exception to any with "bind" in its list of mount options.
40 + I.e., those are *not* dummy entries. */
41 +# define ME_DUMMY(Fs_name, Fs_type) \
42 + (ME_DUMMY_0 (Fs_name, Fs_type) || strcmp (Fs_type, "none") == 0)
43 +
44 +// ----------------------------------------------------------------------------
45 +
46 // find the mount info with the given major:minor
47 // in the supplied linked list of mountinfo structures
48 struct mountinfo *mountinfo_find(struct mountinfo *root, unsigned long major, unsigned long minor) {
@@ -72,6 +115,7 @@ void mountinfo_free(struct mountinfo *mi) {
115 freez(mi->root);
116 freez(mi->mount_point);
117 freez(mi->mount_options);
118 + freez(mi->persistent_id);
119
120 /*
121 if(mi->optional_fields_count) {
@@ -138,14 +182,6 @@ struct mountinfo *mountinfo_read() {
182
183 mi = mallocz(sizeof(struct mountinfo));
184
141 - if(unlikely(!root))
142 - root = last = mi;
143 - else
144 - last->next = mi;
145 -
146 - last = mi;
147 - mi->next = NULL;
148 -
185 unsigned long w = 0;
186 mi->id = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
187 mi->parentid = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
@@ -155,12 +191,15 @@ struct mountinfo *mountinfo_read() {
191
192 if(!*minor) {
193 error("Cannot parse major:minor on '%s' at line %lu of '%s'", major, l + 1, filename);
194 + freez(mi);
195 continue;
196 }
197
198 *minor = '\0';
199 minor++;
200
201 + mi->flags = 0;
202 +
203 mi->major = strtoul(major, NULL, 10);
204 mi->minor = strtoul(minor, NULL, 10);
205
@@ -170,6 +209,10 @@ struct mountinfo *mountinfo_read() {
209 mi->mount_point = strdupz_decoding_octal(procfile_lineword(ff, l, w)); w++;
210 mi->mount_point_hash = simple_hash(mi->mount_point);
211
212 + mi->persistent_id = strdupz(mi->mount_point);
213 + netdata_fix_chart_id(mi->persistent_id);
214 + mi->persistent_id_hash = simple_hash(mi->persistent_id);
215 +
216 mi->mount_options = strdupz(procfile_lineword(ff, l, w)); w++;
217
218 // count the optional fields
@@ -214,29 +257,124 @@ struct mountinfo *mountinfo_read() {
257 mi->mount_source_hash = simple_hash(mi->mount_source);
258
259 mi->super_options = strdupz(procfile_lineword(ff, l, w)); w++;
260 +
261 + if(ME_DUMMY(mi->mount_source, mi->filesystem))
262 + mi->flags |= MOUNTINFO_IS_DUMMY;
263 +
264 + if(ME_REMOTE(mi->mount_source, mi->filesystem))
265 + mi->flags |= MOUNTINFO_IS_REMOTE;
266 +
267 + // mark as BIND the duplicates (i.e. same filesystem + same source)
268 + {
269 + struct stat buf;
270 + if(unlikely(stat(mi->mount_point, &buf) == -1)) {
271 + mi->st_dev = 0;
272 + mi->flags |= MOUNTINFO_NO_STAT;
273 + }
274 + else {
275 + mi->st_dev = buf.st_dev;
276 +
277 + struct mountinfo *mt;
278 + for(mt = root; mt; mt = mt->next) {
279 + if(unlikely(mt->st_dev == mi->st_dev && !(mi->flags & MOUNTINFO_NO_STAT))) {
280 + if(strlen(mi->mount_point) < strlen(mt->mount_point))
281 + mt->flags |= MOUNTINFO_IS_SAME_DEV;
282 + else
283 + mi->flags |= MOUNTINFO_IS_SAME_DEV;
284 + }
285 + }
286 + }
287 + }
288 }
289 else {
290 mi->filesystem = NULL;
291 + mi->filesystem_hash = 0;
292 +
293 mi->mount_source = NULL;
294 + mi->mount_source_hash = 0;
295 +
296 mi->super_options = NULL;
297 +
298 + mi->st_dev = 0;
299 + }
300 +
301 + // check if it has size
302 + {
303 + struct statvfs buff_statvfs;
304 + if(statvfs(mi->mount_point, &buff_statvfs) < 0) {
305 + mi->flags |= MOUNTINFO_NO_STAT;
306 + }
307 + else if(!buff_statvfs.f_blocks /* || !buff_statvfs.f_files */) {
308 + mi->flags |= MOUNTINFO_NO_SIZE;
309 + }
310 }
311
312 + // link it
313 + if(unlikely(!root))
314 + root = mi;
315 + else
316 + last->next = mi;
317 +
318 + last = mi;
319 + mi->next = NULL;
320 +
321 /*
225 - info("MOUNTINFO: %u %u %u:%u root '%s', mount point '%s', mount options '%s', filesystem '%s', mount source '%s', super options '%s'",
322 +#ifdef NETDATA_INTERNAL_CHECKS
323 + fprintf(stderr, "MOUNTINFO: %ld %ld %lu:%lu root '%s', persistent id '%s', mount point '%s', mount options '%s', filesystem '%s', mount source '%s', super options '%s'%s%s%s%s%s%s\n",
324 mi->id,
325 mi->parentid,
326 mi->major,
327 mi->minor,
328 mi->root,
231 - mi->mount_point,
232 - mi->mount_options,
233 - mi->filesystem,
234 - mi->mount_source,
235 - mi->super_options
329 + mi->persistent_id,
330 + (mi->mount_point)?mi->mount_point:"",
331 + (mi->mount_options)?mi->mount_options:"",
332 + (mi->filesystem)?mi->filesystem:"",
333 + (mi->mount_source)?mi->mount_source:"",
334 + (mi->super_options)?mi->super_options:"",
335 + (mi->flags & MOUNTINFO_IS_DUMMY)?" DUMMY":"",
336 + (mi->flags & MOUNTINFO_IS_BIND)?" BIND":"",
337 + (mi->flags & MOUNTINFO_IS_REMOTE)?" REMOTE":"",
338 + (mi->flags & MOUNTINFO_NO_STAT)?" NOSTAT":"",
339 + (mi->flags & MOUNTINFO_NO_SIZE)?" NOSIZE":"",
340 + (mi->flags & MOUNTINFO_IS_SAME_DEV)?" SAMEDEV":""
341 );
342 +#endif
343 */
344 }
345
346 +/*
347 + {
348 + FILE *fp = setmntent(MOUNTED, "r");
349 + if (fp != NULL) {
350 + struct mntent mntbuf;
351 + struct mntent *mnt;
352 + char buf[4096 + 1];
353 +
354 + while ((mnt = getmntent_r(fp, &mntbuf, buf, 4096))) {
355 + char *bind = hasmntopt(mnt, "bind");
356 + if(bind) {
357 + struct mountinfo *mi;
358 + for(mi = root; mi ; mi = mi->next) {
359 + if(strcmp(mnt->mnt_dir, mi->mount_point) == 0) {
360 + fprintf(stderr, "Mount point '%s' is BIND\n", mi->mount_point);
361 + mi->flags |= MOUNTINFO_IS_BIND;
362 + break;
363 + }
364 + }
365 +
366 +#ifdef NETDATA_INTERNAL_CHECKS
367 + if(!mi) {
368 + error("Mount point '%s' not found in /proc/self/mountinfo", mnt->mnt_dir);
369 + }
370 +#endif
371 + }
372 + }
373 + endmntent(fp);
374 + }
375 + }
376 +*/
377 +
378 procfile_close(ff);
379 return root;
380 }
src/proc_self_mountinfo.h
+14
@@ -1,12 +1,22 @@
1 #ifndef NETDATA_PROC_SELF_MOUNTINFO_H
2 #define NETDATA_PROC_SELF_MOUNTINFO_H 1
3
4 +#define MOUNTINFO_IS_DUMMY 0x00000001
5 +#define MOUNTINFO_IS_REMOTE 0x00000002
6 +#define MOUNTINFO_IS_BIND 0x00000004
7 +#define MOUNTINFO_IS_SAME_DEV 0x00000008
8 +#define MOUNTINFO_NO_STAT 0x00000010
9 +#define MOUNTINFO_NO_SIZE 0x00000020
10 +
11 struct mountinfo {
12 long id; // mount ID: unique identifier of the mount (may be reused after umount(2)).
13 long parentid; // parent ID: ID of parent mount (or of self for the top of the mount tree).
14 unsigned long major; // major:minor: value of st_dev for files on filesystem (see stat(2)).
15 unsigned long minor;
16
17 + char *persistent_id; // a calculated persistent id for the mount point
18 + uint32_t persistent_id_hash;
19 +
20 char *root; // root: root of the mount within the filesystem.
21 uint32_t root_hash;
22
@@ -27,6 +37,10 @@ struct mountinfo {
37
38 char *super_options; // super options: per-superblock options.
39
40 + uint32_t flags;
41 +
42 + dev_t st_dev; // id of device as given by stat()
43 +
44 struct mountinfo *next;
45 };
46