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:
parent
4b6da14cfa
commit
06220fa737
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=329612
File diff suppressed because it is too large
Load Diff
@ -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.
|
||||
*/
|
||||
|
@ -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"
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user