[PATCH 23/22] xfs: buffer type changes in xfs_da_root_join

Dave Chinner
2012-11-07T13:16:02Z

xfs: buffer type changes in xfs_da_root_join

From: Dave Chinner <dchinner@redhat.com>

When a root join occurs, a node format tree can be turne dback into
a leaf format tree by copying the last remaining leaf block into the
root block. At this point, the root block changes from a xfs_da_node
to a xfs_attr_leaf, and the magic number changes. However,
xfs_da_root_join treats this block as a xfs_da_node and sets the
verifier up as such. This is the wrong verifier when a leaf block
is moved into the root.

Fix this by copying the verifier from the buffer being copied into
the root block. This ensures that the leaf verifier is moved with
the leaf data, and avoids verifier failures.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
---

I posted this as separate patch rather than going back an
integrating it and then rebasing all the other patches on top it
afterwards. Simpler, faster, and the buf being fixed is more obvious
and easier to review, too. Found from debugging occassional 070 and
117 failures when run in a tight loop for a couple of hours..

fs/xfs/xfs_da_btree.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
index 43db040..eecdf55 100644
--- a/fs/xfs/xfs_da_btree.c
+++ b/fs/xfs/xfs_da_btree.c
@@ -835,7 +835,15 @@ xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk)
xfs_da_blkinfo_onlychild_validate(bp->b_addr,
be16_to_cpu(oldroot->hdr.level));

+ /*
+ * This could be copying a leaf back into the root block in the case of
+ * there only being a single leaf block left in the tree. Hence we have
+ * to update the buf ops pointer as well to match the buffer type change
+ * that could occur.
+ */
memcpy(root_blk->bp->b_addr, bp->b_addr, state->blocksize);
+ root_blk->bp->b_ops = bp->b_ops;
+
xfs_trans_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1);
error = xfs_da_shrink_inode(args, child, bp);
return(error);