Commit afbabf56 authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: drop all altpath buffers at the end of the sibling check

The dirattr btree checking code uses the altpath substructure of the
dirattr state structure to check the sibling pointers of dir/attr tree
blocks.  At the end of sibling checks, xfs_da3_path_shift could have
changed multiple levels of buffer pointers in the altpath structure.
Although we release the leaf level buffer, this isn't enough -- we also
need to release the node buffers that are unique to the altpath.

Not releasing all of the altpath buffers leaves them locked to the
transaction.  This is suboptimal because we should release resources
when we don't need them anymore.  Fix the function to loop all levels of
the altpath, and fix the return logic so that we always run the loop.
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
parent 5885539f
...@@ -219,19 +219,21 @@ xchk_da_btree_block_check_sibling( ...@@ -219,19 +219,21 @@ xchk_da_btree_block_check_sibling(
int direction, int direction,
xfs_dablk_t sibling) xfs_dablk_t sibling)
{ {
struct xfs_da_state_path *path = &ds->state->path;
struct xfs_da_state_path *altpath = &ds->state->altpath;
int retval; int retval;
int plevel;
int error; int error;
memcpy(&ds->state->altpath, &ds->state->path, memcpy(altpath, path, sizeof(ds->state->altpath));
sizeof(ds->state->altpath));
/* /*
* If the pointer is null, we shouldn't be able to move the upper * If the pointer is null, we shouldn't be able to move the upper
* level pointer anywhere. * level pointer anywhere.
*/ */
if (sibling == 0) { if (sibling == 0) {
error = xfs_da3_path_shift(ds->state, &ds->state->altpath, error = xfs_da3_path_shift(ds->state, altpath, direction,
direction, false, &retval); false, &retval);
if (error == 0 && retval == 0) if (error == 0 && retval == 0)
xchk_da_set_corrupt(ds, level); xchk_da_set_corrupt(ds, level);
error = 0; error = 0;
...@@ -239,27 +241,33 @@ xchk_da_btree_block_check_sibling( ...@@ -239,27 +241,33 @@ xchk_da_btree_block_check_sibling(
} }
/* Move the alternate cursor one block in the direction given. */ /* Move the alternate cursor one block in the direction given. */
error = xfs_da3_path_shift(ds->state, &ds->state->altpath, error = xfs_da3_path_shift(ds->state, altpath, direction, false,
direction, false, &retval); &retval);
if (!xchk_da_process_error(ds, level, &error)) if (!xchk_da_process_error(ds, level, &error))
return error; goto out;
if (retval) { if (retval) {
xchk_da_set_corrupt(ds, level); xchk_da_set_corrupt(ds, level);
return error; goto out;
} }
if (ds->state->altpath.blk[level].bp) if (altpath->blk[level].bp)
xchk_buffer_recheck(ds->sc, xchk_buffer_recheck(ds->sc, altpath->blk[level].bp);
ds->state->altpath.blk[level].bp);
/* Compare upper level pointer to sibling pointer. */ /* Compare upper level pointer to sibling pointer. */
if (ds->state->altpath.blk[level].blkno != sibling) if (altpath->blk[level].blkno != sibling)
xchk_da_set_corrupt(ds, level); xchk_da_set_corrupt(ds, level);
if (ds->state->altpath.blk[level].bp) {
xfs_trans_brelse(ds->dargs.trans,
ds->state->altpath.blk[level].bp);
ds->state->altpath.blk[level].bp = NULL;
}
out: out:
/* Free all buffers in the altpath that aren't referenced from path. */
for (plevel = 0; plevel < altpath->active; plevel++) {
if (altpath->blk[plevel].bp == NULL ||
(plevel < path->active &&
altpath->blk[plevel].bp == path->blk[plevel].bp))
continue;
xfs_trans_brelse(ds->dargs.trans, altpath->blk[plevel].bp);
altpath->blk[plevel].bp = NULL;
}
return error; return error;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment