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