subr_devstat.c revision 116182
139229Sgibbs/* 243819Sken * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 339229Sgibbs * All rights reserved. 439229Sgibbs * 539229Sgibbs * Redistribution and use in source and binary forms, with or without 639229Sgibbs * modification, are permitted provided that the following conditions 739229Sgibbs * are met: 839229Sgibbs * 1. Redistributions of source code must retain the above copyright 939229Sgibbs * notice, this list of conditions and the following disclaimer. 1039229Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1139229Sgibbs * notice, this list of conditions and the following disclaimer in the 1239229Sgibbs * documentation and/or other materials provided with the distribution. 1339229Sgibbs * 3. The name of the author may not be used to endorse or promote products 1439229Sgibbs * derived from this software without specific prior written permission. 1539229Sgibbs * 1639229Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1739229Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1839229Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1939229Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2039229Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2139229Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2239229Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2339229Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2439229Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2539229Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2639229Sgibbs * SUCH DAMAGE. 2739229Sgibbs */ 2839229Sgibbs 29116182Sobrien#include <sys/cdefs.h> 30116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/subr_devstat.c 116182 2003-06-11 00:56:59Z obrien $"); 31116182Sobrien 3239229Sgibbs#include <sys/param.h> 3339229Sgibbs#include <sys/kernel.h> 3439229Sgibbs#include <sys/systm.h> 3560041Sphk#include <sys/bio.h> 36112368Sphk#include <sys/devicestat.h> 3739229Sgibbs#include <sys/sysctl.h> 38112001Sphk#include <sys/malloc.h> 39112368Sphk#include <sys/lock.h> 40112368Sphk#include <sys/mutex.h> 41112001Sphk#include <sys/conf.h> 42112001Sphk#include <vm/vm.h> 43112001Sphk#include <vm/pmap.h> 4439229Sgibbs 45112368Sphk#include <machine/atomic.h> 4639229Sgibbs 4739229Sgibbsstatic int devstat_num_devs; 48113599Shartistatic long devstat_generation; 4939229Sgibbsstatic int devstat_version = DEVSTAT_VERSION; 5039229Sgibbsstatic int devstat_current_devnumber; 51112368Sphkstatic struct mtx devstat_mutex; 5239229Sgibbs 5381129Stmmstatic struct devstatlist device_statq; 54112001Sphkstatic struct devstat *devstat_alloc(void); 55112001Sphkstatic void devstat_free(struct devstat *); 56112365Sphkstatic void devstat_add_entry(struct devstat *ds, const void *dev_name, 57112007Sphk int unit_number, u_int32_t block_size, 58112007Sphk devstat_support_flags flags, 59112007Sphk devstat_type_flags device_type, 60112007Sphk devstat_priority priority); 6139229Sgibbs 6239229Sgibbs/* 63112001Sphk * Allocate a devstat and initialize it 64112001Sphk */ 65112001Sphkstruct devstat * 66112365Sphkdevstat_new_entry(const void *dev_name, 67112001Sphk int unit_number, u_int32_t block_size, 68112001Sphk devstat_support_flags flags, 69112001Sphk devstat_type_flags device_type, 70112001Sphk devstat_priority priority) 71112001Sphk{ 72112001Sphk struct devstat *ds; 73112368Sphk static int once; 74112001Sphk 75112368Sphk if (!once) { 76112368Sphk STAILQ_INIT(&device_statq); 77112368Sphk mtx_init(&devstat_mutex, "devstat", NULL, MTX_DEF); 78112368Sphk once = 1; 79112368Sphk } 80112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 81112368Sphk 82112001Sphk ds = devstat_alloc(); 83112368Sphk mtx_lock(&devstat_mutex); 84112369Sphk if (unit_number == -1) { 85112369Sphk ds->id = dev_name; 86112369Sphk binuptime(&ds->creation_time); 87112369Sphk devstat_generation++; 88112369Sphk } else { 89112369Sphk devstat_add_entry(ds, dev_name, unit_number, block_size, 90112369Sphk flags, device_type, priority); 91112369Sphk } 92112368Sphk mtx_unlock(&devstat_mutex); 93112001Sphk return (ds); 94112001Sphk} 95112001Sphk 96112001Sphk/* 9739229Sgibbs * Take a malloced and zeroed devstat structure given to us, fill it in 9839229Sgibbs * and add it to the queue of devices. 9939229Sgibbs */ 100112007Sphkstatic void 101112365Sphkdevstat_add_entry(struct devstat *ds, const void *dev_name, 10239229Sgibbs int unit_number, u_int32_t block_size, 10339229Sgibbs devstat_support_flags flags, 10443819Sken devstat_type_flags device_type, 10543819Sken devstat_priority priority) 10639229Sgibbs{ 10739229Sgibbs struct devstatlist *devstat_head; 10843819Sken struct devstat *ds_tmp; 10939229Sgibbs 110112368Sphk mtx_assert(&devstat_mutex, MA_OWNED); 11139229Sgibbs devstat_num_devs++; 11239229Sgibbs 11339229Sgibbs devstat_head = &device_statq; 11439229Sgibbs 11543819Sken /* 11643819Sken * Priority sort. Each driver passes in its priority when it adds 11743819Sken * its devstat entry. Drivers are sorted first by priority, and 11843819Sken * then by probe order. 11943819Sken * 12043819Sken * For the first device, we just insert it, since the priority 12143819Sken * doesn't really matter yet. Subsequent devices are inserted into 12243819Sken * the list using the order outlined above. 12343819Sken */ 12443819Sken if (devstat_num_devs == 1) 12543819Sken STAILQ_INSERT_TAIL(devstat_head, ds, dev_links); 12643819Sken else { 12772012Sphk STAILQ_FOREACH(ds_tmp, devstat_head, dev_links) { 12843819Sken struct devstat *ds_next; 12939229Sgibbs 13043819Sken ds_next = STAILQ_NEXT(ds_tmp, dev_links); 13143819Sken 13243819Sken /* 13343819Sken * If we find a break between higher and lower 13443819Sken * priority items, and if this item fits in the 13543819Sken * break, insert it. This also applies if the 13643819Sken * "lower priority item" is the end of the list. 13743819Sken */ 13843819Sken if ((priority <= ds_tmp->priority) 13943819Sken && ((ds_next == NULL) 14043819Sken || (priority > ds_next->priority))) { 14143819Sken STAILQ_INSERT_AFTER(devstat_head, ds_tmp, ds, 14243819Sken dev_links); 14343819Sken break; 14443819Sken } else if (priority > ds_tmp->priority) { 14543819Sken /* 14643819Sken * If this is the case, we should be able 14743819Sken * to insert ourselves at the head of the 14843819Sken * list. If we can't, something is wrong. 14943819Sken */ 15043819Sken if (ds_tmp == STAILQ_FIRST(devstat_head)) { 15143819Sken STAILQ_INSERT_HEAD(devstat_head, 15243819Sken ds, dev_links); 15343819Sken break; 15443819Sken } else { 15543819Sken STAILQ_INSERT_TAIL(devstat_head, 15643819Sken ds, dev_links); 15743819Sken printf("devstat_add_entry: HELP! " 15843819Sken "sorting problem detected " 159112365Sphk "for name %p unit %d\n", 160112365Sphk dev_name, unit_number); 16143819Sken break; 16243819Sken } 16343819Sken } 16443819Sken } 16543819Sken } 16643819Sken 16739229Sgibbs ds->device_number = devstat_current_devnumber++; 16839229Sgibbs ds->unit_number = unit_number; 169105354Srobert strlcpy(ds->device_name, dev_name, DEVSTAT_NAME_LEN); 17039229Sgibbs ds->block_size = block_size; 17139229Sgibbs ds->flags = flags; 17239229Sgibbs ds->device_type = device_type; 17343819Sken ds->priority = priority; 174112288Sphk binuptime(&ds->creation_time); 175112368Sphk devstat_generation++; 17639229Sgibbs} 17739229Sgibbs 17839229Sgibbs/* 17939229Sgibbs * Remove a devstat structure from the list of devices. 18039229Sgibbs */ 18139229Sgibbsvoid 18239229Sgibbsdevstat_remove_entry(struct devstat *ds) 18339229Sgibbs{ 18439229Sgibbs struct devstatlist *devstat_head; 18539229Sgibbs 186112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 18739229Sgibbs if (ds == NULL) 18839229Sgibbs return; 18939229Sgibbs 190112368Sphk mtx_lock(&devstat_mutex); 19139229Sgibbs 19239229Sgibbs devstat_head = &device_statq; 19339229Sgibbs 19439229Sgibbs /* Remove this entry from the devstat queue */ 195112368Sphk atomic_add_acq_int(&ds->sequence1, 1); 196112369Sphk if (ds->id == NULL) { 197112369Sphk devstat_num_devs--; 198112369Sphk STAILQ_REMOVE(devstat_head, ds, devstat, dev_links); 199112369Sphk } 200112368Sphk devstat_free(ds); 201112368Sphk devstat_generation++; 202112368Sphk mtx_unlock(&devstat_mutex); 20339229Sgibbs} 20439229Sgibbs 20539229Sgibbs/* 20639229Sgibbs * Record a transaction start. 207112288Sphk * 208112288Sphk * See comments for devstat_end_transaction(). Ordering is very important 209112288Sphk * here. 21039229Sgibbs */ 21139229Sgibbsvoid 212112288Sphkdevstat_start_transaction(struct devstat *ds, struct bintime *now) 21339229Sgibbs{ 214112368Sphk 215112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 216112368Sphk 21739229Sgibbs /* sanity check */ 21839229Sgibbs if (ds == NULL) 21939229Sgibbs return; 22039229Sgibbs 221112368Sphk atomic_add_acq_int(&ds->sequence1, 1); 22239229Sgibbs /* 22339229Sgibbs * We only want to set the start time when we are going from idle 22439229Sgibbs * to busy. The start time is really the start of the latest busy 22539229Sgibbs * period. 22639229Sgibbs */ 227112288Sphk if (ds->start_count == ds->end_count) { 228112288Sphk if (now != NULL) 229112288Sphk ds->busy_from = *now; 230112288Sphk else 231112288Sphk binuptime(&ds->busy_from); 232112288Sphk } 233112288Sphk ds->start_count++; 234112368Sphk atomic_add_rel_int(&ds->sequence0, 1); 23539229Sgibbs} 23639229Sgibbs 237112258Sphkvoid 238112258Sphkdevstat_start_transaction_bio(struct devstat *ds, struct bio *bp) 239112258Sphk{ 240112258Sphk 241112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 242112368Sphk 243112368Sphk /* sanity check */ 244112368Sphk if (ds == NULL) 245112368Sphk return; 246112368Sphk 247112288Sphk binuptime(&bp->bio_t0); 248112288Sphk devstat_start_transaction(ds, &bp->bio_t0); 249112288Sphk} 250112288Sphk 25139229Sgibbs/* 25239229Sgibbs * Record the ending of a transaction, and incrment the various counters. 253112288Sphk * 254112288Sphk * Ordering in this function, and in devstat_start_transaction() is VERY 255112288Sphk * important. The idea here is to run without locks, so we are very 256112288Sphk * careful to only modify some fields on the way "down" (i.e. at 257112288Sphk * transaction start) and some fields on the way "up" (i.e. at transaction 258112288Sphk * completion). One exception is busy_from, which we only modify in 259112288Sphk * devstat_start_transaction() when there are no outstanding transactions, 260112288Sphk * and thus it can't be modified in devstat_end_transaction() 261112288Sphk * simultaneously. 262112368Sphk * 263112368Sphk * The sequence0 and sequence1 fields are provided to enable an application 264112368Sphk * spying on the structures with mmap(2) to tell when a structure is in a 265112368Sphk * consistent state or not. 266112368Sphk * 267112368Sphk * For this to work 100% reliably, it is important that the two fields 268112368Sphk * are at opposite ends of the structure and that they are incremented 269112368Sphk * in the opposite order of how a memcpy(3) in userland would copy them. 270112368Sphk * We assume that the copying happens front to back, but there is actually 271112368Sphk * no way short of writing your own memcpy(3) replacement to guarantee 272112368Sphk * this will be the case. 273112368Sphk * 274112368Sphk * In addition to this, being a kind of locks, they must be updated with 275112368Sphk * atomic instructions using appropriate memory barriers. 27639229Sgibbs */ 27739229Sgibbsvoid 27839229Sgibbsdevstat_end_transaction(struct devstat *ds, u_int32_t bytes, 279112288Sphk devstat_tag_type tag_type, devstat_trans_flags flags, 280112288Sphk struct bintime *now, struct bintime *then) 28139229Sgibbs{ 282112288Sphk struct bintime dt, lnow; 28339229Sgibbs 284112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 285112368Sphk 28639229Sgibbs /* sanity check */ 28739229Sgibbs if (ds == NULL) 28839229Sgibbs return; 28939229Sgibbs 290112288Sphk if (now == NULL) { 291112288Sphk now = &lnow; 292112288Sphk binuptime(now); 293112288Sphk } 29439229Sgibbs 295112368Sphk atomic_add_acq_int(&ds->sequence1, 1); 296112288Sphk /* Update byte and operations counts */ 297112288Sphk ds->bytes[flags] += bytes; 298112288Sphk ds->operations[flags]++; 29939229Sgibbs 30039229Sgibbs /* 30139229Sgibbs * Keep a count of the various tag types sent. 30239229Sgibbs */ 30351397Sphk if ((ds->flags & DEVSTAT_NO_ORDERED_TAGS) == 0 && 30451375Sphk tag_type != DEVSTAT_TAG_NONE) 30539229Sgibbs ds->tag_types[tag_type]++; 30639229Sgibbs 307112288Sphk if (then != NULL) { 308112288Sphk /* Update duration of operations */ 309112288Sphk dt = *now; 310112288Sphk bintime_sub(&dt, then); 311112288Sphk bintime_add(&ds->duration[flags], &dt); 312112288Sphk } 31339229Sgibbs 314112288Sphk /* Accumulate busy time */ 315112288Sphk dt = *now; 316112288Sphk bintime_sub(&dt, &ds->busy_from); 317112288Sphk bintime_add(&ds->busy_time, &dt); 318112288Sphk ds->busy_from = *now; 319112288Sphk 320112288Sphk ds->end_count++; 321112368Sphk atomic_add_rel_int(&ds->sequence0, 1); 32239229Sgibbs} 32339229Sgibbs 32451375Sphkvoid 32558942Sphkdevstat_end_transaction_bio(struct devstat *ds, struct bio *bp) 32658942Sphk{ 32758942Sphk devstat_trans_flags flg; 32858942Sphk 329112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 330112368Sphk 331112368Sphk /* sanity check */ 332112368Sphk if (ds == NULL) 333112368Sphk return; 334112368Sphk 33558942Sphk if (bp->bio_cmd == BIO_DELETE) 33658942Sphk flg = DEVSTAT_FREE; 33758942Sphk else if (bp->bio_cmd == BIO_READ) 33858942Sphk flg = DEVSTAT_READ; 339112368Sphk else if (bp->bio_cmd == BIO_WRITE) 34058942Sphk flg = DEVSTAT_WRITE; 341112368Sphk else 342112368Sphk flg = DEVSTAT_NO_DATA; 34358942Sphk 34458942Sphk devstat_end_transaction(ds, bp->bio_bcount - bp->bio_resid, 345112288Sphk DEVSTAT_TAG_SIMPLE, flg, NULL, &bp->bio_t0); 34658942Sphk} 34758942Sphk 34839229Sgibbs/* 34939229Sgibbs * This is the sysctl handler for the devstat package. The data pushed out 35039229Sgibbs * on the kern.devstat.all sysctl variable consists of the current devstat 35139229Sgibbs * generation number, and then an array of devstat structures, one for each 35239229Sgibbs * device in the system. 35339229Sgibbs * 354112368Sphk * This is more cryptic that obvious, but basically we neither can nor 355112368Sphk * want to hold the devstat_mutex for any amount of time, so we grab it 356112368Sphk * only when we need to and keep an eye on devstat_generation all the time. 35739229Sgibbs */ 35839229Sgibbsstatic int 35962573Sphksysctl_devstat(SYSCTL_HANDLER_ARGS) 36039229Sgibbs{ 361112368Sphk int error; 362113599Sharti long mygen; 36339229Sgibbs struct devstat *nds; 36439229Sgibbs 365112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 366112368Sphk 36739229Sgibbs if (devstat_num_devs == 0) 36839229Sgibbs return(EINVAL); 36939229Sgibbs 37039229Sgibbs /* 371112368Sphk * XXX devstat_generation should really be "volatile" but that 372112368Sphk * XXX freaks out the sysctl macro below. The places where we 373112368Sphk * XXX change it and inspect it are bracketed in the mutex which 374112368Sphk * XXX guarantees us proper write barriers. I don't belive the 375112368Sphk * XXX compiler is allowed to optimize mygen away across calls 376112368Sphk * XXX to other functions, so the following is belived to be safe. 37739229Sgibbs */ 378112368Sphk mygen = devstat_generation; 37939229Sgibbs 380112368Sphk error = SYSCTL_OUT(req, &mygen, sizeof(mygen)); 381112368Sphk 382112368Sphk if (error != 0) 383112368Sphk return (error); 384112368Sphk 385112368Sphk mtx_lock(&devstat_mutex); 386112368Sphk nds = STAILQ_FIRST(&device_statq); 387112368Sphk if (mygen != devstat_generation) 388112368Sphk error = EBUSY; 389112368Sphk mtx_unlock(&devstat_mutex); 390112368Sphk 391112368Sphk if (error != 0) 392112368Sphk return (error); 393112368Sphk 394112368Sphk for (;nds != NULL;) { 39539229Sgibbs error = SYSCTL_OUT(req, nds, sizeof(struct devstat)); 396112368Sphk if (error != 0) 397112368Sphk return (error); 398112368Sphk mtx_lock(&devstat_mutex); 399112368Sphk if (mygen != devstat_generation) 400112368Sphk error = EBUSY; 401112368Sphk else 402112368Sphk nds = STAILQ_NEXT(nds, dev_links); 403112368Sphk mtx_unlock(&devstat_mutex); 404112368Sphk if (error != 0) 405112368Sphk return (error); 406112368Sphk } 40739229Sgibbs return(error); 40839229Sgibbs} 40939229Sgibbs 41039229Sgibbs/* 41139229Sgibbs * Sysctl entries for devstat. The first one is a node that all the rest 41239229Sgibbs * hang off of. 41339229Sgibbs */ 41439229SgibbsSYSCTL_NODE(_kern, OID_AUTO, devstat, CTLFLAG_RD, 0, "Device Statistics"); 41539229Sgibbs 41639229SgibbsSYSCTL_PROC(_kern_devstat, OID_AUTO, all, CTLFLAG_RD|CTLTYPE_OPAQUE, 41746381Sbillf 0, 0, sysctl_devstat, "S,devstat", "All devices in the devstat list"); 41839229Sgibbs/* 41939229Sgibbs * Export the number of devices in the system so that userland utilities 42039229Sgibbs * can determine how much memory to allocate to hold all the devices. 42139229Sgibbs */ 42246381SbillfSYSCTL_INT(_kern_devstat, OID_AUTO, numdevs, CTLFLAG_RD, 42346381Sbillf &devstat_num_devs, 0, "Number of devices in the devstat list"); 424113599ShartiSYSCTL_LONG(_kern_devstat, OID_AUTO, generation, CTLFLAG_RD, 42562622Sjhb &devstat_generation, 0, "Devstat list generation"); 42646381SbillfSYSCTL_INT(_kern_devstat, OID_AUTO, version, CTLFLAG_RD, 42746381Sbillf &devstat_version, 0, "Devstat list version number"); 428112001Sphk 429112368Sphk/* 430112368Sphk * Allocator for struct devstat structures. We sub-allocate these from pages 431112368Sphk * which we get from malloc. These pages are exported for mmap(2)'ing through 432112368Sphk * a miniature device driver 433112368Sphk */ 434112368Sphk 435112001Sphk#define statsperpage (PAGE_SIZE / sizeof(struct devstat)) 436112001Sphk 437112001Sphkstatic d_mmap_t devstat_mmap; 438112001Sphk 439112001Sphkstatic struct cdevsw devstat_cdevsw = { 440112001Sphk .d_open = nullopen, 441112001Sphk .d_close = nullclose, 442112001Sphk .d_mmap = devstat_mmap, 443112001Sphk .d_name = "devstat", 444112001Sphk}; 445112001Sphk 446112001Sphkstruct statspage { 447112001Sphk TAILQ_ENTRY(statspage) list; 448112001Sphk struct devstat *stat; 449112001Sphk u_int nfree; 450112001Sphk}; 451112001Sphk 452112001Sphkstatic TAILQ_HEAD(, statspage) pagelist = TAILQ_HEAD_INITIALIZER(pagelist); 453112001Sphkstatic MALLOC_DEFINE(M_DEVSTAT, "devstat", "Device statistics"); 454112001Sphk 455112001Sphkstatic int 456112569Sjakedevstat_mmap(dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 457112001Sphk{ 458112001Sphk struct statspage *spp; 459112001Sphk 460112001Sphk if (nprot != VM_PROT_READ) 461112001Sphk return (-1); 462112001Sphk TAILQ_FOREACH(spp, &pagelist, list) { 463112001Sphk if (offset == 0) { 464112001Sphk *paddr = vtophys(spp->stat); 465112001Sphk return (0); 466112001Sphk } 467112001Sphk offset -= PAGE_SIZE; 468112001Sphk } 469112001Sphk return (-1); 470112001Sphk} 471112001Sphk 472112001Sphkstatic struct devstat * 473112001Sphkdevstat_alloc(void) 474112001Sphk{ 475112001Sphk struct devstat *dsp; 476112001Sphk struct statspage *spp; 477112001Sphk u_int u; 478112001Sphk static int once; 479112001Sphk 480112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 481112001Sphk if (!once) { 482112001Sphk make_dev(&devstat_cdevsw, 0, 483112326Sphk UID_ROOT, GID_WHEEL, 0400, DEVSTAT_DEVICE_NAME); 484112368Sphk once = 1; 485112001Sphk } 486112368Sphk mtx_lock(&devstat_mutex); 487112368Sphk for (;;) { 488112368Sphk TAILQ_FOREACH(spp, &pagelist, list) { 489112368Sphk if (spp->nfree > 0) 490112368Sphk break; 491112368Sphk } 492112368Sphk if (spp != NULL) 493112001Sphk break; 494112368Sphk /* 495112368Sphk * We had no free slot in any of our pages, drop the mutex 496112368Sphk * and get another page. In theory we could have more than 497112368Sphk * one process doing this at the same time and consequently 498112368Sphk * we may allocate more pages than we will need. That is 499112368Sphk * Just Too Bad[tm], we can live with that. 500112368Sphk */ 501112368Sphk mtx_unlock(&devstat_mutex); 502112001Sphk spp = malloc(sizeof *spp, M_DEVSTAT, M_ZERO | M_WAITOK); 503112001Sphk spp->stat = malloc(PAGE_SIZE, M_DEVSTAT, M_ZERO | M_WAITOK); 504112001Sphk spp->nfree = statsperpage; 505112368Sphk mtx_lock(&devstat_mutex); 506112368Sphk /* 507112368Sphk * It would make more sense to add the new page at the head 508112368Sphk * but the order on the list determine the sequence of the 509112368Sphk * mapping so we can't do that. 510112368Sphk */ 511112368Sphk TAILQ_INSERT_TAIL(&pagelist, spp, list); 512112001Sphk } 513112001Sphk dsp = spp->stat; 514112001Sphk for (u = 0; u < statsperpage; u++) { 515112001Sphk if (dsp->allocated == 0) 516112001Sphk break; 517112001Sphk dsp++; 518112001Sphk } 519112001Sphk spp->nfree--; 520112001Sphk dsp->allocated = 1; 521112368Sphk mtx_unlock(&devstat_mutex); 522112001Sphk return (dsp); 523112001Sphk} 524112001Sphk 525112001Sphkstatic void 526112001Sphkdevstat_free(struct devstat *dsp) 527112001Sphk{ 528112001Sphk struct statspage *spp; 529112001Sphk 530112368Sphk mtx_assert(&devstat_mutex, MA_OWNED); 531112001Sphk bzero(dsp, sizeof *dsp); 532112001Sphk TAILQ_FOREACH(spp, &pagelist, list) { 533112001Sphk if (dsp >= spp->stat && dsp < (spp->stat + statsperpage)) { 534112001Sphk spp->nfree++; 535112001Sphk return; 536112001Sphk } 537112001Sphk } 538112001Sphk} 539112288Sphk 540112288SphkSYSCTL_INT(_debug_sizeof, OID_AUTO, devstat, CTLFLAG_RD, 541112288Sphk 0, sizeof(struct devstat), "sizeof(struct devstat)"); 542