@@ -1163,3 +1163,105 @@ xfs_refcount_decrease_extent(
1163
1163
return __xfs_refcount_add (mp , dfops , XFS_REFCOUNT_DECREASE ,
1164
1164
PREV -> br_startblock , PREV -> br_blockcount );
1165
1165
}
1166
+
1167
+ /*
1168
+ * Given an AG extent, find the lowest-numbered run of shared blocks
1169
+ * within that range and return the range in fbno/flen. If
1170
+ * find_end_of_shared is set, return the longest contiguous extent of
1171
+ * shared blocks; if not, just return the first extent we find. If no
1172
+ * shared blocks are found, fbno and flen will be set to NULLAGBLOCK
1173
+ * and 0, respectively.
1174
+ */
1175
+ int
1176
+ xfs_refcount_find_shared (
1177
+ struct xfs_btree_cur * cur ,
1178
+ xfs_agblock_t agbno ,
1179
+ xfs_extlen_t aglen ,
1180
+ xfs_agblock_t * fbno ,
1181
+ xfs_extlen_t * flen ,
1182
+ bool find_end_of_shared )
1183
+ {
1184
+ struct xfs_refcount_irec tmp ;
1185
+ int i ;
1186
+ int have ;
1187
+ int error ;
1188
+
1189
+ trace_xfs_refcount_find_shared (cur -> bc_mp , cur -> bc_private .a .agno ,
1190
+ agbno , aglen );
1191
+
1192
+ /* By default, skip the whole range */
1193
+ * fbno = NULLAGBLOCK ;
1194
+ * flen = 0 ;
1195
+
1196
+ /* Try to find a refcount extent that crosses the start */
1197
+ error = xfs_refcount_lookup_le (cur , agbno , & have );
1198
+ if (error )
1199
+ goto out_error ;
1200
+ if (!have ) {
1201
+ /* No left extent, look at the next one */
1202
+ error = xfs_btree_increment (cur , 0 , & have );
1203
+ if (error )
1204
+ goto out_error ;
1205
+ if (!have )
1206
+ goto done ;
1207
+ }
1208
+ error = xfs_refcount_get_rec (cur , & tmp , & i );
1209
+ if (error )
1210
+ goto out_error ;
1211
+ XFS_WANT_CORRUPTED_GOTO (cur -> bc_mp , i == 1 , out_error );
1212
+
1213
+ /* If the extent ends before the start, look at the next one */
1214
+ if (tmp .rc_startblock + tmp .rc_blockcount <= agbno ) {
1215
+ error = xfs_btree_increment (cur , 0 , & have );
1216
+ if (error )
1217
+ goto out_error ;
1218
+ if (!have )
1219
+ goto done ;
1220
+ error = xfs_refcount_get_rec (cur , & tmp , & i );
1221
+ if (error )
1222
+ goto out_error ;
1223
+ XFS_WANT_CORRUPTED_GOTO (cur -> bc_mp , i == 1 , out_error );
1224
+ }
1225
+
1226
+ /* If the extent starts after the range we want, bail out */
1227
+ if (tmp .rc_startblock >= agbno + aglen )
1228
+ goto done ;
1229
+
1230
+ /* We found the start of a shared extent! */
1231
+ if (tmp .rc_startblock < agbno ) {
1232
+ tmp .rc_blockcount -= (agbno - tmp .rc_startblock );
1233
+ tmp .rc_startblock = agbno ;
1234
+ }
1235
+
1236
+ * fbno = tmp .rc_startblock ;
1237
+ * flen = min (tmp .rc_blockcount , agbno + aglen - * fbno );
1238
+ if (!find_end_of_shared )
1239
+ goto done ;
1240
+
1241
+ /* Otherwise, find the end of this shared extent */
1242
+ while (* fbno + * flen < agbno + aglen ) {
1243
+ error = xfs_btree_increment (cur , 0 , & have );
1244
+ if (error )
1245
+ goto out_error ;
1246
+ if (!have )
1247
+ break ;
1248
+ error = xfs_refcount_get_rec (cur , & tmp , & i );
1249
+ if (error )
1250
+ goto out_error ;
1251
+ XFS_WANT_CORRUPTED_GOTO (cur -> bc_mp , i == 1 , out_error );
1252
+ if (tmp .rc_startblock >= agbno + aglen ||
1253
+ tmp .rc_startblock != * fbno + * flen )
1254
+ break ;
1255
+ * flen = min (* flen + tmp .rc_blockcount , agbno + aglen - * fbno );
1256
+ }
1257
+
1258
+ done :
1259
+ trace_xfs_refcount_find_shared_result (cur -> bc_mp ,
1260
+ cur -> bc_private .a .agno , * fbno , * flen );
1261
+
1262
+ out_error :
1263
+ if (error )
1264
+ trace_xfs_refcount_find_shared_error (cur -> bc_mp ,
1265
+ cur -> bc_private .a .agno , error , _RET_IP_ );
1266
+ return error ;
1267
+ }
0 commit comments