Date: Tue, 28 Jul 2015 20:24:10 +0000 (UTC) From: Jeff Roberson <jeff@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r285981 - head/sys/kern Message-ID: <201507282024.t6SKOAgg015176@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jeff Date: Tue Jul 28 20:24:09 2015 New Revision: 285981 URL: https://svnweb.freebsd.org/changeset/base/285981 Log: - 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 Modified: head/sys/kern/vfs_bio.c Modified: head/sys/kern/vfs_bio.c ============================================================================== --- head/sys/kern/vfs_bio.c Tue Jul 28 19:59:22 2015 (r285980) +++ head/sys/kern/vfs_bio.c Tue Jul 28 20:24:09 2015 (r285981) @@ -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 q 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, 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) { - nqindex = QUEUE_EMPTY; - nbp = TAILQ_FIRST(&bufqueues[QUEUE_EMPTY]); - } - 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 we're not defragging or low on bufspace attempt to make a new + * buf from a header. */ - 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)) { + 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, retry ignoring the - * lobufspace as the last resort. + * All available buffers might be clean or we need to start recycling. */ - if (nbp == NULL && !TAILQ_EMPTY(&bufqueues[QUEUE_CLEAN])) { + if (nbp == NULL) { nqindex = QUEUE_CLEAN; nbp = TAILQ_FIRST(&bufqueues[QUEUE_CLEAN]); } @@ -2332,28 +2288,21 @@ restart: /* * 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 @@ restart: 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 @@ restart: */ if (defrag) { bp->b_flags |= B_INVAL; - bufkvafree(bp); brelse(bp); defrag = 0; goto restart; @@ -2424,7 +2372,6 @@ restart: */ if (qindex == QUEUE_CLEAN && BUF_LOCKWAITERS(bp)) { bp->b_flags |= B_INVAL; - bufkvafree(bp); brelse(bp); goto restart; } @@ -2437,16 +2384,11 @@ restart: * 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, * 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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201507282024.t6SKOAgg015176>