Skip to content

Commit 350a27a

Browse files
committed
xfs: introduce reflink utility functions
These functions will be used by the other reflink functions to find the maximum length of a range of shared blocks. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.coM> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent d0e853f commit 350a27a

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

fs/xfs/libxfs/xfs_refcount.c

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,3 +1163,105 @@ xfs_refcount_decrease_extent(
11631163
return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_DECREASE,
11641164
PREV->br_startblock, PREV->br_blockcount);
11651165
}
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+
}

fs/xfs/libxfs/xfs_refcount.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,8 @@ extern int xfs_refcount_finish_one(struct xfs_trans *tp,
5454
xfs_fsblock_t *new_fsb, xfs_extlen_t *new_len,
5555
struct xfs_btree_cur **pcur);
5656

57+
extern int xfs_refcount_find_shared(struct xfs_btree_cur *cur,
58+
xfs_agblock_t agbno, xfs_extlen_t aglen, xfs_agblock_t *fbno,
59+
xfs_extlen_t *flen, bool find_end_of_shared);
60+
5761
#endif /* __XFS_REFCOUNT_H__ */

0 commit comments

Comments
 (0)