Index: kern/subr_param.c =================================================================== --- kern/subr_param.c (revision 255201) +++ kern/subr_param.c (working copy) @@ -95,6 +95,7 @@ int nbuf; int bio_transient_maxcnt; int ngroups_max; /* max # groups per process */ int nswbuf; +int nswbufq; pid_t pid_max = PID_MAX; long maxswzone; /* max swmeta KVA storage */ long maxbcache; /* max buffer cache KVA storage */ Index: kern/vfs_bio.c =================================================================== --- kern/vfs_bio.c (revision 255201) +++ kern/vfs_bio.c (working copy) @@ -734,7 +734,9 @@ kern_vfs_bio_buffer_alloc(caddr_t v, long physmem_ * swbufs are used as temporary holders for I/O, such as paging I/O. * We have no less then 16 and no more then 256. */ - nswbuf = max(min(nbuf/4, 256), 16); + nswbuf = max(nbuf/4, 16); + nswbufq = max(min(nswbuf / 512, MAXCPU / 8), 1); + nswbuf = min(nswbuf / nswbufq, 512); #ifdef NSWBUF_MIN if (nswbuf < NSWBUF_MIN) nswbuf = NSWBUF_MIN; @@ -747,7 +749,7 @@ kern_vfs_bio_buffer_alloc(caddr_t v, long physmem_ * Reserve space for the buffer cache buffers */ swbuf = (void *)v; - v = (caddr_t)(swbuf + nswbuf); + v = (caddr_t)(swbuf + nswbuf * nswbufq); buf = (void *)v; v = (caddr_t)(buf + nbuf); Index: sys/buf.h =================================================================== --- sys/buf.h (revision 255201) +++ sys/buf.h (working copy) @@ -138,6 +138,7 @@ struct buf { void *b_fsprivate2; void *b_fsprivate3; int b_pin_count; + int b_queue; }; #define b_object b_bufobj->bo_object @@ -468,6 +469,7 @@ extern int altbufferflushes; extern struct buf *buf; /* The buffer headers. */ extern struct buf *swbuf; /* Swap I/O buffer headers. */ extern int nswbuf; /* Number of swap I/O buffer headers. */ +extern int nswbufq; /* Number of swap I/O buffer queues. */ extern int cluster_pbuf_freecnt; /* Number of pbufs for clusters */ extern int vnode_pbuf_freecnt; /* Number of pbufs for vnode pager */ extern caddr_t unmapped_buf; Index: vm/vm_init.c =================================================================== --- vm/vm_init.c (revision 255201) +++ vm/vm_init.c (working copy) @@ -223,7 +223,7 @@ again: * Allocate the clean map to hold all of the paging and I/O virtual * memory. */ - size = (long)nbuf * BKVASIZE + (long)nswbuf * MAXPHYS + + size = (long)nbuf * BKVASIZE + (long)nswbuf * MAXPHYS * nswbufq + (long)bio_transient_maxcnt * MAXPHYS; kmi->clean_sva = firstaddr = kva_alloc(size); kmi->clean_eva = firstaddr + size; @@ -242,7 +242,7 @@ again: * Now swap kva. */ swapbkva = firstaddr; - size = (long)nswbuf * MAXPHYS; + size = (long)nswbuf * MAXPHYS * nswbufq; firstaddr += size; /* Index: vm/vm_pager.c =================================================================== --- vm/vm_pager.c (revision 255201) +++ vm/vm_pager.c (working copy) @@ -176,8 +176,11 @@ static const int npagers = sizeof(pagertab) / size * (MAXPHYS == 64k) if you want to get the most efficiency. */ struct mtx_padalign pbuf_mtx; -static TAILQ_HEAD(swqueue, buf) bswlist; -static int bswneeded; +static struct { + struct mtx_padalign pbuf_mtx; + TAILQ_HEAD(, buf) bswlist; + int bswneeded; +} pcpubsw[MAX(MAXCPU / 8, 1)]; vm_offset_t swapbkva; /* swap buffers kva */ void @@ -185,7 +188,6 @@ vm_pager_init() { struct pagerops **pgops; - TAILQ_INIT(&bswlist); /* * Initialize known pagers */ @@ -198,7 +200,7 @@ void vm_pager_bufferinit() { struct buf *bp; - int i; + int q, i; mtx_init(&pbuf_mtx, "pbuf mutex", NULL, MTX_DEF); bp = swbuf; @@ -205,12 +207,16 @@ vm_pager_bufferinit() /* * Now set up swap and physical I/O buffer headers. */ - for (i = 0; i < nswbuf; i++, bp++) { - TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist); - BUF_LOCKINIT(bp); - LIST_INIT(&bp->b_dep); - bp->b_rcred = bp->b_wcred = NOCRED; - bp->b_xflags = 0; + for (q = 0; q < nswbufq; q++) { + mtx_init(&pcpubsw[q].pbuf_mtx, "pbuf mutex", NULL, MTX_DEF); + for (i = 0; i < nswbuf; i++, bp++) { + TAILQ_INSERT_HEAD(&pcpubsw[q].bswlist, bp, b_freelist); + BUF_LOCKINIT(bp); + LIST_INIT(&bp->b_dep); + bp->b_rcred = bp->b_wcred = NOCRED; + bp->b_xflags = 0; + bp->b_queue = q; + } } cluster_pbuf_freecnt = nswbuf / 2; @@ -327,28 +333,35 @@ struct buf * getpbuf(int *pfreecnt) { struct buf *bp; + int q; - mtx_lock(&pbuf_mtx); + if (pfreecnt) + q = ((uintptr_t)pfreecnt >> 2) % nswbufq; + else + q = curcpu % nswbufq; + mtx_lock(&pcpubsw[q].pbuf_mtx); for (;;) { if (pfreecnt) { while (*pfreecnt == 0) { - msleep(pfreecnt, &pbuf_mtx, PVM, "wswbuf0", 0); + msleep(pfreecnt, &pcpubsw[q].pbuf_mtx, + PVM, "wswbuf0", 0); } } /* get a bp from the swap buffer header pool */ - if ((bp = TAILQ_FIRST(&bswlist)) != NULL) + if ((bp = TAILQ_FIRST(&pcpubsw[q].bswlist)) != NULL) break; - bswneeded = 1; - msleep(&bswneeded, &pbuf_mtx, PVM, "wswbuf1", 0); + pcpubsw[q].bswneeded = 1; + msleep(&pcpubsw[q].bswneeded, &pcpubsw[q].pbuf_mtx, + PVM, "wswbuf1", 0); /* loop in case someone else grabbed one */ } - TAILQ_REMOVE(&bswlist, bp, b_freelist); + TAILQ_REMOVE(&pcpubsw[q].bswlist, bp, b_freelist); if (pfreecnt) --*pfreecnt; - mtx_unlock(&pbuf_mtx); + mtx_unlock(&pcpubsw[q].pbuf_mtx); initpbuf(bp); return bp; @@ -364,17 +377,22 @@ struct buf * trypbuf(int *pfreecnt) { struct buf *bp; + int q; - mtx_lock(&pbuf_mtx); - if (*pfreecnt == 0 || (bp = TAILQ_FIRST(&bswlist)) == NULL) { - mtx_unlock(&pbuf_mtx); + if (pfreecnt) + q = ((uintptr_t)pfreecnt >> 2) % nswbufq; + else + q = curcpu % nswbufq; + mtx_lock(&pcpubsw[q].pbuf_mtx); + if (*pfreecnt == 0 || (bp = TAILQ_FIRST(&pcpubsw[q].bswlist)) == NULL) { + mtx_unlock(&pcpubsw[q].pbuf_mtx); return NULL; } - TAILQ_REMOVE(&bswlist, bp, b_freelist); + TAILQ_REMOVE(&pcpubsw[q].bswlist, bp, b_freelist); --*pfreecnt; - mtx_unlock(&pbuf_mtx); + mtx_unlock(&pcpubsw[q].pbuf_mtx); initpbuf(bp); @@ -390,6 +408,7 @@ trypbuf(int *pfreecnt) void relpbuf(struct buf *bp, int *pfreecnt) { + int q; if (bp->b_rcred != NOCRED) { crfree(bp->b_rcred); @@ -405,18 +424,19 @@ relpbuf(struct buf *bp, int *pfreecnt) BUF_UNLOCK(bp); - mtx_lock(&pbuf_mtx); - TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist); + q = bp->b_queue; + mtx_lock(&pcpubsw[q].pbuf_mtx); + TAILQ_INSERT_HEAD(&pcpubsw[q].bswlist, bp, b_freelist); - if (bswneeded) { - bswneeded = 0; - wakeup(&bswneeded); + if (pcpubsw[q].bswneeded) { + pcpubsw[q].bswneeded = 0; + wakeup(&pcpubsw[q].bswneeded); } if (pfreecnt) { if (++*pfreecnt == 1) wakeup(pfreecnt); } - mtx_unlock(&pbuf_mtx); + mtx_unlock(&pcpubsw[q].pbuf_mtx); } /*