#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.
}
// 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;
}
else
def_enabled = 0;
+ char *family = d->family;
+ if(!family) family = disk;
+
/*
switch(major) {
case 9: // MDs
}
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
--- /dev/null
+#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;
+}