1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-24 11:29:10 +00:00

- Eliminate the EMPTYKVA queue. It served as a cache of KVA allocations

attached to bufs to avoid the overhead of the vm.  This purposes is now
   better served by vmem.  Freeing the kva immediately when a buf is
   destroyed leads to lower fragmentation and a much simpler scan algorithm.

Reviewed by:	kib
Sponsored by:	EMC / Isilon Storage Division
This commit is contained in:
Jeff Roberson 2015-07-28 20:24:09 +00:00
parent 3a0b9b7735
commit 38750ada8f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=285981

View File

@ -309,13 +309,12 @@ static int bdirtywait;
/*
* Definitions for the buffer free lists.
*/
#define BUFFER_QUEUES 5 /* number of free buffer queues */
#define BUFFER_QUEUES 4 /* number of free buffer queues */
#define QUEUE_NONE 0 /* on no queue */
#define QUEUE_CLEAN 1 /* non-B_DELWRI buffers */
#define QUEUE_DIRTY 2 /* B_DELWRI buffers */
#define QUEUE_EMPTYKVA 3 /* empty buffer headers w/KVA assignment */
#define QUEUE_EMPTY 4 /* empty buffer headers */
#define QUEUE_EMPTY 3 /* empty buffer headers */
#define QUEUE_SENTINEL 1024 /* not an queue index, but mark for sentinel */
/* Queues for free buffers with various properties */
@ -1862,10 +1861,8 @@ brelse(struct buf *bp)
bp->b_xflags &= ~(BX_BKGRDWRITE | BX_ALTDATA);
if (bp->b_vflags & BV_BKGRDINPROG)
panic("losing buffer 1");
if (bp->b_kvasize)
qindex = QUEUE_EMPTYKVA;
else
qindex = QUEUE_EMPTY;
bufkvafree(bp);
qindex = QUEUE_EMPTY;
bp->b_flags |= B_AGE;
/* buffers with junk contents */
} else if (bp->b_flags & (B_INVAL | B_NOCACHE | B_RELBUF) ||
@ -2251,8 +2248,6 @@ getnewbuf_reuse_bp(struct buf *bp, int qindex)
LIST_INIT(&bp->b_dep);
}
static int flushingbufs;
static struct buf *
getnewbuf_scan(int maxsize, int defrag, int unmapped, int metadata)
{
@ -2261,64 +2256,25 @@ getnewbuf_scan(int maxsize, int defrag, int unmapped, int metadata)
KASSERT(!unmapped || !defrag, ("both unmapped and defrag"));
pass = 1;
pass = 0;
restart:
atomic_add_int(&getnewbufrestarts, 1);
if (pass != 0)
atomic_add_int(&getnewbufrestarts, 1);
/*
* Setup for scan. If we do not have enough free buffers,
* we setup a degenerate case that immediately fails. Note
* that if we are specially marked process, we are allowed to
* dip into our reserves.
*
* The scanning sequence is nominally: EMPTY->EMPTYKVA->CLEAN
* for the allocation of the mapped buffer. For unmapped, the
* easiest is to start with EMPTY outright.
*
* We start with EMPTYKVA. If the list is empty we backup to EMPTY.
* However, there are a number of cases (defragging, reusing, ...)
* where we cannot backup.
*/
nbp = NULL;
mtx_lock(&bqclean);
if (!defrag && unmapped) {
/*
* If we're not defragging or low on bufspace attempt to make a new
* buf from a header.
*/
if (defrag == 0 && bufspace + maxsize < hibufspace) {
nqindex = QUEUE_EMPTY;
nbp = TAILQ_FIRST(&bufqueues[QUEUE_EMPTY]);
nbp = TAILQ_FIRST(&bufqueues[nqindex]);
}
/*
* All available buffers might be clean or we need to start recycling.
*/
if (nbp == NULL) {
nqindex = QUEUE_EMPTYKVA;
nbp = TAILQ_FIRST(&bufqueues[QUEUE_EMPTYKVA]);
}
/*
* If no EMPTYKVA buffers and we are either defragging or
* reusing, locate a CLEAN buffer to free or reuse. If
* bufspace useage is low skip this step so we can allocate a
* new buffer.
*/
if (nbp == NULL && (defrag || bufspace >= lobufspace)) {
nqindex = QUEUE_CLEAN;
nbp = TAILQ_FIRST(&bufqueues[QUEUE_CLEAN]);
}
/*
* If we could not find or were not allowed to reuse a CLEAN
* buffer, check to see if it is ok to use an EMPTY buffer.
* We can only use an EMPTY buffer if allocating its KVA would
* not otherwise run us out of buffer space. No KVA is needed
* for the unmapped allocation.
*/
if (nbp == NULL && defrag == 0 && (bufspace + maxsize < hibufspace ||
metadata)) {
nqindex = QUEUE_EMPTY;
nbp = TAILQ_FIRST(&bufqueues[QUEUE_EMPTY]);
}
/*
* All available buffers might be clean, retry ignoring the
* lobufspace as the last resort.
*/
if (nbp == NULL && !TAILQ_EMPTY(&bufqueues[QUEUE_CLEAN])) {
nqindex = QUEUE_CLEAN;
nbp = TAILQ_FIRST(&bufqueues[QUEUE_CLEAN]);
}
@ -2332,28 +2288,21 @@ getnewbuf_scan(int maxsize, int defrag, int unmapped, int metadata)
/*
* Calculate next bp (we can only use it if we do not
* block or do other fancy things).
* release the bqlock)
*/
if ((nbp = TAILQ_NEXT(bp, b_freelist)) == NULL) {
switch (qindex) {
case QUEUE_EMPTY:
nqindex = QUEUE_EMPTYKVA;
nbp = TAILQ_FIRST(&bufqueues[QUEUE_EMPTYKVA]);
if (nbp != NULL)
break;
/* FALLTHROUGH */
case QUEUE_EMPTYKVA:
nqindex = QUEUE_CLEAN;
nbp = TAILQ_FIRST(&bufqueues[QUEUE_CLEAN]);
nbp = TAILQ_FIRST(&bufqueues[nqindex]);
if (nbp != NULL)
break;
/* FALLTHROUGH */
case QUEUE_CLEAN:
if (metadata && pass == 1) {
pass = 2;
if (metadata && pass == 0) {
pass = 1;
nqindex = QUEUE_EMPTY;
nbp = TAILQ_FIRST(
&bufqueues[QUEUE_EMPTY]);
nbp = TAILQ_FIRST(&bufqueues[nqindex]);
}
/*
* nbp is NULL.
@ -2399,11 +2348,11 @@ getnewbuf_scan(int maxsize, int defrag, int unmapped, int metadata)
bremfreel(bp);
mtx_unlock(&bqclean);
/*
* NOTE: nbp is now entirely invalid. We can only restart
* the scan from this point on.
*/
getnewbuf_reuse_bp(bp, qindex);
mtx_assert(&bqclean, MA_NOTOWNED);
@ -2412,7 +2361,6 @@ getnewbuf_scan(int maxsize, int defrag, int unmapped, int metadata)
*/
if (defrag) {
bp->b_flags |= B_INVAL;
bufkvafree(bp);
brelse(bp);
defrag = 0;
goto restart;
@ -2424,7 +2372,6 @@ getnewbuf_scan(int maxsize, int defrag, int unmapped, int metadata)
*/
if (qindex == QUEUE_CLEAN && BUF_LOCKWAITERS(bp)) {
bp->b_flags |= B_INVAL;
bufkvafree(bp);
brelse(bp);
goto restart;
}
@ -2437,16 +2384,11 @@ getnewbuf_scan(int maxsize, int defrag, int unmapped, int metadata)
* KVM space. This occurs in rare situations when multiple
* processes are blocked in getnewbuf() or allocbuf().
*/
if (bufspace >= hibufspace)
flushingbufs = 1;
if (flushingbufs && bp->b_kvasize != 0) {
if (bufspace >= hibufspace && bp->b_kvasize != 0) {
bp->b_flags |= B_INVAL;
bufkvafree(bp);
brelse(bp);
goto restart;
}
if (bufspace < lobufspace)
flushingbufs = 0;
break;
}
return (bp);
@ -2492,7 +2434,6 @@ getnewbuf(struct vnode *vp, int slpflag, int slptimeo, int size, int maxsize,
* async I/O rather then sync I/O.
*/
atomic_add_int(&getnewbufcalls, 1);
atomic_subtract_int(&getnewbufrestarts, 1);
restart:
bp = getnewbuf_scan(maxsize, defrag, (gbflags & (GB_UNMAPPED |
GB_KVAALLOC)) == GB_UNMAPPED, metadata);