- struct disk *next;
-} *disk_root = NULL;
-
-static struct mountinfo *disk_mountinfo_root = NULL;
-
-static inline void mountinfo_reload(int force) {
- static time_t last_loaded = 0;
- time_t now = time(NULL);
-
- if(force || now - last_loaded >= NETDATA_RELOAD_MOUNTINFO_EVERY) {
-//#ifdef NETDATA_INTERNAL_CHECKS
-// info("Reloading mountinfo");
-//#endif
-
- // mountinfo_free() can be called with NULL disk_mountinfo_root
- mountinfo_free(disk_mountinfo_root);
-
- // re-read mountinfo in case something changed
- disk_mountinfo_root = mountinfo_read();
-
- last_loaded = now;
- }
-}
-
-
-// linked list of mount points that are by default disabled
-static struct excluded_mount_point {
- const char *prefix;
- size_t len;
- struct excluded_mount_point *next;
-} *excluded_mount_points = NULL;
-
-static inline int is_mount_point_excluded(const char *mount_point) {
- static int initialized = 0;
-
- if(unlikely(!initialized)) {
- initialized = 1;
-
- char *a = config_get("plugin:proc:/proc/diskstats", "exclude space metrics on paths", "/var/run/user/ /run/user/");
- if(a && *a) {
- char *s = a;
-
- while(s && *s) {
- // skip all spaces
- while(isspace(*s)) s++;
-
- // empty string
- if(unlikely(!*s)) break;
-
- // find the next space
- char *c = s;
- while(*c && !isspace(*c)) c++;
-
- char *n;
- if(likely(*c)) n = c + 1;
- else n = NULL;
-
- // terminate our string
- *c = '\0';
-
- // allocate the structure
- struct excluded_mount_point *m = mallocz(sizeof(struct excluded_mount_point));
- m->prefix = strdup(s);
- m->len = strlen(m->prefix);
- m->next = excluded_mount_points;
- excluded_mount_points = m;
-
- // prepare for next loop
- s = n;
- if(likely(n)) *c = ' ';
- }
- }
- }
-
- size_t len = strlen(mount_point);
- struct excluded_mount_point *m;
- for(m = excluded_mount_points; m ; m = m->next) {
- if(m->len <= len) {
- // fprintf(stderr, "SPACE: comparing '%s' with '%s'\n", mount_point, m->prefix);
- if(strncmp(m->prefix, mount_point, m->len) == 0) {
- // fprintf(stderr, "SPACE: excluded '%s'\n", mount_point);
- return 1;
- }
- }
- }
-
- // fprintf(stderr, "SPACE: included '%s'\n", mount_point);
- return 0;
-}
-
-// Data to be stored in DICTIONARY mount_points used by do_disk_space_stats().
-// This DICTIONARY is used to lookup the settings of the mount point on each iteration.
-struct mount_point_metadata {
- int do_space;
- int do_inodes;
-};
-
-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) {
- static DICTIONARY *mount_points = NULL;
- int do_space, do_inodes;
-
- if(unlikely(!mount_points)) {
- mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
- }
-
- if(unlikely(d)) {
- // verify we collected the metrics for the right disk.
- // if not the mountpoint has changed.
-
- struct stat buff_stat;
- if(stat(mount_point, &buff_stat) == -1) {
- error("Failed to stat() for '%s' (disk '%s')", mount_point, disk);
- return;
- }
- else if(major(buff_stat.st_dev) != d->major || minor(buff_stat.st_dev) != d->minor) {
- error("Disk '%s' (disk '%s') switched major:minor", mount_point, disk);
- freez(d->mount_point);
- d->mount_point = NULL;
- d->mount_point_hash = 0;
- return;
- }
-
- do_space = d->do_space;
- do_inodes = d->do_inodes;
- }
- else {
- struct mount_point_metadata *m = dictionary_get(mount_points, mount_point);
- if(!m) {
- char var_name[4096 + 1];
- snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", mount_point);
-
- int def_space = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
- int def_inodes = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "inodes usage for all disks", CONFIG_ONDEMAND_ONDEMAND);
-
- if(is_mount_point_excluded(mount_point)) {
- def_space = CONFIG_ONDEMAND_NO;
- def_inodes = CONFIG_ONDEMAND_NO;
- }
-
- do_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
- do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
-
- struct mount_point_metadata mp = {
- .do_space = do_space,
- .do_inodes = do_inodes
- };
-
- dictionary_set(mount_points, mount_point, &mp, sizeof(struct mount_point_metadata));
- }
- else {
- do_space = m->do_space;
- do_inodes = m->do_inodes;
- }
- }
-
- if(do_space == CONFIG_ONDEMAND_NO && do_inodes == CONFIG_ONDEMAND_NO)
- return;
-
- struct statvfs buff_statvfs;
- if (statvfs(mount_point, &buff_statvfs) < 0) {
- error("Failed statvfs() for '%s' (disk '%s')", mount_point, disk);
- return;
- }
-
- // taken from get_fs_usage() found in coreutils
- unsigned long bsize = (buff_statvfs.f_frsize) ? buff_statvfs.f_frsize : buff_statvfs.f_bsize;
-
- fsblkcnt_t bavail = buff_statvfs.f_bavail;
- fsblkcnt_t btotal = buff_statvfs.f_blocks;
- fsblkcnt_t bavail_root = buff_statvfs.f_bfree;
- fsblkcnt_t breserved_root = bavail_root - bavail;
- fsblkcnt_t bused;
- if(likely(btotal >= bavail_root))
- bused = btotal - bavail_root;
- else
- bused = bavail_root - btotal;
-
-#ifdef NETDATA_INTERNAL_CHECKS
- if(unlikely(btotal != bavail + breserved_root + bused))
- 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);
-#endif
-
- // --------------------------------------------------------------------------
-
- fsfilcnt_t favail = buff_statvfs.f_favail;
- fsfilcnt_t ftotal = buff_statvfs.f_files;
- fsfilcnt_t favail_root = buff_statvfs.f_ffree;
- fsfilcnt_t freserved_root = favail_root - favail;
- fsfilcnt_t fused = ftotal - favail_root;
-
-#ifdef NETDATA_INTERNAL_CHECKS
- if(unlikely(btotal != bavail + breserved_root + bused))
- 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);
-#endif
-
- // --------------------------------------------------------------------------
-
- RRDSET *st;
-
- if(do_space == CONFIG_ONDEMAND_YES || (do_space == CONFIG_ONDEMAND_ONDEMAND && (bavail || breserved_root || bused))) {
- st = rrdset_find_bytype("disk_space", disk);
- if(!st) {
- char title[4096 + 1];
- snprintfz(title, 4096, "Disk Space Usage for %s [%s]", family, mount_source);
- st = rrdset_create("disk_space", disk, NULL, family, "disk.space", title, "GB", 2023, update_every, RRDSET_TYPE_STACKED);
-
- rrddim_add(st, "avail", NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "used" , NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
- rrddim_add(st, "reserved_for_root", "reserved for root", bsize, 1024*1024*1024, RRDDIM_ABSOLUTE);
- }
- else rrdset_next_usec(st, dt);
-
- rrddim_set(st, "avail", bavail);
- rrddim_set(st, "used", bused);
- rrddim_set(st, "reserved_for_root", breserved_root);
- rrdset_done(st);
- }
-
- // --------------------------------------------------------------------------