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>
This commit is contained in:
Родитель
d0e853f360
Коммит
350a27a6a6
|
@ -1163,3 +1163,105 @@ xfs_refcount_decrease_extent(
|
||||||
return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_DECREASE,
|
return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_DECREASE,
|
||||||
PREV->br_startblock, PREV->br_blockcount);
|
PREV->br_startblock, PREV->br_blockcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given an AG extent, find the lowest-numbered run of shared blocks
|
||||||
|
* within that range and return the range in fbno/flen. If
|
||||||
|
* find_end_of_shared is set, return the longest contiguous extent of
|
||||||
|
* shared blocks; if not, just return the first extent we find. If no
|
||||||
|
* shared blocks are found, fbno and flen will be set to NULLAGBLOCK
|
||||||
|
* and 0, respectively.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xfs_refcount_find_shared(
|
||||||
|
struct xfs_btree_cur *cur,
|
||||||
|
xfs_agblock_t agbno,
|
||||||
|
xfs_extlen_t aglen,
|
||||||
|
xfs_agblock_t *fbno,
|
||||||
|
xfs_extlen_t *flen,
|
||||||
|
bool find_end_of_shared)
|
||||||
|
{
|
||||||
|
struct xfs_refcount_irec tmp;
|
||||||
|
int i;
|
||||||
|
int have;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_private.a.agno,
|
||||||
|
agbno, aglen);
|
||||||
|
|
||||||
|
/* By default, skip the whole range */
|
||||||
|
*fbno = NULLAGBLOCK;
|
||||||
|
*flen = 0;
|
||||||
|
|
||||||
|
/* Try to find a refcount extent that crosses the start */
|
||||||
|
error = xfs_refcount_lookup_le(cur, agbno, &have);
|
||||||
|
if (error)
|
||||||
|
goto out_error;
|
||||||
|
if (!have) {
|
||||||
|
/* No left extent, look at the next one */
|
||||||
|
error = xfs_btree_increment(cur, 0, &have);
|
||||||
|
if (error)
|
||||||
|
goto out_error;
|
||||||
|
if (!have)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
error = xfs_refcount_get_rec(cur, &tmp, &i);
|
||||||
|
if (error)
|
||||||
|
goto out_error;
|
||||||
|
XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error);
|
||||||
|
|
||||||
|
/* If the extent ends before the start, look at the next one */
|
||||||
|
if (tmp.rc_startblock + tmp.rc_blockcount <= agbno) {
|
||||||
|
error = xfs_btree_increment(cur, 0, &have);
|
||||||
|
if (error)
|
||||||
|
goto out_error;
|
||||||
|
if (!have)
|
||||||
|
goto done;
|
||||||
|
error = xfs_refcount_get_rec(cur, &tmp, &i);
|
||||||
|
if (error)
|
||||||
|
goto out_error;
|
||||||
|
XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the extent starts after the range we want, bail out */
|
||||||
|
if (tmp.rc_startblock >= agbno + aglen)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* We found the start of a shared extent! */
|
||||||
|
if (tmp.rc_startblock < agbno) {
|
||||||
|
tmp.rc_blockcount -= (agbno - tmp.rc_startblock);
|
||||||
|
tmp.rc_startblock = agbno;
|
||||||
|
}
|
||||||
|
|
||||||
|
*fbno = tmp.rc_startblock;
|
||||||
|
*flen = min(tmp.rc_blockcount, agbno + aglen - *fbno);
|
||||||
|
if (!find_end_of_shared)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* Otherwise, find the end of this shared extent */
|
||||||
|
while (*fbno + *flen < agbno + aglen) {
|
||||||
|
error = xfs_btree_increment(cur, 0, &have);
|
||||||
|
if (error)
|
||||||
|
goto out_error;
|
||||||
|
if (!have)
|
||||||
|
break;
|
||||||
|
error = xfs_refcount_get_rec(cur, &tmp, &i);
|
||||||
|
if (error)
|
||||||
|
goto out_error;
|
||||||
|
XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error);
|
||||||
|
if (tmp.rc_startblock >= agbno + aglen ||
|
||||||
|
tmp.rc_startblock != *fbno + *flen)
|
||||||
|
break;
|
||||||
|
*flen = min(*flen + tmp.rc_blockcount, agbno + aglen - *fbno);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
trace_xfs_refcount_find_shared_result(cur->bc_mp,
|
||||||
|
cur->bc_private.a.agno, *fbno, *flen);
|
||||||
|
|
||||||
|
out_error:
|
||||||
|
if (error)
|
||||||
|
trace_xfs_refcount_find_shared_error(cur->bc_mp,
|
||||||
|
cur->bc_private.a.agno, error, _RET_IP_);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
|
@ -54,4 +54,8 @@ extern int xfs_refcount_finish_one(struct xfs_trans *tp,
|
||||||
xfs_fsblock_t *new_fsb, xfs_extlen_t *new_len,
|
xfs_fsblock_t *new_fsb, xfs_extlen_t *new_len,
|
||||||
struct xfs_btree_cur **pcur);
|
struct xfs_btree_cur **pcur);
|
||||||
|
|
||||||
|
extern int xfs_refcount_find_shared(struct xfs_btree_cur *cur,
|
||||||
|
xfs_agblock_t agbno, xfs_extlen_t aglen, xfs_agblock_t *fbno,
|
||||||
|
xfs_extlen_t *flen, bool find_end_of_shared);
|
||||||
|
|
||||||
#endif /* __XFS_REFCOUNT_H__ */
|
#endif /* __XFS_REFCOUNT_H__ */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче