Skip to content

Commit a9ab28b

Browse files
Christoph Hellwigcmaiolino
authored andcommitted
xfs: remove xfs_buf_cache.bc_lock
xfs_buf_cache.bc_lock serializes adding buffers to and removing them from the hashtable. But as the rhashtable code already uses fine grained internal locking for inserts and removals the extra protection isn't actually required. It also happens to fix a lock order inversion vs b_lock added by the recent lookup race fix. Fixes: ee10f6f ("xfs: fix buffer lookup vs release race") Reported-by: Lai, Yi <yi1.lai@linux.intel.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Carlos Maiolino <cem@kernel.org>
1 parent 26b63be commit a9ab28b

File tree

2 files changed

+17
-15
lines changed

2 files changed

+17
-15
lines changed

fs/xfs/xfs_buf.c

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ struct kmem_cache *xfs_buf_cache;
4141
*
4242
* xfs_buf_rele:
4343
* b_lock
44-
* pag_buf_lock
45-
* lru_lock
44+
* lru_lock
4645
*
4746
* xfs_buftarg_drain_rele
4847
* lru_lock
@@ -220,14 +219,21 @@ _xfs_buf_alloc(
220219
*/
221220
flags &= ~(XBF_UNMAPPED | XBF_TRYLOCK | XBF_ASYNC | XBF_READ_AHEAD);
222221

223-
spin_lock_init(&bp->b_lock);
222+
/*
223+
* A new buffer is held and locked by the owner. This ensures that the
224+
* buffer is owned by the caller and racing RCU lookups right after
225+
* inserting into the hash table are safe (and will have to wait for
226+
* the unlock to do anything non-trivial).
227+
*/
224228
bp->b_hold = 1;
229+
sema_init(&bp->b_sema, 0); /* held, no waiters */
230+
231+
spin_lock_init(&bp->b_lock);
225232
atomic_set(&bp->b_lru_ref, 1);
226233
init_completion(&bp->b_iowait);
227234
INIT_LIST_HEAD(&bp->b_lru);
228235
INIT_LIST_HEAD(&bp->b_list);
229236
INIT_LIST_HEAD(&bp->b_li_list);
230-
sema_init(&bp->b_sema, 0); /* held, no waiters */
231237
bp->b_target = target;
232238
bp->b_mount = target->bt_mount;
233239
bp->b_flags = flags;
@@ -497,7 +503,6 @@ int
497503
xfs_buf_cache_init(
498504
struct xfs_buf_cache *bch)
499505
{
500-
spin_lock_init(&bch->bc_lock);
501506
return rhashtable_init(&bch->bc_hash, &xfs_buf_hash_params);
502507
}
503508

@@ -647,28 +652,29 @@ xfs_buf_find_insert(
647652
if (error)
648653
goto out_free_buf;
649654

650-
spin_lock(&bch->bc_lock);
655+
/* The new buffer keeps the perag reference until it is freed. */
656+
new_bp->b_pag = pag;
657+
658+
rcu_read_lock();
651659
bp = rhashtable_lookup_get_insert_fast(&bch->bc_hash,
652660
&new_bp->b_rhash_head, xfs_buf_hash_params);
653661
if (IS_ERR(bp)) {
662+
rcu_read_unlock();
654663
error = PTR_ERR(bp);
655-
spin_unlock(&bch->bc_lock);
656664
goto out_free_buf;
657665
}
658666
if (bp && xfs_buf_try_hold(bp)) {
659667
/* found an existing buffer */
660-
spin_unlock(&bch->bc_lock);
668+
rcu_read_unlock();
661669
error = xfs_buf_find_lock(bp, flags);
662670
if (error)
663671
xfs_buf_rele(bp);
664672
else
665673
*bpp = bp;
666674
goto out_free_buf;
667675
}
676+
rcu_read_unlock();
668677

669-
/* The new buffer keeps the perag reference until it is freed. */
670-
new_bp->b_pag = pag;
671-
spin_unlock(&bch->bc_lock);
672678
*bpp = new_bp;
673679
return 0;
674680

@@ -1085,7 +1091,6 @@ xfs_buf_rele_cached(
10851091
}
10861092

10871093
/* we are asked to drop the last reference */
1088-
spin_lock(&bch->bc_lock);
10891094
__xfs_buf_ioacct_dec(bp);
10901095
if (!(bp->b_flags & XBF_STALE) && atomic_read(&bp->b_lru_ref)) {
10911096
/*
@@ -1097,7 +1102,6 @@ xfs_buf_rele_cached(
10971102
bp->b_state &= ~XFS_BSTATE_DISPOSE;
10981103
else
10991104
bp->b_hold--;
1100-
spin_unlock(&bch->bc_lock);
11011105
} else {
11021106
bp->b_hold--;
11031107
/*
@@ -1115,7 +1119,6 @@ xfs_buf_rele_cached(
11151119
ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
11161120
rhashtable_remove_fast(&bch->bc_hash, &bp->b_rhash_head,
11171121
xfs_buf_hash_params);
1118-
spin_unlock(&bch->bc_lock);
11191122
if (pag)
11201123
xfs_perag_put(pag);
11211124
freebuf = true;

fs/xfs/xfs_buf.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ typedef unsigned int xfs_buf_flags_t;
8080
#define XFS_BSTATE_IN_FLIGHT (1 << 1) /* I/O in flight */
8181

8282
struct xfs_buf_cache {
83-
spinlock_t bc_lock;
8483
struct rhashtable bc_hash;
8584
};
8685

0 commit comments

Comments
 (0)