summaryrefslogtreecommitdiff
path: root/src/pmdas/solaris/vnops.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmdas/solaris/vnops.c')
-rw-r--r--src/pmdas/solaris/vnops.c221
1 files changed, 221 insertions, 0 deletions
diff --git a/src/pmdas/solaris/vnops.c b/src/pmdas/solaris/vnops.c
new file mode 100644
index 0000000..69054d8
--- /dev/null
+++ b/src/pmdas/solaris/vnops.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2010 Max Matveev. 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* kstat has counters for vnode operations for each filesystem.
+ *
+ * Unfortunately the counters for mounted fileystems are mixed with counters
+ * for the filesystem types and there is no obvious way to distinguish
+ * between the two except by trying to convert the kstat's name to the number
+ * and see if works */
+
+#include <stdio.h>
+#include <kstat.h>
+#include <sys/mnttab.h>
+#include <sys/stat.h>
+#include "common.h"
+
+struct mountpoint {
+ struct mountpoint *next;
+ dev_t dev;
+ char mountpoint[];
+};
+
+static struct mountpoint *mountpoints;
+static struct timespec mtime;
+
+/* NB! The order of entires in mountopoints list is important:
+ * lofs mounts use the same device number but appear later
+ * in /etc/mnttab then the target filesystem - keeping the
+ * order the same as /etc/mnttab means that more "logical"
+ * mountpoints are reported, in particular the counters
+ * for "/" are not reported as /lib/libc.so.1 */
+static void
+cache_mnttab(void)
+{
+ FILE *f;
+ struct mnttab m;
+ struct mountpoint *mp;
+ struct stat sb;
+ struct mountpoint **tail = &mountpoints;
+
+ if (stat("/etc/mnttab", &sb) < 0)
+ return;
+
+ if (mountpoints &&
+ (sb.st_mtim.tv_sec == mtime.tv_sec) &&
+ (sb.st_mtim.tv_nsec == mtime.tv_nsec))
+ return;
+
+ if ((f = fopen("/etc/mnttab", "r")) == NULL)
+ return;
+
+ for (mp = mountpoints; mp; mp = mountpoints) {
+ mountpoints = mp->next;
+ free(mp);
+ }
+
+ while(getmntent(f, &m) == 0) {
+ char *devop= hasmntopt(&m, "dev");
+ if (devop) {
+ char *end;
+ dev_t d = strtoul(devop+4, &end, 16);
+
+ if ((end != devop+4) && (*end != '\0')) {
+ fprintf(stderr, "Bogus device number %s for filesystem %s\n",
+ devop+4, m.mnt_mountp);
+ continue;
+ }
+
+ mp = malloc(sizeof(*mp) + strlen(m.mnt_mountp) + 1);
+ if (mp == NULL) {
+ fprintf(stderr,
+ "Cannot allocate memory for cache entry of %s\n",
+ m.mnt_mountp);
+ continue;
+ }
+ mp->next = NULL;
+ mp->dev = d;
+ strcpy(mp->mountpoint, m.mnt_mountp);
+ *tail = mp;
+ tail = &mp->next;
+ }
+ }
+ fclose(f);
+ mtime = sb.st_mtim;
+}
+
+static const char *
+mountpoint_bydev(dev_t dev)
+{
+ int i;
+ for (i=0; i < 2; i++) {
+ struct mountpoint *mp = mountpoints;
+ while(mp) {
+ if (mp->dev == dev)
+ return mp->mountpoint;
+ mp = mp->next;
+ }
+ cache_mnttab();
+ }
+ return NULL;
+}
+
+int
+vnops_fetch(pmdaMetric *pm, int inst, pmAtomValue *av)
+{
+ char *fsname;
+ metricdesc_t *md = pm->m_user;
+ kstat_t *k;
+ char *stat = (char *)md->md_offset;
+
+ if (pmid_item(pm->m_desc.pmid) == 1023) { /* hinv.nfilesys */
+ int sts;
+ sts = pmdaCacheOp(indomtab[FILESYS_INDOM].it_indom, PMDA_CACHE_SIZE_ACTIVE);
+ if (sts < 0)
+ return 0;
+ else {
+ av->ul = sts;
+ return 1;
+ }
+ }
+
+ if (pmdaCacheLookup(pm->m_desc.indom, inst, &fsname,
+ (void **)&k) != PMDA_CACHE_ACTIVE)
+ return PM_ERR_INST;
+
+ if (k) {
+ kstat_named_t *kn = kstat_data_lookup(k, stat);
+
+ if (kn == NULL) {
+ fprintf(stderr, "No kstat called %s for %s\n", stat, fsname);
+ return 0;
+ }
+
+ return kstat_named_to_typed_atom(kn, pm->m_desc.type, av);
+ }
+
+ return 0;
+}
+
+static void
+vnops_update_stats(int fetch)
+{
+ kstat_t *k;
+ kstat_ctl_t *kc = kstat_ctl_update();
+
+ if (kc == NULL)
+ return;
+
+ for (k = kc->kc_chain; k != NULL; k = k->ks_next) {
+ int rv;
+ kstat_t *cached;
+ const char *key;
+ dev_t dev;
+ char *end;
+ pmInDom indom;
+
+ if (strcmp(k->ks_module, "unix") ||
+ strncmp(k->ks_name, "vopstats_", sizeof("vopstats_")-1))
+ continue;
+
+ key = k->ks_name + 9;
+ dev = strtoul(key, &end, 16);
+ if ((end != key) && (*end == '\0')) {
+ indom = indomtab[FILESYS_INDOM].it_indom;
+ if ((key = mountpoint_bydev(dev)) == NULL)
+ continue;
+ } else {
+ indom = indomtab[FSTYPE_INDOM].it_indom;
+ }
+
+ if (pmdaCacheLookupName(indom, key, &rv,
+ (void **)&cached) != PMDA_CACHE_ACTIVE) {
+ rv = pmdaCacheStore(indom, PMDA_CACHE_ADD, key, k);
+ if (rv < 0) {
+ __pmNotifyErr(LOG_WARNING,
+ "Cannot create instance for "
+ "filesystem '%s': %s\n",
+ key, pmErrStr(rv));
+ continue;
+ }
+ }
+
+ if (fetch)
+ kstat_read(kc, k, NULL);
+ }
+}
+
+void
+vnops_refresh(void)
+{
+ pmdaCacheOp(indomtab[FILESYS_INDOM].it_indom, PMDA_CACHE_INACTIVE);
+ pmdaCacheOp(indomtab[FSTYPE_INDOM].it_indom, PMDA_CACHE_INACTIVE);
+ vnops_update_stats(1);
+ pmdaCacheOp(indomtab[FILESYS_INDOM].it_indom, PMDA_CACHE_SAVE);
+ pmdaCacheOp(indomtab[FSTYPE_INDOM].it_indom, PMDA_CACHE_SAVE);
+}
+
+void
+vnops_init(int first)
+{
+ pmdaCacheOp(indomtab[FILESYS_INDOM].it_indom, PMDA_CACHE_LOAD);
+ pmdaCacheOp(indomtab[FSTYPE_INDOM].it_indom, PMDA_CACHE_LOAD);
+ vnops_update_stats(0);
+ pmdaCacheOp(indomtab[FILESYS_INDOM].it_indom, PMDA_CACHE_SAVE);
+ pmdaCacheOp(indomtab[FSTYPE_INDOM].it_indom, PMDA_CACHE_SAVE);
+}