@@ -127,15 +127,6 @@ __xfs_buf_ioacct_dec(
127
127
}
128
128
}
129
129
130
- static inline void
131
- xfs_buf_ioacct_dec (
132
- struct xfs_buf * bp )
133
- {
134
- spin_lock (& bp -> b_lock );
135
- __xfs_buf_ioacct_dec (bp );
136
- spin_unlock (& bp -> b_lock );
137
- }
138
-
139
130
/*
140
131
* When we mark a buffer stale, we remove the buffer from the LRU and clear the
141
132
* b_lru_ref count so that the buffer is freed immediately when the buffer
@@ -171,9 +162,9 @@ xfs_buf_stale(
171
162
atomic_set (& bp -> b_lru_ref , 0 );
172
163
if (!(bp -> b_state & XFS_BSTATE_DISPOSE ) &&
173
164
(list_lru_del_obj (& bp -> b_target -> bt_lru , & bp -> b_lru )))
174
- atomic_dec ( & bp -> b_hold ) ;
165
+ bp -> b_hold -- ;
175
166
176
- ASSERT (atomic_read ( & bp -> b_hold ) >= 1 );
167
+ ASSERT (bp -> b_hold >= 1 );
177
168
spin_unlock (& bp -> b_lock );
178
169
}
179
170
@@ -229,14 +220,14 @@ _xfs_buf_alloc(
229
220
*/
230
221
flags &= ~(XBF_UNMAPPED | XBF_TRYLOCK | XBF_ASYNC | XBF_READ_AHEAD );
231
222
232
- atomic_set (& bp -> b_hold , 1 );
223
+ spin_lock_init (& bp -> b_lock );
224
+ bp -> b_hold = 1 ;
233
225
atomic_set (& bp -> b_lru_ref , 1 );
234
226
init_completion (& bp -> b_iowait );
235
227
INIT_LIST_HEAD (& bp -> b_lru );
236
228
INIT_LIST_HEAD (& bp -> b_list );
237
229
INIT_LIST_HEAD (& bp -> b_li_list );
238
230
sema_init (& bp -> b_sema , 0 ); /* held, no waiters */
239
- spin_lock_init (& bp -> b_lock );
240
231
bp -> b_target = target ;
241
232
bp -> b_mount = target -> bt_mount ;
242
233
bp -> b_flags = flags ;
@@ -580,6 +571,20 @@ xfs_buf_find_lock(
580
571
return 0 ;
581
572
}
582
573
574
+ static bool
575
+ xfs_buf_try_hold (
576
+ struct xfs_buf * bp )
577
+ {
578
+ spin_lock (& bp -> b_lock );
579
+ if (bp -> b_hold == 0 ) {
580
+ spin_unlock (& bp -> b_lock );
581
+ return false;
582
+ }
583
+ bp -> b_hold ++ ;
584
+ spin_unlock (& bp -> b_lock );
585
+ return true;
586
+ }
587
+
583
588
static inline int
584
589
xfs_buf_lookup (
585
590
struct xfs_buf_cache * bch ,
@@ -592,7 +597,7 @@ xfs_buf_lookup(
592
597
593
598
rcu_read_lock ();
594
599
bp = rhashtable_lookup (& bch -> bc_hash , map , xfs_buf_hash_params );
595
- if (!bp || !atomic_inc_not_zero ( & bp -> b_hold )) {
600
+ if (!bp || !xfs_buf_try_hold ( bp )) {
596
601
rcu_read_unlock ();
597
602
return - ENOENT ;
598
603
}
@@ -655,7 +660,7 @@ xfs_buf_find_insert(
655
660
spin_unlock (& bch -> bc_lock );
656
661
goto out_free_buf ;
657
662
}
658
- if (bp && atomic_inc_not_zero ( & bp -> b_hold )) {
663
+ if (bp && xfs_buf_try_hold ( bp )) {
659
664
/* found an existing buffer */
660
665
spin_unlock (& bch -> bc_lock );
661
666
error = xfs_buf_find_lock (bp , flags );
@@ -1037,18 +1042,26 @@ xfs_buf_hold(
1037
1042
struct xfs_buf * bp )
1038
1043
{
1039
1044
trace_xfs_buf_hold (bp , _RET_IP_ );
1040
- atomic_inc (& bp -> b_hold );
1045
+
1046
+ spin_lock (& bp -> b_lock );
1047
+ bp -> b_hold ++ ;
1048
+ spin_unlock (& bp -> b_lock );
1041
1049
}
1042
1050
1043
1051
static void
1044
1052
xfs_buf_rele_uncached (
1045
1053
struct xfs_buf * bp )
1046
1054
{
1047
1055
ASSERT (list_empty (& bp -> b_lru ));
1048
- if (atomic_dec_and_test (& bp -> b_hold )) {
1049
- xfs_buf_ioacct_dec (bp );
1050
- xfs_buf_free (bp );
1056
+
1057
+ spin_lock (& bp -> b_lock );
1058
+ if (-- bp -> b_hold ) {
1059
+ spin_unlock (& bp -> b_lock );
1060
+ return ;
1051
1061
}
1062
+ __xfs_buf_ioacct_dec (bp );
1063
+ spin_unlock (& bp -> b_lock );
1064
+ xfs_buf_free (bp );
1052
1065
}
1053
1066
1054
1067
static void
@@ -1058,51 +1071,40 @@ xfs_buf_rele_cached(
1058
1071
struct xfs_buftarg * btp = bp -> b_target ;
1059
1072
struct xfs_perag * pag = bp -> b_pag ;
1060
1073
struct xfs_buf_cache * bch = xfs_buftarg_buf_cache (btp , pag );
1061
- bool release ;
1062
1074
bool freebuf = false;
1063
1075
1064
1076
trace_xfs_buf_rele (bp , _RET_IP_ );
1065
1077
1066
- ASSERT (atomic_read (& bp -> b_hold ) > 0 );
1067
-
1068
- /*
1069
- * We grab the b_lock here first to serialise racing xfs_buf_rele()
1070
- * calls. The pag_buf_lock being taken on the last reference only
1071
- * serialises against racing lookups in xfs_buf_find(). IOWs, the second
1072
- * to last reference we drop here is not serialised against the last
1073
- * reference until we take bp->b_lock. Hence if we don't grab b_lock
1074
- * first, the last "release" reference can win the race to the lock and
1075
- * free the buffer before the second-to-last reference is processed,
1076
- * leading to a use-after-free scenario.
1077
- */
1078
1078
spin_lock (& bp -> b_lock );
1079
- release = atomic_dec_and_lock ( & bp -> b_hold , & bch -> bc_lock );
1080
- if (! release ) {
1079
+ ASSERT ( bp -> b_hold >= 1 );
1080
+ if (bp -> b_hold > 1 ) {
1081
1081
/*
1082
1082
* Drop the in-flight state if the buffer is already on the LRU
1083
1083
* and it holds the only reference. This is racy because we
1084
1084
* haven't acquired the pag lock, but the use of _XBF_IN_FLIGHT
1085
1085
* ensures the decrement occurs only once per-buf.
1086
1086
*/
1087
- if (( atomic_read ( & bp -> b_hold ) == 1 ) && !list_empty (& bp -> b_lru ))
1087
+ if (-- bp -> b_hold == 1 && !list_empty (& bp -> b_lru ))
1088
1088
__xfs_buf_ioacct_dec (bp );
1089
1089
goto out_unlock ;
1090
1090
}
1091
1091
1092
- /* the last reference has been dropped ... */
1092
+ /* we are asked to drop the last reference */
1093
+ spin_lock (& bch -> bc_lock );
1093
1094
__xfs_buf_ioacct_dec (bp );
1094
1095
if (!(bp -> b_flags & XBF_STALE ) && atomic_read (& bp -> b_lru_ref )) {
1095
1096
/*
1096
- * If the buffer is added to the LRU take a new reference to the
1097
+ * If the buffer is added to the LRU, keep the reference to the
1097
1098
* buffer for the LRU and clear the (now stale) dispose list
1098
- * state flag
1099
+ * state flag, else drop the reference.
1099
1100
*/
1100
- if (list_lru_add_obj (& btp -> bt_lru , & bp -> b_lru )) {
1101
+ if (list_lru_add_obj (& btp -> bt_lru , & bp -> b_lru ))
1101
1102
bp -> b_state &= ~XFS_BSTATE_DISPOSE ;
1102
- atomic_inc ( & bp -> b_hold );
1103
- }
1103
+ else
1104
+ bp -> b_hold -- ;
1104
1105
spin_unlock (& bch -> bc_lock );
1105
1106
} else {
1107
+ bp -> b_hold -- ;
1106
1108
/*
1107
1109
* most of the time buffers will already be removed from the
1108
1110
* LRU, so optimise that case by checking for the
@@ -1748,13 +1750,14 @@ xfs_buftarg_drain_rele(
1748
1750
struct xfs_buf * bp = container_of (item , struct xfs_buf , b_lru );
1749
1751
struct list_head * dispose = arg ;
1750
1752
1751
- if (atomic_read (& bp -> b_hold ) > 1 ) {
1753
+ if (!spin_trylock (& bp -> b_lock ))
1754
+ return LRU_SKIP ;
1755
+ if (bp -> b_hold > 1 ) {
1752
1756
/* need to wait, so skip it this pass */
1757
+ spin_unlock (& bp -> b_lock );
1753
1758
trace_xfs_buf_drain_buftarg (bp , _RET_IP_ );
1754
1759
return LRU_SKIP ;
1755
1760
}
1756
- if (!spin_trylock (& bp -> b_lock ))
1757
- return LRU_SKIP ;
1758
1761
1759
1762
/*
1760
1763
* clear the LRU reference count so the buffer doesn't get
@@ -2093,7 +2096,7 @@ xfs_buf_delwri_queue(
2093
2096
*/
2094
2097
bp -> b_flags |= _XBF_DELWRI_Q ;
2095
2098
if (list_empty (& bp -> b_list )) {
2096
- atomic_inc ( & bp -> b_hold );
2099
+ xfs_buf_hold ( bp );
2097
2100
list_add_tail (& bp -> b_list , list );
2098
2101
}
2099
2102
0 commit comments