summaryrefslogtreecommitdiff
path: root/src/pmdas/linux/proc_partitions.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmdas/linux/proc_partitions.c')
-rw-r--r--src/pmdas/linux/proc_partitions.c808
1 files changed, 808 insertions, 0 deletions
diff --git a/src/pmdas/linux/proc_partitions.c b/src/pmdas/linux/proc_partitions.c
new file mode 100644
index 0000000..4901892
--- /dev/null
+++ b/src/pmdas/linux/proc_partitions.c
@@ -0,0 +1,808 @@
+/*
+ * Linux Partitions (disk and disk partition IO stats) Cluster
+ *
+ * Copyright (c) 2012-2014 Red Hat.
+ * Copyright (c) 2008,2012 Aconex. All Rights Reserved.
+ * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>
+
+#include "pmapi.h"
+#include "impl.h"
+#include "pmda.h"
+#include "convert.h"
+#include "clusters.h"
+#include "indom.h"
+#include "proc_partitions.h"
+
+extern int _pm_numdisks;
+
+/*
+ * _pm_ispartition : return true if arg is a partition name
+ * return false if arg is a disk name
+ * ide disks are named e.g. hda
+ * ide partitions are named e.g. hda1
+ *
+ * scsi disks are named e.g. sda
+ * scsi partitions are named e.g. sda1
+ *
+ * device-mapper devices are named dm-[0-9]* and are mapped to their persistent
+ * name using the symlinks in /dev/mapper.
+ *
+ * devfs scsi disks are named e.g. scsi/host0/bus0/target1/lun0/disc
+ * devfs scsi partitions are named e.g. scsi/host0/bus0/target1/lun0/part1
+ *
+ * Mylex raid disks are named e.g. rd/c0d0 or dac960/c0d0
+ * Mylex raid partitions are named e.g. rd/c0d0p1 or dac960/c0d0p1
+ *
+ * What this now tries to do is be a bit smarter, and guess that names
+ * with slashes that end in the form .../c0t0d0[p0], and ones without
+ * are good old 19th century device names like xx0 or xx0a.
+ */
+static int
+_pm_isloop(char *dname)
+{
+ return strncmp(dname, "loop", 4) == 0;
+}
+
+static int
+_pm_isramdisk(char *dname)
+{
+ return strncmp(dname, "ram", 3) == 0;
+}
+
+static int
+_pm_ismmcdisk(char *dname)
+{
+ if (strncmp(dname, "mmcblk", 6) != 0)
+ return 0;
+ /*
+ * Are we a disk or a partition of the disk? If there is a "p"
+ * assume it is a partition - e.g. mmcblk0p6.
+ */
+ return (strchr(dname + 6, 'p') == NULL);
+}
+
+/*
+ * return true if arg is a device-mapper device
+ */
+static int
+_pm_isdm(char *dname)
+{
+ return strncmp(dname, "dm-", 3) == 0;
+}
+
+/*
+ * slight improvement to heuristic suggested by
+ * Tim Bradshaw <tfb@cley.com> on 29 Dec 2003
+ */
+int
+_pm_ispartition(char *dname)
+{
+ int p, m = strlen(dname) - 1;
+
+ /*
+ * looking at something like foo/x, and we hope x ends p<n>, for
+ * a partition, or not for a disk.
+ */
+ if (strchr(dname, '/')) {
+ for (p = m; p > 0 && isdigit((int)dname[p]); p--)
+ ;
+ if (p == m)
+ /* name had no trailing digits. Wildly guess a disk. */
+ return 1;
+ else
+ /*
+ * ends with digits, if preceding character is a 'p' punt
+ * on a partition
+ */
+ return (dname[p] == 'p'? 1 : 0);
+ }
+ else {
+ /*
+ * default test : partition names end in a digit do not
+ * look like loopback devices. Handle other special-cases
+ * here - mostly seems to be RAM-type disk drivers that're
+ * choosing to end device names with numbers.
+ */
+ return isdigit((int)dname[m]) &&
+ !_pm_isloop(dname) &&
+ !_pm_isramdisk(dname) &&
+ !_pm_ismmcdisk(dname) &&
+ !_pm_isdm(dname);
+ }
+}
+
+/*
+ * return true is arg is an xvm volume name
+ */
+static int
+_pm_isxvmvol(char *dname)
+{
+ return strstr(dname, "xvm") != NULL;
+}
+
+/*
+ * return true is arg is a disk name
+ */
+static int
+_pm_isdisk(char *dname)
+{
+ return !_pm_isloop(dname) && !_pm_isramdisk(dname) && !_pm_ispartition(dname) && !_pm_isxvmvol(dname) && !_pm_isdm(dname);
+}
+
+static void
+refresh_udev(pmInDom disk_indom, pmInDom partitions_indom)
+{
+ char buf[MAXNAMELEN];
+ char realname[MAXNAMELEN];
+ char *shortname;
+ char *p;
+ char *udevname;
+ FILE *pfp;
+ partitions_entry_t *entry;
+ int indom;
+ int inst;
+
+ if (access("/dev/xscsi", R_OK) != 0)
+ return;
+ if (!(pfp = popen("find /dev/xscsi -name disc -o -name part[0-9]*", "r")))
+ return;
+ while (fgets(buf, sizeof(buf), pfp)) {
+ if ((p = strrchr(buf, '\n')) != NULL)
+ *p = '\0';
+ if (realpath(buf, realname)) {
+ udevname = buf + 5; /* /dev/xscsi/.... */
+ if ((shortname = strrchr(realname, '/')) != NULL) {
+ shortname++;
+ indom = _pm_ispartition(shortname) ?
+ partitions_indom : disk_indom;
+ if (pmdaCacheLookupName(indom, shortname, &inst, (void **)&entry) != PMDA_CACHE_ACTIVE)
+ continue;
+ entry->udevnamebuf = strdup(udevname);
+ pmdaCacheStore(indom, PMDA_CACHE_HIDE, shortname, entry); /* inactive */
+ pmdaCacheStore(indom, PMDA_CACHE_ADD, udevname, entry); /* active */
+ }
+ }
+ }
+ pclose(pfp);
+}
+
+/*
+ * Replace dm-* in namebuf with it's persistent name. This is a symlink in
+ * /dev/mapper/something -> ../dm-X where dm-X is currently in namebuf. Some
+ * older platforms (e.g. RHEL5) don't have the symlinks, just block devices
+ * in /dev/mapper. On newer kernels, the persistent name mapping is also
+ * exported via sysfs, which we use in preference. If this fails we leave
+ * the argument namebuf unaltered and return 0.
+ */
+static int
+map_persistent_dm_name(char *namebuf, int namelen, int devmajor, int devminor)
+{
+ int fd;
+ char *p;
+ DIR *dp;
+ int found = 0;
+ struct dirent *dentry;
+ struct stat sb;
+ char path[MAXPATHLEN];
+
+ snprintf(path, sizeof(path), "%s/sys/block/%s/dm/name", linux_statspath, namebuf);
+ if ((fd = open(path, O_RDONLY)) >= 0) {
+ memset(path, 0, sizeof(path));
+ if (read(fd, path, sizeof(path)) > 0) {
+ if ((p = strchr(path, '\n')) != NULL)
+ *p = '\0';
+ strncpy(namebuf, path, MIN(sizeof(path), namelen));
+ found = 1;
+ }
+ close(fd);
+ }
+
+ if (!found) {
+ /*
+ * The sysfs name isn't available, so we'll have to walk /dev/mapper
+ * and match up dev_t instead [happens on RHEL5 and maybe elsewhere].
+ */
+ snprintf(path, sizeof(path), "%s/dev/mapper", linux_statspath);
+ if ((dp = opendir(path)) != NULL) {
+ while ((dentry = readdir(dp)) != NULL) {
+ snprintf(path, sizeof(path),
+ "%s/dev/mapper/%s", linux_statspath, dentry->d_name);
+ if (stat(path, &sb) != 0 || !S_ISBLK(sb.st_mode))
+ continue; /* only interested in block devices */
+ if (devmajor == major(sb.st_rdev) && devminor == minor(sb.st_rdev)) {
+ strncpy(namebuf, dentry->d_name, namelen);
+ found = 1;
+ break;
+ }
+ }
+ closedir(dp);
+ }
+ }
+
+ return found;
+}
+
+int
+refresh_proc_partitions(pmInDom disk_indom, pmInDom partitions_indom, pmInDom dm_indom)
+{
+ FILE *fp;
+ int devmin;
+ int devmaj;
+ int n;
+ int indom;
+ int have_proc_diskstats;
+ int inst;
+ unsigned long long blocks;
+ partitions_entry_t *p;
+ int indom_changes = 0;
+ char *dmname;
+ char buf[MAXPATHLEN];
+ char namebuf[MAXPATHLEN];
+ static int first = 1;
+
+ if (first) {
+ /* initialize the instance domain caches */
+ pmdaCacheOp(disk_indom, PMDA_CACHE_LOAD);
+ pmdaCacheOp(partitions_indom, PMDA_CACHE_LOAD);
+ pmdaCacheOp(dm_indom, PMDA_CACHE_LOAD);
+
+ first = 0;
+ indom_changes = 1;
+ }
+
+ pmdaCacheOp(disk_indom, PMDA_CACHE_INACTIVE);
+ pmdaCacheOp(partitions_indom, PMDA_CACHE_INACTIVE);
+ pmdaCacheOp(dm_indom, PMDA_CACHE_INACTIVE);
+
+ if ((fp = linux_statsfile("/proc/diskstats", buf, sizeof(buf))) != NULL)
+ /* 2.6 style disk stats */
+ have_proc_diskstats = 1;
+ else {
+ if ((fp = linux_statsfile("/proc/partitions", buf, sizeof(buf))) != NULL)
+ have_proc_diskstats = 0;
+ else
+ return -oserror();
+ }
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ dmname = NULL;
+ if (buf[0] != ' ' || buf[0] == '\n') {
+ /* skip heading */
+ continue;
+ }
+
+ if (have_proc_diskstats) {
+ if ((n = sscanf(buf, "%d %d %s", &devmaj, &devmin, namebuf)) != 3)
+ continue;
+ }
+ else {
+ /* /proc/partitions */
+ if ((n = sscanf(buf, "%d %d %llu %s", &devmaj, &devmin, &blocks, namebuf)) != 4)
+ continue;
+ }
+
+ if (_pm_isdm(namebuf)) {
+ indom = dm_indom;
+ dmname = strdup(namebuf);
+ }
+ else if (_pm_ispartition(namebuf))
+ indom = partitions_indom;
+ else if (_pm_isdisk(namebuf))
+ indom = disk_indom;
+ else
+ continue;
+
+ if (indom == dm_indom) {
+ /* replace dm-[0-9]* with the persistent name from /dev/mapper */
+ if (!map_persistent_dm_name(namebuf, sizeof(namebuf), devmaj, devmin)) {
+ /* skip dm devices that have no persistent name mapping */
+ free(dmname);
+ continue;
+ }
+ }
+
+ p = NULL;
+ if (pmdaCacheLookupName(indom, namebuf, &inst, (void **)&p) < 0 || !p) {
+ /* not found: allocate and add a new entry */
+ p = (partitions_entry_t *)malloc(sizeof(partitions_entry_t));
+ memset(p, 0, sizeof(partitions_entry_t));
+ indom_changes++;
+ }
+
+ if (p->dmname)
+ free(p->dmname);
+ p->dmname = dmname; /* NULL if not a dm device */
+
+ if (!p->namebuf)
+ p->namebuf = strdup(namebuf);
+ else
+ if (strcmp(namebuf, p->namebuf) != 0) {
+ free(p->namebuf);
+ p->namebuf = strdup(namebuf);
+ }
+
+ /* activate this entry */
+ if (p->udevnamebuf)
+ /* long xscsi name */
+ inst = pmdaCacheStore(indom, PMDA_CACHE_ADD, p->udevnamebuf, p);
+ else
+ /* short /proc/diskstats or /proc/partitions name */
+ inst = pmdaCacheStore(indom, PMDA_CACHE_ADD, namebuf, p);
+
+ if (have_proc_diskstats) {
+ /* 2.6 style /proc/diskstats */
+ p->nr_blocks = 0;
+ namebuf[0] = '\0';
+ /* Linux source: block/genhd.c::diskstats_show(1) */
+ n = sscanf(buf, "%u %u %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u",
+ &p->major, &p->minor, namebuf,
+ &p->rd_ios, &p->rd_merges, &p->rd_sectors, &p->rd_ticks,
+ &p->wr_ios, &p->wr_merges, &p->wr_sectors, &p->wr_ticks,
+ &p->ios_in_flight, &p->io_ticks, &p->aveq);
+ if (n != 14) {
+ p->rd_merges = p->wr_merges = p->wr_ticks =
+ p->ios_in_flight = p->io_ticks = p->aveq = 0;
+ /* Linux source: block/genhd.c::diskstats_show(2) */
+ n = sscanf(buf, "%u %u %s %u %u %u %u\n",
+ &p->major, &p->minor, namebuf,
+ (unsigned int *)&p->rd_ios, (unsigned int *)&p->rd_sectors,
+ (unsigned int *)&p->wr_ios, (unsigned int *)&p->wr_sectors);
+ }
+ }
+ else {
+ /* 2.4 style /proc/partitions */
+ namebuf[0] = '\0';
+ n = sscanf(buf, "%u %u %lu %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u",
+ &p->major, &p->minor, &p->nr_blocks, namebuf,
+ &p->rd_ios, &p->rd_merges, &p->rd_sectors,
+ &p->rd_ticks, &p->wr_ios, &p->wr_merges,
+ &p->wr_sectors, &p->wr_ticks, &p->ios_in_flight,
+ &p->io_ticks, &p->aveq);
+ }
+
+ }
+
+ /*
+ * If any new disks or partitions have appeared then we
+ * we need to remap the long device names (if /dev/xscsi
+ * exists) and then flush the pmda cache.
+ *
+ * We just let inactive instances rot in the inactive state
+ * (this doesn't happen very often, so is only a minor leak).
+ */
+ if (indom_changes) {
+ refresh_udev(disk_indom, partitions_indom);
+ pmdaCacheOp(disk_indom, PMDA_CACHE_SAVE);
+ pmdaCacheOp(partitions_indom, PMDA_CACHE_SAVE);
+ pmdaCacheOp(dm_indom, PMDA_CACHE_SAVE);
+ }
+
+ /*
+ * success
+ */
+ if (fp)
+ fclose(fp);
+ return 0;
+}
+
+/*
+ * This table must always match the definitions in root_linux
+ * and metrictab[] in pmda.c
+ */
+static pmID disk_metric_table[] = {
+ /* disk.dev.read */ PMDA_PMID(CLUSTER_STAT,4),
+ /* disk.dev.write */ PMDA_PMID(CLUSTER_STAT,5),
+ /* disk.dev.total */ PMDA_PMID(CLUSTER_STAT,28),
+ /* disk.dev.blkread */ PMDA_PMID(CLUSTER_STAT,6),
+ /* disk.dev.blkwrite */ PMDA_PMID(CLUSTER_STAT,7),
+ /* disk.dev.blktotal */ PMDA_PMID(CLUSTER_STAT,36),
+ /* disk.dev.read_bytes */ PMDA_PMID(CLUSTER_STAT,38),
+ /* disk.dev.write_bytes */ PMDA_PMID(CLUSTER_STAT,39),
+ /* disk.dev.total_bytes */ PMDA_PMID(CLUSTER_STAT,40),
+ /* disk.dev.read_merge */ PMDA_PMID(CLUSTER_STAT,49),
+ /* disk.dev.write_merge */ PMDA_PMID(CLUSTER_STAT,50),
+ /* disk.dev.avactive */ PMDA_PMID(CLUSTER_STAT,46),
+ /* disk.dev.aveq */ PMDA_PMID(CLUSTER_STAT,47),
+ /* disk.dev.scheduler */ PMDA_PMID(CLUSTER_STAT,59),
+ /* disk.dev.read_rawactive */ PMDA_PMID(CLUSTER_STAT,72),
+ /* disk.dev.write_rawactive */ PMDA_PMID(CLUSTER_STAT,73),
+
+ /* disk.all.read */ PMDA_PMID(CLUSTER_STAT,24),
+ /* disk.all.write */ PMDA_PMID(CLUSTER_STAT,25),
+ /* disk.all.total */ PMDA_PMID(CLUSTER_STAT,29),
+ /* disk.all.blkread */ PMDA_PMID(CLUSTER_STAT,26),
+ /* disk.all.blkwrite */ PMDA_PMID(CLUSTER_STAT,27),
+ /* disk.all.blktotal */ PMDA_PMID(CLUSTER_STAT,37),
+ /* disk.all.read_bytes */ PMDA_PMID(CLUSTER_STAT,41),
+ /* disk.all.write_bytes */ PMDA_PMID(CLUSTER_STAT,42),
+ /* disk.all.total_bytes */ PMDA_PMID(CLUSTER_STAT,43),
+ /* disk.all.read_merge */ PMDA_PMID(CLUSTER_STAT,51),
+ /* disk.all.write_merge */ PMDA_PMID(CLUSTER_STAT,52),
+ /* disk.all.avactive */ PMDA_PMID(CLUSTER_STAT,44),
+ /* disk.all.aveq */ PMDA_PMID(CLUSTER_STAT,45),
+ /* disk.all.read_rawactive */ PMDA_PMID(CLUSTER_STAT,74),
+ /* disk.all.write_rawactive */ PMDA_PMID(CLUSTER_STAT,75),
+
+ /* disk.partitions.read */ PMDA_PMID(CLUSTER_PARTITIONS,0),
+ /* disk.partitions.write */ PMDA_PMID(CLUSTER_PARTITIONS,1),
+ /* disk.partitions.total */ PMDA_PMID(CLUSTER_PARTITIONS,2),
+ /* disk.partitions.blkread */ PMDA_PMID(CLUSTER_PARTITIONS,3),
+ /* disk.partitions.blkwrite */ PMDA_PMID(CLUSTER_PARTITIONS,4),
+ /* disk.partitions.blktotal */ PMDA_PMID(CLUSTER_PARTITIONS,5),
+ /* disk.partitions.read_bytes */ PMDA_PMID(CLUSTER_PARTITIONS,6),
+ /* disk.partitions.write_bytes */PMDA_PMID(CLUSTER_PARTITIONS,7),
+ /* disk.partitions.total_bytes */PMDA_PMID(CLUSTER_PARTITIONS,8),
+
+ /* hinv.ndisk */ PMDA_PMID(CLUSTER_STAT,33),
+
+ /* disk.dm.read */ PMDA_PMID(CLUSTER_DM,0),
+ /* disk.dm.write */ PMDA_PMID(CLUSTER_DM,1),
+ /* disk.dm.total */ PMDA_PMID(CLUSTER_DM,2),
+ /* disk.dm.blkread */ PMDA_PMID(CLUSTER_DM,3),
+ /* disk.dm.blkwrite */ PMDA_PMID(CLUSTER_DM,4),
+ /* disk.dm.blktotal */ PMDA_PMID(CLUSTER_DM,5),
+ /* disk.dm.read_bytes */ PMDA_PMID(CLUSTER_DM,6),
+ /* disk.dm.write_bytes */ PMDA_PMID(CLUSTER_DM,7),
+ /* disk.dm.total_bytes */ PMDA_PMID(CLUSTER_DM,8),
+ /* disk.dm.read_merge */ PMDA_PMID(CLUSTER_DM,9),
+ /* disk.dm.write_merge */ PMDA_PMID(CLUSTER_DM,10),
+ /* disk.dm.avactive */ PMDA_PMID(CLUSTER_DM,11),
+ /* disk.dm.aveq */ PMDA_PMID(CLUSTER_DM,12),
+ /* hinv.map.dmname */ PMDA_PMID(CLUSTER_DM,13),
+ /* disk.dm.read_rawactive */ PMDA_PMID(CLUSTER_DM,14),
+ /* disk.dm.write_rawactive */ PMDA_PMID(CLUSTER_DM,15),
+};
+
+int
+is_partitions_metric(pmID full_pmid)
+{
+ int i;
+ static pmID *p = NULL;
+ __pmID_int *idp = (__pmID_int *)&(full_pmid);
+ pmID pmid = PMDA_PMID(idp->cluster, idp->item);
+ int n = sizeof(disk_metric_table) / sizeof(disk_metric_table[0]);
+
+ if (p && *p == PMDA_PMID(idp->cluster, idp->item))
+ return 1;
+ for (p = disk_metric_table, i=0; i < n; i++, p++) {
+ if (*p == pmid)
+ return 1;
+ }
+ return 0;
+}
+
+char *
+_pm_ioscheduler(const char *device)
+{
+ FILE *fp;
+ char *p, *q;
+ static char buf[1024];
+ char path[MAXNAMELEN];
+
+ /*
+ * Extract scheduler from /sys/block/<device>/queue/scheduler.
+ * File format: "noop anticipatory [deadline] cfq"
+ * In older kernels (incl. RHEL5 and SLES10) this doesn't exist,
+ * but we can still look in /sys/block/<device>/queue/iosched to
+ * intuit the ones we know about (cfq, deadline, as, noop) based
+ * on the different status files they create.
+ */
+ sprintf(path, "%s/sys/block/%s/queue/scheduler", linux_statspath, device);
+ if ((fp = fopen(path, "r")) != NULL) {
+ p = fgets(buf, sizeof(buf), fp);
+ fclose(fp);
+ if (!p)
+ goto unknown;
+ for (p = q = buf; p && *p && *p != ']'; p++) {
+ if (*p == '[')
+ q = p+1;
+ }
+ if (q == buf)
+ goto unknown;
+ if (*p != ']')
+ goto unknown;
+ *p = '\0';
+ return q;
+ }
+ else {
+#define BLKQUEUE "%s/sys/block/%s/queue/"
+ /* sniff around, maybe we'll get lucky and find something */
+ sprintf(path, BLKQUEUE "iosched/quantum", linux_statspath, device);
+ if (access(path, F_OK) == 0)
+ return "cfq";
+ sprintf(path, BLKQUEUE "iosched/fifo_batch", linux_statspath, device);
+ if (access(path, F_OK) == 0)
+ return "deadline";
+ sprintf(path, BLKQUEUE "iosched/antic_expire", linux_statspath, device);
+ if (access(path, F_OK) == 0)
+ return "anticipatory";
+ /* punt. noop has no files to match on ... */
+ sprintf(path, BLKQUEUE "iosched", linux_statspath, device);
+ if (access(path, F_OK) == 0)
+ return "noop";
+ /* else fall though ... */
+#undef BLKQUEUE
+ }
+
+unknown:
+ return "unknown";
+}
+
+int
+proc_partitions_fetch(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom)
+{
+ __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid);
+ int i;
+ partitions_entry_t *p = NULL;
+
+ if (inst != PM_IN_NULL) {
+ if (pmdaCacheLookup(mdesc->m_desc.indom, inst, NULL, (void **)&p) < 0)
+ return PM_ERR_INST;
+ }
+
+ switch (idp->cluster) {
+ case CLUSTER_STAT:
+ /*
+ * disk.{dev,all} remain in CLUSTER_STAT for backward compatibility
+ */
+ switch(idp->item) {
+ case 4: /* disk.dev.read */
+ if (p == NULL)
+ return PM_ERR_INST;
+ _pm_assign_ulong(atom, p->rd_ios);
+ break;
+ case 5: /* disk.dev.write */
+ if (p == NULL)
+ return PM_ERR_INST;
+ _pm_assign_ulong(atom, p->wr_ios);
+ break;
+ case 6: /* disk.dev.blkread */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->ull = p->rd_sectors;
+ break;
+ case 7: /* disk.dev.blkwrite */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->ull = p->wr_sectors;
+ break;
+ case 28: /* disk.dev.total */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->ull = p->rd_ios + p->wr_ios;
+ break;
+ case 36: /* disk.dev.blktotal */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->ull = p->rd_sectors + p->wr_sectors;
+ break;
+ case 38: /* disk.dev.read_bytes */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->ull = p->rd_sectors / 2;
+ break;
+ case 39: /* disk.dev.write_bytes */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->ull = p->wr_sectors / 2;
+ break;
+ case 40: /* disk.dev.total_bytes */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->ull = (p->rd_sectors + p->wr_sectors) / 2;
+ break;
+ case 46: /* disk.dev.avactive ... already msec from /proc/diskstats */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->ul = p->io_ticks;
+ break;
+ case 47: /* disk.dev.aveq ... already msec from /proc/diskstats */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->ul = p->aveq;
+ break;
+ case 49: /* disk.dev.read_merge */
+ if (p == NULL)
+ return PM_ERR_INST;
+ _pm_assign_ulong(atom, p->rd_merges);
+ break;
+ case 50: /* disk.dev.write_merge */
+ if (p == NULL)
+ return PM_ERR_INST;
+ _pm_assign_ulong(atom, p->wr_merges);
+ break;
+ case 59: /* disk.dev.scheduler */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->cp = _pm_ioscheduler(p->namebuf);
+ break;
+ case 72: /* disk.dev.read_rawactive already ms from /proc/diskstats */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->ul = p->rd_ticks;
+ break;
+ case 73: /* disk.dev.write_rawactive already ms from /proc/diskstats */
+ if (p == NULL)
+ return PM_ERR_INST;
+ atom->ul = p->wr_ticks;
+ break;
+ default:
+ /* disk.all.* is a singular instance domain */
+ atom->ull = 0;
+ for (pmdaCacheOp(INDOM(DISK_INDOM), PMDA_CACHE_WALK_REWIND);;) {
+ if ((i = pmdaCacheOp(INDOM(DISK_INDOM), PMDA_CACHE_WALK_NEXT)) < 0)
+ break;
+ if (!pmdaCacheLookup(INDOM(DISK_INDOM), i, NULL, (void **)&p) || !p)
+ continue;
+ switch (idp->item) {
+ case 24: /* disk.all.read */
+ atom->ull += p->rd_ios;
+ break;
+ case 25: /* disk.all.write */
+ atom->ull += p->wr_ios;
+ break;
+ case 26: /* disk.all.blkread */
+ atom->ull += p->rd_sectors;
+ break;
+ case 27: /* disk.all.blkwrite */
+ atom->ull += p->wr_sectors;
+ break;
+ case 29: /* disk.all.total */
+ atom->ull += p->rd_ios + p->wr_ios;
+ break;
+ case 37: /* disk.all.blktotal */
+ atom->ull += p->rd_sectors + p->wr_sectors;
+ break;
+ case 41: /* disk.all.read_bytes */
+ atom->ull += p->rd_sectors / 2;
+ break;
+ case 42: /* disk.all.write_bytes */
+ atom->ull += p->wr_sectors / 2;
+ break;
+ case 43: /* disk.all.total_bytes */
+ atom->ull += (p->rd_sectors + p->wr_sectors) / 2;
+ break;
+ case 44: /* disk.all.avactive ... already msec from /proc/diskstats */
+ atom->ull += p->io_ticks;
+ break;
+ case 45: /* disk.all.aveq ... already msec from /proc/diskstats */
+ atom->ull += p->aveq;
+ break;
+ case 51: /* disk.all.read_merge */
+ atom->ull += p->rd_merges;
+ break;
+ case 52: /* disk.all.write_merge */
+ atom->ull += p->wr_merges;
+ break;
+ case 74: /* disk.all.read_rawactive ... already msec from /proc/diskstats */
+ atom->ull += p->rd_ticks;
+ break;
+ case 75: /* disk.all.write_rawactive ... already msec from /proc/diskstats */
+ atom->ull += p->wr_ticks;
+ break;
+ default:
+ return PM_ERR_PMID;
+ }
+ } /* loop */
+ }
+ break;
+
+ case CLUSTER_PARTITIONS:
+ if (p == NULL)
+ return PM_ERR_INST;
+ switch(idp->item) {
+ /* disk.partitions */
+ case 0: /* disk.partitions.read */
+ atom->ul = p->rd_ios;
+ break;
+ case 1: /* disk.partitions.write */
+ atom->ul = p->wr_ios;
+ break;
+ case 2: /* disk.partitions.total */
+ atom->ul = p->wr_ios +
+ p->rd_ios;
+ break;
+ case 3: /* disk.partitions.blkread */
+ atom->ul = p->rd_sectors;
+ break;
+ case 4: /* disk.partitions.blkwrite */
+ atom->ul = p->wr_sectors;
+ break;
+ case 5: /* disk.partitions.blktotal */
+ atom->ul = p->rd_sectors +
+ p->wr_sectors;
+ break;
+ case 6: /* disk.partitions.read_bytes */
+ atom->ul = p->rd_sectors / 2;
+ break;
+ case 7: /* disk.partitions.write_bytes */
+ atom->ul = p->wr_sectors / 2;
+ break;
+ case 8: /* disk.partitions.total_bytes */
+ atom->ul = (p->rd_sectors +
+ p->wr_sectors) / 2;
+ break;
+ default:
+ return PM_ERR_PMID;
+ }
+ break;
+
+ case CLUSTER_DM:
+ if (p == NULL)
+ return PM_ERR_INST;
+ switch(idp->item) {
+ case 0: /* disk.dm.read */
+ atom->ull = p->rd_ios;
+ break;
+ case 1: /* disk.dm.write */
+ atom->ull = p->wr_ios;
+ break;
+ case 2: /* disk.dm.total */
+ atom->ull = p->rd_ios + p->wr_ios;
+ break;
+ case 3: /* disk.dm.blkread */
+ atom->ull = p->rd_sectors;
+ break;
+ case 4: /* disk.dm.blkwrite */
+ atom->ull = p->wr_sectors;
+ break;
+ case 5: /* disk.dm.blktotal */
+ atom->ull = p->rd_sectors + p->wr_sectors;
+ break;
+ case 6: /* disk.dm.read_bytes */
+ atom->ull = p->rd_sectors / 2;
+ break;
+ case 7: /* disk.dm.write_bytes */
+ atom->ull = p->wr_sectors / 2;
+ break;
+ case 8: /* disk.dm.total_bytes */
+ atom->ull = (p->rd_sectors + p->wr_sectors) / 2;
+ break;
+ case 9: /* disk.dm.read_merge */
+ atom->ull = p->rd_merges;
+ break;
+ case 10: /* disk.dm.write_merge */
+ atom->ull = p->wr_merges;
+ break;
+ case 11: /* disk.dm.avactive */
+ atom->ull = p->io_ticks;
+ break;
+ case 12: /* disk.dm.aveq */
+ atom->ull = p->aveq;
+ break;
+ case 13: /* hinv.map.dmname */
+ atom->cp = p->dmname;
+ break;
+ case 14: /* disk.dm.read_rawactive */
+ atom->ul = p->rd_ticks;
+ break;
+ case 15: /* disk.dm.write_rawactive */
+ atom->ul = p->wr_ticks;
+ break;
+ default:
+ return PM_ERR_PMID;
+ }
+ break;
+
+ default: /* switch cluster */
+ return PM_ERR_PMID;
+ }
+
+ return 1;
+}