From: Dave Chinner <dchinner@xxxxxxxxxx> THis tracks all the buffers in a given btcache, hence allowing us to purge all the buffers from a cache without having to walk the global buffer cache LRU list. This will useful for per-AG scan operations, allowing us to purge the cache when we've completed processing on specific AGs and don't need the cache anymore. Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> --- libxfs/buftarg.c | 63 +++++++++++++++++++++++++++++++++++++++++++- libxfs/libxfs_io.h | 8 ++++++ libxfs/rdwr.c | 4 +-- libxfs/xfs_buftarg.h | 2 ++ 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/libxfs/buftarg.c b/libxfs/buftarg.c index 4f4254e4fd70..dbecab833cb2 100644 --- a/libxfs/buftarg.c +++ b/libxfs/buftarg.c @@ -428,8 +428,16 @@ xfs_buf_associate_memory( /* * Buffer cache hash implementation +* + * Lock orders: + * + * hash->lock cache hash chain lock + * btc->lock cache lock + * + * btc->lock cache lock + * bp->b_lock buffer state lock + * */ - struct btcache * btc_init( unsigned int hashsize) @@ -456,6 +464,7 @@ btc_init( btc->hashsize = hashsize; btc->hashshift = libxfs_highbit32(hashsize); pthread_mutex_init(&btc->lock, NULL); + list_head_init(&btc->lru); for (i = 0; i < hashsize; i++) { list_head_init(&btc->hash[i].chain); @@ -475,6 +484,7 @@ btc_destroy( if (!btc) return; + list_head_destroy(&btc->lru); for (i = 0; i < btc->hashsize; i++) { list_head_destroy(&btc->hash[i].chain); pthread_mutex_destroy(&btc->hash[i].lock); @@ -635,6 +645,10 @@ btc_node_insert( head = &hash->chain; pthread_mutex_lock(&hash->lock); + pthread_mutex_lock(&btc->lock); + list_add(&bp->b_btc_list, &btc->lru); + pthread_mutex_unlock(&btc->lock); + list_add(&bp->b_hash, head); hash->count++; atomic_inc(&btc->count); @@ -653,8 +667,55 @@ btc_node_remove( hash = btc->hash + hashidx; pthread_mutex_lock(&hash->lock); + pthread_mutex_lock(&btc->lock); + list_del(&bp->b_btc_list); + pthread_mutex_unlock(&btc->lock); + list_del(&bp->b_hash); hash->count--; atomic_dec(&btc->count); pthread_mutex_unlock(&hash->lock); } + +/* + * Purge the buffers from the cache list. + * + * This is nasty - it steals the buffer cache LRU reference and drops it, + * using the dispose flag to indicate it's about to go away. + */ +static void +btc_purge_buffers( + struct btcache *btc) +{ + struct xfs_buf *bp, *n; + LIST_HEAD (dispose); + + pthread_mutex_lock(&btc->lock); + list_for_each_entry_safe(bp, n, &btc->lru, b_btc_list) { + if (bp->b_state & XFS_BSTATE_DISPOSE) + continue; + spin_lock(&bp->b_lock); + atomic_set(&bp->b_lru_ref, 0); + bp->b_state |= XFS_BSTATE_DISPOSE; + list_move(&bp->b_btc_list, &dispose); + spin_unlock(&bp->b_lock); + } + pthread_mutex_unlock(&btc->lock); + + while (!list_empty(&dispose)) { + bp = list_first_entry(&dispose, struct xfs_buf, b_btc_list); + list_del_init(&bp->b_btc_list); + libxfs_brelse(&bp->b_node); + } +} + +void +xfs_buftarg_purge_ag( + struct xfs_buftarg *btp, + xfs_agnumber_t agno) +{ + struct xfs_perag *pag = xfs_perag_get(btp->bt_mount, agno); + + btc_purge_buffers(pag->pag_buf_hash); + xfs_perag_put(pag); +} diff --git a/libxfs/libxfs_io.h b/libxfs/libxfs_io.h index 31c21abce8c9..2e7c943d8978 100644 --- a/libxfs/libxfs_io.h +++ b/libxfs/libxfs_io.h @@ -42,6 +42,8 @@ struct xfs_buf_ops { xfs_failaddr_t (*verify_struct)(struct xfs_buf *); }; +#define XFS_BSTATE_DISPOSE (1 << 0) /* buffer being discarded */ + struct xfs_buf { struct cache_node b_node; struct list_head b_hash; /* will replace b_node */ @@ -66,6 +68,10 @@ struct xfs_buf { int b_io_remaining; int b_io_error; struct list_head b_list; + + struct list_head b_btc_list; + unsigned int b_state; + atomic_t b_lru_ref; }; bool xfs_verify_magic(struct xfs_buf *bp, __be32 dmagic); @@ -98,6 +104,8 @@ int libxfs_buf_priority(struct xfs_buf *bp); extern struct cache *libxfs_bcache; extern struct cache_operations libxfs_bcache_operations; +void libxfs_brelse(struct cache_node *node); + #define LIBXFS_GETBUF_TRYLOCK (1 << 0) diff --git a/libxfs/rdwr.c b/libxfs/rdwr.c index 371a6d221bb2..fcc4ff9b394e 100644 --- a/libxfs/rdwr.c +++ b/libxfs/rdwr.c @@ -21,8 +21,6 @@ #include "libxfs.h" -static void libxfs_brelse(struct cache_node *node); - /* * Important design/architecture note: * @@ -740,7 +738,7 @@ libxfs_whine_dirty_buf( bp->b_target->flags |= XFS_BUFTARG_LOST_WRITE; } -static void +void libxfs_brelse( struct cache_node *node) { diff --git a/libxfs/xfs_buftarg.h b/libxfs/xfs_buftarg.h index fee20c60db1c..129b43e037ad 100644 --- a/libxfs/xfs_buftarg.h +++ b/libxfs/xfs_buftarg.h @@ -55,6 +55,7 @@ struct xfs_buftarg *xfs_buftarg_alloc(struct xfs_mount *mp, dev_t bdev); void xfs_buftarg_free(struct xfs_buftarg *target); void xfs_buftarg_wait(struct xfs_buftarg *target); int xfs_buftarg_setsize(struct xfs_buftarg *target, unsigned int size); +void xfs_buftarg_purge_ag(struct xfs_buftarg *btp, xfs_agnumber_t agno); #define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev) @@ -136,6 +137,7 @@ struct btcache { unsigned long long misses; /* cache misses */ unsigned long long hits; /* cache hits */ unsigned int max; /* max nodes ever used */ + struct list_head lru; /* list of all items in cache */ }; struct btcache *btc_init(unsigned int hashsize); -- 2.28.0