From 00e6684d340c48618251cde845e61deff681e804 Mon Sep 17 00:00:00 2001 From: "Costa Tsaousis (ktsaou)" Date: Fri, 29 Apr 2016 02:16:30 +0300 Subject: [PATCH] disk now get the mount point at the menu (only when they are not partitions) #295 --- .gitignore | 2 + src/Makefile.am | 1 + src/proc_diskstats.c | 49 ++++++++--- src/proc_self_mountinfo.c | 170 ++++++++++++++++++++++++++++++++++++++ src/proc_self_mountinfo.h | 30 +++++++ web/index.html | 12 +-- 6 files changed, 248 insertions(+), 16 deletions(-) create mode 100644 src/proc_self_mountinfo.c create mode 100644 src/proc_self_mountinfo.h diff --git a/.gitignore b/.gitignore index 72c79d86..d3ae3ba6 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,5 @@ apps.plugin-profiler.sh CMakeCache.txt CMakeFiles/ cmake_install.cmake + +.jetbrains* diff --git a/src/Makefile.am b/src/Makefile.am index 69c5e550..9226e4c6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,6 +52,7 @@ netdata_SOURCES = \ proc_net_stat_conntrack.c \ proc_net_stat_synproxy.c \ proc_stat.c \ + proc_self_mountinfo.c proc_self_mountinfo.h \ proc_sys_kernel_random_entropy_avail.c \ proc_vmstat.c \ sys_kernel_mm_ksm.c \ diff --git a/src/proc_diskstats.c b/src/proc_diskstats.c index c2b84aae..98298d03 100644 --- a/src/proc_diskstats.c +++ b/src/proc_diskstats.c @@ -15,17 +15,21 @@ #include "rrd.h" #include "plugin_proc.h" +#include "proc_self_mountinfo.h" + #define RRD_TYPE_DISK "disk" struct disk { unsigned long major; unsigned long minor; int partition_id; // -1 = this is not a partition + char *family; struct disk *next; } *disk_root = NULL; struct disk *get_disk(unsigned long major, unsigned long minor) { static char path_find_block_device_partition[FILENAME_MAX + 1] = ""; + static struct mountinfo *mountinfo_root = NULL; struct disk *d; // search for it in our RAM list. @@ -81,6 +85,28 @@ struct disk *get_disk(unsigned long major, unsigned long minor) { } // if the /partition file does not exist, it is a disk, not a partition + // ------------------------------------------------------------------------ + // check if we can find its mount point + + // mountinfo_find() can be called with NULL mountinfo_root + struct mountinfo *mi = mountinfo_find(mountinfo_root, d->major, d->minor); + if(unlikely(!mi)) { + // mountinfo_free() can be called with NULL mountinfo_root + mountinfo_free(mountinfo_root); + + // re-read mountinfo in case something changed + mountinfo_root = mountinfo_read(); + + // search again for this disk + mi = mountinfo_find(mountinfo_root, d->major, d->minor); + } + + if(mi) + d->family = strdup(mi->mount_point); + // no need to check for NULL + else + d->family = NULL; + return d; } @@ -189,6 +215,9 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { else def_enabled = 0; + char *family = d->family; + if(!family) family = disk; + /* switch(major) { case 9: // MDs @@ -379,7 +408,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { } else error("Cannot read sector size for device %s from %s. Assuming 512.", disk, ssfilename); - st = rrdset_create(RRD_TYPE_DISK, disk, NULL, disk, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA); + st = rrdset_create(RRD_TYPE_DISK, disk, NULL, family, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA); rrddim_add(st, "reads", NULL, sector_size, 1024, RRDDIM_INCREMENTAL); rrddim_add(st, "writes", NULL, sector_size * -1, 1024, RRDDIM_INCREMENTAL); @@ -396,7 +425,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { if(ddo_ops) { st = rrdset_find_bytype("disk_ops", disk); if(!st) { - st = rrdset_create("disk_ops", disk, NULL, disk, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE); + st = rrdset_create("disk_ops", disk, NULL, family, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL); @@ -414,7 +443,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { if(ddo_qops) { st = rrdset_find_bytype("disk_qops", disk); if(!st) { - st = rrdset_create("disk_qops", disk, NULL, disk, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE); + st = rrdset_create("disk_qops", disk, NULL, family, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE); @@ -430,7 +459,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { if(ddo_backlog) { st = rrdset_find_bytype("disk_backlog", disk); if(!st) { - st = rrdset_create("disk_backlog", disk, NULL, disk, "disk.backlog", "Disk Backlog", "backlog (ms)", 2003, update_every, RRDSET_TYPE_AREA); + st = rrdset_create("disk_backlog", disk, NULL, family, "disk.backlog", "Disk Backlog", "backlog (ms)", 2003, update_every, RRDSET_TYPE_AREA); st->isdetail = 1; rrddim_add(st, "backlog", NULL, 1, 10, RRDDIM_INCREMENTAL); @@ -446,7 +475,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { if(ddo_util) { st = rrdset_find_bytype("disk_util", disk); if(!st) { - st = rrdset_create("disk_util", disk, NULL, disk, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA); + st = rrdset_create("disk_util", disk, NULL, family, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA); st->isdetail = 1; rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL); @@ -462,7 +491,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { if(ddo_mops) { st = rrdset_find_bytype("disk_mops", disk); if(!st) { - st = rrdset_create("disk_mops", disk, NULL, disk, "disk.mops", "Disk Merged Operations", "merged operations/s", 2021, update_every, RRDSET_TYPE_LINE); + st = rrdset_create("disk_mops", disk, NULL, family, "disk.mops", "Disk Merged Operations", "merged operations/s", 2021, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL); @@ -480,7 +509,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { if(ddo_iotime) { st = rrdset_find_bytype("disk_iotime", disk); if(!st) { - st = rrdset_create("disk_iotime", disk, NULL, disk, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE); + st = rrdset_create("disk_iotime", disk, NULL, family, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL); @@ -501,7 +530,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { if(ddo_iotime && ddo_ops) { st = rrdset_find_bytype("disk_await", disk); if(!st) { - st = rrdset_create("disk_await", disk, NULL, disk, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE); + st = rrdset_create("disk_await", disk, NULL, family, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE); @@ -517,7 +546,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { if(ddo_io && ddo_ops) { st = rrdset_find_bytype("disk_avgsz", disk); if(!st) { - st = rrdset_create("disk_avgsz", disk, NULL, disk, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA); + st = rrdset_create("disk_avgsz", disk, NULL, family, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA); st->isdetail = 1; rrddim_add(st, "reads", NULL, sector_size, 1024, RRDDIM_ABSOLUTE); @@ -533,7 +562,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { if(ddo_util && ddo_ops) { st = rrdset_find_bytype("disk_svctm", disk); if(!st) { - st = rrdset_create("disk_svctm", disk, NULL, disk, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE); + st = rrdset_create("disk_svctm", disk, NULL, family, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE); st->isdetail = 1; rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE); diff --git a/src/proc_self_mountinfo.c b/src/proc_self_mountinfo.c new file mode 100644 index 00000000..4337a2b9 --- /dev/null +++ b/src/proc_self_mountinfo.c @@ -0,0 +1,170 @@ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "log.h" +#include "appconfig.h" + +#include "proc_self_mountinfo.h" + +// find the mount info with the given major:minor +// in the supplied linked list of mountinfo structures +struct mountinfo *mountinfo_find(struct mountinfo *root, unsigned long major, unsigned long minor) { + struct mountinfo *mi; + + for(mi = root; mi ; mi = mi->next) + if(mi->major == major && mi->minor == minor) + return mi; + + return NULL; +} + +// free a linked list of mountinfo structures +void mountinfo_free(struct mountinfo *mi) { + if(unlikely(!mi)) + return; + + if(likely(mi->next)) + mountinfo_free(mi->next); + + free(mi->root); + free(mi->mount_point); + free(mi->mount_options); + + if(mi->optional_fields_count) { + int i; + for(i = 0; i < mi->optional_fields_count ; i++) + free(mi->optional_fields[i]); + } + free(mi->optional_fields); + + free(mi->filesystem); + free(mi->mount_source); + free(mi->super_options); + free(mi); +} + +// read the whole mountinfo into a linked list +struct mountinfo *mountinfo_read() { + procfile *ff = NULL; + + char filename[FILENAME_MAX + 1]; + snprintf(filename, FILENAME_MAX, "%s/proc/self/mountinfo", global_host_prefix); + ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT); + if(!ff) { + snprintf(filename, FILENAME_MAX, "%s/proc/1/mountinfo", global_host_prefix); + ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT); + if(!ff) return NULL; + } + + ff = procfile_readall(ff); + if(!ff) return NULL; + + struct mountinfo *root = NULL, *last = NULL, *mi = NULL; + + unsigned long l, lines = procfile_lines(ff); + error("MOUNTINFO: file has %u lines", lines); + for(l = 0; l < lines ;l++) { + if(procfile_linewords(ff, l) < 5) + continue; + + mi = malloc(sizeof(struct mountinfo)); + if(unlikely(!mi)) fatal("Cannot allocate memory for mountinfo"); + + if(unlikely(!root)) + root = last = mi; + else + last->next = mi; + + last = mi; + mi->next = NULL; + + unsigned long w = 0; + mi->id = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++; + mi->parentid = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++; + + char *major = procfile_lineword(ff, l, w), *minor; w++; + for(minor = major; *minor && *minor != ':' ;minor++) ; + *minor = '\0'; + minor++; + + mi->major = strtoul(major, NULL, 10); + mi->minor = strtoul(minor, NULL, 10); + + mi->root = strdup(procfile_lineword(ff, l, w)); w++; + if(unlikely(!mi->root)) fatal("Cannot allocate memory"); + + mi->mount_point = strdup(procfile_lineword(ff, l, w)); w++; + if(unlikely(!mi->mount_point)) fatal("Cannot allocate memory"); + + mi->mount_options = strdup(procfile_lineword(ff, l, w)); w++; + if(unlikely(!mi->mount_options)) fatal("Cannot allocate memory"); + + // count the optional fields + unsigned long wo = w; + mi->optional_fields_count = 0; + char *s = procfile_lineword(ff, l, w); + while(*s && *s != '-') { + w++; + s = procfile_lineword(ff, l, w); + mi->optional_fields_count++; + } + + if(unlikely(mi->optional_fields_count)) { + // we have some optional fields + // read them into a new array of pointers; + + mi->optional_fields = malloc(mi->optional_fields_count * sizeof(char *)); + if(unlikely(!mi->optional_fields)) + fatal("Cannot allocate memory for %d mountinfo optional fields", mi->optional_fields_count); + + int i; + for(i = 0; i < mi->optional_fields_count ; i++) { + mi->optional_fields[wo] = strdup(procfile_lineword(ff, l, w)); + if(!mi->optional_fields[wo]) fatal("Cannot allocate memory"); + wo++; + } + } + else + mi->optional_fields = NULL; + + if(likely(*s == '-')) { + mi->filesystem = strdup(procfile_lineword(ff, l, w)); w++; + if(!mi->filesystem) fatal("Cannot allocate memory"); + + mi->mount_source = strdup(procfile_lineword(ff, l, w)); w++; + if(!mi->mount_source) fatal("Cannot allocate memory"); + + mi->super_options = strdup(procfile_lineword(ff, l, w)); w++; + if(!mi->super_options) fatal("Cannot allocate memory"); + } + else { + mi->filesystem = NULL; + mi->mount_source = NULL; + mi->super_options = NULL; + } + + //info("MOUNTINFO: %u %u %u:%u root '%s', mount point '%s', mount options '%s', filesystem '%s', mount source '%s', super options '%s'", + // mi->id, + // mi->parentid, + // mi->major, + // mi->minor, + // mi->root, + // mi->mount_point, + // mi->mount_options, + // mi->filesystem, + // mi->mount_source, + // mi->super_options + //); + } + + procfile_close(ff); + return root; +} diff --git a/src/proc_self_mountinfo.h b/src/proc_self_mountinfo.h new file mode 100644 index 00000000..c215ad60 --- /dev/null +++ b/src/proc_self_mountinfo.h @@ -0,0 +1,30 @@ +#include "procfile.h" + +#ifndef NETDATA_PROC_SELF_MOUNTINFO_H +#define NETDATA_PROC_SELF_MOUNTINFO_H 1 + +struct mountinfo { + long id; // mount ID: unique identifier of the mount (may be reused after umount(2)). + long parentid; // parent ID: ID of parent mount (or of self for the top of the mount tree). + unsigned long major; // major:minor: value of st_dev for files on filesystem (see stat(2)). + unsigned long minor; + + char *root; // root: root of the mount within the filesystem. + char *mount_point; // mount point: mount point relative to the process's root. + char *mount_options; // mount options: per-mount options. + + int optional_fields_count; + char **optional_fields; // optional fields: zero or more fields of the form "tag[:value]". + + char *filesystem; // filesystem type: name of filesystem in the form "type[.subtype]". + char *mount_source; // mount source: filesystem-specific information or "none". + char *super_options; // super options: per-superblock options. + + struct mountinfo *next; +}; + +extern struct mountinfo *mountinfo_find(struct mountinfo *root, unsigned long major, unsigned long minor); +extern void mountinfo_free(struct mountinfo *mi); +extern struct mountinfo *mountinfo_read(); + +#endif /* NETDATA_PROC_SELF_MOUNTINFO_H */ \ No newline at end of file diff --git a/web/index.html b/web/index.html index 7be0bc3b..d5e0b27d 100644 --- a/web/index.html +++ b/web/index.html @@ -1442,11 +1442,11 @@ function enrichChartData(chart) { function name2id(s) { return s - .replace(' ', '_') - .replace('(', '_') - .replace(')', '_') - .replace('.', '_') - .replace('/', '_'); + .replace(/ /g, '_') + .replace(/\(/g, '_') + .replace(/\)/g, '_') + .replace(/\./g, '_') + .replace(/\//g, '_'); } function headMain(charts, duration) { @@ -1601,7 +1601,7 @@ function renderPage(menus, data) { // generate an entry at the main menu - sidebar += '
  • ' + menus[menu].title + '