]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: introduce reflink utility functions
authorDarrick J. Wong <darrick.wong@oracle.com>
Tue, 25 Oct 2016 01:29:22 +0000 (12:29 +1100)
committerDave Chinner <david@fromorbit.com>
Tue, 25 Oct 2016 01:29:22 +0000 (12:29 +1100)
Source kernel commit: 350a27a6a65cc5dd2ba1b220e8641993414816d2

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>
include/xfs_trace.h
libxfs/xfs_refcount.c
libxfs/xfs_refcount.h

index 582f04a7a70e72336b401b4b2abcda1ae7fd88f7..c96d53c2aca3340d2f638db529bc7b49b8f4116c 100644 (file)
 #define trace_xfs_refcount_deferred(...)               ((void) 0)
 #define trace_xfs_refcount_defer(...)                  ((void) 0)
 #define trace_xfs_refcount_finish_one_leftover(...)    ((void) 0)
-
-
+#define trace_xfs_refcount_find_shared(...)            ((void) 0)
+#define trace_xfs_refcount_find_shared_result(...)     ((void) 0)
+#define trace_xfs_refcount_find_shared_error(...)      ((void) 0)
 
 /* set c = c to avoid unused var warnings */
 #define trace_xfs_perag_get(a,b,c,d)           ((c) = (c))
index 2080a8acae78c33f9c6ff1d2cd552dab3d176ab7..a4a3e23caa6bc01a82b47a4a513398e3410ff5f7 100644 (file)
@@ -1162,3 +1162,105 @@ xfs_refcount_decrease_extent(
        return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_DECREASE,
                        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;
+}
index 0a1f290269df228dab9e695be94c3e7c6a8edf14..adba3ae2b55f216e0f3c6b84419c41b06c5a54fc 100644 (file)
@@ -54,4 +54,8 @@ extern int xfs_refcount_finish_one(struct xfs_trans *tp,
                xfs_fsblock_t *new_fsb, xfs_extlen_t *new_len,
                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__ */