summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/cmd/stat/common/acquire_iodevs.c17
-rw-r--r--usr/src/cmd/stat/common/dsr.c992
-rw-r--r--usr/src/cmd/stat/common/dsr.h73
-rw-r--r--usr/src/cmd/stat/common/statcommon.h11
-rw-r--r--usr/src/cmd/stat/iostat/iostat.c38
-rw-r--r--usr/src/cmd/stat/mpstat/mpstat.c9
-rw-r--r--usr/src/cmd/truss/print.c4
-rw-r--r--usr/src/lib/libdevinfo/Makefile.com2
-rw-r--r--usr/src/lib/libdevinfo/devinfo_devlink.c1
-rw-r--r--usr/src/lib/libdevinfo/devinfo_dim.c149
-rw-r--r--usr/src/lib/libdevinfo/libdevinfo.h16
-rw-r--r--usr/src/lib/libdevinfo/mapfile-vers4
-rw-r--r--usr/src/uts/common/os/kstat_fr.c18
-rw-r--r--usr/src/uts/common/os/modctl.c82
-rw-r--r--usr/src/uts/common/os/policy.c13
-rw-r--r--usr/src/uts/common/sys/modctl.h2
16 files changed, 622 insertions, 809 deletions
diff --git a/usr/src/cmd/stat/common/acquire_iodevs.c b/usr/src/cmd/stat/common/acquire_iodevs.c
index cd7d167c97..be29ff88ef 100644
--- a/usr/src/cmd/stat/common/acquire_iodevs.c
+++ b/usr/src/cmd/stat/common/acquire_iodevs.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -543,7 +542,7 @@ get_pretty_name(enum snapshot_types types, struct iodev_snapshot *iodev,
if (!*tmp)
return;
(void) strlcpy(buf, iodev->is_name, 1 + tmp - iodev->is_name);
- dl = lookup_ks_name(buf);
+ dl = lookup_ks_name(buf, (types & SNAP_IODEV_DEVID) ? 1 : 0);
if (dl == NULL || dl->dsk == NULL)
return;
len = strlen(dl->dsk) + strlen(tmp) + 1;
@@ -553,7 +552,7 @@ get_pretty_name(enum snapshot_types types, struct iodev_snapshot *iodev,
goto out;
}
- dl = lookup_ks_name(iodev->is_name);
+ dl = lookup_ks_name(iodev->is_name, (types & SNAP_IODEV_DEVID) ? 1 : 0);
if (dl == NULL)
return;
@@ -655,6 +654,12 @@ acquire_iodevs(struct snapshot *ss, kstat_ctl_t *kc, struct iodev_filter *df)
ss->s_nr_iodevs = 0;
+ /*
+ * Call cleanup_iodevs_snapshot() so that a cache miss in
+ * lookup_ks_name() will result in a fresh snapshot.
+ */
+ cleanup_iodevs_snapshot();
+
for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
enum iodev_type type;
diff --git a/usr/src/cmd/stat/common/dsr.c b/usr/src/cmd/stat/common/dsr.c
index f3c5a18fe4..b25637a73b 100644
--- a/usr/src/cmd/stat/common/dsr.c
+++ b/usr/src/cmd/stat/common/dsr.c
@@ -56,770 +56,362 @@
#include "dsr.h"
#include "statcommon.h"
-static void rummage_dev(ldinfo_t *);
-static void do_snm(char *, char *);
-static int look_up_name(const char *, disk_list_t *);
-static disk_list_t *make_an_entry(char *, char *,
- char *, dir_info_t *, int, ldinfo_t *);
-static char *trim(char *, char *, int);
-static ldinfo_t *rummage_devinfo(void);
-static void pline(char *, int, char *, char *, ldinfo_t **);
-static void insert_dlist_ent(disk_list_t *, disk_list_t **);
-static int str_is_digit(char *);
-static ldinfo_t *find_ldinfo_match(char *, ldinfo_t *);
-
-static void insert_into_dlist(dir_info_t *, disk_list_t *);
-static void cleanup_dlist(dir_info_t *);
-static void cleanup_ldinfo(ldinfo_t *);
-static int devinfo_ident_disks(di_node_t, void *);
-static int devinfo_ident_tapes(di_node_t, void *);
-static void process_dir_ent(char *dent, int curr_type,
- char *last_snm, dir_info_t *, ldinfo_t *);
-
-static char *get_nfs_by_minor(uint_t);
-static char *cur_hostname(uint_t, kstat_ctl_t *);
-static char *cur_special(char *, char *);
-
-extern kstat_ctl_t *kc;
-extern mnt_t *nfs;
+/* disk/tape info */
+static di_node_t di_root; /* for devid */
+static di_dim_t di_dim; /* for /dev names */
+typedef struct {
+ char *minor_name;
+ int minor_isdisk;
+} minor_match_t;
+static minor_match_t mm_disk = {"a", 1};
+static minor_match_t mm_tape = {"", 0};
+static char md_minor_name[MAXPATHLEN];
+static minor_match_t mm_md = {md_minor_name, 0};
+static minor_match_t *mma_disk_tape[] = {&mm_disk, &mm_tape, NULL};
+static minor_match_t *mma_md[] = {&mm_md, NULL};
+static char *mdsetno2name(int setno);
+#define DISKLIST_MOD 256 /* ^2 instunit mod hash */
+static disk_list_t *disklist[DISKLIST_MOD];
+
+/* nfs info */
+extern kstat_ctl_t *kc;
+extern mnt_t *nfs;
+static int nfs_tried;
+static char *get_nfs_by_minor(uint_t);
+static char *cur_hostname(uint_t, kstat_ctl_t *);
+static char *cur_special(char *, char *);
/*
- * To do: add VXVM support: /dev/vx/dsk and ap support: /dev/ap/
- *
- * Note: Adding support for VxVM is *not* as simple as adding another
- * entry in the table and magically getting to see stuff related to
- * VxVM. The structure is radically different *AND* they don't produce
- * any IO kstats.
+ * Clear the snapshot so a cache miss in lookup_ks_name() will cause a fresh
+ * snapshot in drvinstunit2dev().
*/
-
-#define OSA_DISK 0
-#define DISK 1
-#define MD_DISK 2
-#define TAPE 3
-
-#define MAX_TYPES 4
-
-#define OSA_DISK_PATH "/dev/osa/dev/dsk"
-#define MD_DISK_PATH "/dev/md/dsk"
-#define DISK_PATH "/dev/dsk"
-#define TAPE_PATH "/dev/rmt"
-
-#define BASE_TRIM "../../devices"
-#define MD_TRIM "../../../devices"
-#define COLON ':'
-#define COMMA ','
-
-#define NAME_BUFLEN 256
-
-static dir_info_t dlist[MAX_TYPES] = {
- OSA_DISK_PATH, 0, 0, 0, 0, "sd", BASE_TRIM, COLON,
- DISK_PATH, 0, 0, 0, 0, "sd", BASE_TRIM, COLON,
- MD_DISK_PATH, 0, 0, 0, 1, "md", MD_TRIM, COMMA,
- TAPE_PATH, 0, 0, 0, 0, "st", BASE_TRIM, COLON,
-};
-
-/*
- * Build a list of disks attached to the system.
- */
-static void
-build_disk_list(void)
+void
+cleanup_iodevs_snapshot()
{
- ldinfo_t *ptoi;
-
- /*
- * Build the list of devices connected to the system.
- */
- ptoi = rummage_devinfo();
- rummage_dev(ptoi);
- cleanup_ldinfo(ptoi);
-}
+ if (di_dim) {
+ di_dim_fini(di_dim);
+ di_dim = NULL;
+ }
-/*
- * Walk the /dev/dsk and /dev/rmt directories building a
- * list of interesting devices. Interesting is everything in the
- * /dev/dsk directory. We skip some of the stuff in the /dev/rmt
- * directory.
- *
- * Note that not finding one or more of the directories is not an
- * error.
- */
-static void
-rummage_dev(ldinfo_t *ptoi)
-{
- DIR *dskp;
- int i;
- struct stat buf;
-
- for (i = 0; i < MAX_TYPES; i++) {
- if (stat(dlist[i].name, &buf) == 0) {
- if (dlist[i].mtime != buf.st_mtime) {
- /*
- * We've found a change. We need to cleanup
- * old information and then rebuild the list
- * for this device type.
- */
- cleanup_dlist(&dlist[i]);
- dlist[i].mtime = buf.st_mtime;
- if ((dskp = opendir(dlist[i].name))) {
- struct dirent *bpt;
- char last_snm[NAME_BUFLEN];
-
- last_snm[0] = NULL;
- while ((bpt = readdir(dskp)) != NULL) {
- if (bpt->d_name[0] != '.') {
- process_dir_ent(
- bpt->d_name,
- i, last_snm,
- &dlist[i],
- ptoi);
- }
- }
- }
- (void) closedir(dskp);
- }
- }
+ if (di_root) {
+ di_fini(di_root);
+ di_root = DI_NODE_NIL;
}
+
+ nfs_tried = 0;
}
/*
- * Walk the list of located devices and see if we've
- * seen this device before. We look at the short name.
+ * Find information for (driver, instunit) device: return zero on failure.
+ *
+ * NOTE: Failure of drvinstunit2dev works out OK for the caller if the kstat
+ * name is the same as public name: the caller will just use kstat name.
*/
static int
-look_up_name(const char *nm, disk_list_t *list)
+drvinstunit2dev(char *driver, int instunit,
+ char **devpathp, char **adevpathp, char **devidp, int *isdiskp)
{
- while (list) {
- if (strcmp(list->dsk, nm) != 0)
- list = list->next;
- else {
- return (1);
- }
+ int instance;
+ minor_match_t **mma;
+ minor_match_t *mm;
+ char *devpath;
+ char *devid;
+ char *a, *s;
+ int mdsetno;
+ char *mdsetname = NULL;
+ char amdsetname[MAXPATHLEN];
+ char *devicespath;
+ di_node_t node;
+
+
+ /* setup "no result" return values */
+ if (devpathp)
+ *devpathp = NULL;
+ if (adevpathp)
+ *adevpathp = NULL;
+ if (devidp)
+ *devidp = NULL;
+ if (isdiskp)
+ *isdiskp = 0;
+
+ /* take <driver><instance><minor_name> snapshot if not established */
+ if (di_dim == NULL) {
+ di_dim = di_dim_init();
+ if (di_dim == NULL)
+ return (0);
}
- return (0);
-}
-/*
- * Take a name of the form cNtNdNsN or cNtNdNpN
- * or /dev/dsk/CNtNdNsN or /dev/dsk/cNtNdNpN
- * remove the trailing sN or pN. Simply looking
- * for the first 's' or 'p' doesn't cut it.
- */
-static void
-do_snm(char *orig, char *shortnm)
-{
- char *tmp;
- char *ptmp;
- int done = 0;
- char repl_char = 0;
-
- tmp = strrchr(orig, 's');
- if (tmp) {
- ptmp = tmp;
- ptmp++;
- done = str_is_digit(ptmp);
- }
- if (done == 0) {
+ /*
+ * Determine if 'instunit' is an 'instance' or 'unit' based on the
+ * 'driver'. The current code only detects 'md' metadevice 'units',
+ * and defaults to 'instance' for everything else.
+ *
+ * For a metadevice, 'driver' is either "md" or "<setno>/md".
+ */
+ s = strstr(driver, "/md");
+ if ((strcmp(driver, "md") == 0) ||
+ (s && isdigit(*driver) && (strcmp(s, "/md") == 0))) {
/*
- * The string either has no 's' in it
- * or the stuff trailing the s has a
- * non-numeric in it. Look to see if
- * we have an ending 'p' followed by
- * numerics.
+ * "md" unit: Special case translation of "md" kstat names.
+ * For the local set the kstat name is "md<unit>", and for
+ * a shared set the kstat name is "<setno>/md<unit>": we map
+ * these to the minor paths "/pseudo/md@0:<unit>,blk" and
+ * "/pseudo/md@0:<set>,<unit>,blk" respectively.
*/
- tmp = strrchr(orig, 'p');
- if (tmp) {
- ptmp = tmp;
- ptmp++;
- if (str_is_digit(ptmp))
- repl_char = 'p';
- else
- tmp = 0;
- }
- } else {
- repl_char = 's';
- }
- if (tmp)
- *tmp = '\0';
- (void) strcpy(shortnm, orig);
- if (repl_char)
- *tmp = repl_char;
-}
-
-/*
- * Create and insert an entry into the device list.
- */
-static disk_list_t *
-make_an_entry(char *lname, char *shortnm, char *longnm,
- dir_info_t *drent, int devtype, ldinfo_t *ptoi)
-{
- disk_list_t *entry;
- char *nlnm;
- char snm[NAME_BUFLEN];
- ldinfo_t *p;
+ if (isdigit(*driver)) {
+ mdsetno = atoi(driver);
- entry = safe_alloc(sizeof (disk_list_t));
+ /* convert setno to setname */
+ mdsetname = mdsetno2name(mdsetno);
+ } else
+ mdsetno = 0;
- nlnm = trim(lname, drent->trimstr, drent->trimchr);
- entry->dsk = safe_strdup(shortnm);
- do_snm(longnm, snm);
- entry->dname = safe_strdup(snm);
- entry->devtype = devtype;
- entry->devidstr = NULL;
- if ((p = find_ldinfo_match(nlnm, ptoi))) {
- entry->dnum = p->dnum;
- entry->dtype = safe_strdup(p->dtype);
- if (p->devidstr)
- entry->devidstr = safe_strdup(p->devidstr);
+ driver = "md";
+ instance = 0;
+ mma = mma_md; /* metadevice dynamic minor */
+ (void) snprintf(md_minor_name, sizeof (md_minor_name),
+ "%d,%d,blk", mdsetno, instunit);
} else {
- entry->dtype = safe_strdup(drent->dtype);
- entry->dnum = -1;
- if (drent->dtype) {
- if (strcmp(drent->dtype, "md") == 0) {
- (void) sscanf(shortnm, "d%d", &entry->dnum);
- }
- }
+ instance = instunit;
+ mma = mma_disk_tape; /* disk/tape minors */
}
- entry->seen = 0;
- entry->next = 0;
- insert_dlist_ent(entry, &drent->list);
- return (entry);
-}
-/*
- * slice stuff off beginning and end of /devices directory names derived from
- * device links.
- */
-static char *
-trim(char *fnm, char *lname, int rchr)
-{
- char *ptr;
-
- while (*lname == *fnm) {
- lname++;
- fnm++;
+ /* Try to find a minor_match that works */
+ for (mm = *mma++; mm; mm = *mma++) {
+ if ((devpath = di_dim_path_dev(di_dim,
+ driver, instance, mm->minor_name)) != NULL)
+ break;
}
- if ((ptr = strrchr(fnm, rchr)))
- *ptr = NULL;
- return (fnm);
-}
+ if (devpath == NULL)
+ return (0);
-/*
- * Find an entry matching the name passed in
- */
-static ldinfo_t *
-find_ldinfo_match(char *name, ldinfo_t *ptoi)
-{
- if (name) {
- while (ptoi) {
- if (strcmp(ptoi->name, name))
- ptoi = ptoi->next;
- else
- return (ptoi);
- }
- }
- return (NULL);
-}
+ /*
+ * At this point we have a devpath result. Return the information about
+ * the result that the caller is asking for.
+ */
+ if (devpathp) /* devpath */
+ *devpathp = safe_strdup(devpath);
-/*
- * Determine if a name is already in the list of disks. If not, insert the
- * name in the list.
- */
-static void
-insert_dlist_ent(disk_list_t *n, disk_list_t **hd)
-{
- disk_list_t *tmp_ptr;
-
- if (n->dtype != NULL) {
- tmp_ptr = *hd;
- while (tmp_ptr) {
- if (strcmp(n->dsk, tmp_ptr->dsk) != 0)
- tmp_ptr = tmp_ptr->next;
- else
- break;
- }
- if (tmp_ptr == NULL) {
+ if (adevpathp) { /* abbreviated devpath */
+ if (mm->minor_isdisk) {
/*
- * We don't do anything with MD_DISK types here
- * since they don't have partitions.
+ * For disks we return the last component (with
+ * trailing "s#" or "p#" stripped off for disks).
+ * For example for devpath of "/dev/dsk/c0t0d0s0" the
+ * abbreviated devpath would be "c0t0d0".
*/
- if (n->devtype == DISK || n->devtype == OSA_DISK) {
- n->flags = SLICES_OK;
-#if defined(__i386)
- n->flags |= PARTITIONS_OK;
-#endif
- } else {
- n->flags = 0;
+ a = strrchr(devpath, '/');
+ if (a == NULL) {
+ free(devpath);
+ return (0);
}
+ a++;
+ s = strrchr(a, 's');
+ if (s == NULL) {
+ s = strrchr(a, 'p');
+ if (s == NULL) {
+ free(devpath);
+ return (0);
+ }
+ }
+ /* don't include slice information in devpath */
+ *s = '\0';
+ } else {
/*
- * Figure out where to insert the name. The list is
- * ostensibly in sorted order.
+ * remove "/dev/", and "/dsk/", from 'devpath' (like
+ * "/dev/md/dsk/d0") to form the abbreviated devpath
+ * (like "md/d0").
*/
- if (*hd) {
- disk_list_t *follw;
- int mv;
-
- tmp_ptr = *hd;
-
- /*
- * Look through the list. While the strcmp
- * value is less than the current value,
- */
- while (tmp_ptr) {
- if ((mv = strcmp(n->dtype,
- tmp_ptr->dtype)) < 0) {
- follw = tmp_ptr;
- tmp_ptr = tmp_ptr->next;
- } else
- break;
- }
- if (mv == 0) {
- /*
- * We're now in the area where the
- * leading chars of the kstat name
- * match. We need to insert in numeric
- * order after that.
- */
- while (tmp_ptr) {
- if (strcmp(n->dtype,
- tmp_ptr->dtype) != 0)
- break;
- if (n->dnum > tmp_ptr->dnum) {
- follw = tmp_ptr;
- tmp_ptr = tmp_ptr->next;
- } else
- break;
- }
- }
- /*
- * We should now be ready to insert an
- * entry...
- */
- if (mv >= 0) {
- if (tmp_ptr == *hd) {
- n->next = tmp_ptr;
- *hd = n;
- } else {
- n->next = follw->next;
- follw->next = n;
- }
- } else {
- /*
- * insert at the end of the
- * list
- */
- follw->next = n;
- n->next = 0;
- }
+ if ((s = strstr(devpath, "/dev/")) != NULL)
+ (void) strcpy(s + 1, s + 5);
+ if ((s = strstr(devpath, "/dsk/")) != NULL)
+ (void) strcpy(s + 1, s + 5);
+
+ /*
+ * If we have an mdsetname, convert abbreviated setno
+ * notation (like "md/shared/1/d0" to abbreviated
+ * setname notation (like "md/red/d0").
+ */
+ if (mdsetname) {
+ a = strrchr(devpath, '/');
+ (void) snprintf(amdsetname, sizeof (amdsetname),
+ "md/%s%s", mdsetname, a);
+ free(mdsetname);
+ a = amdsetname;
} else {
- *hd = n;
- n->next = 0;
+ if (*devpath == '/')
+ a = devpath + 1;
+ else
+ a = devpath;
}
}
- }
-}
-
-/*
- * find an entry matching the given kstat name in the list
- * of disks, tapes and metadevices.
- */
-disk_list_t *
-lookup_ks_name(char *dev_nm)
-{
- int tried = 0;
- int dv;
- int len;
- char cmpbuf[PATH_MAX + 1];
- struct list_of_disks *list;
- char *nm;
- dev_name_t *tmp;
- uint_t i;
-
- /*
- * extract the device type from the kstat name. We expect the
- * name to be one or more alphabetics followed by the device
- * numeric id. We do this solely for speed purposes .
- */
- len = 0;
- nm = dev_nm;
- while (*nm) {
- if (isalpha(*nm)) {
- nm++;
- len++;
- } else
- break;
+ *adevpathp = safe_strdup(a);
}
- if (!*nm)
- return (NULL);
-
- /*
- * For each of the elements in the dlist array we keep
- * an array of pointers to chains for each of the kstat
- * prefixes found within that directory. This is typically
- * 'sd' and 'ssd'. We walk the list in the directory and
- * match on that type. Since the same prefixes can be
- * in multiple places we keep checking if we don't find
- * it in the first place.
- */
-
- (void) strncpy(cmpbuf, dev_nm, len);
- cmpbuf[len] = NULL;
- dv = atoi(nm);
-
-retry:
- for (i = 0; i < MAX_TYPES; i++) {
- tmp = dlist[i].nf;
- while (tmp) {
- if (strcmp(tmp->name, cmpbuf) == 0) {
- /*
- * As an optimization we keep mins
- * and maxes for the devices found.
- * This helps chop the lists up and
- * avoid some really long chains as
- * we would get if we kept only prefix
- * lists.
- */
- if (dv >= tmp->min && dv <= tmp->max) {
- list = tmp->list_start;
- while (list) {
- if (list->dnum < dv)
- list = list->next;
- else
- break;
- }
- if (list && list->dnum == dv) {
- return (list);
- }
- }
+ if (devidp) { /* lookup the devid */
+ /* take snapshots if not established */
+ if (di_root == DI_NODE_NIL) {
+ di_root = di_init("/", DINFOCACHE);
+ }
+ if (di_root) {
+ /* get path to /devices devinfo node */
+ devicespath = di_dim_path_devices(di_dim,
+ driver, instance, NULL);
+ if (devicespath) {
+ /* find the node in the snapshot */
+ node = di_lookup_node(di_root, devicespath);
+ free(devicespath);
+
+ /* and lookup devid property on the node */
+ if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
+ DEVID_PROP_NAME, &devid) != -1)
+ *devidp = devid;
}
- tmp = tmp->next;
}
}
- if (!tried) {
- tried = 1;
- build_disk_list();
- goto retry;
- }
+ if (isdiskp)
+ *isdiskp = mm->minor_isdisk;
- return (0);
-}
-
-static int
-str_is_digit(char *str)
-{
- while (*str) {
- if (isdigit(*str))
- str++;
- else
- return (0);
- }
- return (1);
-}
-
-static void
-insert_into_dlist(dir_info_t *d, disk_list_t *e)
-{
- dev_name_t *tmp;
-
- tmp = d->nf;
- while (tmp) {
- if (strcmp(e->dtype, tmp->name) != 0) {
- tmp = tmp->next;
- } else {
- if (e->dnum < tmp->min) {
- tmp->min = e->dnum;
- tmp->list_start = e;
- } else if (e->dnum > tmp->max) {
- tmp->max = e->dnum;
- tmp->list_end = e;
- }
- break;
- }
- }
- if (tmp == NULL) {
- tmp = safe_alloc(sizeof (dev_name_t));
- tmp->name = e->dtype;
- tmp->min = e->dnum;
- tmp->max = e->dnum;
- tmp->list_start = e;
- tmp->list_end = e;
- tmp->next = d->nf;
- d->nf = tmp;
- }
+ free(devpath);
+ return (1); /* success */
}
/*
- * devinfo_ident_disks() and devinfo_ident_tapes() are the callback functions we
- * use while walking the device tree snapshot provided by devinfo. If
- * devinfo_ident_disks() identifies that the device being considered has one or
- * more minor nodes _and_ is a block device, then it is a potential disk.
- * Similarly for devinfo_ident_tapes(), except that the second criterion is that
- * the minor_node be a character device. (This is more inclusive than only
- * tape devices, but will match any entries in /dev/rmt/.)
+ * Find/create a disk_list entry for "<driver><instunit>" given a kstat name.
+ * The basic format of a kstat name is "<driver><instunit>,<partition>". The
+ * <instunit> is a base10 number, and the ",<partition>" part is optional.
*
- * Note: if a driver was previously loaded but is now unloaded, the kstat may
- * still be around (e.g., st) but no information will be found in the
- * libdevinfo tree.
+ * NOTE: In the case of non-local metadevices, the format of "<driver>" in
+ * a kstat name is acutally "<setno>/md".
*/
-
-static int
-devinfo_ident_disks(di_node_t node, void *arg)
+disk_list_t *
+lookup_ks_name(char *ks_name, int want_devid)
{
- di_minor_t minor = DI_MINOR_NIL;
-
- if ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
- int spectype = di_minor_spectype(minor);
-
- if (S_ISBLK(spectype)) {
- char *physical_path = di_devfs_path(node);
- int instance = di_instance(node);
- char *driver_name = di_driver_name(node);
- char *devidstr;
-
- /* lookup the devid, devt specific first */
- if ((di_prop_lookup_strings(di_minor_devt(minor), node,
- DEVID_PROP_NAME, &devidstr) == -1) &&
- (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
- DEVID_PROP_NAME, &devidstr) == -1))
- devidstr = NULL;
-
- if (driver_name == NULL)
- driver_name = "<nil>";
-
- pline(physical_path, instance,
- driver_name, devidstr, arg);
- di_devfs_path_free(physical_path);
+ char *p;
+ int len;
+ char driver[MAXNAMELEN];
+ int instunit;
+ disk_list_t **dlhp; /* disklist head */
+ disk_list_t *entry;
+ char *devpath;
+ char *adevpath = NULL;
+ char *devid = NULL;
+ int isdisk;
+
+ /*
+ * Extract <driver> and <instunit> from kstat name.
+ * Filter out illegal forms (like all digits).
+ */
+ if ((ks_name == NULL) || (*ks_name == 0) ||
+ (strspn(ks_name, "0123456789") == strlen(ks_name)))
+ return (NULL);
+ p = strrchr(ks_name, ','); /* start of ",partition" */
+ if (p == NULL)
+ p = &ks_name[strlen(ks_name) - 1]; /* last char */
+ else
+ p--; /* before ",partition" */
+
+ while ((p >= ks_name) && isdigit(*p))
+ p--; /* backwards over digits */
+ p++; /* start of instunit */
+ if ((*p == '\0') || (*p == ','))
+ return (NULL); /* no <instunit> */
+ len = p - ks_name;
+ (void) strncpy(driver, ks_name, len);
+ driver[len] = '\0';
+ instunit = atoi(p);
+
+ /* hash and search for existing disklist entry */
+ dlhp = &disklist[instunit & (DISKLIST_MOD - 1)];
+ for (entry = *dlhp; entry; entry = entry->next) {
+ if ((strcmp(entry->dtype, driver) == 0) &&
+ (entry->dnum == instunit)) {
+ return (entry);
}
}
- return (DI_WALK_CONTINUE);
-}
-static int
-devinfo_ident_tapes(di_node_t node, void *arg)
-{
- di_minor_t minor = DI_MINOR_NIL;
-
- if ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
- int spectype = di_minor_spectype(minor);
-
- if (S_ISCHR(spectype)) {
- char *physical_path = di_devfs_path(node);
- int instance = di_instance(node);
- char *binding_name = di_binding_name(node);
-
- pline(physical_path, instance,
- binding_name, NULL, arg);
- di_devfs_path_free(physical_path);
- }
+ /* not found, try to get dev information */
+ if (drvinstunit2dev(driver, instunit, &devpath, &adevpath,
+ want_devid ? &devid : NULL, &isdisk) == 0) {
+ return (NULL);
}
- return (DI_WALK_CONTINUE);
-}
-/*
- * rummage_devinfo() is the driver routine that walks the devinfo snapshot.
- */
-static ldinfo_t *
-rummage_devinfo(void)
-{
- di_node_t root_node;
- ldinfo_t *rv = NULL;
-
- if ((root_node = di_init("/", DINFOCACHE)) != DI_NODE_NIL) {
- (void) di_walk_node(root_node, DI_WALK_CLDFIRST, (void *)&rv,
- devinfo_ident_disks);
- (void) di_walk_node(root_node, DI_WALK_CLDFIRST, (void *)&rv,
- devinfo_ident_tapes);
- di_fini(root_node);
+ /* and make a new disklist entry ... */
+ entry = safe_alloc(sizeof (disk_list_t));
+ entry->dtype = safe_strdup(driver);
+ entry->dnum = instunit;
+ entry->dname = devpath;
+ entry->dsk = adevpath;
+ entry->devidstr = devid;
+ entry->flags = 0;
+ if (isdisk) {
+ entry->flags |= SLICES_OK;
+#if defined(__i386)
+ entry->flags |= PARTITIONS_OK;
+#endif
}
- return (rv);
-}
+ entry->seen = 0;
-/*
- * pline() performs the lookup of the device path in the current list of disks,
- * and adds the appropriate information to the nms list in the case of a match.
- */
-static void
-pline(char *devfs_path, int instance,
- char *driver_name, char *devidstr, ldinfo_t **list)
-{
- ldinfo_t *entry;
-
- entry = safe_alloc(sizeof (ldinfo_t));
- entry->dnum = instance;
- entry->name = safe_strdup(devfs_path);
- entry->dtype = safe_strdup(driver_name);
- entry->devidstr = safe_strdup(devidstr);
- entry->next = *list;
- *list = entry;
+ /* add new entry to head of instunit hashed list */
+ entry->next = *dlhp;
+ *dlhp = entry;
+ return (entry);
}
/*
- * Cleanup space allocated in dlist processing.
- * We're only interested in cleaning up the list and nf
- * fields in the structure. Everything else is static
- * data.
+ * Convert metadevice setno to setname by looking in /dev/md for symlinks
+ * that point to "shared/setno" - the name of such a symlink is the setname.
+ * The caller is responsible for freeing the returned string.
*/
-static void
-cleanup_dlist(dir_info_t *d)
+static char *
+mdsetno2name(int setno)
{
- dev_name_t *tmp;
- dev_name_t *t1;
- disk_list_t *t2;
- disk_list_t *t3;
+ char setlink[MAXPATHLEN + 1];
+ char link[MAXPATHLEN + 1];
+ char path[MAXPATHLEN + 1];
+ char *p;
+ DIR *dirp;
+ struct dirent *dp;
+ size_t len;
+ char *mdsetname = NULL;
+
+ /* we are looking for a link to setlink */
+ (void) snprintf(setlink, MAXPATHLEN, "shared/%d", setno);
+
+ /* in the directory /dev/md */
+ (void) strcpy(path, "/dev/md/");
+ p = path + strlen(path);
+ dirp = opendir(path);
+ if (dirp == NULL)
+ return (NULL);
- /*
- * All of the entries in a dev_name_t use information
- * from a disk_list_t structure that is freed later.
- * All we need do here is free the dev_name_t
- * structure itself.
- */
- tmp = d->nf;
- while (tmp) {
- t1 = tmp->next;
- free(tmp);
- tmp = t1;
- }
- d->nf = 0;
- /*
- * "Later". Free the disk_list_t structures and their
- * data attached to this portion of the dir_info
- * structure.
- */
- t2 = d->list;
- while (t2) {
- if (t2->dtype) {
- free(t2->dtype);
- t2->dtype = NULL;
- }
- if (t2->dsk) {
- free(t2->dsk);
- t2->dsk = NULL;
- }
- if (t2->dname) {
- free(t2->dname);
- t2->dname = NULL;
- }
- t3 = t2->next;
- free(t2);
- t2 = t3;
- }
- d->list = 0;
-}
+ /* loop through /dev/md directory entries */
+ while ((dp = readdir(dirp)) != NULL) {
-static void
-process_dir_ent(char *dent, int curr_type, char *last_snm,
- dir_info_t *dp, ldinfo_t *ptoi)
-{
- struct stat sbuf;
- char dnmbuf[PATH_MAX + 1];
- char lnm[NAME_BUFLEN];
- char snm[NAME_BUFLEN];
- char *npt;
-
- snm[0] = NULL;
- if (curr_type == DISK || curr_type == OSA_DISK) {
- /*
- * get the short name - omitting
- * the trailing sN or PN
- */
- (void) strcpy(lnm, dent);
- do_snm(dent, snm);
- } else if (curr_type == MD_DISK) {
- (void) strcpy(lnm, dent);
- (void) strcpy(snm, dent);
- } else {
- /*
- * don't want all rewind/etc
- * devices for a tape
- */
- if (!str_is_digit(dent))
- return;
- (void) snprintf(snm, sizeof (snm), "rmt/%s", dent);
- (void) snprintf(lnm, sizeof (snm), "rmt/%s", dent);
- }
- /*
- * See if we've already processed an entry for this device.
- * If so, we're just another partition so we get another
- * entry.
- *
- * last_snm is an optimization to avoid the function call
- * and lookup since we'll often see partition records
- * immediately after the disk record.
- */
- if (dp->skip_lookup == 0) {
- if (strcmp(snm, last_snm) != 0) {
- /*
- * a zero return means that
- * no record was found. We'd
- * return a pointer otherwise.
- */
- if (look_up_name(snm,
- dp->list) == 0) {
- (void) strcpy(last_snm, snm);
- } else
- return;
- } else
- return;
- }
- /*
- * Get the real device name for this beast
- * by following the link into /devices.
- */
- (void) snprintf(dnmbuf, sizeof (dnmbuf), "%s/%s", dp->name, dent);
- if (lstat(dnmbuf, &sbuf) != -1) {
- if ((sbuf.st_mode & S_IFMT) == S_IFLNK) {
- /*
- * It's a link. Get the real name.
- */
- char nmbuf[PATH_MAX + 1];
- int nbyr;
-
- if ((nbyr = readlink(dnmbuf, nmbuf,
- sizeof (nmbuf))) != 1) {
- npt = nmbuf;
- /*
- * readlink does not terminate
- * the string so we have to
- * do it.
- */
- nmbuf[nbyr] = NULL;
- } else
- npt = NULL;
- } else
- npt = lnm;
- /*
- * make an entry in the device list
- */
- if (npt) {
- disk_list_t *d;
+ /* doing a readlink of entry (fails for non-symlinks) */
+ *p = '\0';
+ (void) strcpy(p, dp->d_name);
+ if ((len = readlink(path, link, MAXPATHLEN)) == (size_t)-1)
+ continue;
- d = make_an_entry(npt, snm,
- dnmbuf, dp,
- curr_type, ptoi);
- insert_into_dlist(dp, d);
- }
- }
-}
-static void
-cleanup_ldinfo(ldinfo_t *list)
-{
- ldinfo_t *tmp;
- while (list) {
- tmp = list;
- list = list->next;
- free(tmp->name);
- free(tmp->dtype);
- if (tmp->devidstr)
- free(tmp->devidstr);
- free(tmp);
+ /* and looking for a link to setlink */
+ link[len] = '\0';
+ if (strcmp(setlink, link))
+ continue;
+
+ /* found- name of link is the setname */
+ mdsetname = safe_strdup(dp->d_name);
+ break;
}
+
+ (void) closedir(dirp);
+ return (mdsetname);
}
char *
lookup_nfs_name(char *ks, kstat_ctl_t *kc)
{
- int tried = 0;
uint_t minor;
char *host, *path;
char *cp;
@@ -855,8 +447,8 @@ retry:
} else {
rstr = safe_strdup(cp);
}
- } else if (!tried) {
- tried = 1;
+ } else if (nfs_tried == 0) {
+ nfs_tried = 1;
do_mnttab();
goto retry;
}
diff --git a/usr/src/cmd/stat/common/dsr.h b/usr/src/cmd/stat/common/dsr.h
index dc14576efb..96757e68a8 100644
--- a/usr/src/cmd/stat/common/dsr.h
+++ b/usr/src/cmd/stat/common/dsr.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -43,7 +42,6 @@ typedef struct list_of_disks {
char *dname; /* in form of /dev/dsk/cNtNdN */
char *devidstr; /* in form of "id1,sd@XXXX" */
uint_t flags; /* see SLICES_OK and PARTITIONS_OK above */
- int devtype; /* disk, metadevice, tape */
uint_t seen; /* Used for diffing disk lists */
struct list_of_disks *next; /* link to next one */
} disk_list_t;
@@ -60,68 +58,6 @@ typedef struct mnt_info {
} mnt_t;
/*
- * A basic description of each device found
- * on the system by walking the device tree.
- * These entries are used to select the
- * relevent entries from the actual /dev
- * entries.
- */
-typedef struct ldinfo {
- char *name;
- char *dtype;
- char *devidstr;
- int dnum;
- struct ldinfo *next;
-} ldinfo_t;
-
-/*
- * Optimization for lookup of kstats.
- * For each kstat prefix (e.g., 'sd')
- * found in a directory one of these
- * structures will be created.
- *
- * name: prefix of kstat name (e.g., 'ssd')
- * min: smallest number seen from kstat
- * name (e.g., 101 from 'sd101')
- * max: largest number seen from kstat
- * list_start: beginning of disk_list structures
- * for this kstat type in the main list for
- * this directory
- * list_end: end of entries for this kstat type
- * in this directory.
- */
-typedef struct dev_name {
- char *name;
- uint_t min;
- uint_t max;
- disk_list_t *list_start;
- disk_list_t *list_end;
- struct dev_name *next;
-} dev_name_t;
-
-/*
- * Definition of a "type" of disk device.
- * Tied to the directory containing entries
- * for that device. Divides the list of
- * devices into localized chunks and allows
- * quick determination as to whether an entry
- * exists or whether we need to look at the
- * devices upon a state change.
- */
-typedef struct dir_info {
- char *name; /* directory name */
- time_t mtime; /* mod time */
- disk_list_t *list; /* master list of devices */
- dev_name_t *nf; /* lists per name */
- uint_t skip_lookup; /* skip lookup if device */
- /* does not have partitions */
- char *dtype; /* Type of device */
- char *trimstr; /* What do we prune */
- char trimchr; /* Char denoting end */
- /* of interesting data */
-} dir_info_t;
-
-/*
* The following are used to control treatment of kstat names
* which fall beyond the number of disk partitions allowed on
* the particular ISA. PARTITIONS_OK is set only on an Intel
@@ -132,8 +68,9 @@ typedef struct dir_info {
void do_mnttab(void);
mnt_t *lookup_mntent_byname(char *);
-disk_list_t *lookup_ks_name(char *);
+disk_list_t *lookup_ks_name(char *, int);
char *lookup_nfs_name(char *, kstat_ctl_t *);
+void cleanup_iodevs_snapshot();
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/stat/common/statcommon.h b/usr/src/cmd/stat/common/statcommon.h
index efc48e57ae..674148da6b 100644
--- a/usr/src/cmd/stat/common/statcommon.h
+++ b/usr/src/cmd/stat/common/statcommon.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Common routines for acquiring snapshots of kstats for
@@ -80,7 +79,9 @@ enum snapshot_types {
/* disk error stats */
SNAP_IODEV_ERRORS = 1 << 8,
/* pretty names for iodevs */
- SNAP_IODEV_PRETTY = 1 << 9
+ SNAP_IODEV_PRETTY = 1 << 9,
+ /* devid for iodevs */
+ SNAP_IODEV_DEVID = 1 << 10
};
struct cpu_snapshot {
diff --git a/usr/src/cmd/stat/iostat/iostat.c b/usr/src/cmd/stat/iostat/iostat.c
index 3499695347..1199870792 100644
--- a/usr/src/cmd/stat/iostat/iostat.c
+++ b/usr/src/cmd/stat/iostat/iostat.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* rewritten from UCB 4.13 83/09/25
@@ -203,6 +202,7 @@ main(int argc, char **argv)
enum snapshot_types types = SNAP_SYSTEM;
kstat_ctl_t *kc;
long hz;
+ int iiter;
do_args(argc, argv);
do_format();
@@ -228,6 +228,8 @@ main(int argc, char **argv)
df.if_allowed_types |= IODEV_PARTITION;
if (do_conversions)
types |= SNAP_IODEV_PRETTY;
+ if (do_devid)
+ types |= SNAP_IODEV_DEVID;
if (do_controller) {
if (!(do_disk & PRINT_VERTICAL) ||
(do_disk & DISK_EXTENDED_ERRORS))
@@ -253,6 +255,7 @@ main(int argc, char **argv)
kc = open_kstat();
newss = acquire_snapshot(kc, types, &df);
+ iiter = iter;
do {
if (do_tty || do_cpu) {
kstat_t *oldks;
@@ -277,6 +280,10 @@ main(int argc, char **argv)
(void) fflush(stdout);
}
+ /* only doing a single iteration, we are done */
+ if (iiter == 1)
+ continue;
+
if (interval > 0 && iter != 1)
(void) pause();
@@ -297,6 +304,8 @@ main(int argc, char **argv)
free_snapshot(oldss);
free_snapshot(newss);
+ (void) kstat_close(kc);
+
return (0);
}
@@ -345,7 +354,7 @@ show_disk_name(void *v1, void *v2, void *data)
(void) snprintf(fbuf, sizeof (fbuf),
"%*s", width, name);
name = fbuf;
- push_out("%-14.14s", name);
+ push_out("%-13.13s ", name);
} else {
push_out(name);
}
@@ -1242,7 +1251,10 @@ do_format(void)
default:
break;
}
- if (do_disk == DISK_ERRORS) {
+
+ /* do DISK_ERRORS header (already added above for DISK_EXTENDED) */
+ if ((do_disk & DISK_ERRORS) &&
+ ((do_disk & DISK_IO_MASK) != DISK_EXTENDED)) {
char *sep;
if (!do_conversions) {
@@ -1256,9 +1268,12 @@ do_format(void)
if (do_raw == 0) {
(void) snprintf(disk_header,
sizeof (disk_header),
- " %s", header);
- } else
- (void) strcpy(disk_header, header);
+ " %sdevice", header);
+ } else {
+ (void) snprintf(disk_header,
+ sizeof (disk_header),
+ "%s,device", header);
+ }
}
} else {
/*
@@ -1557,6 +1572,11 @@ print_err_hdr(void)
{
char obuf[SMALL_SCRATCH_BUFLEN];
+ if (do_raw) {
+ push_out("errors");
+ return;
+ }
+
if (do_conversions == 0) {
if (!(do_disk & DISK_EXTENDED)) {
(void) snprintf(obuf, sizeof (obuf),
diff --git a/usr/src/cmd/stat/mpstat/mpstat.c b/usr/src/cmd/stat/mpstat/mpstat.c
index b2c1793a8b..9ca510bf3d 100644
--- a/usr/src/cmd/stat/mpstat/mpstat.c
+++ b/usr/src/cmd/stat/mpstat/mpstat.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -163,6 +162,8 @@ main(int argc, char **argv)
(void) poll(NULL, 0, poll_interval);
}
+ (void) kstat_close(kc);
+
return (0);
}
diff --git a/usr/src/cmd/truss/print.c b/usr/src/cmd/truss/print.c
index ccaaf61485..f284539c1a 100644
--- a/usr/src/cmd/truss/print.c
+++ b/usr/src/cmd/truss/print.c
@@ -1102,6 +1102,10 @@ prt_mod(private_t *pri, int raw, long val) /* print modctl() code */
case MODDEVEXISTS: s = "MODDEVEXISTS"; break;
case MODDEVREADDIR: s = "MODDEVREADDIR"; break;
case MODDEVNAME: s = "MODDEVNAME"; break;
+ case MODGETDEVFSPATH_MI_LEN:
+ s = "MODGETDEVFSPATH_MI_LEN"; break;
+ case MODGETDEVFSPATH_MI:
+ s = "MODGETDEVFSPATH_MI"; break;
}
}
diff --git a/usr/src/lib/libdevinfo/Makefile.com b/usr/src/lib/libdevinfo/Makefile.com
index adcea87c26..42cf90b29d 100644
--- a/usr/src/lib/libdevinfo/Makefile.com
+++ b/usr/src/lib/libdevinfo/Makefile.com
@@ -30,7 +30,7 @@ VERS= .1
OBJECTS= devfsinfo.o devinfo.o devinfo_prop_decode.o devinfo_devlink.o \
devinfo_devperm.o devfsmap.o devinfo_devname.o \
- devinfo_finddev.o devinfo_dli.o
+ devinfo_finddev.o devinfo_dli.o devinfo_dim.o
include ../../Makefile.lib
include ../../Makefile.rootfs
diff --git a/usr/src/lib/libdevinfo/devinfo_devlink.c b/usr/src/lib/libdevinfo/devinfo_devlink.c
index 3bc5dadf6d..cd259eaee1 100644
--- a/usr/src/lib/libdevinfo/devinfo_devlink.c
+++ b/usr/src/lib/libdevinfo/devinfo_devlink.c
@@ -1032,6 +1032,7 @@ handle_free(struct di_devlink_handle **pp)
assert(hdp->lock_fd == -1);
free(hdp->dev_dir);
+ free(hdp->db_dir);
free(hdp);
}
diff --git a/usr/src/lib/libdevinfo/devinfo_dim.c b/usr/src/lib/libdevinfo/devinfo_dim.c
new file mode 100644
index 0000000000..141f5a9514
--- /dev/null
+++ b/usr/src/lib/libdevinfo/devinfo_dim.c
@@ -0,0 +1,149 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libdevinfo.h"
+#include <strings.h>
+#include <sys/modctl.h>
+
+/*
+ *
+ * This file contains interfaces to translate <driver><instance><minorname>
+ * information into /devices and /dev paths. It does this using interfaces to
+ * the kernel instance tree so that it can provide translations for devices
+ * which are no longer present. An example consumer of these interfaces is
+ * iostat(1M) - which shows, in its first iteration, activity since reboot.
+ * With persistant kstats, a device which was busy a long time ago can still
+ * have a decaying presence in iostat output, and that output, when '-n' is
+ * used, should show the public name.
+ */
+
+typedef struct {
+ di_devlink_handle_t i_devlink_hdl;
+} *idim_t;
+
+di_dim_t
+di_dim_init()
+{
+ idim_t idim;
+
+ if ((idim = (idim_t)malloc(sizeof (*idim))) == NULL)
+ return (NULL);
+ idim->i_devlink_hdl = di_devlink_init(NULL, 0);
+ if (idim->i_devlink_hdl == NULL) {
+ free(idim);
+ return (NULL);
+ }
+ return ((di_dim_t)idim);
+}
+
+void
+di_dim_fini(di_dim_t dim)
+{
+ idim_t idim = (idim_t)dim;
+
+ if (idim->i_devlink_hdl) {
+ (void) di_devlink_fini(&idim->i_devlink_hdl);
+ }
+ free(idim);
+}
+
+/*ARGSUSED*/
+char *
+di_dim_path_devices(di_dim_t dim, char *drv_name, int instance,
+ char *minor_name)
+{
+ major_t major;
+ int len;
+ int mlen;
+ char *devices;
+
+ /* convert drv_name to major_t */
+ if (modctl(MODGETMAJBIND, drv_name, strlen(drv_name) + 1, &major) < 0)
+ return (NULL);
+
+ /* find the length of the devices path given major,instance */
+ if (modctl(MODGETDEVFSPATH_MI_LEN, major, instance, &len) != 0)
+ return (NULL);
+
+ /*
+ * MODGETDEVFSPATH_MI_LEN result includes '\0' termination, but we
+ * may need to add space for ":<minor_name>"
+ */
+ if (minor_name)
+ mlen = len + 1 + strlen(minor_name);
+ else
+ mlen = len;
+ if ((devices = (char *)malloc(mlen)) == NULL)
+ return (NULL);
+
+ if (modctl(MODGETDEVFSPATH_MI, major, instance, len, devices) != 0) {
+ free(devices);
+ return (NULL);
+ }
+
+ if (minor_name) {
+ /* add ':<minot_name>' to the end of /devices path */
+ (void) strcat(devices, ":");
+ (void) strcat(devices, minor_name);
+ }
+ return (devices);
+}
+
+/* di_dim_path_dev di_devlink callback */
+static int
+di_dim_path_dev_callback(di_devlink_t dl, void *arg)
+{
+ char **devp = (char **)arg;
+ char *devpath = (char *)di_devlink_path(dl);
+
+ if (devpath)
+ *devp = strdup(devpath);
+ return (DI_WALK_TERMINATE);
+}
+
+char *
+di_dim_path_dev(di_dim_t dim, char *drv_name, int instance, char *minor_name)
+{
+ idim_t idim = (idim_t)dim;
+ char *devices;
+ char *dev = NULL;
+
+ /* we must have a minor_name to resolve to a public name */
+ if (minor_name == NULL)
+ return (NULL);
+
+ /* convert <driver><instance><minor_name> to /devices path */
+ devices = di_dim_path_devices(dim, drv_name, instance, minor_name);
+ if (devices == NULL)
+ return (NULL);
+
+ /* convert /devices path to /dev path */
+ (void) di_devlink_walk(idim->i_devlink_hdl, NULL,
+ devices, DI_PRIMARY_LINK, (void *)&dev, di_dim_path_dev_callback);
+ free(devices);
+ return (dev);
+}
diff --git a/usr/src/lib/libdevinfo/libdevinfo.h b/usr/src/lib/libdevinfo/libdevinfo.h
index 0fac182582..56c4b4982c 100644
--- a/usr/src/lib/libdevinfo/libdevinfo.h
+++ b/usr/src/lib/libdevinfo/libdevinfo.h
@@ -431,6 +431,22 @@ extern int di_prof_add_exclude(di_prof_t, const char *);
extern int di_prof_add_symlink(di_prof_t, const char *, const char *);
extern int di_prof_add_map(di_prof_t, const char *, const char *);
+/*
+ * Private interfaces for <driver><instance><minor> to path conversion.
+ * NOTE: These interfaces do not require or cause attach. The implementation
+ * uses the kernel instance-tree (/etc/path_to_inst) and the di_devlinks
+ * database information.
+ */
+typedef struct __di_dim *di_dim_t;
+
+extern di_dim_t di_dim_init();
+extern void di_dim_fini(di_dim_t);
+extern char *di_dim_path_devices(di_dim_t,
+ char *drv_name, int instance, char *minor_name);
+extern char *di_dim_path_dev(di_dim_t,
+ char *drv_name, int instance, char *minor_name);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libdevinfo/mapfile-vers b/usr/src/lib/libdevinfo/mapfile-vers
index 5a6310b03d..34251800bd 100644
--- a/usr/src/lib/libdevinfo/mapfile-vers
+++ b/usr/src/lib/libdevinfo/mapfile-vers
@@ -150,6 +150,10 @@ SUNWprivate_1.1 {
di_devname_action_on_key;
di_devname_print_mapinfo;
di_driver_private_data;
+ di_dim_fini;
+ di_dim_init;
+ di_dim_path_dev;
+ di_dim_path_devices;
di_init_driver;
di_init_impl;
di_lookup_node;
diff --git a/usr/src/uts/common/os/kstat_fr.c b/usr/src/uts/common/os/kstat_fr.c
index db3cf68ffd..1f4525fabb 100644
--- a/usr/src/uts/common/os/kstat_fr.c
+++ b/usr/src/uts/common/os/kstat_fr.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -710,17 +709,20 @@ default_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
scalehrtime(&kiop->rlastupdate);
if (kiop->wcnt != 0) {
+ /* like kstat_waitq_exit */
hrtime_t wfix = cur_time - kiop->wlastupdate;
- kiop->wtime += wfix;
+ kiop->wlastupdate = cur_time;
kiop->wlentime += kiop->wcnt * wfix;
+ kiop->wtime += wfix;
}
- kiop->wlastupdate = cur_time;
+
if (kiop->rcnt != 0) {
+ /* like kstat_runq_exit */
hrtime_t rfix = cur_time - kiop->rlastupdate;
- kiop->rtime += rfix;
+ kiop->rlastupdate = cur_time;
kiop->rlentime += kiop->rcnt * rfix;
+ kiop->rtime += rfix;
}
- kiop->rlastupdate = cur_time;
break;
case KSTAT_TYPE_NAMED:
diff --git a/usr/src/uts/common/os/modctl.c b/usr/src/uts/common/os/modctl.c
index 3509231ee2..4acbaae74f 100644
--- a/usr/src/uts/common/os/modctl.c
+++ b/usr/src/uts/common/os/modctl.c
@@ -1098,7 +1098,7 @@ modctl_get_minorname(dev_t dev, int spectype, uint_t len, char *uname)
}
/*
- * Return the size of the devfspath name.
+ * Return the size of the (dev_t,spectype) devfspath name.
*/
static int
modctl_devfspath_len(dev_t dev, int spectype, uint_t *len)
@@ -1124,7 +1124,7 @@ modctl_devfspath_len(dev_t dev, int spectype, uint_t *len)
}
/*
- * Return the devfspath name.
+ * Return the (dev_t,spectype) devfspath name.
*/
static int
modctl_devfspath(dev_t dev, int spectype, uint_t len, char *uname)
@@ -1155,6 +1155,66 @@ modctl_devfspath(dev_t dev, int spectype, uint_t len, char *uname)
return (err);
}
+/*
+ * Return the size of the (major,instance) devfspath name.
+ */
+static int
+modctl_devfspath_mi_len(major_t major, int instance, uint_t *len)
+{
+ uint_t sz;
+ char *name;
+
+ /* get the path name */
+ name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ if (e_ddi_majorinstance_to_path(major, instance, name) != DDI_SUCCESS) {
+ kmem_free(name, MAXPATHLEN);
+ return (EINVAL);
+ }
+
+ sz = strlen(name) + 1;
+ kmem_free(name, MAXPATHLEN);
+
+ /* copy out the size of the path name */
+ if (copyout(&sz, len, sizeof (sz)) != 0)
+ return (EFAULT);
+
+ return (0);
+}
+
+/*
+ * Return the (major_instance) devfspath name.
+ * NOTE: e_ddi_majorinstance_to_path does not require the device to attach to
+ * return a path - it uses the instance tree.
+ */
+static int
+modctl_devfspath_mi(major_t major, int instance, uint_t len, char *uname)
+{
+ uint_t sz;
+ char *name;
+ int err = 0;
+
+ /* get the path name */
+ name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+ if (e_ddi_majorinstance_to_path(major, instance, name) != DDI_SUCCESS) {
+ kmem_free(name, MAXPATHLEN);
+ return (EINVAL);
+ }
+
+ sz = strlen(name) + 1;
+
+ /* Error if the path name is larger than the space allocated */
+ if (sz > len) {
+ kmem_free(name, MAXPATHLEN);
+ return (ENOSPC);
+ }
+
+ /* copy out the path name */
+ if (copyout(name, uname, sz) != 0)
+ err = EFAULT;
+ kmem_free(name, MAXPATHLEN);
+ return (err);
+}
+
static int
modctl_get_fbname(char *path)
{
@@ -1874,7 +1934,7 @@ modctl(int cmd, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
error = modctl_get_devid(dev, (uint_t)a2, (ddi_devid_t)a3);
break;
- case MODSIZEOF_MINORNAME: /* sizeof minor nm of dev_t/spectype */
+ case MODSIZEOF_MINORNAME: /* sizeof minor nm (dev_t,spectype) */
if (get_udatamodel() == DATAMODEL_NATIVE) {
error = modctl_sizeof_minorname((dev_t)a1, (int)a2,
(uint_t *)a3);
@@ -1888,7 +1948,7 @@ modctl(int cmd, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
#endif
break;
- case MODGETMINORNAME: /* get minor name of dev_t and spec type */
+ case MODGETMINORNAME: /* get minor name of (dev_t,spectype) */
if (get_udatamodel() == DATAMODEL_NATIVE) {
error = modctl_get_minorname((dev_t)a1, (int)a2,
(uint_t)a3, (char *)a4);
@@ -1901,7 +1961,7 @@ modctl(int cmd, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
#endif
break;
- case MODGETDEVFSPATH_LEN: /* sizeof path nm of dev_t/spectype */
+ case MODGETDEVFSPATH_LEN: /* sizeof path nm of (dev_t,spectype) */
if (get_udatamodel() == DATAMODEL_NATIVE) {
error = modctl_devfspath_len((dev_t)a1, (int)a2,
(uint_t *)a3);
@@ -1915,7 +1975,7 @@ modctl(int cmd, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
#endif
break;
- case MODGETDEVFSPATH: /* get path name of dev_t and spec type */
+ case MODGETDEVFSPATH: /* get path name of (dev_t,spec) type */
if (get_udatamodel() == DATAMODEL_NATIVE) {
error = modctl_devfspath((dev_t)a1, (int)a2,
(uint_t)a3, (char *)a4);
@@ -1928,6 +1988,16 @@ modctl(int cmd, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
#endif
break;
+ case MODGETDEVFSPATH_MI_LEN: /* sizeof path nm of (major,instance) */
+ error = modctl_devfspath_mi_len((major_t)a1, (int)a2,
+ (uint_t *)a3);
+ break;
+
+ case MODGETDEVFSPATH_MI: /* get path name of (major,instance) */
+ error = modctl_devfspath_mi((major_t)a1, (int)a2,
+ (uint_t)a3, (char *)a4);
+ break;
+
case MODEVENTS:
error = modctl_modevents((int)a1, a2, a3, a4, (uint_t)a5);
diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c
index 592c6a97be..2f804b1d0e 100644
--- a/usr/src/uts/common/os/policy.c
+++ b/usr/src/uts/common/os/policy.c
@@ -1654,13 +1654,22 @@ secpolicy_modctl(const cred_t *cr, int cmd)
{
switch (cmd) {
case MODINFO:
+ case MODGETMAJBIND:
case MODGETPATH:
case MODGETPATHLEN:
- case MODGETFBNAME:
case MODGETNAME:
+ case MODGETFBNAME:
case MODGETDEVPOLICY:
case MODGETDEVPOLICYBYNAME:
- case MODGETMAJBIND:
+ case MODDEVT2INSTANCE:
+ case MODSIZEOF_DEVID:
+ case MODGETDEVID:
+ case MODSIZEOF_MINORNAME:
+ case MODGETMINORNAME:
+ case MODGETDEVFSPATH_LEN:
+ case MODGETDEVFSPATH:
+ case MODGETDEVFSPATH_MI_LEN:
+ case MODGETDEVFSPATH_MI:
/* Unprivileged */
return (0);
case MODLOAD:
diff --git a/usr/src/uts/common/sys/modctl.h b/usr/src/uts/common/sys/modctl.h
index 5e9450dde5..255d02d7b2 100644
--- a/usr/src/uts/common/sys/modctl.h
+++ b/usr/src/uts/common/sys/modctl.h
@@ -256,6 +256,8 @@ struct modlinkage {
#define MODDEVEXISTS 35
#define MODDEVREADDIR 36
#define MODDEVNAME 37
+#define MODGETDEVFSPATH_MI_LEN 38
+#define MODGETDEVFSPATH_MI 39
/*
* sub cmds for MODEVENTS