Skip to content

Commit e7b58f7

Browse files
author
Darrick J. Wong
committed
xfs: teach buftargs to maintain their own buffer hashtable
Currently, cached buffers are indexed by per-AG hashtables. This works great for the data device, but won't work for in-memory btrees. To handle that use case, buftargs will need to be able to index buffers independently of other data structures. We accomplish this by hoisting the rhashtable and its lock into a separate xfs_buf_cache structure, make the buftarg point to the _buf_cache structure, and rework various functions to use it. This will enable the in-memory buftarg to come up with its own _buf_cache. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent 1c51ac0 commit e7b58f7

5 files changed

Lines changed: 67 additions & 38 deletions

File tree

fs/xfs/libxfs/xfs_ag.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ xfs_free_perag(
264264
xfs_defer_drain_free(&pag->pag_intents_drain);
265265

266266
cancel_delayed_work_sync(&pag->pag_blockgc_work);
267-
xfs_buf_hash_destroy(pag);
267+
xfs_buf_cache_destroy(&pag->pag_bcache);
268268

269269
/* drop the mount's active reference */
270270
xfs_perag_rele(pag);
@@ -352,7 +352,7 @@ xfs_free_unused_perag_range(
352352
spin_unlock(&mp->m_perag_lock);
353353
if (!pag)
354354
break;
355-
xfs_buf_hash_destroy(pag);
355+
xfs_buf_cache_destroy(&pag->pag_bcache);
356356
xfs_defer_drain_free(&pag->pag_intents_drain);
357357
kfree(pag);
358358
}
@@ -419,7 +419,7 @@ xfs_initialize_perag(
419419
pag->pagb_tree = RB_ROOT;
420420
#endif /* __KERNEL__ */
421421

422-
error = xfs_buf_hash_init(pag);
422+
error = xfs_buf_cache_init(&pag->pag_bcache);
423423
if (error)
424424
goto out_remove_pag;
425425

fs/xfs/libxfs/xfs_ag.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,7 @@ struct xfs_perag {
106106
int pag_ici_reclaimable; /* reclaimable inodes */
107107
unsigned long pag_ici_reclaim_cursor; /* reclaim restart point */
108108

109-
/* buffer cache index */
110-
spinlock_t pag_buf_lock; /* lock for pag_buf_hash */
111-
struct rhashtable pag_buf_hash;
109+
struct xfs_buf_cache pag_bcache;
112110

113111
/* background prealloc block trimming */
114112
struct delayed_work pag_blockgc_work;

fs/xfs/xfs_buf.c

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -510,18 +510,18 @@ static const struct rhashtable_params xfs_buf_hash_params = {
510510
};
511511

512512
int
513-
xfs_buf_hash_init(
514-
struct xfs_perag *pag)
513+
xfs_buf_cache_init(
514+
struct xfs_buf_cache *bch)
515515
{
516-
spin_lock_init(&pag->pag_buf_lock);
517-
return rhashtable_init(&pag->pag_buf_hash, &xfs_buf_hash_params);
516+
spin_lock_init(&bch->bc_lock);
517+
return rhashtable_init(&bch->bc_hash, &xfs_buf_hash_params);
518518
}
519519

520520
void
521-
xfs_buf_hash_destroy(
522-
struct xfs_perag *pag)
521+
xfs_buf_cache_destroy(
522+
struct xfs_buf_cache *bch)
523523
{
524-
rhashtable_destroy(&pag->pag_buf_hash);
524+
rhashtable_destroy(&bch->bc_hash);
525525
}
526526

527527
static int
@@ -584,7 +584,7 @@ xfs_buf_find_lock(
584584

585585
static inline int
586586
xfs_buf_lookup(
587-
struct xfs_perag *pag,
587+
struct xfs_buf_cache *bch,
588588
struct xfs_buf_map *map,
589589
xfs_buf_flags_t flags,
590590
struct xfs_buf **bpp)
@@ -593,7 +593,7 @@ xfs_buf_lookup(
593593
int error;
594594

595595
rcu_read_lock();
596-
bp = rhashtable_lookup(&pag->pag_buf_hash, map, xfs_buf_hash_params);
596+
bp = rhashtable_lookup(&bch->bc_hash, map, xfs_buf_hash_params);
597597
if (!bp || !atomic_inc_not_zero(&bp->b_hold)) {
598598
rcu_read_unlock();
599599
return -ENOENT;
@@ -618,6 +618,7 @@ xfs_buf_lookup(
618618
static int
619619
xfs_buf_find_insert(
620620
struct xfs_buftarg *btp,
621+
struct xfs_buf_cache *bch,
621622
struct xfs_perag *pag,
622623
struct xfs_buf_map *cmap,
623624
struct xfs_buf_map *map,
@@ -646,18 +647,18 @@ xfs_buf_find_insert(
646647
goto out_free_buf;
647648
}
648649

649-
spin_lock(&pag->pag_buf_lock);
650-
bp = rhashtable_lookup_get_insert_fast(&pag->pag_buf_hash,
650+
spin_lock(&bch->bc_lock);
651+
bp = rhashtable_lookup_get_insert_fast(&bch->bc_hash,
651652
&new_bp->b_rhash_head, xfs_buf_hash_params);
652653
if (IS_ERR(bp)) {
653654
error = PTR_ERR(bp);
654-
spin_unlock(&pag->pag_buf_lock);
655+
spin_unlock(&bch->bc_lock);
655656
goto out_free_buf;
656657
}
657658
if (bp) {
658659
/* found an existing buffer */
659660
atomic_inc(&bp->b_hold);
660-
spin_unlock(&pag->pag_buf_lock);
661+
spin_unlock(&bch->bc_lock);
661662
error = xfs_buf_find_lock(bp, flags);
662663
if (error)
663664
xfs_buf_rele(bp);
@@ -668,17 +669,36 @@ xfs_buf_find_insert(
668669

669670
/* The new buffer keeps the perag reference until it is freed. */
670671
new_bp->b_pag = pag;
671-
spin_unlock(&pag->pag_buf_lock);
672+
spin_unlock(&bch->bc_lock);
672673
*bpp = new_bp;
673674
return 0;
674675

675676
out_free_buf:
676677
xfs_buf_free(new_bp);
677678
out_drop_pag:
678-
xfs_perag_put(pag);
679+
if (pag)
680+
xfs_perag_put(pag);
679681
return error;
680682
}
681683

684+
static inline struct xfs_perag *
685+
xfs_buftarg_get_pag(
686+
struct xfs_buftarg *btp,
687+
const struct xfs_buf_map *map)
688+
{
689+
struct xfs_mount *mp = btp->bt_mount;
690+
691+
return xfs_perag_get(mp, xfs_daddr_to_agno(mp, map->bm_bn));
692+
}
693+
694+
static inline struct xfs_buf_cache *
695+
xfs_buftarg_buf_cache(
696+
struct xfs_buftarg *btp,
697+
struct xfs_perag *pag)
698+
{
699+
return &pag->pag_bcache;
700+
}
701+
682702
/*
683703
* Assembles a buffer covering the specified range. The code is optimised for
684704
* cache hits, as metadata intensive workloads will see 3 orders of magnitude
@@ -692,6 +712,7 @@ xfs_buf_get_map(
692712
xfs_buf_flags_t flags,
693713
struct xfs_buf **bpp)
694714
{
715+
struct xfs_buf_cache *bch;
695716
struct xfs_perag *pag;
696717
struct xfs_buf *bp = NULL;
697718
struct xfs_buf_map cmap = { .bm_bn = map[0].bm_bn };
@@ -707,10 +728,10 @@ xfs_buf_get_map(
707728
if (error)
708729
return error;
709730

710-
pag = xfs_perag_get(btp->bt_mount,
711-
xfs_daddr_to_agno(btp->bt_mount, cmap.bm_bn));
731+
pag = xfs_buftarg_get_pag(btp, &cmap);
732+
bch = xfs_buftarg_buf_cache(btp, pag);
712733

713-
error = xfs_buf_lookup(pag, &cmap, flags, &bp);
734+
error = xfs_buf_lookup(bch, &cmap, flags, &bp);
714735
if (error && error != -ENOENT)
715736
goto out_put_perag;
716737

@@ -722,13 +743,14 @@ xfs_buf_get_map(
722743
goto out_put_perag;
723744

724745
/* xfs_buf_find_insert() consumes the perag reference. */
725-
error = xfs_buf_find_insert(btp, pag, &cmap, map, nmaps,
746+
error = xfs_buf_find_insert(btp, bch, pag, &cmap, map, nmaps,
726747
flags, &bp);
727748
if (error)
728749
return error;
729750
} else {
730751
XFS_STATS_INC(btp->bt_mount, xb_get_locked);
731-
xfs_perag_put(pag);
752+
if (pag)
753+
xfs_perag_put(pag);
732754
}
733755

734756
/* We do not hold a perag reference anymore. */
@@ -756,7 +778,8 @@ xfs_buf_get_map(
756778
return 0;
757779

758780
out_put_perag:
759-
xfs_perag_put(pag);
781+
if (pag)
782+
xfs_perag_put(pag);
760783
return error;
761784
}
762785

@@ -1016,7 +1039,9 @@ static void
10161039
xfs_buf_rele_cached(
10171040
struct xfs_buf *bp)
10181041
{
1042+
struct xfs_buftarg *btp = bp->b_target;
10191043
struct xfs_perag *pag = bp->b_pag;
1044+
struct xfs_buf_cache *bch = xfs_buftarg_buf_cache(btp, pag);
10201045
bool release;
10211046
bool freebuf = false;
10221047

@@ -1035,7 +1060,7 @@ xfs_buf_rele_cached(
10351060
* leading to a use-after-free scenario.
10361061
*/
10371062
spin_lock(&bp->b_lock);
1038-
release = atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock);
1063+
release = atomic_dec_and_lock(&bp->b_hold, &bch->bc_lock);
10391064
if (!release) {
10401065
/*
10411066
* Drop the in-flight state if the buffer is already on the LRU
@@ -1056,11 +1081,11 @@ xfs_buf_rele_cached(
10561081
* buffer for the LRU and clear the (now stale) dispose list
10571082
* state flag
10581083
*/
1059-
if (list_lru_add_obj(&bp->b_target->bt_lru, &bp->b_lru)) {
1084+
if (list_lru_add_obj(&btp->bt_lru, &bp->b_lru)) {
10601085
bp->b_state &= ~XFS_BSTATE_DISPOSE;
10611086
atomic_inc(&bp->b_hold);
10621087
}
1063-
spin_unlock(&pag->pag_buf_lock);
1088+
spin_unlock(&bch->bc_lock);
10641089
} else {
10651090
/*
10661091
* most of the time buffers will already be removed from the
@@ -1069,16 +1094,17 @@ xfs_buf_rele_cached(
10691094
* was on was the disposal list
10701095
*/
10711096
if (!(bp->b_state & XFS_BSTATE_DISPOSE)) {
1072-
list_lru_del_obj(&bp->b_target->bt_lru, &bp->b_lru);
1097+
list_lru_del_obj(&btp->bt_lru, &bp->b_lru);
10731098
} else {
10741099
ASSERT(list_empty(&bp->b_lru));
10751100
}
10761101

10771102
ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
1078-
rhashtable_remove_fast(&pag->pag_buf_hash, &bp->b_rhash_head,
1079-
xfs_buf_hash_params);
1080-
spin_unlock(&pag->pag_buf_lock);
1081-
xfs_perag_put(pag);
1103+
rhashtable_remove_fast(&bch->bc_hash, &bp->b_rhash_head,
1104+
xfs_buf_hash_params);
1105+
spin_unlock(&bch->bc_lock);
1106+
if (pag)
1107+
xfs_perag_put(pag);
10821108
freebuf = true;
10831109
}
10841110

fs/xfs/xfs_buf.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ typedef unsigned int xfs_buf_flags_t;
8383
#define XFS_BSTATE_DISPOSE (1 << 0) /* buffer being discarded */
8484
#define XFS_BSTATE_IN_FLIGHT (1 << 1) /* I/O in flight */
8585

86+
struct xfs_buf_cache {
87+
spinlock_t bc_lock;
88+
struct rhashtable bc_hash;
89+
};
90+
91+
int xfs_buf_cache_init(struct xfs_buf_cache *bch);
92+
void xfs_buf_cache_destroy(struct xfs_buf_cache *bch);
93+
8694
/*
8795
* The xfs_buftarg contains 2 notions of "sector size" -
8896
*

fs/xfs/xfs_mount.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -505,9 +505,6 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d)
505505
return (xfs_agblock_t) do_div(ld, mp->m_sb.sb_agblocks);
506506
}
507507

508-
int xfs_buf_hash_init(struct xfs_perag *pag);
509-
void xfs_buf_hash_destroy(struct xfs_perag *pag);
510-
511508
extern void xfs_uuid_table_free(void);
512509
extern uint64_t xfs_default_resblks(xfs_mount_t *mp);
513510
extern int xfs_mountfs(xfs_mount_t *mp);

0 commit comments

Comments
 (0)