Further parallelize the buffer cache.

Provide multiple clean queues partitioned into 'domains'.  Each domain manages
its own bufspace and has its own bufspace daemon.  Each domain has a set of
subqueues indexed by the current cpuid to reduce lock contention on the cleanq.

Refine the sleep/wakeup around the bufspace daemon to use atomics as much as
possible.

Add a B_REUSE flag that is used to requeue bufs during the scan to approximate
LRU rather than locking the queue on every use of a frequently accessed buf.

Implement bufspace_reserve with only atomic_fetchadd to avoid loop restarts.

Reviewed by:	markj
Tested by:	pho
Sponsored by:	Netflix, Dell/EMC Isilon
Differential Revision:	https://reviews.freebsd.org/D14274
This commit is contained in:
Jeff Roberson 2018-02-20 00:06:07 +00:00
parent 4b6da14cfa
commit 06220fa737
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=329612
4 changed files with 606 additions and 390 deletions

File diff suppressed because it is too large Load Diff

View File

@ -362,7 +362,6 @@ static int
vnode_init(void *mem, int size, int flags)
{
struct vnode *vp;
struct bufobj *bo;
vp = mem;
bzero(vp, size);
@ -379,11 +378,7 @@ vnode_init(void *mem, int size, int flags)
/*
* Initialize bufobj.
*/
bo = &vp->v_bufobj;
rw_init(BO_LOCKPTR(bo), "bufobj interlock");
bo->bo_private = vp;
TAILQ_INIT(&bo->bo_clean.bv_hd);
TAILQ_INIT(&bo->bo_dirty.bv_hd);
bufobj_init(&vp->v_bufobj, vp);
/*
* Initialize namecache.
*/

View File

@ -112,7 +112,9 @@ struct buf {
off_t b_offset; /* Offset into file. */
TAILQ_ENTRY(buf) b_bobufs; /* (V) Buffer's associated vnode. */
uint32_t b_vflags; /* (V) BV_* flags */
unsigned short b_qindex; /* (Q) buffer queue index */
uint8_t b_qindex; /* (Q) buffer queue index */
uint8_t b_domain; /* (Q) buf domain this resides in */
uint16_t b_subqueue; /* (Q) per-cpu q if any */
uint32_t b_flags; /* B_* flags. */
b_xflags_t b_xflags; /* extra flags */
struct lock b_lock; /* Buffer lock */
@ -217,7 +219,7 @@ struct buf {
#define B_DONE 0x00000200 /* I/O completed. */
#define B_EINTR 0x00000400 /* I/O was interrupted */
#define B_NOREUSE 0x00000800 /* Contents not reused once released. */
#define B_00001000 0x00001000 /* Available flag. */
#define B_REUSE 0x00001000 /* Contents reused, second chance. */
#define B_INVAL 0x00002000 /* Does not contain valid info. */
#define B_BARRIER 0x00004000 /* Write this and all preceding first. */
#define B_NOCACHE 0x00008000 /* Do not cache block after use. */
@ -241,7 +243,7 @@ struct buf {
#define PRINT_BUF_FLAGS "\20\40remfree\37cluster\36vmio\35ram\34managed" \
"\33paging\32infreecnt\31nocopy\30b23\27relbuf\26b21\25b20" \
"\24b19\23b18\22clusterok\21malloc\20nocache\17b14\16inval" \
"\15b12\14noreuse\13eintr\12done\11b8\10delwri" \
"\15reuse\14noreuse\13eintr\12done\11b8\10delwri" \
"\7validsuspwrt\6cache\5deferred\4direct\3async\2needcommit\1age"
/*

View File

@ -106,6 +106,7 @@ struct bufobj {
struct bufv bo_dirty; /* i Dirty buffers */
long bo_numoutput; /* i Writes in progress */
u_int bo_flag; /* i Flags */
int bo_domain; /* - Clean queue affinity */
int bo_bsize; /* - Block size for i/o */
};
@ -126,6 +127,7 @@ struct bufobj {
#define ASSERT_BO_LOCKED(bo) rw_assert(BO_LOCKPTR((bo)), RA_LOCKED)
#define ASSERT_BO_UNLOCKED(bo) rw_assert(BO_LOCKPTR((bo)), RA_UNLOCKED)
void bufobj_init(struct bufobj *bo, void *private);
void bufobj_wdrop(struct bufobj *bo);
void bufobj_wref(struct bufobj *bo);
void bufobj_wrefl(struct bufobj *bo);