aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2016-10-03 12:11:25 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2016-10-03 12:11:25 -0400
commit350a27a6a65cc5dd2ba1b220e8641993414816d2 (patch)
treee5744fb102288ea8903ca77e05484095c3ffccbf
parentd0e853f3600cd2a3f7c4a067dc38155c77c51df9 (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.c102
-rw-r--r--fs/xfs/libxfs/xfs_refcount.h4
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 */
1175int
1176xfs_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
1258done:
1259 trace_xfs_refcount_find_shared_result(cur->bc_mp,
1260 cur->bc_private.a.agno, *fbno, *flen);
1261
1262out_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
57extern 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__ */