subr_devstat.c revision 112368
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 * 2850477Speter * $FreeBSD: head/sys/kern/subr_devstat.c 112368 2003-03-18 09:20:20Z phk $ 2939229Sgibbs */ 3039229Sgibbs 3139229Sgibbs#include <sys/param.h> 3239229Sgibbs#include <sys/kernel.h> 3339229Sgibbs#include <sys/systm.h> 3460041Sphk#include <sys/bio.h> 35112368Sphk#include <sys/devicestat.h> 3639229Sgibbs#include <sys/sysctl.h> 37112001Sphk#include <sys/malloc.h> 38112368Sphk#include <sys/lock.h> 39112368Sphk#include <sys/mutex.h> 40112001Sphk#include <sys/conf.h> 41112001Sphk#include <vm/vm.h> 42112001Sphk#include <vm/pmap.h> 4339229Sgibbs 44112368Sphk#include <machine/atomic.h> 4539229Sgibbs 4639229Sgibbsstatic int devstat_num_devs; 47112368Sphkstatic u_int devstat_generation; 4839229Sgibbsstatic int devstat_version = DEVSTAT_VERSION; 4939229Sgibbsstatic int devstat_current_devnumber; 50112368Sphkstatic struct mtx devstat_mutex; 5139229Sgibbs 5281129Stmmstatic struct devstatlist device_statq; 53112001Sphkstatic struct devstat *devstat_alloc(void); 54112001Sphkstatic void devstat_free(struct devstat *); 55112365Sphkstatic void devstat_add_entry(struct devstat *ds, const void *dev_name, 56112007Sphk int unit_number, u_int32_t block_size, 57112007Sphk devstat_support_flags flags, 58112007Sphk devstat_type_flags device_type, 59112007Sphk devstat_priority priority); 6039229Sgibbs 6139229Sgibbs/* 62112001Sphk * Allocate a devstat and initialize it 63112001Sphk */ 64112001Sphkstruct devstat * 65112365Sphkdevstat_new_entry(const void *dev_name, 66112001Sphk int unit_number, u_int32_t block_size, 67112001Sphk devstat_support_flags flags, 68112001Sphk devstat_type_flags device_type, 69112001Sphk devstat_priority priority) 70112001Sphk{ 71112001Sphk struct devstat *ds; 72112368Sphk static int once; 73112001Sphk 74112368Sphk if (!once) { 75112368Sphk STAILQ_INIT(&device_statq); 76112368Sphk mtx_init(&devstat_mutex, "devstat", NULL, MTX_DEF); 77112368Sphk once = 1; 78112368Sphk } 79112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 80112368Sphk 81112001Sphk ds = devstat_alloc(); 82112368Sphk mtx_lock(&devstat_mutex); 83112001Sphk devstat_add_entry(ds, dev_name, unit_number, block_size, 84112001Sphk flags, device_type, priority); 85112368Sphk mtx_unlock(&devstat_mutex); 86112001Sphk return (ds); 87112001Sphk} 88112001Sphk 89112001Sphk/* 9039229Sgibbs * Take a malloced and zeroed devstat structure given to us, fill it in 9139229Sgibbs * and add it to the queue of devices. 9239229Sgibbs */ 93112007Sphkstatic void 94112365Sphkdevstat_add_entry(struct devstat *ds, const void *dev_name, 9539229Sgibbs int unit_number, u_int32_t block_size, 9639229Sgibbs devstat_support_flags flags, 9743819Sken devstat_type_flags device_type, 9843819Sken devstat_priority priority) 9939229Sgibbs{ 10039229Sgibbs struct devstatlist *devstat_head; 10143819Sken struct devstat *ds_tmp; 10239229Sgibbs 103112368Sphk mtx_assert(&devstat_mutex, MA_OWNED); 10439229Sgibbs devstat_num_devs++; 10539229Sgibbs 10639229Sgibbs devstat_head = &device_statq; 10739229Sgibbs 10843819Sken /* 10943819Sken * Priority sort. Each driver passes in its priority when it adds 11043819Sken * its devstat entry. Drivers are sorted first by priority, and 11143819Sken * then by probe order. 11243819Sken * 11343819Sken * For the first device, we just insert it, since the priority 11443819Sken * doesn't really matter yet. Subsequent devices are inserted into 11543819Sken * the list using the order outlined above. 11643819Sken */ 11743819Sken if (devstat_num_devs == 1) 11843819Sken STAILQ_INSERT_TAIL(devstat_head, ds, dev_links); 11943819Sken else { 12072012Sphk STAILQ_FOREACH(ds_tmp, devstat_head, dev_links) { 12143819Sken struct devstat *ds_next; 12239229Sgibbs 12343819Sken ds_next = STAILQ_NEXT(ds_tmp, dev_links); 12443819Sken 12543819Sken /* 12643819Sken * If we find a break between higher and lower 12743819Sken * priority items, and if this item fits in the 12843819Sken * break, insert it. This also applies if the 12943819Sken * "lower priority item" is the end of the list. 13043819Sken */ 13143819Sken if ((priority <= ds_tmp->priority) 13243819Sken && ((ds_next == NULL) 13343819Sken || (priority > ds_next->priority))) { 13443819Sken STAILQ_INSERT_AFTER(devstat_head, ds_tmp, ds, 13543819Sken dev_links); 13643819Sken break; 13743819Sken } else if (priority > ds_tmp->priority) { 13843819Sken /* 13943819Sken * If this is the case, we should be able 14043819Sken * to insert ourselves at the head of the 14143819Sken * list. If we can't, something is wrong. 14243819Sken */ 14343819Sken if (ds_tmp == STAILQ_FIRST(devstat_head)) { 14443819Sken STAILQ_INSERT_HEAD(devstat_head, 14543819Sken ds, dev_links); 14643819Sken break; 14743819Sken } else { 14843819Sken STAILQ_INSERT_TAIL(devstat_head, 14943819Sken ds, dev_links); 15043819Sken printf("devstat_add_entry: HELP! " 15143819Sken "sorting problem detected " 152112365Sphk "for name %p unit %d\n", 153112365Sphk dev_name, unit_number); 15443819Sken break; 15543819Sken } 15643819Sken } 15743819Sken } 15843819Sken } 15943819Sken 16039229Sgibbs ds->device_number = devstat_current_devnumber++; 16139229Sgibbs ds->unit_number = unit_number; 162105354Srobert strlcpy(ds->device_name, dev_name, DEVSTAT_NAME_LEN); 16339229Sgibbs ds->block_size = block_size; 16439229Sgibbs ds->flags = flags; 16539229Sgibbs ds->device_type = device_type; 16643819Sken ds->priority = priority; 167112288Sphk binuptime(&ds->creation_time); 168112368Sphk devstat_generation++; 16939229Sgibbs} 17039229Sgibbs 17139229Sgibbs/* 17239229Sgibbs * Remove a devstat structure from the list of devices. 17339229Sgibbs */ 17439229Sgibbsvoid 17539229Sgibbsdevstat_remove_entry(struct devstat *ds) 17639229Sgibbs{ 17739229Sgibbs struct devstatlist *devstat_head; 17839229Sgibbs 179112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 18039229Sgibbs if (ds == NULL) 18139229Sgibbs return; 18239229Sgibbs 183112368Sphk mtx_lock(&devstat_mutex); 18439229Sgibbs 18539229Sgibbs devstat_head = &device_statq; 18639229Sgibbs 18739229Sgibbs /* Remove this entry from the devstat queue */ 188112368Sphk atomic_add_acq_int(&ds->sequence1, 1); 189112368Sphk devstat_num_devs--; 19060938Sjake STAILQ_REMOVE(devstat_head, ds, devstat, dev_links); 191112368Sphk devstat_free(ds); 192112368Sphk devstat_generation++; 193112368Sphk mtx_unlock(&devstat_mutex); 19439229Sgibbs} 19539229Sgibbs 19639229Sgibbs/* 19739229Sgibbs * Record a transaction start. 198112288Sphk * 199112288Sphk * See comments for devstat_end_transaction(). Ordering is very important 200112288Sphk * here. 20139229Sgibbs */ 20239229Sgibbsvoid 203112288Sphkdevstat_start_transaction(struct devstat *ds, struct bintime *now) 20439229Sgibbs{ 205112368Sphk 206112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 207112368Sphk 20839229Sgibbs /* sanity check */ 20939229Sgibbs if (ds == NULL) 21039229Sgibbs return; 21139229Sgibbs 212112368Sphk atomic_add_acq_int(&ds->sequence1, 1); 21339229Sgibbs /* 21439229Sgibbs * We only want to set the start time when we are going from idle 21539229Sgibbs * to busy. The start time is really the start of the latest busy 21639229Sgibbs * period. 21739229Sgibbs */ 218112288Sphk if (ds->start_count == ds->end_count) { 219112288Sphk if (now != NULL) 220112288Sphk ds->busy_from = *now; 221112288Sphk else 222112288Sphk binuptime(&ds->busy_from); 223112288Sphk } 224112288Sphk ds->start_count++; 225112368Sphk atomic_add_rel_int(&ds->sequence0, 1); 22639229Sgibbs} 22739229Sgibbs 228112258Sphkvoid 229112258Sphkdevstat_start_transaction_bio(struct devstat *ds, struct bio *bp) 230112258Sphk{ 231112258Sphk 232112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 233112368Sphk 234112368Sphk /* sanity check */ 235112368Sphk if (ds == NULL) 236112368Sphk return; 237112368Sphk 238112288Sphk binuptime(&bp->bio_t0); 239112288Sphk devstat_start_transaction(ds, &bp->bio_t0); 240112288Sphk} 241112288Sphk 24239229Sgibbs/* 24339229Sgibbs * Record the ending of a transaction, and incrment the various counters. 244112288Sphk * 245112288Sphk * Ordering in this function, and in devstat_start_transaction() is VERY 246112288Sphk * important. The idea here is to run without locks, so we are very 247112288Sphk * careful to only modify some fields on the way "down" (i.e. at 248112288Sphk * transaction start) and some fields on the way "up" (i.e. at transaction 249112288Sphk * completion). One exception is busy_from, which we only modify in 250112288Sphk * devstat_start_transaction() when there are no outstanding transactions, 251112288Sphk * and thus it can't be modified in devstat_end_transaction() 252112288Sphk * simultaneously. 253112368Sphk * 254112368Sphk * The sequence0 and sequence1 fields are provided to enable an application 255112368Sphk * spying on the structures with mmap(2) to tell when a structure is in a 256112368Sphk * consistent state or not. 257112368Sphk * 258112368Sphk * For this to work 100% reliably, it is important that the two fields 259112368Sphk * are at opposite ends of the structure and that they are incremented 260112368Sphk * in the opposite order of how a memcpy(3) in userland would copy them. 261112368Sphk * We assume that the copying happens front to back, but there is actually 262112368Sphk * no way short of writing your own memcpy(3) replacement to guarantee 263112368Sphk * this will be the case. 264112368Sphk * 265112368Sphk * In addition to this, being a kind of locks, they must be updated with 266112368Sphk * atomic instructions using appropriate memory barriers. 26739229Sgibbs */ 26839229Sgibbsvoid 26939229Sgibbsdevstat_end_transaction(struct devstat *ds, u_int32_t bytes, 270112288Sphk devstat_tag_type tag_type, devstat_trans_flags flags, 271112288Sphk struct bintime *now, struct bintime *then) 27239229Sgibbs{ 273112288Sphk struct bintime dt, lnow; 27439229Sgibbs 275112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 276112368Sphk 27739229Sgibbs /* sanity check */ 27839229Sgibbs if (ds == NULL) 27939229Sgibbs return; 28039229Sgibbs 281112288Sphk if (now == NULL) { 282112288Sphk now = &lnow; 283112288Sphk binuptime(now); 284112288Sphk } 28539229Sgibbs 286112368Sphk atomic_add_acq_int(&ds->sequence1, 1); 287112288Sphk /* Update byte and operations counts */ 288112288Sphk ds->bytes[flags] += bytes; 289112288Sphk ds->operations[flags]++; 29039229Sgibbs 29139229Sgibbs /* 29239229Sgibbs * Keep a count of the various tag types sent. 29339229Sgibbs */ 29451397Sphk if ((ds->flags & DEVSTAT_NO_ORDERED_TAGS) == 0 && 29551375Sphk tag_type != DEVSTAT_TAG_NONE) 29639229Sgibbs ds->tag_types[tag_type]++; 29739229Sgibbs 298112288Sphk if (then != NULL) { 299112288Sphk /* Update duration of operations */ 300112288Sphk dt = *now; 301112288Sphk bintime_sub(&dt, then); 302112288Sphk bintime_add(&ds->duration[flags], &dt); 303112288Sphk } 30439229Sgibbs 305112288Sphk /* Accumulate busy time */ 306112288Sphk dt = *now; 307112288Sphk bintime_sub(&dt, &ds->busy_from); 308112288Sphk bintime_add(&ds->busy_time, &dt); 309112288Sphk ds->busy_from = *now; 310112288Sphk 311112288Sphk ds->end_count++; 312112368Sphk atomic_add_rel_int(&ds->sequence0, 1); 31339229Sgibbs} 31439229Sgibbs 31551375Sphkvoid 31658942Sphkdevstat_end_transaction_bio(struct devstat *ds, struct bio *bp) 31758942Sphk{ 31858942Sphk devstat_trans_flags flg; 31958942Sphk 320112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 321112368Sphk 322112368Sphk /* sanity check */ 323112368Sphk if (ds == NULL) 324112368Sphk return; 325112368Sphk 32658942Sphk if (bp->bio_cmd == BIO_DELETE) 32758942Sphk flg = DEVSTAT_FREE; 32858942Sphk else if (bp->bio_cmd == BIO_READ) 32958942Sphk flg = DEVSTAT_READ; 330112368Sphk else if (bp->bio_cmd == BIO_WRITE) 33158942Sphk flg = DEVSTAT_WRITE; 332112368Sphk else 333112368Sphk flg = DEVSTAT_NO_DATA; 33458942Sphk 33558942Sphk devstat_end_transaction(ds, bp->bio_bcount - bp->bio_resid, 336112288Sphk DEVSTAT_TAG_SIMPLE, flg, NULL, &bp->bio_t0); 33758942Sphk} 33858942Sphk 33939229Sgibbs/* 34039229Sgibbs * This is the sysctl handler for the devstat package. The data pushed out 34139229Sgibbs * on the kern.devstat.all sysctl variable consists of the current devstat 34239229Sgibbs * generation number, and then an array of devstat structures, one for each 34339229Sgibbs * device in the system. 34439229Sgibbs * 345112368Sphk * This is more cryptic that obvious, but basically we neither can nor 346112368Sphk * want to hold the devstat_mutex for any amount of time, so we grab it 347112368Sphk * only when we need to and keep an eye on devstat_generation all the time. 34839229Sgibbs */ 34939229Sgibbsstatic int 35062573Sphksysctl_devstat(SYSCTL_HANDLER_ARGS) 35139229Sgibbs{ 352112368Sphk int error; 353112368Sphk u_int mygen; 35439229Sgibbs struct devstat *nds; 35539229Sgibbs 356112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 357112368Sphk 35839229Sgibbs if (devstat_num_devs == 0) 35939229Sgibbs return(EINVAL); 36039229Sgibbs 36139229Sgibbs /* 362112368Sphk * XXX devstat_generation should really be "volatile" but that 363112368Sphk * XXX freaks out the sysctl macro below. The places where we 364112368Sphk * XXX change it and inspect it are bracketed in the mutex which 365112368Sphk * XXX guarantees us proper write barriers. I don't belive the 366112368Sphk * XXX compiler is allowed to optimize mygen away across calls 367112368Sphk * XXX to other functions, so the following is belived to be safe. 36839229Sgibbs */ 369112368Sphk mygen = devstat_generation; 37039229Sgibbs 371112368Sphk error = SYSCTL_OUT(req, &mygen, sizeof(mygen)); 372112368Sphk 373112368Sphk if (error != 0) 374112368Sphk return (error); 375112368Sphk 376112368Sphk mtx_lock(&devstat_mutex); 377112368Sphk nds = STAILQ_FIRST(&device_statq); 378112368Sphk if (mygen != devstat_generation) 379112368Sphk error = EBUSY; 380112368Sphk mtx_unlock(&devstat_mutex); 381112368Sphk 382112368Sphk if (error != 0) 383112368Sphk return (error); 384112368Sphk 385112368Sphk for (;nds != NULL;) { 38639229Sgibbs error = SYSCTL_OUT(req, nds, sizeof(struct devstat)); 387112368Sphk if (error != 0) 388112368Sphk return (error); 389112368Sphk mtx_lock(&devstat_mutex); 390112368Sphk if (mygen != devstat_generation) 391112368Sphk error = EBUSY; 392112368Sphk else 393112368Sphk nds = STAILQ_NEXT(nds, dev_links); 394112368Sphk mtx_unlock(&devstat_mutex); 395112368Sphk if (error != 0) 396112368Sphk return (error); 397112368Sphk } 39839229Sgibbs return(error); 39939229Sgibbs} 40039229Sgibbs 40139229Sgibbs/* 40239229Sgibbs * Sysctl entries for devstat. The first one is a node that all the rest 40339229Sgibbs * hang off of. 40439229Sgibbs */ 40539229SgibbsSYSCTL_NODE(_kern, OID_AUTO, devstat, CTLFLAG_RD, 0, "Device Statistics"); 40639229Sgibbs 40739229SgibbsSYSCTL_PROC(_kern_devstat, OID_AUTO, all, CTLFLAG_RD|CTLTYPE_OPAQUE, 40846381Sbillf 0, 0, sysctl_devstat, "S,devstat", "All devices in the devstat list"); 40939229Sgibbs/* 41039229Sgibbs * Export the number of devices in the system so that userland utilities 41139229Sgibbs * can determine how much memory to allocate to hold all the devices. 41239229Sgibbs */ 41346381SbillfSYSCTL_INT(_kern_devstat, OID_AUTO, numdevs, CTLFLAG_RD, 41446381Sbillf &devstat_num_devs, 0, "Number of devices in the devstat list"); 41539498SkenSYSCTL_LONG(_kern_devstat, OID_AUTO, generation, CTLFLAG_RD, 41662622Sjhb &devstat_generation, 0, "Devstat list generation"); 41746381SbillfSYSCTL_INT(_kern_devstat, OID_AUTO, version, CTLFLAG_RD, 41846381Sbillf &devstat_version, 0, "Devstat list version number"); 419112001Sphk 420112368Sphk/* 421112368Sphk * Allocator for struct devstat structures. We sub-allocate these from pages 422112368Sphk * which we get from malloc. These pages are exported for mmap(2)'ing through 423112368Sphk * a miniature device driver 424112368Sphk */ 425112368Sphk 426112001Sphk#define statsperpage (PAGE_SIZE / sizeof(struct devstat)) 427112001Sphk 428112001Sphkstatic d_mmap_t devstat_mmap; 429112001Sphk 430112001Sphkstatic struct cdevsw devstat_cdevsw = { 431112001Sphk .d_open = nullopen, 432112001Sphk .d_close = nullclose, 433112001Sphk .d_mmap = devstat_mmap, 434112001Sphk .d_name = "devstat", 435112001Sphk}; 436112001Sphk 437112001Sphkstruct statspage { 438112001Sphk TAILQ_ENTRY(statspage) list; 439112001Sphk struct devstat *stat; 440112001Sphk u_int nfree; 441112001Sphk}; 442112001Sphk 443112001Sphkstatic TAILQ_HEAD(, statspage) pagelist = TAILQ_HEAD_INITIALIZER(pagelist); 444112001Sphkstatic MALLOC_DEFINE(M_DEVSTAT, "devstat", "Device statistics"); 445112001Sphk 446112001Sphkstatic int 447112001Sphkdevstat_mmap(dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nprot) 448112001Sphk{ 449112001Sphk struct statspage *spp; 450112001Sphk 451112001Sphk if (nprot != VM_PROT_READ) 452112001Sphk return (-1); 453112001Sphk TAILQ_FOREACH(spp, &pagelist, list) { 454112001Sphk if (offset == 0) { 455112001Sphk *paddr = vtophys(spp->stat); 456112001Sphk return (0); 457112001Sphk } 458112001Sphk offset -= PAGE_SIZE; 459112001Sphk } 460112001Sphk return (-1); 461112001Sphk} 462112001Sphk 463112001Sphkstatic struct devstat * 464112001Sphkdevstat_alloc(void) 465112001Sphk{ 466112001Sphk struct devstat *dsp; 467112001Sphk struct statspage *spp; 468112001Sphk u_int u; 469112001Sphk static int once; 470112001Sphk 471112368Sphk mtx_assert(&devstat_mutex, MA_NOTOWNED); 472112001Sphk if (!once) { 473112001Sphk make_dev(&devstat_cdevsw, 0, 474112326Sphk UID_ROOT, GID_WHEEL, 0400, DEVSTAT_DEVICE_NAME); 475112368Sphk once = 1; 476112001Sphk } 477112368Sphk mtx_lock(&devstat_mutex); 478112368Sphk for (;;) { 479112368Sphk TAILQ_FOREACH(spp, &pagelist, list) { 480112368Sphk if (spp->nfree > 0) 481112368Sphk break; 482112368Sphk } 483112368Sphk if (spp != NULL) 484112001Sphk break; 485112368Sphk /* 486112368Sphk * We had no free slot in any of our pages, drop the mutex 487112368Sphk * and get another page. In theory we could have more than 488112368Sphk * one process doing this at the same time and consequently 489112368Sphk * we may allocate more pages than we will need. That is 490112368Sphk * Just Too Bad[tm], we can live with that. 491112368Sphk */ 492112368Sphk mtx_unlock(&devstat_mutex); 493112001Sphk spp = malloc(sizeof *spp, M_DEVSTAT, M_ZERO | M_WAITOK); 494112001Sphk spp->stat = malloc(PAGE_SIZE, M_DEVSTAT, M_ZERO | M_WAITOK); 495112001Sphk spp->nfree = statsperpage; 496112368Sphk mtx_lock(&devstat_mutex); 497112368Sphk /* 498112368Sphk * It would make more sense to add the new page at the head 499112368Sphk * but the order on the list determine the sequence of the 500112368Sphk * mapping so we can't do that. 501112368Sphk */ 502112368Sphk TAILQ_INSERT_TAIL(&pagelist, spp, list); 503112001Sphk } 504112001Sphk dsp = spp->stat; 505112001Sphk for (u = 0; u < statsperpage; u++) { 506112001Sphk if (dsp->allocated == 0) 507112001Sphk break; 508112001Sphk dsp++; 509112001Sphk } 510112001Sphk spp->nfree--; 511112001Sphk dsp->allocated = 1; 512112368Sphk mtx_unlock(&devstat_mutex); 513112001Sphk return (dsp); 514112001Sphk} 515112001Sphk 516112001Sphkstatic void 517112001Sphkdevstat_free(struct devstat *dsp) 518112001Sphk{ 519112001Sphk struct statspage *spp; 520112001Sphk 521112368Sphk mtx_assert(&devstat_mutex, MA_OWNED); 522112001Sphk bzero(dsp, sizeof *dsp); 523112001Sphk TAILQ_FOREACH(spp, &pagelist, list) { 524112001Sphk if (dsp >= spp->stat && dsp < (spp->stat + statsperpage)) { 525112001Sphk spp->nfree++; 526112001Sphk return; 527112001Sphk } 528112001Sphk } 529112001Sphk} 530112288Sphk 531112288SphkSYSCTL_INT(_debug_sizeof, OID_AUTO, devstat, CTLFLAG_RD, 532112288Sphk 0, sizeof(struct devstat), "sizeof(struct devstat)"); 533