From: "Darrick J. Wong" <darrick.wong@oracle.com>
To: david@fromorbit.com
Cc: linux-fsdevel@vger.kernel.org, xfs@oss.sgi.com
Subject: Re: [PATCH 40/58] libxfs: adjust refcount of an extent of blocks in refcount btree
Date: Fri, 30 Oct 2015 13:56:02 -0700 [thread overview]
Message-ID: <20151030205602.GP10397@birch.djwong.org> (raw)
In-Reply-To: <20151027190533.GO10397@birch.djwong.org>
On Tue, Oct 27, 2015 at 12:05:33PM -0700, Darrick J. Wong wrote:
> On Tue, Oct 06, 2015 at 09:59:33PM -0700, Darrick J. Wong wrote:
> > Provide functions to adjust the reference counts for an extent of
> > physical blocks stored in the refcount btree.
> >
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> > ---
> > fs/xfs/libxfs/xfs_refcount.c | 771 ++++++++++++++++++++++++++++++++++++++++++
> > fs/xfs/libxfs/xfs_refcount.h | 8
> > 2 files changed, 779 insertions(+)
> >
> >
> > diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
> > index b3f2c25..02892bc 100644
> > --- a/fs/xfs/libxfs/xfs_refcount.c
> > +++ b/fs/xfs/libxfs/xfs_refcount.c
> > @@ -167,3 +167,774 @@ xfs_refcountbt_delete(
> > out_error:
> > return error;
> > }
> > +
> > +/*
> > + * Adjusting the Reference Count
> > + *
> > + * As stated elsewhere, the reference count btree (refcbt) stores
> > + * >1 reference counts for extents of physical blocks. In this
> > + * operation, we're either raising or lowering the reference count of
> > + * some subrange stored in the tree:
> > + *
> > + * <------ adjustment range ------>
> > + * ----+ +---+-----+ +--+--------+---------
> > + * 2 | | 3 | 4 | |17| 55 | 10
> > + * ----+ +---+-----+ +--+--------+---------
> > + * X axis is physical blocks number;
> > + * reference counts are the numbers inside the rectangles
> > + *
> > + * The first thing we need to do is to ensure that there are no
> > + * refcount extents crossing either boundary of the range to be
> > + * adjusted. For any extent that does cross a boundary, split it into
> > + * two extents so that we can increment the refcount of one of the
> > + * pieces later:
> > + *
> > + * <------ adjustment range ------>
> > + * ----+ +---+-----+ +--+--------+----+----
> > + * 2 | | 3 | 2 | |17| 55 | 10 | 10
> > + * ----+ +---+-----+ +--+--------+----+----
> > + *
> > + * For this next step, let's assume that all the physical blocks in
> > + * the adjustment range are mapped to a file and are therefore in use
> > + * at least once. Therefore, we can infer that any gap in the
> > + * refcount tree within the adjustment range represents a physical
> > + * extent with refcount == 1:
> > + *
> > + * <------ adjustment range ------>
> > + * ----+---+---+-----+-+--+--------+----+----
> > + * 2 |"1"| 3 | 2 |1|17| 55 | 10 | 10
> > + * ----+---+---+-----+-+--+--------+----+----
> > + * ^
> > + *
> > + * For each extent that falls within the interval range, figure out
> > + * which extent is to the left or the right of that extent. Now we
> > + * have a left, current, and right extent. If the new reference count
> > + * of the center extent enables us to merge left, center, and right
> > + * into one record covering all three, do so. If the center extent is
> > + * at the left end of the range, abuts the left extent, and its new
> > + * reference count matches the left extent's record, then merge them.
> > + * If the center extent is at the right end of the range, abuts the
> > + * right extent, and the reference counts match, merge those. In the
> > + * example, we can left merge (assuming an increment operation):
> > + *
> > + * <------ adjustment range ------>
> > + * --------+---+-----+-+--+--------+----+----
> > + * 2 | 3 | 2 |1|17| 55 | 10 | 10
> > + * --------+---+-----+-+--+--------+----+----
> > + * ^
> > + *
> > + * For all other extents within the range, adjust the reference count
> > + * or delete it if the refcount falls below 2. If we were
> > + * incrementing, the end result looks like this:
> > + *
> > + * <------ adjustment range ------>
> > + * --------+---+-----+-+--+--------+----+----
> > + * 2 | 4 | 3 |2|18| 56 | 11 | 10
> > + * --------+---+-----+-+--+--------+----+----
> > + *
> > + * The result of a decrement operation looks as such:
> > + *
> > + * <------ adjustment range ------>
> > + * ----+ +---+ +--+--------+----+----
> > + * 2 | | 2 | |16| 54 | 9 | 10
> > + * ----+ +---+ +--+--------+----+----
> > + * DDDD 111111DD
> > + *
> > + * The blocks marked "D" are freed; the blocks marked "1" are only
> > + * referenced once and therefore the record is removed from the
> > + * refcount btree.
> > + */
> > +
> > +#define RLNEXT(rl) ((rl).rc_startblock + (rl).rc_blockcount)
> > +/*
> > + * Split a left rlextent that crosses agbno.
> > + */
> > +STATIC int
> > +try_split_left_rlextent(
> > + struct xfs_btree_cur *cur,
> > + xfs_agblock_t agbno)
> > +{
> > + struct xfs_refcount_irec left, tmp;
> > + int found_rec;
> > + int error;
> > +
> > + error = xfs_refcountbt_lookup_le(cur, agbno, &found_rec);
> > + if (error)
> > + goto out_error;
> > + if (!found_rec)
> > + return 0;
> > +
> > + error = xfs_refcountbt_get_rec(cur, &left, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
> > + if (left.rc_startblock >= agbno || RLNEXT(left) <= agbno)
> > + return 0;
> > +
> > + trace_xfs_refcount_split_left_extent(cur->bc_mp, cur->bc_private.a.agno,
> > + &left, agbno);
> > + tmp = left;
> > + tmp.rc_blockcount = agbno - left.rc_startblock;
> > + error = xfs_refcountbt_update(cur, &tmp);
> > + if (error)
> > + goto out_error;
> > +
> > + error = xfs_btree_increment(cur, 0, &found_rec);
> > + if (error)
> > + goto out_error;
> > +
> > + tmp = left;
> > + tmp.rc_startblock = agbno;
> > + tmp.rc_blockcount -= (agbno - left.rc_startblock);
> > + error = xfs_refcountbt_insert(cur, &tmp, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
> > + return error;
> > +
> > +out_error:
> > + trace_xfs_refcount_split_left_extent_error(cur->bc_mp,
> > + cur->bc_private.a.agno, error, _RET_IP_);
> > + return error;
> > +}
> > +
> > +/*
> > + * Split a right rlextent that crosses agbno.
> > + */
> > +STATIC int
> > +try_split_right_rlextent(
> > + struct xfs_btree_cur *cur,
> > + xfs_agblock_t agbnext)
> > +{
> > + struct xfs_refcount_irec right, tmp;
> > + int found_rec;
> > + int error;
> > +
> > + error = xfs_refcountbt_lookup_le(cur, agbnext - 1, &found_rec);
> > + if (error)
> > + goto out_error;
> > + if (!found_rec)
> > + return 0;
> > +
> > + error = xfs_refcountbt_get_rec(cur, &right, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
> > + if (RLNEXT(right) <= agbnext)
> > + return 0;
> > +
> > + trace_xfs_refcount_split_right_extent(cur->bc_mp,
> > + cur->bc_private.a.agno, &right, agbnext);
> > + tmp = right;
> > + tmp.rc_startblock = agbnext;
> > + tmp.rc_blockcount -= (agbnext - right.rc_startblock);
> > + error = xfs_refcountbt_update(cur, &tmp);
> > + if (error)
> > + goto out_error;
> > +
> > + tmp = right;
> > + tmp.rc_blockcount = agbnext - right.rc_startblock;
> > + error = xfs_refcountbt_insert(cur, &tmp, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
> > + return error;
> > +
> > +out_error:
> > + trace_xfs_refcount_split_right_extent_error(cur->bc_mp,
> > + cur->bc_private.a.agno, error, _RET_IP_);
> > + return error;
> > +}
> > +
> > +/*
> > + * Merge the left, center, and right extents.
> > + */
> > +STATIC int
> > +merge_center(
> > + struct xfs_btree_cur *cur,
> > + struct xfs_refcount_irec *left,
> > + struct xfs_refcount_irec *center,
> > + unsigned long long extlen,
> > + xfs_agblock_t *agbno,
> > + xfs_extlen_t *aglen)
> > +{
> > + int error;
> > + int found_rec;
> > +
> > + error = xfs_refcountbt_lookup_ge(cur, center->rc_startblock,
> > + &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
> > +
> > + error = xfs_refcountbt_delete(cur, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
> > +
> > + if (center->rc_refcount > 1) {
> > + error = xfs_refcountbt_delete(cur, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
> > + out_error);
> > + }
> > +
> > + error = xfs_refcountbt_lookup_le(cur, left->rc_startblock,
> > + &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
> > +
> > + left->rc_blockcount = extlen;
> > + error = xfs_refcountbt_update(cur, left);
> > + if (error)
> > + goto out_error;
> > +
> > + *aglen = 0;
> > + return error;
> > +
> > +out_error:
> > + trace_xfs_refcount_merge_center_extents_error(cur->bc_mp,
> > + cur->bc_private.a.agno, error, _RET_IP_);
> > + return error;
> > +}
> > +
> > +/*
> > + * Merge with the left extent.
> > + */
> > +STATIC int
> > +merge_left(
> > + struct xfs_btree_cur *cur,
> > + struct xfs_refcount_irec *left,
> > + struct xfs_refcount_irec *cleft,
> > + xfs_agblock_t *agbno,
> > + xfs_extlen_t *aglen)
> > +{
> > + int error;
> > + int found_rec;
> > +
> > + if (cleft->rc_refcount > 1) {
> > + error = xfs_refcountbt_lookup_le(cur, cleft->rc_startblock,
> > + &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
> > + out_error);
> > +
> > + error = xfs_refcountbt_delete(cur, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
> > + out_error);
> > + }
> > +
> > + error = xfs_refcountbt_lookup_le(cur, left->rc_startblock,
> > + &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
> > +
> > + left->rc_blockcount += cleft->rc_blockcount;
> > + error = xfs_refcountbt_update(cur, left);
> > + if (error)
> > + goto out_error;
> > +
> > + *agbno += cleft->rc_blockcount;
> > + *aglen -= cleft->rc_blockcount;
> > + return error;
> > +
> > +out_error:
> > + trace_xfs_refcount_merge_left_extent_error(cur->bc_mp,
> > + cur->bc_private.a.agno, error, _RET_IP_);
> > + return error;
> > +}
> > +
> > +/*
> > + * Merge with the right extent.
> > + */
> > +STATIC int
> > +merge_right(
> > + struct xfs_btree_cur *cur,
> > + struct xfs_refcount_irec *right,
> > + struct xfs_refcount_irec *cright,
> > + xfs_agblock_t *agbno,
> > + xfs_extlen_t *aglen)
> > +{
> > + int error;
> > + int found_rec;
> > +
> > + if (cright->rc_refcount > 1) {
> > + error = xfs_refcountbt_lookup_le(cur, cright->rc_startblock,
> > + &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
> > + out_error);
> > +
> > + error = xfs_refcountbt_delete(cur, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
> > + out_error);
> > + }
> > +
> > + error = xfs_refcountbt_lookup_le(cur, right->rc_startblock,
> > + &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
> > +
> > + right->rc_startblock -= cright->rc_blockcount;
> > + right->rc_blockcount += cright->rc_blockcount;
> > + error = xfs_refcountbt_update(cur, right);
> > + if (error)
> > + goto out_error;
> > +
> > + *aglen -= cright->rc_blockcount;
> > + return error;
> > +
> > +out_error:
> > + trace_xfs_refcount_merge_right_extent_error(cur->bc_mp,
> > + cur->bc_private.a.agno, error, _RET_IP_);
> > + return error;
> > +}
> > +
> > +/*
> > + * Find the left extent and the one after it (cleft). This function assumes
> > + * that we've already split any extent crossing agbno.
> > + */
> > +STATIC int
> > +find_left_extent(
> > + struct xfs_btree_cur *cur,
> > + struct xfs_refcount_irec *left,
> > + struct xfs_refcount_irec *cleft,
> > + xfs_agblock_t agbno,
> > + xfs_extlen_t aglen)
> > +{
> > + struct xfs_refcount_irec tmp;
> > + int error;
> > + int found_rec;
> > +
> > + left->rc_blockcount = cleft->rc_blockcount = 0;
> > + error = xfs_refcountbt_lookup_le(cur, agbno - 1, &found_rec);
> > + if (error)
> > + goto out_error;
> > + if (!found_rec)
> > + return 0;
> > +
> > + error = xfs_refcountbt_get_rec(cur, &tmp, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
> > +
> > + if (RLNEXT(tmp) != agbno)
> > + return 0;
> > + /* We have a left extent; retrieve (or invent) the next right one */
> > + *left = tmp;
> > +
> > + error = xfs_btree_increment(cur, 0, &found_rec);
> > + if (error)
> > + goto out_error;
> > + if (found_rec) {
> > + error = xfs_refcountbt_get_rec(cur, &tmp, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
> > + out_error);
> > +
> > + if (tmp.rc_startblock == agbno)
> > + *cleft = tmp;
> > + else {
> > + cleft->rc_startblock = agbno;
> > + cleft->rc_blockcount = min(aglen,
> > + tmp.rc_startblock - agbno);
> > + cleft->rc_refcount = 1;
> > + }
> > + } else {
> > + cleft->rc_startblock = agbno;
> > + cleft->rc_blockcount = aglen;
> > + cleft->rc_refcount = 1;
> > + }
> > + trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_private.a.agno,
> > + left, cleft, agbno);
> > + return error;
> > +
> > +out_error:
> > + trace_xfs_refcount_find_left_extent_error(cur->bc_mp,
> > + cur->bc_private.a.agno, error, _RET_IP_);
> > + return error;
> > +}
> > +
> > +/*
> > + * Find the right extent and the one before it (cright). This function
> > + * assumes that we've already split any extents crossing agbno + aglen.
> > + */
> > +STATIC int
> > +find_right_extent(
> > + struct xfs_btree_cur *cur,
> > + struct xfs_refcount_irec *right,
> > + struct xfs_refcount_irec *cright,
> > + xfs_agblock_t agbno,
> > + xfs_extlen_t aglen)
> > +{
> > + struct xfs_refcount_irec tmp;
> > + int error;
> > + int found_rec;
> > +
> > + right->rc_blockcount = cright->rc_blockcount = 0;
> > + error = xfs_refcountbt_lookup_ge(cur, agbno + aglen, &found_rec);
> > + if (error)
> > + goto out_error;
> > + if (!found_rec)
> > + return 0;
> > +
> > + error = xfs_refcountbt_get_rec(cur, &tmp, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
> > +
> > + if (tmp.rc_startblock != agbno + aglen)
> > + return 0;
> > + /* We have a right extent; retrieve (or invent) the next left one */
> > + *right = tmp;
> > +
> > + error = xfs_btree_decrement(cur, 0, &found_rec);
> > + if (error)
> > + goto out_error;
> > + if (found_rec) {
> > + error = xfs_refcountbt_get_rec(cur, &tmp, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
> > + out_error);
> > +
> > + if (tmp.rc_startblock == agbno)
>
> Since tmp represents the refcount extent immediately to the left of (agbno +
> aglen), we want to copy tmp into cright if the end of tmp coincides with (agbno
> + aglen). This is probably a copy-pasta mistake.
>
> Also, s/RLNEXT/RCNEXT/ since these are refcount extents, not reflink extents.
> (Weird anachronism).
>
> --D
>
> > + *cright = tmp;
> > + else {
> > + cright->rc_startblock = max(agbno,
> > + RLNEXT(tmp));
> > + cright->rc_blockcount = right->rc_startblock -
> > + cright->rc_startblock;
> > + cright->rc_refcount = 1;
> > + }
> > + } else {
> > + cright->rc_startblock = agbno;
> > + cright->rc_blockcount = aglen;
> > + cright->rc_refcount = 1;
> > + }
> > + trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_private.a.agno,
> > + cright, right, agbno + aglen);
> > + return error;
> > +
> > +out_error:
> > + trace_xfs_refcount_find_right_extent_error(cur->bc_mp,
> > + cur->bc_private.a.agno, error, _RET_IP_);
> > + return error;
> > +}
> > +#undef RLNEXT
> > +
> > +/*
> > + * Try to merge with any extents on the boundaries of the adjustment range.
> > + */
> > +STATIC int
> > +try_merge_rlextents(
> > + struct xfs_btree_cur *cur,
> > + xfs_agblock_t *agbno,
> > + xfs_extlen_t *aglen,
> > + int adjust)
> > +{
> > + struct xfs_refcount_irec left, cleft, cright, right;
> > + int error;
> > + unsigned long long ulen;
> > +
> > + left.rc_blockcount = cleft.rc_blockcount = 0;
> > + cright.rc_blockcount = right.rc_blockcount = 0;
> > +
> > + /*
> > + * Find extents abutting the start and end of the range, and
> > + * the adjacent extents inside the range.
> > + */
> > + error = find_left_extent(cur, &left, &cleft, *agbno, *aglen);
> > + if (error)
> > + return error;
> > + error = find_right_extent(cur, &right, &cright, *agbno, *aglen);
> > + if (error)
> > + return error;
> > +
> > + /* No left or right extent to merge; exit. */
> > + if (left.rc_blockcount == 0 && right.rc_blockcount == 0)
> > + return 0;
> > +
> > + /* Try a center merge */
> > + ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount +
> > + right.rc_blockcount;
> > + if (left.rc_blockcount != 0 && right.rc_blockcount != 0 &&
> > + memcmp(&cleft, &cright, sizeof(cleft)) == 0 &&
> > + left.rc_refcount == cleft.rc_refcount + adjust &&
> > + right.rc_refcount == cleft.rc_refcount + adjust &&
> > + ulen < MAXREFCEXTLEN) {
> > + trace_xfs_refcount_merge_center_extents(cur->bc_mp,
> > + cur->bc_private.a.agno, &left, &cleft, &right);
> > + return merge_center(cur, &left, &cleft, ulen, agbno, aglen);
> > + }
> > +
> > + /* Try a left merge */
> > + ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount;
> > + if (left.rc_blockcount != 0 &&
> > + left.rc_refcount == cleft.rc_refcount + adjust &&
> > + ulen < MAXREFCEXTLEN) {
> > + trace_xfs_refcount_merge_left_extent(cur->bc_mp,
> > + cur->bc_private.a.agno, &left, &cleft);
> > + return merge_left(cur, &left, &cleft, agbno, aglen);
> > + }
We shouldn't return unconditionally here -- suppose that left, cleft, cright,
and right are all distinct extents and we want to merge left:cleft and merge
cright:right? You'd miss that second merge this way.
--D
> > +
> > + /* Try a right merge */
> > + ulen = (unsigned long long)right.rc_blockcount + cright.rc_blockcount;
> > + if (right.rc_blockcount != 0 &&
> > + right.rc_refcount == cright.rc_refcount + adjust &&
> > + ulen < MAXREFCEXTLEN) {
> > + trace_xfs_refcount_merge_right_extent(cur->bc_mp,
> > + cur->bc_private.a.agno, &cright, &right);
> > + return merge_right(cur, &right, &cright, agbno, aglen);
> > + }
> > +
> > + return error;
> > +}
> > +
> > +/*
> > + * Adjust the refcounts of middle extents. At this point we should have
> > + * split extents that crossed the adjustment range; merged with adjacent
> > + * extents; and updated agbno/aglen to reflect the merges. Therefore,
> > + * all we have to do is update the extents inside [agbno, agbno + aglen].
> > + */
> > +STATIC int
> > +adjust_rlextents(
> > + struct xfs_btree_cur *cur,
> > + xfs_agblock_t agbno,
> > + xfs_extlen_t aglen,
> > + int adj,
> > + struct xfs_bmap_free *flist,
> > + struct xfs_owner_info *oinfo)
> > +{
> > + struct xfs_refcount_irec ext, tmp;
> > + int error;
> > + int found_rec, found_tmp;
> > + xfs_fsblock_t fsbno;
> > +
> > + error = xfs_refcountbt_lookup_ge(cur, agbno, &found_rec);
> > + if (error)
> > + goto out_error;
> > +
> > + while (aglen > 0) {
> > + error = xfs_refcountbt_get_rec(cur, &ext, &found_rec);
> > + if (error)
> > + goto out_error;
> > + if (!found_rec) {
> > + ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks;
> > + ext.rc_blockcount = 0;
> > + ext.rc_refcount = 0;
> > + }
> > +
> > + /*
> > + * Deal with a hole in the refcount tree; if a file maps to
> > + * these blocks and there's no refcountbt recourd, pretend that
> > + * there is one with refcount == 1.
> > + */
> > + if (ext.rc_startblock != agbno) {
> > + tmp.rc_startblock = agbno;
> > + tmp.rc_blockcount = min(aglen,
> > + ext.rc_startblock - agbno);
> > + tmp.rc_refcount = 1 + adj;
> > + trace_xfs_refcount_modify_extent(cur->bc_mp,
> > + cur->bc_private.a.agno, &tmp);
> > +
> > + /*
> > + * Either cover the hole (increment) or
> > + * delete the range (decrement).
> > + */
> > + if (tmp.rc_refcount) {
> > + error = xfs_refcountbt_insert(cur, &tmp,
> > + &found_tmp);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
> > + found_tmp == 1, out_error);
> > + } else {
> > + fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
> > + cur->bc_private.a.agno,
> > + tmp.rc_startblock);
> > + xfs_bmap_add_free(cur->bc_mp, flist, fsbno,
> > + tmp.rc_blockcount, oinfo);
> > + }
> > +
> > + agbno += tmp.rc_blockcount;
> > + aglen -= tmp.rc_blockcount;
> > +
> > + error = xfs_refcountbt_lookup_ge(cur, agbno,
> > + &found_rec);
> > + if (error)
> > + goto out_error;
> > + }
> > +
> > + /* Stop if there's nothing left to modify */
> > + if (aglen == 0)
> > + break;
> > +
> > + /*
> > + * Adjust the reference count and either update the tree
> > + * (incr) or free the blocks (decr).
> > + */
> > + ext.rc_refcount += adj;
> > + trace_xfs_refcount_modify_extent(cur->bc_mp,
> > + cur->bc_private.a.agno, &ext);
> > + if (ext.rc_refcount > 1) {
> > + error = xfs_refcountbt_update(cur, &ext);
> > + if (error)
> > + goto out_error;
> > + } else if (ext.rc_refcount == 1) {
> > + error = xfs_refcountbt_delete(cur, &found_rec);
> > + if (error)
> > + goto out_error;
> > + XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
> > + found_rec == 1, out_error);
> > + goto advloop;
> > + } else {
> > + fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
> > + cur->bc_private.a.agno,
> > + ext.rc_startblock);
> > + xfs_bmap_add_free(cur->bc_mp, flist, fsbno,
> > + ext.rc_blockcount, oinfo);
> > + }
> > +
> > + error = xfs_btree_increment(cur, 0, &found_rec);
> > + if (error)
> > + goto out_error;
> > +
> > +advloop:
> > + agbno += ext.rc_blockcount;
> > + aglen -= ext.rc_blockcount;
> > + }
> > +
> > + return error;
> > +out_error:
> > + trace_xfs_refcount_modify_extent_error(cur->bc_mp,
> > + cur->bc_private.a.agno, error, _RET_IP_);
> > + return error;
> > +}
> > +
> > +/*
> > + * Adjust the reference count of a range of AG blocks.
> > + *
> > + * @mp: XFS mount object
> > + * @tp: XFS transaction object
> > + * @agbp: Buffer containing the AGF
> > + * @agno: AG number
> > + * @agbno: Start of range to adjust
> > + * @aglen: Length of range to adjust
> > + * @adj: +1 to increment, -1 to decrement reference count
> > + * @flist: freelist (only required if adj == -1)
> > + * @owner: owner of the blocks (only required if adj == -1)
> > + */
> > +STATIC int
> > +xfs_refcountbt_adjust_refcount(
> > + struct xfs_mount *mp,
> > + struct xfs_trans *tp,
> > + struct xfs_buf *agbp,
> > + xfs_agnumber_t agno,
> > + xfs_agblock_t agbno,
> > + xfs_extlen_t aglen,
> > + int adj,
> > + struct xfs_bmap_free *flist,
> > + struct xfs_owner_info *oinfo)
> > +{
> > + struct xfs_btree_cur *cur;
> > + int error;
> > +
> > + cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, flist);
> > +
> > + /*
> > + * Ensure that no rlextents cross the boundary of the adjustment range.
> > + */
> > + error = try_split_left_rlextent(cur, agbno);
> > + if (error)
> > + goto out_error;
> > +
> > + error = try_split_right_rlextent(cur, agbno + aglen);
> > + if (error)
> > + goto out_error;
> > +
> > + /*
> > + * Try to merge with the left or right extents of the range.
> > + */
> > + error = try_merge_rlextents(cur, &agbno, &aglen, adj);
> > + if (error)
> > + goto out_error;
> > +
> > + /* Now that we've taken care of the ends, adjust the middle extents */
> > + error = adjust_rlextents(cur, agbno, aglen, adj, flist, oinfo);
> > + if (error)
> > + goto out_error;
> > +
> > + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
> > + return 0;
> > +
> > +out_error:
> > + trace_xfs_refcount_adjust_error(mp, agno, error, _RET_IP_);
> > + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
> > + return error;
> > +}
> > +
> > +/**
> > + * Increase the reference count of a range of AG blocks.
> > + *
> > + * @mp: XFS mount object
> > + * @tp: XFS transaction object
> > + * @agbp: Buffer containing the AGF
> > + * @agno: AG number
> > + * @agbno: Start of range to adjust
> > + * @aglen: Length of range to adjust
> > + * @flist: List of blocks to free
> > + */
> > +int
> > +xfs_refcount_increase(
> > + struct xfs_mount *mp,
> > + struct xfs_trans *tp,
> > + struct xfs_buf *agbp,
> > + xfs_agnumber_t agno,
> > + xfs_agblock_t agbno,
> > + xfs_extlen_t aglen,
> > + struct xfs_bmap_free *flist)
> > +{
> > + trace_xfs_refcount_increase(mp, agno, agbno, aglen);
> > + return xfs_refcountbt_adjust_refcount(mp, tp, agbp, agno, agbno,
> > + aglen, 1, flist, NULL);
> > +}
> > +
> > +/**
> > + * Decrease the reference count of a range of AG blocks.
> > + *
> > + * @mp: XFS mount object
> > + * @tp: XFS transaction object
> > + * @agbp: Buffer containing the AGF
> > + * @agno: AG number
> > + * @agbno: Start of range to adjust
> > + * @aglen: Length of range to adjust
> > + * @flist: List of blocks to free
> > + * @owner: Extent owner
> > + */
> > +int
> > +xfs_refcount_decrease(
> > + struct xfs_mount *mp,
> > + struct xfs_trans *tp,
> > + struct xfs_buf *agbp,
> > + xfs_agnumber_t agno,
> > + xfs_agblock_t agbno,
> > + xfs_extlen_t aglen,
> > + struct xfs_bmap_free *flist,
> > + struct xfs_owner_info *oinfo)
> > +{
> > + trace_xfs_refcount_decrease(mp, agno, agbno, aglen);
> > + return xfs_refcountbt_adjust_refcount(mp, tp, agbp, agno, agbno,
> > + aglen, -1, flist, oinfo);
> > +}
> > diff --git a/fs/xfs/libxfs/xfs_refcount.h b/fs/xfs/libxfs/xfs_refcount.h
> > index 033a9b1..6640e3d 100644
> > --- a/fs/xfs/libxfs/xfs_refcount.h
> > +++ b/fs/xfs/libxfs/xfs_refcount.h
> > @@ -26,4 +26,12 @@ extern int xfs_refcountbt_lookup_ge(struct xfs_btree_cur *cur,
> > extern int xfs_refcountbt_get_rec(struct xfs_btree_cur *cur,
> > struct xfs_refcount_irec *irec, int *stat);
> >
> > +extern int xfs_refcount_increase(struct xfs_mount *mp, struct xfs_trans *tp,
> > + struct xfs_buf *agbp, xfs_agnumber_t agno, xfs_agblock_t agbno,
> > + xfs_extlen_t aglen, struct xfs_bmap_free *flist);
> > +extern int xfs_refcount_decrease(struct xfs_mount *mp, struct xfs_trans *tp,
> > + struct xfs_buf *agbp, xfs_agnumber_t agno, xfs_agblock_t agbno,
> > + xfs_extlen_t aglen, struct xfs_bmap_free *flist,
> > + struct xfs_owner_info *oinfo);
> > +
> > #endif /* __XFS_REFCOUNT_H__ */
> >
> > _______________________________________________
> > xfs mailing list
> > xfs@oss.sgi.com
> > http://oss.sgi.com/mailman/listinfo/xfs
>
> _______________________________________________
> xfs mailing list
> xfs@oss.sgi.com
> http://oss.sgi.com/mailman/listinfo/xfs
next prev parent reply other threads:[~2015-10-30 20:56 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-10-07 4:54 [RFCv3 00/58] xfs: add reverse-mapping, reflink, and dedupe support Darrick J. Wong
2015-10-07 4:54 ` [PATCH 01/58] libxfs: make xfs_alloc_fix_freelist non-static Darrick J. Wong
2015-10-07 4:54 ` [PATCH 02/58] xfs: fix log ticket type printing Darrick J. Wong
2015-10-07 4:55 ` [PATCH 03/58] xfs: introduce rmap btree definitions Darrick J. Wong
2015-10-07 4:55 ` [PATCH 04/58] xfs: add rmap btree stats infrastructure Darrick J. Wong
2015-10-07 4:55 ` [PATCH 05/58] xfs: rmap btree add more reserved blocks Darrick J. Wong
2015-10-07 4:55 ` [PATCH 06/58] xfs: add owner field to extent allocation and freeing Darrick J. Wong
2015-10-07 4:55 ` [PATCH 07/58] xfs: add extended " Darrick J. Wong
2015-10-07 4:55 ` [PATCH 08/58] xfs: introduce rmap extent operation stubs Darrick J. Wong
2015-10-07 4:55 ` [PATCH 09/58] xfs: extend rmap extent operation stubs to take full owner info Darrick J. Wong
2015-10-07 4:55 ` [PATCH 10/58] xfs: define the on-disk rmap btree format Darrick J. Wong
2015-10-07 4:55 ` [PATCH 11/58] xfs: enhance " Darrick J. Wong
2015-10-07 4:56 ` [PATCH 12/58] xfs: add rmap btree growfs support Darrick J. Wong
2015-10-07 4:56 ` [PATCH 13/58] xfs: enhance " Darrick J. Wong
2015-10-07 4:56 ` [PATCH 14/58] xfs: rmap btree transaction reservations Darrick J. Wong
2015-10-07 4:56 ` [PATCH 15/58] xfs: rmap btree requires more reserved free space Darrick J. Wong
2015-10-07 4:56 ` [PATCH 16/58] libxfs: fix min freelist length calculation Darrick J. Wong
2015-10-07 4:56 ` [PATCH 17/58] xfs: add rmap btree operations Darrick J. Wong
2015-10-07 4:57 ` [PATCH 18/58] xfs: enhance " Darrick J. Wong
2015-10-07 4:57 ` [PATCH 19/58] xfs: add an extent to the rmap btree Darrick J. Wong
2015-10-07 4:57 ` [PATCH 20/58] xfs: add tracepoints for the rmap-mirrors-bmbt functions Darrick J. Wong
2015-10-07 4:57 ` [PATCH 21/58] xfs: teach rmap_alloc how to deal with our larger rmap btree Darrick J. Wong
2015-10-07 4:57 ` [PATCH 22/58] xfs: remove an extent from the " Darrick J. Wong
2015-10-07 4:57 ` [PATCH 23/58] xfs: enhanced " Darrick J. Wong
2015-10-07 4:57 ` [PATCH 24/58] xfs: add rmap btree insert and delete helpers Darrick J. Wong
2015-10-07 4:57 ` [PATCH 25/58] xfs: bmap btree changes should update rmap btree Darrick J. Wong
2015-10-21 21:39 ` Darrick J. Wong
2015-10-07 4:57 ` [PATCH 26/58] xfs: add rmap btree geometry feature flag Darrick J. Wong
2015-10-07 4:58 ` [PATCH 27/58] xfs: add rmap btree block detection to log recovery Darrick J. Wong
2015-10-07 4:58 ` [PATCH 28/58] xfs: enable the rmap btree functionality Darrick J. Wong
2015-10-07 4:58 ` [PATCH 29/58] xfs: disable XFS_IOC_SWAPEXT when rmap btree is enabled Darrick J. Wong
2015-10-07 4:58 ` [PATCH 30/58] xfs: implement " Darrick J. Wong
2015-10-07 4:58 ` [PATCH 31/58] libxfs: refactor short btree block verification Darrick J. Wong
2015-10-07 4:58 ` [PATCH 32/58] xfs: don't update rmapbt when fixing agfl Darrick J. Wong
2015-10-07 4:58 ` [PATCH 33/58] xfs: introduce refcount btree definitions Darrick J. Wong
2015-10-07 4:58 ` [PATCH 34/58] xfs: add refcount btree stats infrastructure Darrick J. Wong
2015-10-07 4:58 ` [PATCH 35/58] xfs: refcount btree add more reserved blocks Darrick J. Wong
2015-10-07 4:59 ` [PATCH 36/58] xfs: define the on-disk refcount btree format Darrick J. Wong
2015-10-07 4:59 ` [PATCH 37/58] xfs: define tracepoints for refcount/reflink activities Darrick J. Wong
2015-10-07 4:59 ` [PATCH 38/58] xfs: add refcount btree support to growfs Darrick J. Wong
2015-10-07 4:59 ` [PATCH 39/58] xfs: add refcount btree operations Darrick J. Wong
2015-10-07 4:59 ` [PATCH 40/58] libxfs: adjust refcount of an extent of blocks in refcount btree Darrick J. Wong
2015-10-27 19:05 ` Darrick J. Wong
2015-10-30 20:56 ` Darrick J. Wong [this message]
2015-10-07 4:59 ` [PATCH 41/58] libxfs: adjust refcount when unmapping file blocks Darrick J. Wong
2015-10-07 4:59 ` [PATCH 42/58] xfs: add refcount btree block detection to log recovery Darrick J. Wong
2015-10-07 4:59 ` [PATCH 43/58] xfs: map an inode's offset to an exact physical block Darrick J. Wong
2015-10-07 4:59 ` [PATCH 44/58] xfs: add reflink feature flag to geometry Darrick J. Wong
2015-10-07 5:00 ` [PATCH 45/58] xfs: create a separate workqueue for copy-on-write activities Darrick J. Wong
2015-10-07 5:00 ` [PATCH 46/58] xfs: implement copy-on-write for reflinked blocks Darrick J. Wong
2015-10-07 5:00 ` [PATCH 47/58] xfs: handle directio " Darrick J. Wong
2015-10-07 5:00 ` [PATCH 48/58] xfs: copy-on-write reflinked blocks when zeroing ranges of blocks Darrick J. Wong
2015-10-21 21:17 ` Darrick J. Wong
2015-10-07 5:00 ` [PATCH 49/58] xfs: clear inode reflink flag when freeing blocks Darrick J. Wong
2015-10-07 5:00 ` [PATCH 50/58] xfs: reflink extents from one file to another Darrick J. Wong
2015-10-07 5:12 ` kbuild test robot
2015-10-07 5:00 ` [PATCH 51/58] xfs: add clone file and clone range ioctls Darrick J. Wong
2015-10-07 5:13 ` kbuild test robot
2015-10-07 6:46 ` kbuild test robot
2015-10-07 7:35 ` kbuild test robot
2015-10-07 5:00 ` [PATCH 52/58] xfs: emulate the btrfs dedupe extent same ioctl Darrick J. Wong
2015-10-07 5:00 ` [PATCH 53/58] xfs: teach fiemap about reflink'd extents Darrick J. Wong
2015-10-07 5:01 ` [PATCH 54/58] xfs: swap inode reflink flags when swapping inode extents Darrick J. Wong
2015-10-07 5:01 ` [PATCH 55/58] vfs: add a FALLOC_FL_UNSHARE mode to fallocate to unshare a range of blocks Darrick J. Wong
2015-10-07 5:01 ` [PATCH 56/58] xfs: unshare a range of blocks via fallocate Darrick J. Wong
2015-10-07 5:01 ` [PATCH 57/58] xfs: support XFS_XFLAG_REFLINK (and FS_NOCOW_FL) on reflink filesystems Darrick J. Wong
2015-10-07 5:01 ` [PATCH 58/58] xfs: recognize the reflink feature bit Darrick J. Wong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20151030205602.GP10397@birch.djwong.org \
--to=darrick.wong@oracle.com \
--cc=david@fromorbit.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=xfs@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).