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 25/58] xfs: bmap btree changes should update rmap btree Date: Wed, 21 Oct 2015 14:39:53 -0700 [thread overview] Message-ID: <20151021213953.GN10397@birch.djwong.org> (raw) In-Reply-To: <20151007045752.30457.78721.stgit@birch.djwong.org> On Tue, Oct 06, 2015 at 09:57:52PM -0700, Darrick J. Wong wrote: > Any update to a file's bmap should make the corresponding change to > the rmapbt. On a reflink filesystem, this is absolutely required > because a given (file data) physical block can have multiple owners > and the only sane way to find an rmap given a bmap is if there is a > 1:1 correspondence. > > (At some point we can optimize this for non-reflink filesystems > because regular merge still works there.) Still working on this; xfs_repair will have to be taught to merge the extent rmaps for non-reflink filesystems, and the functions that are called by the functions in xfs_bmap.c will of course need to be shut off on !reflink. > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> > --- > fs/xfs/libxfs/xfs_bmap.c | 262 ++++++++++++++++++++++++++++++++++- > fs/xfs/libxfs/xfs_bmap.h | 1 > fs/xfs/libxfs/xfs_rmap.c | 296 ++++++++++++++++++++++++++++++++++++++++ > fs/xfs/libxfs/xfs_rmap_btree.h | 20 +++ > 4 files changed, 568 insertions(+), 11 deletions(-) > > > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c > index e740ef5..81f0ae0 100644 > --- a/fs/xfs/libxfs/xfs_bmap.c > +++ b/fs/xfs/libxfs/xfs_bmap.c > @@ -45,6 +45,7 @@ > #include "xfs_symlink.h" > #include "xfs_attr_leaf.h" > #include "xfs_filestream.h" > +#include "xfs_rmap_btree.h" > > > kmem_zone_t *xfs_bmap_free_item_zone; > @@ -1861,6 +1862,10 @@ xfs_bmap_add_extent_delay_real( > if (error) > goto done; > } > + error = xfs_rmap_combine(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, &LEFT, &RIGHT, &PREV); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: > @@ -1893,6 +1898,10 @@ xfs_bmap_add_extent_delay_real( > if (error) > goto done; > } > + error = xfs_rmap_lcombine(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, &LEFT, &PREV); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: > @@ -1924,6 +1933,10 @@ xfs_bmap_add_extent_delay_real( > if (error) > goto done; > } > + error = xfs_rmap_rcombine(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, &RIGHT, &PREV, new); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: > @@ -1953,6 +1966,10 @@ xfs_bmap_add_extent_delay_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_insert(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG: > @@ -1988,6 +2005,10 @@ xfs_bmap_add_extent_delay_real( > if (error) > goto done; > } > + error = xfs_rmap_lcombine(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, &LEFT, new); > + if (error) > + goto done; > da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), > startblockval(PREV.br_startblock)); > xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); > @@ -2023,6 +2044,10 @@ xfs_bmap_add_extent_delay_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_insert(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > > if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { > error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, > @@ -2071,6 +2096,8 @@ xfs_bmap_add_extent_delay_real( > if (error) > goto done; > } > + error = xfs_rmap_rcombine(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, &RIGHT, new, new); > > da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), > startblockval(PREV.br_startblock)); > @@ -2107,6 +2134,10 @@ xfs_bmap_add_extent_delay_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_insert(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > > if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { > error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, > @@ -2176,6 +2207,10 @@ xfs_bmap_add_extent_delay_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_insert(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > > if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { > error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, > @@ -2271,7 +2306,8 @@ xfs_bmap_add_extent_unwritten_real( > xfs_bmbt_irec_t *new, /* new data to add to file extents */ > xfs_fsblock_t *first, /* pointer to firstblock variable */ > xfs_bmap_free_t *flist, /* list of extents to be freed */ > - int *logflagsp) /* inode logging flags */ > + int *logflagsp, /* inode logging flags */ > + struct xfs_btree_cur *rcur)/* rmap btree pointer */ > { > xfs_btree_cur_t *cur; /* btree cursor */ > xfs_bmbt_rec_host_t *ep; /* extent entry for idx */ > @@ -2417,6 +2453,10 @@ xfs_bmap_add_extent_unwritten_real( > RIGHT.br_blockcount, LEFT.br_state))) > goto done; > } > + error = xfs_rmap_combine(rcur, ip->i_ino, > + XFS_DATA_FORK, &LEFT, &RIGHT, &PREV); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: > @@ -2454,6 +2494,10 @@ xfs_bmap_add_extent_unwritten_real( > LEFT.br_state))) > goto done; > } > + error = xfs_rmap_lcombine(rcur, ip->i_ino, > + XFS_DATA_FORK, &LEFT, &PREV); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: > @@ -2489,6 +2533,10 @@ xfs_bmap_add_extent_unwritten_real( > newext))) > goto done; > } > + error = xfs_rmap_rcombine(rcur, ip->i_ino, > + XFS_DATA_FORK, &RIGHT, &PREV, new); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: Missing a xfs_rmap operation to update the rmap here. > @@ -2562,6 +2610,14 @@ xfs_bmap_add_extent_unwritten_real( > if (error) > goto done; > } > + error = xfs_rmap_move(rcur, ip->i_ino, > + XFS_DATA_FORK, &PREV, new->br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_resize(rcur, ip->i_ino, > + XFS_DATA_FORK, &LEFT, -new->br_blockcount); The move operation moves the start of PREV rightward, so the arg to resize should be positive to make LEFT bigger. > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING: > @@ -2600,6 +2656,14 @@ xfs_bmap_add_extent_unwritten_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_move(rcur, ip->i_ino, > + XFS_DATA_FORK, &PREV, new->br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_insert(rcur, ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > break; > > case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: > @@ -2642,6 +2706,14 @@ xfs_bmap_add_extent_unwritten_real( > newext))) > goto done; > } > + error = xfs_rmap_resize(rcur, ip->i_ino, > + XFS_DATA_FORK, &PREV, -new->br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_move(rcur, ip->i_ino, > + XFS_DATA_FORK, &RIGHT, -new->br_blockcount); > + if (error) > + goto done; > break; > > case BMAP_RIGHT_FILLING: > @@ -2682,6 +2754,14 @@ xfs_bmap_add_extent_unwritten_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_resize(rcur, ip->i_ino, > + XFS_DATA_FORK, &PREV, -new->br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_insert(rcur, ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > break; > > case 0: > @@ -2743,6 +2823,17 @@ xfs_bmap_add_extent_unwritten_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_resize(rcur, ip->i_ino, XFS_DATA_FORK, &PREV, > + new->br_startoff - PREV.br_startoff - > + PREV.br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_insert(rcur, ip->i_ino, XFS_DATA_FORK, new); > + if (error) > + goto done; > + error = xfs_rmap_insert(rcur, ip->i_ino, XFS_DATA_FORK, &r[1]); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: > @@ -2946,6 +3037,7 @@ xfs_bmap_add_extent_hole_real( > int rval=0; /* return value (logging flags) */ > int state; /* state bits, accessed thru macros */ > struct xfs_mount *mp; > + struct xfs_bmbt_irec prev; /* fake previous extent entry */ > > mp = bma->tp ? bma->tp->t_mountp : NULL; > ifp = XFS_IFORK_PTR(bma->ip, whichfork); > @@ -3053,6 +3145,12 @@ xfs_bmap_add_extent_hole_real( > if (error) > goto done; > } > + prev = *new; > + prev.br_startblock = nullstartblock(0); > + error = xfs_rmap_combine(bma->rcur, bma->ip->i_ino, > + whichfork, &left, &right, &prev); > + if (error) > + goto done; > break; > > case BMAP_LEFT_CONTIG: > @@ -3085,6 +3183,10 @@ xfs_bmap_add_extent_hole_real( > if (error) > goto done; > } > + error = xfs_rmap_resize(bma->rcur, bma->ip->i_ino, > + whichfork, &left, new->br_blockcount); > + if (error) > + goto done; > break; > > case BMAP_RIGHT_CONTIG: > @@ -3119,6 +3221,10 @@ xfs_bmap_add_extent_hole_real( > if (error) > goto done; > } > + error = xfs_rmap_move(bma->rcur, bma->ip->i_ino, > + whichfork, &right, -new->br_blockcount); > + if (error) > + goto done; > break; > > case 0: > @@ -3147,6 +3253,10 @@ xfs_bmap_add_extent_hole_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_insert(bma->rcur, bma->ip->i_ino, > + whichfork, new); > + if (error) > + goto done; > break; > } > > @@ -4276,6 +4386,59 @@ xfs_bmapi_delay( > return 0; > } > > +static int > +alloc_rcur( > + struct xfs_mount *mp, > + struct xfs_trans *tp, > + struct xfs_btree_cur **pcur, > + xfs_fsblock_t fsblock) > +{ > + struct xfs_btree_cur *cur = *pcur; > + struct xfs_buf *agbp; > + int error; > + xfs_agnumber_t agno; > + > + agno = XFS_FSB_TO_AGNO(mp, fsblock); > + if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) > + return 0; > + if (cur && cur->bc_private.a.agno == agno) > + return 0; > + if (isnullstartblock(fsblock)) > + return 0; > + > + error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); > + if (error) > + return error; > + > + cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); > + if (!cur) { > + xfs_trans_brelse(tp, agbp); > + return -ENOMEM; > + } > + > + *pcur = cur; > + return 0; > +} > + > +static void > +free_rcur( > + struct xfs_btree_cur **pcur, > + int bt_error) > +{ > + struct xfs_btree_cur *cur = *pcur; > + struct xfs_buf *agbp; > + struct xfs_trans *tp; > + > + if (cur == NULL) > + return; > + > + agbp = cur->bc_private.a.agbp; > + tp = cur->bc_tp; > + xfs_btree_del_cursor(cur, bt_error); > + xfs_trans_brelse(tp, agbp); > + > + *pcur = NULL; > +} So this whole strategy of updating rmaps right after updating the bmbt has an unfortunate flaw -- we iterate file extents in logical offset order, which means that we have no guarantee that the extents we process will be in order of increasing AG. This violates the deadlock prevention rule that says we must only lock thing in increasing AG order, and indeed I've seen some deadlocks with generic/013. A solution to this is to pursue a strategy similar to the xfs_bmap_free list handling -- collect rmap update intents in a list that's kept sorted in first AG and then chronological order, then when we're done making bmbt updates we can use xfs_trans_roll to make all the rmapbt updates in AG order as part of a separate transaction. I don't know if that's a good strategy since it means that bmbt and rmapbt updates commit in different transactions, but it at least gets rid of some deadlock opportunities. A side benefit is that we can hang the rmap intents off the xfs_bmap_free structure which should reduce the amount of code changes. > > static int > xfs_bmapi_allocate( > @@ -4368,6 +4531,10 @@ xfs_bmapi_allocate( > xfs_sb_version_hasextflgbit(&mp->m_sb)) > bma->got.br_state = XFS_EXT_UNWRITTEN; > > + error = alloc_rcur(mp, bma->tp, &bma->rcur, bma->got.br_startblock); > + if (error) > + return error; > + > if (bma->wasdel) > error = xfs_bmap_add_extent_delay_real(bma); > else > @@ -4429,9 +4596,14 @@ xfs_bmapi_convert_unwritten( > mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN) > ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN; > > + error = alloc_rcur(bma->ip->i_mount, bma->tp, &bma->rcur, > + mval->br_startblock); > + if (error) > + return error; > + > error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, &bma->idx, > &bma->cur, mval, bma->firstblock, bma->flist, > - &tmp_logflags); > + &tmp_logflags, bma->rcur); > /* > * Log the inode core unconditionally in the unwritten extent conversion > * path because the conversion might not have done so (e.g., if the > @@ -4633,6 +4805,7 @@ xfs_bmapi_write( > } > *nmap = n; > > + free_rcur(&bma.rcur, XFS_BTREE_NOERROR); > /* > * Transform from btree to extents, give it cur. > */ > @@ -4652,6 +4825,7 @@ xfs_bmapi_write( > XFS_IFORK_MAXEXT(ip, whichfork)); > error = 0; > error0: > + free_rcur(&bma.rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); > /* > * Log everything. Do this after conversion, there's no point in > * logging the extent records if we've converted to btree format. > @@ -4704,7 +4878,8 @@ xfs_bmap_del_extent( > xfs_btree_cur_t *cur, /* if null, not a btree */ > xfs_bmbt_irec_t *del, /* data to remove from extents */ > int *logflagsp, /* inode logging flags */ > - int whichfork) /* data or attr fork */ > + int whichfork, /* data or attr fork */ > + struct xfs_btree_cur *rcur) /* rmap btree */ > { > xfs_filblks_t da_new; /* new delay-alloc indirect blocks */ > xfs_filblks_t da_old; /* old delay-alloc indirect blocks */ > @@ -4822,6 +4997,9 @@ xfs_bmap_del_extent( > XFS_IFORK_NEXT_SET(ip, whichfork, > XFS_IFORK_NEXTENTS(ip, whichfork) - 1); > flags |= XFS_ILOG_CORE; > + error = xfs_rmap_delete(rcur, ip->i_ino, whichfork, &got); > + if (error) > + goto done; > if (!cur) { > flags |= xfs_ilog_fext(whichfork); > break; > @@ -4849,6 +5027,10 @@ xfs_bmap_del_extent( > } > xfs_bmbt_set_startblock(ep, del_endblock); > trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); > + error = xfs_rmap_move(rcur, ip->i_ino, whichfork, > + &got, del->br_blockcount); > + if (error) > + goto done; > if (!cur) { > flags |= xfs_ilog_fext(whichfork); > break; > @@ -4875,6 +5057,10 @@ xfs_bmap_del_extent( > break; > } > trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); > + error = xfs_rmap_resize(rcur, ip->i_ino, whichfork, > + &got, -del->br_blockcount); > + if (error) > + goto done; > if (!cur) { > flags |= xfs_ilog_fext(whichfork); > break; > @@ -4900,6 +5086,15 @@ xfs_bmap_del_extent( > if (!delay) { > new.br_startblock = del_endblock; > flags |= XFS_ILOG_CORE; > + error = xfs_rmap_resize(rcur, ip->i_ino, > + whichfork, &got, > + temp - got.br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_insert(rcur, ip->i_ino, > + whichfork, &new); > + if (error) > + goto done; > if (cur) { > if ((error = xfs_bmbt_update(cur, > got.br_startoff, > @@ -5052,6 +5247,7 @@ xfs_bunmapi( > int wasdel; /* was a delayed alloc extent */ > int whichfork; /* data or attribute fork */ > xfs_fsblock_t sum; > + struct xfs_btree_cur *rcur = NULL; /* rmap btree */ > > trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_); > > @@ -5136,6 +5332,11 @@ xfs_bunmapi( > got.br_startoff + got.br_blockcount - 1); > if (bno < start) > break; > + > + error = alloc_rcur(mp, tp, &rcur, got.br_startblock); > + if (error) > + goto error0; > + > /* > * Then deal with the (possibly delayed) allocated space > * we found. > @@ -5195,7 +5396,7 @@ xfs_bunmapi( > del.br_state = XFS_EXT_UNWRITTEN; > error = xfs_bmap_add_extent_unwritten_real(tp, ip, > &lastx, &cur, &del, firstblock, flist, > - &logflags); > + &logflags, rcur); > if (error) > goto error0; > goto nodelete; > @@ -5253,7 +5454,8 @@ xfs_bunmapi( > lastx--; > error = xfs_bmap_add_extent_unwritten_real(tp, > ip, &lastx, &cur, &prev, > - firstblock, flist, &logflags); > + firstblock, flist, &logflags, > + rcur); > if (error) > goto error0; > goto nodelete; > @@ -5262,7 +5464,8 @@ xfs_bunmapi( > del.br_state = XFS_EXT_UNWRITTEN; > error = xfs_bmap_add_extent_unwritten_real(tp, > ip, &lastx, &cur, &del, > - firstblock, flist, &logflags); > + firstblock, flist, &logflags, > + rcur); > if (error) > goto error0; > goto nodelete; > @@ -5315,7 +5518,7 @@ xfs_bunmapi( > goto error0; > } > error = xfs_bmap_del_extent(ip, tp, &lastx, flist, cur, &del, > - &tmp_logflags, whichfork); > + &tmp_logflags, whichfork, rcur); > logflags |= tmp_logflags; > if (error) > goto error0; > @@ -5339,6 +5542,7 @@ nodelete: > } > *done = bno == (xfs_fileoff_t)-1 || bno < start || lastx < 0; > > + free_rcur(&rcur, XFS_BTREE_NOERROR); > /* > * Convert to a btree if necessary. > */ > @@ -5366,6 +5570,7 @@ nodelete: > */ > error = 0; > error0: > + free_rcur(&rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); > /* > * Log everything. Do this after conversion, there's no point in > * logging the extent records if we've converted to btree format. > @@ -5438,7 +5643,8 @@ xfs_bmse_merge( > struct xfs_bmbt_rec_host *gotp, /* extent to shift */ > struct xfs_bmbt_rec_host *leftp, /* preceding extent */ > struct xfs_btree_cur *cur, > - int *logflags) /* output */ > + int *logflags, /* output */ > + struct xfs_btree_cur *rcur) /* rmap btree */ > { > struct xfs_bmbt_irec got; > struct xfs_bmbt_irec left; > @@ -5469,6 +5675,13 @@ xfs_bmse_merge( > XFS_IFORK_NEXT_SET(ip, whichfork, > XFS_IFORK_NEXTENTS(ip, whichfork) - 1); > *logflags |= XFS_ILOG_CORE; > + error = xfs_rmap_resize(rcur, ip->i_ino, whichfork, &left, > + blockcount - left.br_blockcount); > + if (error) > + return error; > + error = xfs_rmap_delete(rcur, ip->i_ino, whichfork, &got); > + if (error) > + return error; > if (!cur) { > *logflags |= XFS_ILOG_DEXT; > return 0; > @@ -5511,7 +5724,8 @@ xfs_bmse_shift_one( > struct xfs_bmbt_rec_host *gotp, > struct xfs_btree_cur *cur, > int *logflags, > - enum shift_direction direction) > + enum shift_direction direction, > + struct xfs_btree_cur *rcur) > { > struct xfs_ifork *ifp; > struct xfs_mount *mp; > @@ -5561,7 +5775,7 @@ xfs_bmse_shift_one( > offset_shift_fsb)) { > return xfs_bmse_merge(ip, whichfork, offset_shift_fsb, > *current_ext, gotp, adj_irecp, > - cur, logflags); > + cur, logflags, rcur); > } > } else { > startoff = got.br_startoff + offset_shift_fsb; > @@ -5598,6 +5812,10 @@ update_current_ext: > (*current_ext)--; > xfs_bmbt_set_startoff(gotp, startoff); > *logflags |= XFS_ILOG_CORE; > + error = xfs_rmap_slide(rcur, ip->i_ino, whichfork, > + &got, startoff - got.br_startoff); > + if (error) > + return error; > if (!cur) { > *logflags |= XFS_ILOG_DEXT; > return 0; > @@ -5649,6 +5867,7 @@ xfs_bmap_shift_extents( > int error = 0; > int whichfork = XFS_DATA_FORK; > int logflags = 0; > + struct xfs_btree_cur *rcur = NULL; > > if (unlikely(XFS_TEST_ERROR( > (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && > @@ -5737,9 +5956,14 @@ xfs_bmap_shift_extents( > } > > while (nexts++ < num_exts) { > + xfs_bmbt_get_all(gotp, &got); > + error = alloc_rcur(mp, tp, &rcur, got.br_startblock); > + if (error) > + return error; > + > error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb, > ¤t_ext, gotp, cur, &logflags, > - direction); > + direction, rcur); > if (error) > goto del_cursor; > /* > @@ -5765,6 +5989,7 @@ xfs_bmap_shift_extents( > } > > del_cursor: > + free_rcur(&rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); > if (cur) > xfs_btree_del_cursor(cur, > error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); > @@ -5801,6 +6026,7 @@ xfs_bmap_split_extent_at( > int error = 0; > int logflags = 0; > int i = 0; > + struct xfs_btree_cur *rcur = NULL; > > if (unlikely(XFS_TEST_ERROR( > (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && > @@ -5895,6 +6121,18 @@ xfs_bmap_split_extent_at( > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor); > } > > + /* update rmapbt */ > + error = alloc_rcur(mp, tp, &rcur, new.br_startblock); > + if (error) > + goto del_cursor; > + error = xfs_rmap_resize(rcur, ip->i_ino, whichfork, &got, -gotblkcnt); got is modified by the previous code clause, so this causes incorrect rmap entries to end up in the rmapbt. > + if (error) > + goto del_cursor; > + error = xfs_rmap_insert(rcur, ip->i_ino, whichfork, &new); > + if (error) > + goto del_cursor; > + free_rcur(&rcur, XFS_BTREE_NOERROR); > + > /* > * Convert to a btree if necessary. > */ > @@ -5908,6 +6146,8 @@ xfs_bmap_split_extent_at( > } > > del_cursor: > + free_rcur(&rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); > + > if (cur) { > cur->bc_private.b.allocated = 0; > xfs_btree_del_cursor(cur, > diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h > index 89fa3dd..59f26cf 100644 > --- a/fs/xfs/libxfs/xfs_bmap.h > +++ b/fs/xfs/libxfs/xfs_bmap.h > @@ -56,6 +56,7 @@ struct xfs_bmalloca { > bool aeof; /* allocated space at eof */ > bool conv; /* overwriting unwritten extents */ > int flags; > + struct xfs_btree_cur *rcur; /* rmap btree cursor */ > }; > > /* > diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c > index 045f9a7..d821b1a 100644 > --- a/fs/xfs/libxfs/xfs_rmap.c > +++ b/fs/xfs/libxfs/xfs_rmap.c > @@ -563,3 +563,299 @@ out_error: > xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); > return error; > } > + > +/* Encode logical offset for a rmapbt record */ > +STATIC uint64_t > +b2r_off( > + int whichfork, > + xfs_fileoff_t off) > +{ > + uint64_t x; > + > + x = off; > + if (whichfork == XFS_ATTR_FORK) > + x |= XFS_RMAP_OFF_ATTR; > + return x; > +} > + > +/* Encode blockcount for a rmapbt record */ > +STATIC xfs_extlen_t > +b2r_len( > + struct xfs_bmbt_irec *irec) > +{ > + xfs_extlen_t x; > + > + x = irec->br_blockcount; > + if (irec->br_state == XFS_EXT_UNWRITTEN) > + x |= XFS_RMAP_LEN_UNWRITTEN; > + return x; > +} > + > +/* Combine two adjacent rmap extents */ > +int > +xfs_rmap_combine( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *LEFT, > + struct xfs_bmbt_irec *RIGHT, > + struct xfs_bmbt_irec *PREV) > +{ > + int error; > + > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_combine(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, LEFT, PREV, RIGHT); > + > + /* Delete right rmap */ > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, RIGHT->br_startblock), > + b2r_len(RIGHT), ino, > + b2r_off(whichfork, RIGHT->br_startoff)); > + if (error) > + goto done; > + > + /* Delete prev rmap */ > + if (!isnullstartblock(PREV->br_startblock)) { > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, > + PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff)); > + if (error) > + goto done; > + } > + > + /* Enlarge left rmap */ > + return xfs_rmap_resize(rcur, ino, whichfork, LEFT, > + PREV->br_blockcount + RIGHT->br_blockcount); > +done: > + return error; > +} > + > +/* Extend a left rmap extent */ > +int > +xfs_rmap_lcombine( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *LEFT, > + struct xfs_bmbt_irec *PREV) > +{ > + int error; > + > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_lcombine(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, LEFT, PREV); > + > + /* Delete prev rmap */ > + if (!isnullstartblock(PREV->br_startblock)) { > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, > + PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff)); > + if (error) > + goto done; > + } > + > + /* Enlarge left rmap */ > + return xfs_rmap_resize(rcur, ino, whichfork, LEFT, PREV->br_blockcount); > +done: > + return error; > +} > + > +/* Extend a right rmap extent */ > +int > +xfs_rmap_rcombine( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *RIGHT, > + struct xfs_bmbt_irec *PREV, > + struct xfs_bmbt_irec *new) > +{ > + int error; > + > + if (!rcur) > + return 0; > + ASSERT(PREV->br_startoff == new->br_startoff); > + > + trace_xfs_rmap_rcombine(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, RIGHT, PREV); > + > + /* Delete prev rmap */ > + if (!isnullstartblock(PREV->br_startblock)) { > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, > + PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff)); > + if (error) > + goto done; > + } > + > + /* Enlarge right rmap */ > + return xfs_rmap_resize(rcur, ino, whichfork, RIGHT, > + -PREV->br_blockcount); The starting point of RIGHT should be moved leftward to the start of PREV, so this is really an xfs_rmap_move(..., -PREV->br_blockcount); --D > +done: > + return error; > +} > + > +/* Insert a rmap extent */ > +int > +xfs_rmap_insert( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *new) > +{ > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, new); > + > + return xfs_rmapbt_insert(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, new->br_startblock), > + b2r_len(new), ino, > + b2r_off(whichfork, new->br_startoff)); > +} > + > +/* Delete a rmap extent */ > +int > +xfs_rmap_delete( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *new) > +{ > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, new); > + > + return xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, new->br_startblock), > + b2r_len(new), ino, > + b2r_off(whichfork, new->br_startoff)); > +} > + > +/* Change the start of an rmap */ > +int > +xfs_rmap_move( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *PREV, > + long start_adj) > +{ > + int error; > + struct xfs_bmbt_irec irec; > + > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_move(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, PREV, start_adj); > + > + /* Delete prev rmap */ > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff)); > + if (error) > + goto done; > + > + /* Re-add rmap with new start */ > + irec = *PREV; > + irec.br_startblock += start_adj; > + irec.br_startoff += start_adj; > + irec.br_blockcount -= start_adj; > + return xfs_rmapbt_insert(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, irec.br_startblock), > + b2r_len(&irec), ino, > + b2r_off(whichfork, irec.br_startoff)); > +done: > + return error; > +} > + > +/* Change the logical offset of an rmap */ > +int > +xfs_rmap_slide( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *PREV, > + long start_adj) > +{ > + int error; > + > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_slide(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, PREV, start_adj); > + > + /* Delete prev rmap */ > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff)); > + if (error) > + goto done; > + > + /* Re-add rmap with new logical offset */ > + return xfs_rmapbt_insert(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff + start_adj)); > +done: > + return error; > +} > + > +/* Change the size of an rmap */ > +int > +xfs_rmap_resize( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *PREV, > + long size_adj) > +{ > + int i; > + int error; > + struct xfs_bmbt_irec irec; > + struct xfs_rmap_irec rrec; > + > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_resize(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, PREV, size_adj); > + > + error = xfs_rmap_lookup_eq(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff), &i); > + if (error) > + goto done; > + XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done); > + error = xfs_rmap_get_rec(rcur, &rrec, &i); > + if (error) > + goto done; > + XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done); > + irec = *PREV; > + irec.br_blockcount += size_adj; > + rrec.rm_blockcount = b2r_len(&irec); > + error = xfs_rmap_update(rcur, &rrec); > + if (error) > + goto done; > +done: > + return error; > +} > diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h > index d7c9722..0131d9a 100644 > --- a/fs/xfs/libxfs/xfs_rmap_btree.h > +++ b/fs/xfs/libxfs/xfs_rmap_btree.h > @@ -68,4 +68,24 @@ int xfs_rmap_free(struct xfs_trans *tp, struct xfs_buf *agbp, > xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, > struct xfs_owner_info *oinfo); > > +/* functions for updating the rmapbt based on bmbt map/unmap operations */ > +int xfs_rmap_combine(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *LEFT, struct xfs_bmbt_irec *RIGHT, > + struct xfs_bmbt_irec *PREV); > +int xfs_rmap_lcombine(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *LEFT, struct xfs_bmbt_irec *PREV); > +int xfs_rmap_rcombine(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *RIGHT, struct xfs_bmbt_irec *PREV, > + struct xfs_bmbt_irec *new); > +int xfs_rmap_insert(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *new); > +int xfs_rmap_delete(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *new); > +int xfs_rmap_move(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *PREV, long start_adj); > +int xfs_rmap_slide(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *PREV, long start_adj); > +int xfs_rmap_resize(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *PREV, long size_adj); > + > #endif /* __XFS_RMAP_BTREE_H__ */ > > _______________________________________________ > xfs mailing list > xfs@oss.sgi.com > http://oss.sgi.com/mailman/listinfo/xfs
WARNING: multiple messages have this Message-ID (diff)
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 25/58] xfs: bmap btree changes should update rmap btree Date: Wed, 21 Oct 2015 14:39:53 -0700 [thread overview] Message-ID: <20151021213953.GN10397@birch.djwong.org> (raw) In-Reply-To: <20151007045752.30457.78721.stgit@birch.djwong.org> On Tue, Oct 06, 2015 at 09:57:52PM -0700, Darrick J. Wong wrote: > Any update to a file's bmap should make the corresponding change to > the rmapbt. On a reflink filesystem, this is absolutely required > because a given (file data) physical block can have multiple owners > and the only sane way to find an rmap given a bmap is if there is a > 1:1 correspondence. > > (At some point we can optimize this for non-reflink filesystems > because regular merge still works there.) Still working on this; xfs_repair will have to be taught to merge the extent rmaps for non-reflink filesystems, and the functions that are called by the functions in xfs_bmap.c will of course need to be shut off on !reflink. > > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> > --- > fs/xfs/libxfs/xfs_bmap.c | 262 ++++++++++++++++++++++++++++++++++- > fs/xfs/libxfs/xfs_bmap.h | 1 > fs/xfs/libxfs/xfs_rmap.c | 296 ++++++++++++++++++++++++++++++++++++++++ > fs/xfs/libxfs/xfs_rmap_btree.h | 20 +++ > 4 files changed, 568 insertions(+), 11 deletions(-) > > > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c > index e740ef5..81f0ae0 100644 > --- a/fs/xfs/libxfs/xfs_bmap.c > +++ b/fs/xfs/libxfs/xfs_bmap.c > @@ -45,6 +45,7 @@ > #include "xfs_symlink.h" > #include "xfs_attr_leaf.h" > #include "xfs_filestream.h" > +#include "xfs_rmap_btree.h" > > > kmem_zone_t *xfs_bmap_free_item_zone; > @@ -1861,6 +1862,10 @@ xfs_bmap_add_extent_delay_real( > if (error) > goto done; > } > + error = xfs_rmap_combine(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, &LEFT, &RIGHT, &PREV); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: > @@ -1893,6 +1898,10 @@ xfs_bmap_add_extent_delay_real( > if (error) > goto done; > } > + error = xfs_rmap_lcombine(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, &LEFT, &PREV); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: > @@ -1924,6 +1933,10 @@ xfs_bmap_add_extent_delay_real( > if (error) > goto done; > } > + error = xfs_rmap_rcombine(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, &RIGHT, &PREV, new); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: > @@ -1953,6 +1966,10 @@ xfs_bmap_add_extent_delay_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_insert(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG: > @@ -1988,6 +2005,10 @@ xfs_bmap_add_extent_delay_real( > if (error) > goto done; > } > + error = xfs_rmap_lcombine(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, &LEFT, new); > + if (error) > + goto done; > da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), > startblockval(PREV.br_startblock)); > xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); > @@ -2023,6 +2044,10 @@ xfs_bmap_add_extent_delay_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_insert(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > > if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { > error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, > @@ -2071,6 +2096,8 @@ xfs_bmap_add_extent_delay_real( > if (error) > goto done; > } > + error = xfs_rmap_rcombine(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, &RIGHT, new, new); > > da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), > startblockval(PREV.br_startblock)); > @@ -2107,6 +2134,10 @@ xfs_bmap_add_extent_delay_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_insert(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > > if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { > error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, > @@ -2176,6 +2207,10 @@ xfs_bmap_add_extent_delay_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_insert(bma->rcur, bma->ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > > if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { > error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, > @@ -2271,7 +2306,8 @@ xfs_bmap_add_extent_unwritten_real( > xfs_bmbt_irec_t *new, /* new data to add to file extents */ > xfs_fsblock_t *first, /* pointer to firstblock variable */ > xfs_bmap_free_t *flist, /* list of extents to be freed */ > - int *logflagsp) /* inode logging flags */ > + int *logflagsp, /* inode logging flags */ > + struct xfs_btree_cur *rcur)/* rmap btree pointer */ > { > xfs_btree_cur_t *cur; /* btree cursor */ > xfs_bmbt_rec_host_t *ep; /* extent entry for idx */ > @@ -2417,6 +2453,10 @@ xfs_bmap_add_extent_unwritten_real( > RIGHT.br_blockcount, LEFT.br_state))) > goto done; > } > + error = xfs_rmap_combine(rcur, ip->i_ino, > + XFS_DATA_FORK, &LEFT, &RIGHT, &PREV); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: > @@ -2454,6 +2494,10 @@ xfs_bmap_add_extent_unwritten_real( > LEFT.br_state))) > goto done; > } > + error = xfs_rmap_lcombine(rcur, ip->i_ino, > + XFS_DATA_FORK, &LEFT, &PREV); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: > @@ -2489,6 +2533,10 @@ xfs_bmap_add_extent_unwritten_real( > newext))) > goto done; > } > + error = xfs_rmap_rcombine(rcur, ip->i_ino, > + XFS_DATA_FORK, &RIGHT, &PREV, new); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: Missing a xfs_rmap operation to update the rmap here. > @@ -2562,6 +2610,14 @@ xfs_bmap_add_extent_unwritten_real( > if (error) > goto done; > } > + error = xfs_rmap_move(rcur, ip->i_ino, > + XFS_DATA_FORK, &PREV, new->br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_resize(rcur, ip->i_ino, > + XFS_DATA_FORK, &LEFT, -new->br_blockcount); The move operation moves the start of PREV rightward, so the arg to resize should be positive to make LEFT bigger. > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING: > @@ -2600,6 +2656,14 @@ xfs_bmap_add_extent_unwritten_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_move(rcur, ip->i_ino, > + XFS_DATA_FORK, &PREV, new->br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_insert(rcur, ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > break; > > case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: > @@ -2642,6 +2706,14 @@ xfs_bmap_add_extent_unwritten_real( > newext))) > goto done; > } > + error = xfs_rmap_resize(rcur, ip->i_ino, > + XFS_DATA_FORK, &PREV, -new->br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_move(rcur, ip->i_ino, > + XFS_DATA_FORK, &RIGHT, -new->br_blockcount); > + if (error) > + goto done; > break; > > case BMAP_RIGHT_FILLING: > @@ -2682,6 +2754,14 @@ xfs_bmap_add_extent_unwritten_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_resize(rcur, ip->i_ino, > + XFS_DATA_FORK, &PREV, -new->br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_insert(rcur, ip->i_ino, > + XFS_DATA_FORK, new); > + if (error) > + goto done; > break; > > case 0: > @@ -2743,6 +2823,17 @@ xfs_bmap_add_extent_unwritten_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_resize(rcur, ip->i_ino, XFS_DATA_FORK, &PREV, > + new->br_startoff - PREV.br_startoff - > + PREV.br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_insert(rcur, ip->i_ino, XFS_DATA_FORK, new); > + if (error) > + goto done; > + error = xfs_rmap_insert(rcur, ip->i_ino, XFS_DATA_FORK, &r[1]); > + if (error) > + goto done; > break; > > case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: > @@ -2946,6 +3037,7 @@ xfs_bmap_add_extent_hole_real( > int rval=0; /* return value (logging flags) */ > int state; /* state bits, accessed thru macros */ > struct xfs_mount *mp; > + struct xfs_bmbt_irec prev; /* fake previous extent entry */ > > mp = bma->tp ? bma->tp->t_mountp : NULL; > ifp = XFS_IFORK_PTR(bma->ip, whichfork); > @@ -3053,6 +3145,12 @@ xfs_bmap_add_extent_hole_real( > if (error) > goto done; > } > + prev = *new; > + prev.br_startblock = nullstartblock(0); > + error = xfs_rmap_combine(bma->rcur, bma->ip->i_ino, > + whichfork, &left, &right, &prev); > + if (error) > + goto done; > break; > > case BMAP_LEFT_CONTIG: > @@ -3085,6 +3183,10 @@ xfs_bmap_add_extent_hole_real( > if (error) > goto done; > } > + error = xfs_rmap_resize(bma->rcur, bma->ip->i_ino, > + whichfork, &left, new->br_blockcount); > + if (error) > + goto done; > break; > > case BMAP_RIGHT_CONTIG: > @@ -3119,6 +3221,10 @@ xfs_bmap_add_extent_hole_real( > if (error) > goto done; > } > + error = xfs_rmap_move(bma->rcur, bma->ip->i_ino, > + whichfork, &right, -new->br_blockcount); > + if (error) > + goto done; > break; > > case 0: > @@ -3147,6 +3253,10 @@ xfs_bmap_add_extent_hole_real( > goto done; > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); > } > + error = xfs_rmap_insert(bma->rcur, bma->ip->i_ino, > + whichfork, new); > + if (error) > + goto done; > break; > } > > @@ -4276,6 +4386,59 @@ xfs_bmapi_delay( > return 0; > } > > +static int > +alloc_rcur( > + struct xfs_mount *mp, > + struct xfs_trans *tp, > + struct xfs_btree_cur **pcur, > + xfs_fsblock_t fsblock) > +{ > + struct xfs_btree_cur *cur = *pcur; > + struct xfs_buf *agbp; > + int error; > + xfs_agnumber_t agno; > + > + agno = XFS_FSB_TO_AGNO(mp, fsblock); > + if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) > + return 0; > + if (cur && cur->bc_private.a.agno == agno) > + return 0; > + if (isnullstartblock(fsblock)) > + return 0; > + > + error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); > + if (error) > + return error; > + > + cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); > + if (!cur) { > + xfs_trans_brelse(tp, agbp); > + return -ENOMEM; > + } > + > + *pcur = cur; > + return 0; > +} > + > +static void > +free_rcur( > + struct xfs_btree_cur **pcur, > + int bt_error) > +{ > + struct xfs_btree_cur *cur = *pcur; > + struct xfs_buf *agbp; > + struct xfs_trans *tp; > + > + if (cur == NULL) > + return; > + > + agbp = cur->bc_private.a.agbp; > + tp = cur->bc_tp; > + xfs_btree_del_cursor(cur, bt_error); > + xfs_trans_brelse(tp, agbp); > + > + *pcur = NULL; > +} So this whole strategy of updating rmaps right after updating the bmbt has an unfortunate flaw -- we iterate file extents in logical offset order, which means that we have no guarantee that the extents we process will be in order of increasing AG. This violates the deadlock prevention rule that says we must only lock thing in increasing AG order, and indeed I've seen some deadlocks with generic/013. A solution to this is to pursue a strategy similar to the xfs_bmap_free list handling -- collect rmap update intents in a list that's kept sorted in first AG and then chronological order, then when we're done making bmbt updates we can use xfs_trans_roll to make all the rmapbt updates in AG order as part of a separate transaction. I don't know if that's a good strategy since it means that bmbt and rmapbt updates commit in different transactions, but it at least gets rid of some deadlock opportunities. A side benefit is that we can hang the rmap intents off the xfs_bmap_free structure which should reduce the amount of code changes. > > static int > xfs_bmapi_allocate( > @@ -4368,6 +4531,10 @@ xfs_bmapi_allocate( > xfs_sb_version_hasextflgbit(&mp->m_sb)) > bma->got.br_state = XFS_EXT_UNWRITTEN; > > + error = alloc_rcur(mp, bma->tp, &bma->rcur, bma->got.br_startblock); > + if (error) > + return error; > + > if (bma->wasdel) > error = xfs_bmap_add_extent_delay_real(bma); > else > @@ -4429,9 +4596,14 @@ xfs_bmapi_convert_unwritten( > mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN) > ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN; > > + error = alloc_rcur(bma->ip->i_mount, bma->tp, &bma->rcur, > + mval->br_startblock); > + if (error) > + return error; > + > error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, &bma->idx, > &bma->cur, mval, bma->firstblock, bma->flist, > - &tmp_logflags); > + &tmp_logflags, bma->rcur); > /* > * Log the inode core unconditionally in the unwritten extent conversion > * path because the conversion might not have done so (e.g., if the > @@ -4633,6 +4805,7 @@ xfs_bmapi_write( > } > *nmap = n; > > + free_rcur(&bma.rcur, XFS_BTREE_NOERROR); > /* > * Transform from btree to extents, give it cur. > */ > @@ -4652,6 +4825,7 @@ xfs_bmapi_write( > XFS_IFORK_MAXEXT(ip, whichfork)); > error = 0; > error0: > + free_rcur(&bma.rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); > /* > * Log everything. Do this after conversion, there's no point in > * logging the extent records if we've converted to btree format. > @@ -4704,7 +4878,8 @@ xfs_bmap_del_extent( > xfs_btree_cur_t *cur, /* if null, not a btree */ > xfs_bmbt_irec_t *del, /* data to remove from extents */ > int *logflagsp, /* inode logging flags */ > - int whichfork) /* data or attr fork */ > + int whichfork, /* data or attr fork */ > + struct xfs_btree_cur *rcur) /* rmap btree */ > { > xfs_filblks_t da_new; /* new delay-alloc indirect blocks */ > xfs_filblks_t da_old; /* old delay-alloc indirect blocks */ > @@ -4822,6 +4997,9 @@ xfs_bmap_del_extent( > XFS_IFORK_NEXT_SET(ip, whichfork, > XFS_IFORK_NEXTENTS(ip, whichfork) - 1); > flags |= XFS_ILOG_CORE; > + error = xfs_rmap_delete(rcur, ip->i_ino, whichfork, &got); > + if (error) > + goto done; > if (!cur) { > flags |= xfs_ilog_fext(whichfork); > break; > @@ -4849,6 +5027,10 @@ xfs_bmap_del_extent( > } > xfs_bmbt_set_startblock(ep, del_endblock); > trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); > + error = xfs_rmap_move(rcur, ip->i_ino, whichfork, > + &got, del->br_blockcount); > + if (error) > + goto done; > if (!cur) { > flags |= xfs_ilog_fext(whichfork); > break; > @@ -4875,6 +5057,10 @@ xfs_bmap_del_extent( > break; > } > trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); > + error = xfs_rmap_resize(rcur, ip->i_ino, whichfork, > + &got, -del->br_blockcount); > + if (error) > + goto done; > if (!cur) { > flags |= xfs_ilog_fext(whichfork); > break; > @@ -4900,6 +5086,15 @@ xfs_bmap_del_extent( > if (!delay) { > new.br_startblock = del_endblock; > flags |= XFS_ILOG_CORE; > + error = xfs_rmap_resize(rcur, ip->i_ino, > + whichfork, &got, > + temp - got.br_blockcount); > + if (error) > + goto done; > + error = xfs_rmap_insert(rcur, ip->i_ino, > + whichfork, &new); > + if (error) > + goto done; > if (cur) { > if ((error = xfs_bmbt_update(cur, > got.br_startoff, > @@ -5052,6 +5247,7 @@ xfs_bunmapi( > int wasdel; /* was a delayed alloc extent */ > int whichfork; /* data or attribute fork */ > xfs_fsblock_t sum; > + struct xfs_btree_cur *rcur = NULL; /* rmap btree */ > > trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_); > > @@ -5136,6 +5332,11 @@ xfs_bunmapi( > got.br_startoff + got.br_blockcount - 1); > if (bno < start) > break; > + > + error = alloc_rcur(mp, tp, &rcur, got.br_startblock); > + if (error) > + goto error0; > + > /* > * Then deal with the (possibly delayed) allocated space > * we found. > @@ -5195,7 +5396,7 @@ xfs_bunmapi( > del.br_state = XFS_EXT_UNWRITTEN; > error = xfs_bmap_add_extent_unwritten_real(tp, ip, > &lastx, &cur, &del, firstblock, flist, > - &logflags); > + &logflags, rcur); > if (error) > goto error0; > goto nodelete; > @@ -5253,7 +5454,8 @@ xfs_bunmapi( > lastx--; > error = xfs_bmap_add_extent_unwritten_real(tp, > ip, &lastx, &cur, &prev, > - firstblock, flist, &logflags); > + firstblock, flist, &logflags, > + rcur); > if (error) > goto error0; > goto nodelete; > @@ -5262,7 +5464,8 @@ xfs_bunmapi( > del.br_state = XFS_EXT_UNWRITTEN; > error = xfs_bmap_add_extent_unwritten_real(tp, > ip, &lastx, &cur, &del, > - firstblock, flist, &logflags); > + firstblock, flist, &logflags, > + rcur); > if (error) > goto error0; > goto nodelete; > @@ -5315,7 +5518,7 @@ xfs_bunmapi( > goto error0; > } > error = xfs_bmap_del_extent(ip, tp, &lastx, flist, cur, &del, > - &tmp_logflags, whichfork); > + &tmp_logflags, whichfork, rcur); > logflags |= tmp_logflags; > if (error) > goto error0; > @@ -5339,6 +5542,7 @@ nodelete: > } > *done = bno == (xfs_fileoff_t)-1 || bno < start || lastx < 0; > > + free_rcur(&rcur, XFS_BTREE_NOERROR); > /* > * Convert to a btree if necessary. > */ > @@ -5366,6 +5570,7 @@ nodelete: > */ > error = 0; > error0: > + free_rcur(&rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); > /* > * Log everything. Do this after conversion, there's no point in > * logging the extent records if we've converted to btree format. > @@ -5438,7 +5643,8 @@ xfs_bmse_merge( > struct xfs_bmbt_rec_host *gotp, /* extent to shift */ > struct xfs_bmbt_rec_host *leftp, /* preceding extent */ > struct xfs_btree_cur *cur, > - int *logflags) /* output */ > + int *logflags, /* output */ > + struct xfs_btree_cur *rcur) /* rmap btree */ > { > struct xfs_bmbt_irec got; > struct xfs_bmbt_irec left; > @@ -5469,6 +5675,13 @@ xfs_bmse_merge( > XFS_IFORK_NEXT_SET(ip, whichfork, > XFS_IFORK_NEXTENTS(ip, whichfork) - 1); > *logflags |= XFS_ILOG_CORE; > + error = xfs_rmap_resize(rcur, ip->i_ino, whichfork, &left, > + blockcount - left.br_blockcount); > + if (error) > + return error; > + error = xfs_rmap_delete(rcur, ip->i_ino, whichfork, &got); > + if (error) > + return error; > if (!cur) { > *logflags |= XFS_ILOG_DEXT; > return 0; > @@ -5511,7 +5724,8 @@ xfs_bmse_shift_one( > struct xfs_bmbt_rec_host *gotp, > struct xfs_btree_cur *cur, > int *logflags, > - enum shift_direction direction) > + enum shift_direction direction, > + struct xfs_btree_cur *rcur) > { > struct xfs_ifork *ifp; > struct xfs_mount *mp; > @@ -5561,7 +5775,7 @@ xfs_bmse_shift_one( > offset_shift_fsb)) { > return xfs_bmse_merge(ip, whichfork, offset_shift_fsb, > *current_ext, gotp, adj_irecp, > - cur, logflags); > + cur, logflags, rcur); > } > } else { > startoff = got.br_startoff + offset_shift_fsb; > @@ -5598,6 +5812,10 @@ update_current_ext: > (*current_ext)--; > xfs_bmbt_set_startoff(gotp, startoff); > *logflags |= XFS_ILOG_CORE; > + error = xfs_rmap_slide(rcur, ip->i_ino, whichfork, > + &got, startoff - got.br_startoff); > + if (error) > + return error; > if (!cur) { > *logflags |= XFS_ILOG_DEXT; > return 0; > @@ -5649,6 +5867,7 @@ xfs_bmap_shift_extents( > int error = 0; > int whichfork = XFS_DATA_FORK; > int logflags = 0; > + struct xfs_btree_cur *rcur = NULL; > > if (unlikely(XFS_TEST_ERROR( > (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && > @@ -5737,9 +5956,14 @@ xfs_bmap_shift_extents( > } > > while (nexts++ < num_exts) { > + xfs_bmbt_get_all(gotp, &got); > + error = alloc_rcur(mp, tp, &rcur, got.br_startblock); > + if (error) > + return error; > + > error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb, > ¤t_ext, gotp, cur, &logflags, > - direction); > + direction, rcur); > if (error) > goto del_cursor; > /* > @@ -5765,6 +5989,7 @@ xfs_bmap_shift_extents( > } > > del_cursor: > + free_rcur(&rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); > if (cur) > xfs_btree_del_cursor(cur, > error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); > @@ -5801,6 +6026,7 @@ xfs_bmap_split_extent_at( > int error = 0; > int logflags = 0; > int i = 0; > + struct xfs_btree_cur *rcur = NULL; > > if (unlikely(XFS_TEST_ERROR( > (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && > @@ -5895,6 +6121,18 @@ xfs_bmap_split_extent_at( > XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor); > } > > + /* update rmapbt */ > + error = alloc_rcur(mp, tp, &rcur, new.br_startblock); > + if (error) > + goto del_cursor; > + error = xfs_rmap_resize(rcur, ip->i_ino, whichfork, &got, -gotblkcnt); got is modified by the previous code clause, so this causes incorrect rmap entries to end up in the rmapbt. > + if (error) > + goto del_cursor; > + error = xfs_rmap_insert(rcur, ip->i_ino, whichfork, &new); > + if (error) > + goto del_cursor; > + free_rcur(&rcur, XFS_BTREE_NOERROR); > + > /* > * Convert to a btree if necessary. > */ > @@ -5908,6 +6146,8 @@ xfs_bmap_split_extent_at( > } > > del_cursor: > + free_rcur(&rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); > + > if (cur) { > cur->bc_private.b.allocated = 0; > xfs_btree_del_cursor(cur, > diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h > index 89fa3dd..59f26cf 100644 > --- a/fs/xfs/libxfs/xfs_bmap.h > +++ b/fs/xfs/libxfs/xfs_bmap.h > @@ -56,6 +56,7 @@ struct xfs_bmalloca { > bool aeof; /* allocated space at eof */ > bool conv; /* overwriting unwritten extents */ > int flags; > + struct xfs_btree_cur *rcur; /* rmap btree cursor */ > }; > > /* > diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c > index 045f9a7..d821b1a 100644 > --- a/fs/xfs/libxfs/xfs_rmap.c > +++ b/fs/xfs/libxfs/xfs_rmap.c > @@ -563,3 +563,299 @@ out_error: > xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); > return error; > } > + > +/* Encode logical offset for a rmapbt record */ > +STATIC uint64_t > +b2r_off( > + int whichfork, > + xfs_fileoff_t off) > +{ > + uint64_t x; > + > + x = off; > + if (whichfork == XFS_ATTR_FORK) > + x |= XFS_RMAP_OFF_ATTR; > + return x; > +} > + > +/* Encode blockcount for a rmapbt record */ > +STATIC xfs_extlen_t > +b2r_len( > + struct xfs_bmbt_irec *irec) > +{ > + xfs_extlen_t x; > + > + x = irec->br_blockcount; > + if (irec->br_state == XFS_EXT_UNWRITTEN) > + x |= XFS_RMAP_LEN_UNWRITTEN; > + return x; > +} > + > +/* Combine two adjacent rmap extents */ > +int > +xfs_rmap_combine( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *LEFT, > + struct xfs_bmbt_irec *RIGHT, > + struct xfs_bmbt_irec *PREV) > +{ > + int error; > + > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_combine(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, LEFT, PREV, RIGHT); > + > + /* Delete right rmap */ > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, RIGHT->br_startblock), > + b2r_len(RIGHT), ino, > + b2r_off(whichfork, RIGHT->br_startoff)); > + if (error) > + goto done; > + > + /* Delete prev rmap */ > + if (!isnullstartblock(PREV->br_startblock)) { > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, > + PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff)); > + if (error) > + goto done; > + } > + > + /* Enlarge left rmap */ > + return xfs_rmap_resize(rcur, ino, whichfork, LEFT, > + PREV->br_blockcount + RIGHT->br_blockcount); > +done: > + return error; > +} > + > +/* Extend a left rmap extent */ > +int > +xfs_rmap_lcombine( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *LEFT, > + struct xfs_bmbt_irec *PREV) > +{ > + int error; > + > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_lcombine(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, LEFT, PREV); > + > + /* Delete prev rmap */ > + if (!isnullstartblock(PREV->br_startblock)) { > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, > + PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff)); > + if (error) > + goto done; > + } > + > + /* Enlarge left rmap */ > + return xfs_rmap_resize(rcur, ino, whichfork, LEFT, PREV->br_blockcount); > +done: > + return error; > +} > + > +/* Extend a right rmap extent */ > +int > +xfs_rmap_rcombine( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *RIGHT, > + struct xfs_bmbt_irec *PREV, > + struct xfs_bmbt_irec *new) > +{ > + int error; > + > + if (!rcur) > + return 0; > + ASSERT(PREV->br_startoff == new->br_startoff); > + > + trace_xfs_rmap_rcombine(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, RIGHT, PREV); > + > + /* Delete prev rmap */ > + if (!isnullstartblock(PREV->br_startblock)) { > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, > + PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff)); > + if (error) > + goto done; > + } > + > + /* Enlarge right rmap */ > + return xfs_rmap_resize(rcur, ino, whichfork, RIGHT, > + -PREV->br_blockcount); The starting point of RIGHT should be moved leftward to the start of PREV, so this is really an xfs_rmap_move(..., -PREV->br_blockcount); --D > +done: > + return error; > +} > + > +/* Insert a rmap extent */ > +int > +xfs_rmap_insert( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *new) > +{ > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, new); > + > + return xfs_rmapbt_insert(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, new->br_startblock), > + b2r_len(new), ino, > + b2r_off(whichfork, new->br_startoff)); > +} > + > +/* Delete a rmap extent */ > +int > +xfs_rmap_delete( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *new) > +{ > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, new); > + > + return xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, new->br_startblock), > + b2r_len(new), ino, > + b2r_off(whichfork, new->br_startoff)); > +} > + > +/* Change the start of an rmap */ > +int > +xfs_rmap_move( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *PREV, > + long start_adj) > +{ > + int error; > + struct xfs_bmbt_irec irec; > + > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_move(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, PREV, start_adj); > + > + /* Delete prev rmap */ > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff)); > + if (error) > + goto done; > + > + /* Re-add rmap with new start */ > + irec = *PREV; > + irec.br_startblock += start_adj; > + irec.br_startoff += start_adj; > + irec.br_blockcount -= start_adj; > + return xfs_rmapbt_insert(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, irec.br_startblock), > + b2r_len(&irec), ino, > + b2r_off(whichfork, irec.br_startoff)); > +done: > + return error; > +} > + > +/* Change the logical offset of an rmap */ > +int > +xfs_rmap_slide( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *PREV, > + long start_adj) > +{ > + int error; > + > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_slide(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, PREV, start_adj); > + > + /* Delete prev rmap */ > + error = xfs_rmapbt_delete(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff)); > + if (error) > + goto done; > + > + /* Re-add rmap with new logical offset */ > + return xfs_rmapbt_insert(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff + start_adj)); > +done: > + return error; > +} > + > +/* Change the size of an rmap */ > +int > +xfs_rmap_resize( > + struct xfs_btree_cur *rcur, > + xfs_ino_t ino, > + int whichfork, > + struct xfs_bmbt_irec *PREV, > + long size_adj) > +{ > + int i; > + int error; > + struct xfs_bmbt_irec irec; > + struct xfs_rmap_irec rrec; > + > + if (!rcur) > + return 0; > + > + trace_xfs_rmap_resize(rcur->bc_mp, rcur->bc_private.a.agno, ino, > + whichfork, PREV, size_adj); > + > + error = xfs_rmap_lookup_eq(rcur, > + XFS_FSB_TO_AGBNO(rcur->bc_mp, PREV->br_startblock), > + b2r_len(PREV), ino, > + b2r_off(whichfork, PREV->br_startoff), &i); > + if (error) > + goto done; > + XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done); > + error = xfs_rmap_get_rec(rcur, &rrec, &i); > + if (error) > + goto done; > + XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done); > + irec = *PREV; > + irec.br_blockcount += size_adj; > + rrec.rm_blockcount = b2r_len(&irec); > + error = xfs_rmap_update(rcur, &rrec); > + if (error) > + goto done; > +done: > + return error; > +} > diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h > index d7c9722..0131d9a 100644 > --- a/fs/xfs/libxfs/xfs_rmap_btree.h > +++ b/fs/xfs/libxfs/xfs_rmap_btree.h > @@ -68,4 +68,24 @@ int xfs_rmap_free(struct xfs_trans *tp, struct xfs_buf *agbp, > xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, > struct xfs_owner_info *oinfo); > > +/* functions for updating the rmapbt based on bmbt map/unmap operations */ > +int xfs_rmap_combine(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *LEFT, struct xfs_bmbt_irec *RIGHT, > + struct xfs_bmbt_irec *PREV); > +int xfs_rmap_lcombine(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *LEFT, struct xfs_bmbt_irec *PREV); > +int xfs_rmap_rcombine(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *RIGHT, struct xfs_bmbt_irec *PREV, > + struct xfs_bmbt_irec *new); > +int xfs_rmap_insert(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *new); > +int xfs_rmap_delete(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *new); > +int xfs_rmap_move(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *PREV, long start_adj); > +int xfs_rmap_slide(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *PREV, long start_adj); > +int xfs_rmap_resize(struct xfs_btree_cur *rcur, xfs_ino_t ino, int whichfork, > + struct xfs_bmbt_irec *PREV, long size_adj); > + > #endif /* __XFS_RMAP_BTREE_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-21 21:40 UTC|newest] Thread overview: 131+ 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 ` 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 ` Darrick J. Wong 2015-10-07 4:54 ` [PATCH 02/58] xfs: fix log ticket type printing Darrick J. Wong 2015-10-07 4:54 ` Darrick J. Wong 2015-10-07 4:55 ` [PATCH 03/58] xfs: introduce rmap btree definitions Darrick J. Wong 2015-10-07 4:55 ` 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 ` 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 ` Darrick J. Wong 2015-10-07 4:55 ` [PATCH 07/58] xfs: add extended " Darrick J. Wong 2015-10-07 4:55 ` 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 ` 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 ` 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 ` Darrick J. Wong 2015-10-07 4:55 ` [PATCH 11/58] xfs: enhance " Darrick J. Wong 2015-10-07 4:55 ` 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 ` Darrick J. Wong 2015-10-07 4:56 ` [PATCH 13/58] xfs: enhance " Darrick J. Wong 2015-10-07 4:56 ` Darrick J. Wong 2015-10-07 4:56 ` [PATCH 14/58] xfs: rmap btree transaction reservations Darrick J. Wong 2015-10-07 4:56 ` 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 ` 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 ` 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 ` 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 ` 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 ` 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 ` Darrick J. Wong 2015-10-07 4:57 ` [PATCH 23/58] xfs: enhanced " Darrick J. Wong 2015-10-07 4:57 ` 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 ` Darrick J. Wong 2015-10-07 4:57 ` [PATCH 25/58] xfs: bmap btree changes should update rmap btree Darrick J. Wong 2015-10-07 4:57 ` Darrick J. Wong 2015-10-21 21:39 ` Darrick J. Wong [this message] 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:57 ` 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 ` 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 ` 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 ` Darrick J. Wong 2015-10-07 4:58 ` [PATCH 30/58] xfs: implement " Darrick J. Wong 2015-10-07 4:58 ` 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 ` 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 ` Darrick J. Wong 2015-10-07 4:58 ` [PATCH 33/58] xfs: introduce refcount btree definitions Darrick J. Wong 2015-10-07 4:58 ` 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 ` 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:58 ` 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 ` 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 ` 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 ` Darrick J. Wong 2015-10-07 4:59 ` [PATCH 39/58] xfs: add refcount btree operations Darrick J. Wong 2015-10-07 4:59 ` 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-07 4:59 ` Darrick J. Wong 2015-10-27 19:05 ` Darrick J. Wong 2015-10-27 19:05 ` Darrick J. Wong 2015-10-30 20:56 ` Darrick J. Wong 2015-10-30 20:56 ` Darrick J. Wong 2015-10-07 4:59 ` [PATCH 41/58] libxfs: adjust refcount when unmapping file blocks Darrick J. Wong 2015-10-07 4:59 ` 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 ` 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 ` Darrick J. Wong 2015-10-07 4:59 ` [PATCH 44/58] xfs: add reflink feature flag to geometry Darrick J. Wong 2015-10-07 4:59 ` 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 ` 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 ` Darrick J. Wong 2015-10-07 5:00 ` [PATCH 47/58] xfs: handle directio " Darrick J. Wong 2015-10-07 5:00 ` 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-07 5:00 ` Darrick J. Wong 2015-10-21 21:17 ` 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 ` 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:00 ` Darrick J. Wong 2015-10-07 5:12 ` kbuild test robot 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:00 ` Darrick J. Wong 2015-10-07 5:13 ` kbuild test robot 2015-10-07 5:13 ` kbuild test robot 2015-10-07 6:46 ` kbuild test robot 2015-10-07 6:46 ` kbuild test robot 2015-10-07 7:35 ` 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 ` 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:00 ` 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 ` 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 ` 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 ` 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 ` Darrick J. Wong 2015-10-07 5:01 ` [PATCH 58/58] xfs: recognize the reflink feature bit Darrick J. Wong 2015-10-07 5:01 ` 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=20151021213953.GN10397@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: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.