[PATCH 23/58] xfs: enhanced remove an extent from the rmap btree

Darrick J. Wong
2015-10-07T04:57:42Z

Simplify the rmap extent removal since we never merge extents or anything
fancy like that.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
fs/xfs/libxfs/xfs_rmap.c | 49 ++++++++++++++++++++++++++++++----------------
1 file changed, 32 insertions(+), 17 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c
index 92e417d..073fb96 100644
--- a/fs/xfs/libxfs/xfs_rmap.c
+++ b/fs/xfs/libxfs/xfs_rmap.c
@@ -121,15 +121,8 @@ xfs_rmap_get_rec(
/*
* Find the extent in the rmap btree and remove it.
*
- * The record we find should always span a range greater than or equal to the
- * the extent being freed. This makes the code simple as, in theory, we do not
- * have to handle ranges that are split across multiple records as extents that
- * result in bmap btree extent merges should also result in rmap btree extent
- * merges. The owner field ensures we don't merge extents from different
- * structures into the same record, hence this property should always hold true
- * if we ensure that the rmap btree supports at least the same size maximum
- * extent as the bmap btree (bmbt MAXEXTLEN is 2^21 blocks at present, rmap
- * btree record can hold 2^32 blocks in a single extent).
+ * The record we find should always be an exact match for the extent that we're
+ * looking for, since we insert them into the btree without modification.
*
* Special Case #1: when growing the filesystem, we "free" an extent when
* growing the last AG. This extent is new space and so it is not tracked as
@@ -155,8 +148,11 @@ xfs_rmap_free(
struct xfs_mount *mp = tp->t_mountp;
struct xfs_btree_cur *cur;
struct xfs_rmap_irec ltrec;
+ uint64_t ltoff;
int error = 0;
int i;
+ uint64_t owner;
+ uint64_t offset;

if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
return 0;
@@ -164,12 +160,15 @@ xfs_rmap_free(
trace_xfs_rmap_free_extent(mp, agno, bno, len, oinfo);
cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno);

+ xfs_owner_info_unpack(oinfo, &owner, &offset);
+ ASSERT(XFS_RMAP_NON_INODE_OWNER(owner) || XFS_RMAP_IS_BMBT(offset));
+ ltoff = ltrec.rm_offset & ~XFS_RMAP_OFF_BMBT;
/*
* We should always have a left record because there's a static record
* for the AG headers at rm_startblock == 0 created by mkfs/growfs that
* will not ever be removed from the tree.
*/
- error = xfs_rmap_lookup_le(cur, bno, len, owner, &i);
+ error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, &i);
if (error)
goto out_error;
XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error);
@@ -200,15 +199,30 @@ xfs_rmap_free(
// ltrec.rm_blockcount, ltrec.rm_owner);

/* make sure the extent we found covers the entire freeing range. */
- XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno, out_error);
- XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_blockcount >= len, out_error);
- XFS_WANT_CORRUPTED_GOTO(mp,
- bno <= ltrec.rm_startblock + ltrec.rm_blockcount, out_error);
+ XFS_WANT_CORRUPTED_GOTO(mp, !XFS_RMAP_IS_UNWRITTEN(ltrec.rm_blockcount),
+ out_error);
+ XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno &&
+ ltrec.rm_startblock + XFS_RMAP_LEN(ltrec.rm_blockcount) >=
+ bno + len, out_error);

/* make sure the owner matches what we expect to find in the tree */
XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner ||
- (owner < XFS_RMAP_OWN_NULL &&
- owner >= XFS_RMAP_OWN_MIN), out_error);
+ XFS_RMAP_NON_INODE_OWNER(owner), out_error);
+
+ /* check the offset, if necessary */
+ if (!XFS_RMAP_NON_INODE_OWNER(owner)) {
+ if (XFS_RMAP_IS_BMBT(offset)) {
+ XFS_WANT_CORRUPTED_GOTO(mp,
+ XFS_RMAP_IS_BMBT(ltrec.rm_offset),
+ out_error);
+ } else {
+ XFS_WANT_CORRUPTED_GOTO(mp,
+ ltrec.rm_offset <= offset, out_error);
+ XFS_WANT_CORRUPTED_GOTO(mp,
+ offset <= ltoff + ltrec.rm_blockcount,
+ out_error);
+ }
+ }

if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
//printk("remove exact\n");
@@ -267,7 +281,7 @@ xfs_rmap_free(
xfs_extlen_t orig_len = ltrec.rm_blockcount;
//printk("remove middle\n");

- ltrec.rm_blockcount = bno - ltrec.rm_startblock;;
+ ltrec.rm_blockcount = bno - ltrec.rm_startblock;
error = xfs_rmap_update(cur, &ltrec);
if (error)
goto out_error;
@@ -280,6 +294,7 @@ xfs_rmap_free(
cur->bc_rec.r.rm_blockcount = orig_len - len -
ltrec.rm_blockcount;
cur->bc_rec.r.rm_owner = ltrec.rm_owner;
+ cur->bc_rec.r.rm_offset = offset;
error = xfs_btree_insert(cur, &i);
if (error)
goto out_error;