diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-01-12 20:21:37 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-01-12 20:21:37 +0000 |
commit | 6c3c7152302dce08b17b6fac14272fc435778145 (patch) | |
tree | cee094e02a544a7c9210d26eeda5c006c750989b /sys/kern/subr_disk.c | |
parent | 484706ec2d7791c35fcf9aea53e46db186855c74 (diff) |
from netbsd;
New generic disk framework. Highlights:
New metrics handling. Metrics are now kept in the new `struct disk'.
Busy time is now stored as a timeval, and transfer count in bytes.
Storage for disklabels is now dynamically allocated, so that the size
of the disk structure is not machine-dependent.
Several new functions for attaching and detaching disks, and handling
metrics calculation.
Old-style instrumentation is still supported in drivers that did it
before. However, old-style instrumentation is being deprecated, and
will go away once the userland utilities are updated for the new
framework.
For usage and architectural details, see the forthcoming disk(9)
manual page.
Diffstat (limited to 'sys/kern/subr_disk.c')
-rw-r--r-- | sys/kern/subr_disk.c | 184 |
1 files changed, 181 insertions, 3 deletions
diff --git a/sys/kern/subr_disk.c b/sys/kern/subr_disk.c index f3615211358..8ec8d7d9d10 100644 --- a/sys/kern/subr_disk.c +++ b/sys/kern/subr_disk.c @@ -1,6 +1,7 @@ -/* $NetBSD: subr_disk.c,v 1.14 1995/12/28 19:16:39 thorpej Exp $ */ +/* $NetBSD: subr_disk.c,v 1.15 1996/01/07 22:03:49 thorpej Exp $ */ /* + * Copyright (c) 1995 Jason R. Thorpe. All rights reserved. * Copyright (c) 1982, 1986, 1988, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. @@ -42,12 +43,23 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> #include <sys/buf.h> -#include <sys/disklabel.h> #include <sys/syslog.h> +#include <sys/time.h> +#include <sys/disklabel.h> +#include <sys/disk.h> #include <sys/dkstat.h> /* XXX */ /* + * A global list of all disks attached to the system. May grow or + * shrink over time. + */ +struct disklist_head disklist; /* TAILQ_HEAD */ +int disk_count; /* number of drives in global disklist */ + +/* * Old-style disk instrumentation structures. These will go away * someday. */ @@ -57,7 +69,7 @@ long dk_wds[DK_NDRIVE]; long dk_wpms[DK_NDRIVE]; long dk_xfer[DK_NDRIVE]; int dk_busy; -int dk_ndrive = DK_NDRIVE; +int dk_ndrive; int dkn; /* number of slots filled so far */ /* @@ -231,3 +243,169 @@ diskerr(bp, dname, what, pri, blkdone, lp) (*pr)(" tn %d sn %d)", sn / lp->d_nsectors, sn % lp->d_nsectors); } } + +/* + * Initialize the disklist. Called by main() before autoconfiguration. + */ +void +disk_init() +{ + + TAILQ_INIT(&disklist); + disk_count = 0; + dk_ndrive = DK_NDRIVE; /* XXX */ +} + +/* + * Searches the disklist for the disk corresponding to the + * name provided. + */ +struct disk * +disk_find(name) + char *name; +{ + struct disk *diskp; + + if ((name == NULL) || (disk_count <= 0)) + return (NULL); + + for (diskp = disklist.tqh_first; diskp != NULL; + diskp = diskp->dk_link.tqe_next) + if (strcmp(diskp->dk_name, name) == 0) + return (diskp); + + return (NULL); +} + +/* + * Attach a disk. + */ +void +disk_attach(diskp) + struct disk *diskp; +{ + int s; + + /* + * Allocate and initialize the disklabel structures. Note that + * it's not safe to sleep here, since we're probably going to be + * called during autoconfiguration. + */ + diskp->dk_label = malloc(sizeof(struct disklabel), M_DEVBUF, M_NOWAIT); + diskp->dk_cpulabel = malloc(sizeof(struct cpu_disklabel), M_DEVBUF, + M_NOWAIT); + if ((diskp->dk_label == NULL) || (diskp->dk_cpulabel == NULL)) + panic("disk_attach: can't allocate storage for disklabel"); + + bzero(diskp->dk_label, sizeof(struct disklabel)); + bzero(diskp->dk_cpulabel, sizeof(struct cpu_disklabel)); + + /* + * Set the attached timestamp. + */ + s = splclock(); + diskp->dk_attachtime = mono_time; + splx(s); + + /* + * Link into the disklist. + */ + TAILQ_INSERT_TAIL(&disklist, diskp, dk_link); + ++disk_count; +} + +/* + * Detatch a disk. + */ +void +disk_detatch(diskp) + struct disk *diskp; +{ + + /* + * Free the space used by the disklabel structures. + */ + free(diskp->dk_label, M_DEVBUF); + free(diskp->dk_cpulabel, M_DEVBUF); + + /* + * Remove from the disklist. + */ + TAILQ_REMOVE(&disklist, diskp, dk_link); + if (--disk_count < 0) + panic("disk_detatch: disk_count < 0"); +} + +/* + * Increment a disk's busy counter. If the counter is going from + * 0 to 1, set the timestamp. + */ +void +disk_busy(diskp) + struct disk *diskp; +{ + int s; + + /* + * XXX We'd like to use something as accurate as microtime(), + * but that doesn't depend on the system TOD clock. + */ + if (diskp->dk_busy++ == 0) { + s = splclock(); + diskp->dk_timestamp = mono_time; + splx(s); + } +} + +/* + * Decrement a disk's busy counter, increment the byte count, total busy + * time, and reset the timestamp. + */ +void +disk_unbusy(diskp, bcount) + struct disk *diskp; + long bcount; +{ + int s; + struct timeval dv_time, diff_time; + + if (diskp->dk_busy-- == 0) + panic("disk_unbusy: %s: dk_busy < 0", diskp->dk_name); + + s = splclock(); + dv_time = mono_time; + splx(s); + + timersub(&dv_time, &diskp->dk_timestamp, &diff_time); + timeradd(&diskp->dk_time, &diff_time, &diskp->dk_time); + + diskp->dk_timestamp = dv_time; + if (bcount > 0) { + diskp->dk_bytes += bcount; + diskp->dk_xfer++; + } +} + +/* + * Reset the metrics counters on the given disk. Note that we cannot + * reset the busy counter, as it may case a panic in disk_unbusy(). + * We also must avoid playing with the timestamp information, as it + * may skew any pending transfer results. + */ +void +disk_resetstat(diskp) + struct disk *diskp; +{ + int s = splbio(), t; + + diskp->dk_xfer = 0; + diskp->dk_bytes = 0; + + t = splclock(); + diskp->dk_attachtime = mono_time; + splx(t); + + timerclear(&diskp->dk_time); + + splx(s); +} |