calculate disk space statistics much like df does; fixes #1148
Costa Tsaousis (ktsaou) committed
Oct 22, 2016 at 13:15 UTC
b507120a95d168f1a334d2510324bbcb86663a84
1 file changed
+109
-74
src/proc_diskstats.c
+109
-74
@@ -29,6 +29,107 @@ static struct disk {
29
struct disk *next;
30
} *disk_root = NULL;
31
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; }
37
+
38
+static inline void disk_space_stats(struct disk *d, const char *disk, const char *family, int update_every, unsigned long long dt) {
39
+ struct statvfs buff_statvfs;
40
+ RRDSET *st;
41
+
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;
46
+
47
+ // verify we collected the metrics for the right disk.
48
+ // if not the mountpoint has changed.
49
+
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;
68
+
69
+#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);
72
+#endif
73
+
74
+ // --------------------------------------------------------------------------
75
+
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;
81
+
82
+#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);
85
+#endif
86
+
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;
91
+
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;
96
+
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);
102
+
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
+ }
108
+
109
+ // --------------------------------------------------------------------------
110
+
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;
116
+
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);
122
+
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
+ }
129
+ }
130
+ }
131
+}
132
+
133
static struct mountinfo *disk_mountinfo_root = NULL;
134
135
static struct disk *get_disk(unsigned long major, unsigned long minor, char *disk) {
@@ -189,8 +290,6 @@ static inline int select_positive_option(int option1, int option2) {
290
291
int do_proc_diskstats(int update_every, unsigned long long dt) {
292
static procfile *ff = NULL;
192
- static struct statvfs buff_statvfs;
193
- static struct stat buff_stat;
293
static int global_enable_new_disks_detected_at_runtime = CONFIG_ONDEMAND_YES,
294
global_enable_performance_for_physical_disks = CONFIG_ONDEMAND_ONDEMAND,
295
global_enable_performance_for_virtual_disks = CONFIG_ONDEMAND_NO,
@@ -250,22 +349,21 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
349
// Read parameters
350
351
char *disk;
253
- unsigned long long major = 0, minor = 0,
254
- reads = 0, mreads = 0, readsectors = 0, readms = 0,
352
+ unsigned long major = 0, minor = 0;
353
+
354
+ collected_number reads = 0, mreads = 0, readsectors = 0, readms = 0,
355
writes = 0, mwrites = 0, writesectors = 0, writems = 0,
256
- queued_ios = 0, busy_ms = 0, backlog_ms = 0,
257
- space_avail = 0, space_avail_root = 0, space_used = 0,
258
- inodes_avail = 0, inodes_avail_root = 0, inodes_used = 0;
356
+ queued_ios = 0, busy_ms = 0, backlog_ms = 0;
357
260
- unsigned long long last_reads = 0, last_readsectors = 0, last_readms = 0,
358
+ collected_number last_reads = 0, last_readsectors = 0, last_readms = 0,
359
last_writes = 0, last_writesectors = 0, last_writems = 0,
360
last_busy_ms = 0;
361
362
words = procfile_linewords(ff, l);
363
if(words < 14) continue;
364
267
- major = strtoull(procfile_lineword(ff, l, 0), NULL, 10);
268
- minor = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
365
+ major = strtoul(procfile_lineword(ff, l, 0), NULL, 10);
366
+ minor = strtoul(procfile_lineword(ff, l, 1), NULL, 10);
367
disk = procfile_lineword(ff, l, 2);
368
369
// # of reads completed # of writes completed
@@ -372,7 +470,6 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
470
471
if(d->mount_point)
472
def_performance = select_positive_option(def_performance, global_enable_performance_for_virtual_mountpoints);
375
-
473
break;
474
}
475
@@ -630,69 +727,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
727
// space metrics
728
729
if(d->mount_point && (d->do_space || d->do_inodes) ) {
633
- // collect space metrics using statvfs
634
-
635
- if (statvfs(d->mount_point, &buff_statvfs) < 0)
636
- error("Failed statvfs() for '%s' (disk '%s')", d->mount_point, d->disk);
637
- else {
638
- space_avail = buff_statvfs.f_bavail * buff_statvfs.f_bsize;
639
- space_avail_root = (buff_statvfs.f_bfree - buff_statvfs.f_bavail) * buff_statvfs.f_bsize;
640
- space_used = (buff_statvfs.f_blocks - buff_statvfs.f_bfree) * buff_statvfs.f_bsize;
641
-
642
- inodes_avail = buff_statvfs.f_favail;
643
- inodes_avail_root = buff_statvfs.f_ffree - buff_statvfs.f_favail;
644
- inodes_used = buff_statvfs.f_files - buff_statvfs.f_ffree;
645
-
646
- // verify we collected the metrics for the right disk.
647
- // if not the mountpoint has changed.
648
-
649
- if(stat(d->mount_point, &buff_stat) == -1)
650
- error("Failed to stat() for '%s' (disk '%s')", d->mount_point, d->disk);
651
- else {
652
- if(major(buff_stat.st_dev) == major && minor(buff_stat.st_dev) == minor) {
653
-
654
- // --------------------------------------------------------------------------
655
-
656
- if(d->do_space == CONFIG_ONDEMAND_YES || (d->do_space == CONFIG_ONDEMAND_ONDEMAND && (space_avail || space_avail_root || space_used))) {
657
- st = rrdset_find_bytype("disk_space", disk);
658
- if(!st) {
659
- st = rrdset_create("disk_space", disk, NULL, family, "disk.space", "Disk Space Usage", "GB", 2023, update_every, RRDSET_TYPE_STACKED);
660
- st->isdetail = 1;
661
-
662
- rrddim_add(st, "avail", NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
663
- rrddim_add(st, "used" , NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
664
- rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
665
- }
666
- else rrdset_next_usec(st, dt);
667
-
668
- rrddim_set(st, "avail", space_avail);
669
- rrddim_set(st, "used", space_used);
670
- rrddim_set(st, "reserved_for_root", space_avail_root);
671
- rrdset_done(st);
672
- }
673
-
674
- // --------------------------------------------------------------------------
675
-
676
- if(d->do_inodes == CONFIG_ONDEMAND_YES || (d->do_inodes == CONFIG_ONDEMAND_ONDEMAND && (inodes_avail || inodes_avail_root || inodes_used))) {
677
- st = rrdset_find_bytype("disk_inodes", disk);
678
- if(!st) {
679
- st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", "Disk Inodes Usage", "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
680
- st->isdetail = 1;
681
-
682
- rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
683
- rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
684
- rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
685
- }
686
- else rrdset_next_usec(st, dt);
687
-
688
- rrddim_set(st, "avail", inodes_avail);
689
- rrddim_set(st, "used", inodes_used);
690
- rrddim_set(st, "reserved_for_root", inodes_avail_root);
691
- rrdset_done(st);
692
- }
693
- }
694
- }
695
- }
730
+ disk_space_stats(d, disk, family, update_every, dt);
731
}
732
}
733