diskstats: Change default behaviour
Display statistics for physical disks and mounted disks by default. Prevent alloc/free statvfs on each iteration. Minor perormance and readability changes.
Simon Nagl committed
May 1, 2016 at 15:57 UTC
af20533fbaac680e74205d7d1e6a7918c7eb2873
1 file changed
+76
-62
src/proc_diskstats.c
+76
-62
@@ -1,13 +1,15 @@
1
#ifdef HAVE_CONFIG_H
2
#include <config.h>
3
#endif
4
+#include <dirent.h>
5
+#include <fcntl.h>
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <string.h>
7
-#include <sys/types.h>
8
-#include <sys/stat.h>
9
#include <sys/statvfs.h>
10
-#include <fcntl.h>
10
+#include <sys/types.h>
11
+#include <unistd.h>
12
+
13
14
#include "common.h"
15
#include "log.h"
@@ -20,17 +22,20 @@
22
23
#define RRD_TYPE_DISK "disk"
24
25
+#define DISK_TYPE_PHYSICAL 1
26
+#define DISK_TYPE_PARTITION 2
27
+#define DISK_TYPE_CONTAINER 3
28
+
29
struct disk {
30
unsigned long major;
31
unsigned long minor;
26
- int partition_id; // -1 = this is not a partition
32
+ int type;
33
char *mount_point;
28
- char *family;
34
struct disk *next;
35
} *disk_root = NULL;
36
37
struct disk *get_disk(unsigned long major, unsigned long minor) {
33
- static char path_find_block_device_partition[FILENAME_MAX + 1] = "";
38
+ static char path_find_block_device[FILENAME_MAX + 1] = "";
39
static struct mountinfo *mountinfo_root = NULL;
40
struct disk *d;
41
@@ -46,10 +51,10 @@ struct disk *get_disk(unsigned long major, unsigned long minor) {
51
if(likely(d))
52
return d;
53
49
- if(unlikely(!path_find_block_device_partition[0])) {
50
- char filename[FILENAME_MAX + 1];
51
- snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/partition");
52
- snprintfz(path_find_block_device_partition, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device partition", filename));
54
+ if(unlikely(!path_find_block_device[0])) {
55
+ char dirname[FILENAME_MAX + 1];
56
+ snprintfz(dirname, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/%s");
57
+ snprintfz(path_find_block_device, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device infos", dirname));
58
}
59
60
// not found
@@ -59,7 +64,7 @@ struct disk *get_disk(unsigned long major, unsigned long minor) {
64
65
d->major = major;
66
d->minor = minor;
62
- d->partition_id = -1;
67
+ d->type = DISK_TYPE_PHYSICAL; // Default type. Changed later if not correct.
68
d->next = NULL;
69
70
// append it to the list
@@ -71,21 +76,36 @@ struct disk *get_disk(unsigned long major, unsigned long minor) {
76
last->next = d;
77
}
78
79
+ // ------------------------------------------------------------------------
80
+ // find the type of the device
81
+
82
// find if it is a partition
75
- // by reading /sys/dev/block/MAJOR:MINOR/partition
83
+ // by checking if /sys/dev/block/MAJOR:MINOR/partition is readable.
84
char buffer[FILENAME_MAX + 1];
77
- snprintfz(buffer, FILENAME_MAX, path_find_block_device_partition, major, minor);
78
-
79
- int fd = open(buffer, O_RDONLY, 0666);
80
- if(likely(fd != -1)) {
81
- // we opened it
82
- int bytes = read(fd, buffer, FILENAME_MAX);
83
- close(fd);
84
-
85
- if(bytes > 0)
86
- d->partition_id = strtoul(buffer, NULL, 10);
85
+ snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "partition");
86
+ if(access(buffer, R_OK) == 0) {
87
+ d->type = DISK_TYPE_PARTITION;
88
+ } else {
89
+ // find if it is a container
90
+ // by checking if /sys/dev/block/MAJOR:MINOR/slaves has entries
91
+ int is_container = 0;
92
+ snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "slaves/");
93
+ DIR *dirp = opendir(buffer);
94
+ if (dirp != NULL) {
95
+ struct dirent *dp;
96
+ while(dp = readdir(dirp)) {
97
+ // . and .. are also files in empty folders.
98
+ if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
99
+ continue;
100
+ }
101
+ d->type = DISK_TYPE_CONTAINER;
102
+ // Stop the loop after we found one file.
103
+ break;
104
+ }
105
+ if(closedir(dirp) == -1)
106
+ error("Unable to close dir %s", buffer);
107
+ }
108
}
88
- // if the /partition file does not exist, it is a disk, not a partition
109
110
// ------------------------------------------------------------------------
111
// check if we can find its mount point
@@ -117,6 +137,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
137
static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
138
static int enable_new_disks = -1;
139
static int do_io = -1, do_ops = -1, do_mops = -1, do_iotime = -1, do_qops = -1, do_util = -1, do_backlog = -1, do_space = -1;
140
+ static struct statvfs buff_statvfs;
141
142
if(enable_new_disks == -1) enable_new_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", CONFIG_ONDEMAND_ONDEMAND);
143
@@ -145,12 +166,6 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
166
ff = procfile_readall(ff);
167
if(!ff) return 0; // we return 0, so that we will retry to open it next time
168
148
- struct statvfs * buff_statvfs;
149
- if ( !(buff_statvfs = (struct statvfs *)
150
- malloc(sizeof(struct statvfs)))) {
151
- error("Failed to allocate memory to buffer.");
152
- }
153
-
169
uint32_t lines = procfile_lines(ff), l;
170
uint32_t words;
171
@@ -221,16 +236,17 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
236
237
struct disk *d = get_disk(major, minor);
238
224
- /*
225
- if(d->partition_id == -1)
239
+ // Enable statistics for physical disks and mount points by default.
240
+ if( (d->type == DISK_TYPE_PHYSICAL) || (d->mount_point != NULL) ) {
241
def_enabled = enable_new_disks;
227
- else
228
- def_enabled = 0;
229
- */
242
+ }
243
231
- // Enable real disks by default.
244
+ /*
245
+ // Enable physical disks by default.
246
// To fine out if it is a harddrive we use
247
// Linux Assigned Names and Numbers Authority (http://www.lanana.org/)
248
+ // We can't do that because proprietary disk drivers do not stick to
249
+ // the standard. To detect re
250
switch(major) {
251
case 8: // SCSI disk devices (0-15)
252
if(!(minor % 16)) {
@@ -461,6 +477,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
477
def_enabled = 0;
478
break;
479
}
480
+ */
481
482
char *mount_point = d->mount_point;
483
char *family = d->mount_point;
@@ -651,35 +668,33 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
668
// --------------------------------------------------------------------
669
670
if(ddo_space) {
654
- if(mount_point) {
655
- st = rrdset_find_bytype("disk_space", disk);
656
- if(!st) {
657
- st = rrdset_create("disk_space", disk, NULL, family, "disk.space", "Disk Space Usage", "Megabyte", 2023, update_every, RRDSET_TYPE_AREA);
658
- st->isdetail = 1;
659
-
660
- rrddim_add(st, "avail", NULL, 1, 1048576, RRDDIM_ABSOLUTE);
661
- rrddim_add(st, "reserved for root", NULL, 1, 1048576, RRDDIM_ABSOLUTE);
662
- rrddim_add(st, "used" , NULL, 1, 1045576, RRDDIM_ABSOLUTE);
671
+ if(!mount_point) {
672
+ if(ddo_space != CONFIG_ONDEMAND_ONDEMAND) {
673
+ error("Cannot find space usage for disk %s. It does not have a mount point.", family);
674
}
664
- else rrdset_next_usec(st, dt);
665
-
666
-
667
-
668
- if (statvfs(family, buff_statvfs) < 0) {
669
- error("Faild checking disk space usage of %s", family);
675
+ } else {
676
+ if (statvfs(family, &buff_statvfs) < 0) {
677
+ error("Failed checking disk space usage of %s", family);
678
} else {
671
- space_avail = buff_statvfs->f_bavail * buff_statvfs->f_bsize;
672
- space_avail_root = (buff_statvfs->f_bfree - buff_statvfs->f_bavail) * buff_statvfs->f_bsize;
673
- space_used = (buff_statvfs->f_blocks - buff_statvfs->f_bfree) * buff_statvfs->f_bsize;
674
- }
679
+ space_avail = buff_statvfs.f_bavail * buff_statvfs.f_bsize;
680
+ space_avail_root = (buff_statvfs.f_bfree - buff_statvfs.f_bavail) * buff_statvfs.f_bsize;
681
+ space_used = (buff_statvfs.f_blocks - buff_statvfs.f_bfree) * buff_statvfs.f_bsize;
682
+
683
+ st = rrdset_find_bytype("disk_space", disk);
684
+ if(!st) {
685
+ st = rrdset_create("disk_space", disk, NULL, family, "disk.space", "Disk Space Usage", "GB", 2023, update_every, RRDSET_TYPE_STACKED);
686
+ st->isdetail = 1;
687
+
688
+ rrddim_add(st, "avail", NULL, 1, 1000*1000*1000, RRDDIM_ABSOLUTE);
689
+ rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1000*1000*1000, RRDDIM_ABSOLUTE);
690
+ rrddim_add(st, "used" , NULL, 1, 1000*1000*1000, RRDDIM_ABSOLUTE);
691
+ }
692
+ else rrdset_next_usec(st, dt);
693
676
- rrddim_set(st, "avail", space_avail);
677
- rrddim_set(st, "reserved for root", space_avail_root);
678
- rrddim_set(st, "used", space_used);
679
- rrdset_done(st);
680
- } else {
681
- if(ddo_space != CONFIG_ONDEMAND_ONDEMAND) {
682
- error("Cannot find space usage for disk %s. It does not have a mount point.", family);
694
+ rrddim_set(st, "avail", space_avail);
695
+ rrddim_set(st, "reserved_for_root", space_avail_root);
696
+ rrddim_set(st, "used", space_used);
697
+ rrdset_done(st);
698
}
699
}
700
}
@@ -736,7 +751,6 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
751
}
752
}
753
}
739
- free(buff_statvfs);
754
755
return 0;
756
}