Index: sys/kern/subr_devstat.c =================================================================== --- sys/kern/subr_devstat.c (revision 197266) +++ sys/kern/subr_devstat.c (working copy) @@ -469,7 +469,7 @@ devstat_alloc(void) { struct devstat *dsp; - struct statspage *spp; + struct statspage *spp, *spp2; u_int u; static int once; @@ -479,6 +479,7 @@ UID_ROOT, GID_WHEEL, 0400, DEVSTAT_DEVICE_NAME); once = 1; } + spp2 = NULL; mtx_lock(&devstat_mutex); for (;;) { TAILQ_FOREACH(spp, &pagelist, list) { @@ -487,24 +488,30 @@ } if (spp != NULL) break; + mtx_unlock(&devstat_mutex); + spp2 = malloc(sizeof *spp, M_DEVSTAT, M_ZERO | M_WAITOK); + spp2->stat = malloc(PAGE_SIZE, M_DEVSTAT, M_ZERO | M_WAITOK); + spp2->nfree = statsperpage; + /* - * We had no free slot in any of our pages, drop the mutex - * and get another page. In theory we could have more than - * one process doing this at the same time and consequently - * we may allocate more pages than we will need. That is - * Just Too Bad[tm], we can live with that. + * If free statspages were added while the lock was released + * just reuse them. */ - mtx_unlock(&devstat_mutex); - spp = malloc(sizeof *spp, M_DEVSTAT, M_ZERO | M_WAITOK); - spp->stat = malloc(PAGE_SIZE, M_DEVSTAT, M_ZERO | M_WAITOK); - spp->nfree = statsperpage; mtx_lock(&devstat_mutex); - /* - * It would make more sense to add the new page at the head - * but the order on the list determine the sequence of the - * mapping so we can't do that. - */ - TAILQ_INSERT_TAIL(&pagelist, spp, list); + TAILQ_FOREACH(spp, &pagelist, list) + if (spp->nfree > 0) + break; + if (spp == NULL) { + spp = spp2; + + /* + * It would make more sense to add the new page at the + * head but the order on the list determine the + * sequence of the mapping so we can't do that. + */ + TAILQ_INSERT_TAIL(&pagelist, spp, list); + } else + break; } dsp = spp->stat; for (u = 0; u < statsperpage; u++) { @@ -515,6 +522,10 @@ spp->nfree--; dsp->allocated = 1; mtx_unlock(&devstat_mutex); + if (spp2 != NULL && spp2 != spp) { + free(spp2->stat, M_DEVSTAT); + free(spp2, M_DEVSTAT); + } return (dsp); }