]> arthur.barton.de Git - netdata.git/commitdiff
disk now get the mount point at the menu (only when they are not partitions) #295
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Thu, 28 Apr 2016 23:16:30 +0000 (02:16 +0300)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Thu, 28 Apr 2016 23:16:30 +0000 (02:16 +0300)
.gitignore
src/Makefile.am
src/proc_diskstats.c
src/proc_self_mountinfo.c [new file with mode: 0644]
src/proc_self_mountinfo.h [new file with mode: 0644]
web/index.html

index 72c79d863305dbcb8a0c616dd36016cf75223820..d3ae3ba614e9bb2d9103a377d812766c80f7eb39 100644 (file)
@@ -72,3 +72,5 @@ apps.plugin-profiler.sh
 CMakeCache.txt
 CMakeFiles/
 cmake_install.cmake
+
+.jetbrains*
index 69c5e550cc645bff491aab803ec27e02c5dd13f1..9226e4c6ca686d7c7d330b66bc82da90fb47c763 100644 (file)
@@ -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 \
index c2b84aae10d11c65519d77a581372346ec8a2461..98298d03a6ed6a38b9e75cc0ff5d543acfca19e8 100644 (file)
 #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 (file)
index 0000000..4337a2b
--- /dev/null
@@ -0,0 +1,170 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#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 (file)
index 0000000..c215ad6
--- /dev/null
@@ -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
index 7be0bc3b35b58a6179f9301de18b1eef006c5ae4..d5e0b27db20a4d6464e9149c142d6dc3d3803474 100644 (file)
@@ -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 += '<li class=""><a href="#' + menu + '">' + menus[menu].title + '</a><ul class="nav">';
+               sidebar += '<li class=""><a href="#' + name2id(menu) + '">' + menus[menu].title + '</a><ul class="nav">';
                html += '<div role="section"><div role="sectionhead"><h1 id="' + menu + '" role="heading">' + menus[menu].title + '</h1></div><div id="' + menu + '" role="document">';
 
                if(menus[menu].info !== null)