diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2016-10-03 12:11:25 -0400 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2016-10-03 12:11:25 -0400 |
commit | 350a27a6a65cc5dd2ba1b220e8641993414816d2 (patch) | |
tree | e5744fb102288ea8903ca77e05484095c3ffccbf | |
parent | d0e853f3600cd2a3f7c4a067dc38155c77c51df9 (diff) |
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>
-rw-r--r-- | fs/xfs/libxfs/xfs_refcount.c | 102 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_refcount.h | 4 |
2 files changed, 106 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c index 4a31a7c2f2c4..ab8c30d2a605 100644 --- a/fs/xfs/libxfs/xfs_refcount.c +++ b/fs/xfs/libxfs/xfs_refcount.c | |||
@@ -1163,3 +1163,105 @@ xfs_refcount_decrease_extent( | |||
1163 | return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_DECREASE, | 1163 | return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_DECREASE, |
1164 | PREV->br_startblock, PREV->br_blockcount); | 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 | } | ||
diff --git a/fs/xfs/libxfs/xfs_refcount.h b/fs/xfs/libxfs/xfs_refcount.h index 0a1f290269df..adba3ae2b55f 100644 --- a/fs/xfs/libxfs/xfs_refcount.h +++ b/fs/xfs/libxfs/xfs_refcount.h | |||
@@ -54,4 +54,8 @@ extern int xfs_refcount_finish_one(struct xfs_trans *tp, | |||
54 | xfs_fsblock_t *new_fsb, xfs_extlen_t *new_len, | 54 | xfs_fsblock_t *new_fsb, xfs_extlen_t *new_len, |
55 | struct xfs_btree_cur **pcur); | 55 | struct xfs_btree_cur **pcur); |
56 | 56 | ||
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 | |||
57 | #endif /* __XFS_REFCOUNT_H__ */ | 61 | #endif /* __XFS_REFCOUNT_H__ */ |