Skip to content

Commit

Permalink
xfs: fully initialise temp leaf in xfs_attr3_leaf_compact
Browse files Browse the repository at this point in the history
xfs_attr3_leaf_compact() uses a temporary buffer for compacting the
the entries in a leaf. It copies the the original buffer into the
temporary buffer, then zeros the original buffer completely. It then
copies the entries back into the original buffer.  However, the
original buffer has not been correctly initialised, and so the
movement of the entries goes horribly wrong.

Make sure the zeroed destination buffer is fully initialised, and
once we've set up the destination incore header appropriately, write
is back to the buffer before starting to move entries around.

While debugging this, the _d/_s prefixes weren't sufficient to
remind me what buffer was what, so rename then all _src/_dst.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Ben Myers <bpm@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>

(cherry picked from commit d4c712b)
  • Loading branch information
Dave Chinner authored and Ben Myers committed May 30, 2013
1 parent 9e80c76 commit 634fd53
Showing 1 changed file with 26 additions and 16 deletions.
42 changes: 26 additions & 16 deletions fs/xfs/xfs_attr_leaf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1445,41 +1445,51 @@ xfs_attr3_leaf_add_work(
STATIC void
xfs_attr3_leaf_compact(
struct xfs_da_args *args,
struct xfs_attr3_icleaf_hdr *ichdr_d,
struct xfs_attr3_icleaf_hdr *ichdr_dst,
struct xfs_buf *bp)
{
xfs_attr_leafblock_t *leaf_s, *leaf_d;
struct xfs_attr3_icleaf_hdr ichdr_s;
struct xfs_attr_leafblock *leaf_src;
struct xfs_attr_leafblock *leaf_dst;
struct xfs_attr3_icleaf_hdr ichdr_src;
struct xfs_trans *trans = args->trans;
struct xfs_mount *mp = trans->t_mountp;
char *tmpbuffer;

trace_xfs_attr_leaf_compact(args);

tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP);
ASSERT(tmpbuffer != NULL);
memcpy(tmpbuffer, bp->b_addr, XFS_LBSIZE(mp));
memset(bp->b_addr, 0, XFS_LBSIZE(mp));
leaf_src = (xfs_attr_leafblock_t *)tmpbuffer;
leaf_dst = bp->b_addr;

/*
* Copy basic information
* Copy the on-disk header back into the destination buffer to ensure
* all the information in the header that is not part of the incore
* header structure is preserved.
*/
leaf_s = (xfs_attr_leafblock_t *)tmpbuffer;
leaf_d = bp->b_addr;
ichdr_s = *ichdr_d; /* struct copy */
ichdr_d->firstused = XFS_LBSIZE(mp);
ichdr_d->usedbytes = 0;
ichdr_d->count = 0;
ichdr_d->holes = 0;
ichdr_d->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_s);
ichdr_d->freemap[0].size = ichdr_d->firstused - ichdr_d->freemap[0].base;
memcpy(bp->b_addr, tmpbuffer, xfs_attr3_leaf_hdr_size(leaf_src));

/* Initialise the incore headers */
ichdr_src = *ichdr_dst; /* struct copy */
ichdr_dst->firstused = XFS_LBSIZE(mp);
ichdr_dst->usedbytes = 0;
ichdr_dst->count = 0;
ichdr_dst->holes = 0;
ichdr_dst->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_src);
ichdr_dst->freemap[0].size = ichdr_dst->firstused -
ichdr_dst->freemap[0].base;


/* write the header back to initialise the underlying buffer */
xfs_attr3_leaf_hdr_to_disk(leaf_dst, ichdr_dst);

/*
* Copy all entry's in the same (sorted) order,
* but allocate name/value pairs packed and in sequence.
*/
xfs_attr3_leaf_moveents(leaf_s, &ichdr_s, 0, leaf_d, ichdr_d, 0,
ichdr_s.count, mp);
xfs_attr3_leaf_moveents(leaf_src, &ichdr_src, 0, leaf_dst, ichdr_dst, 0,
ichdr_src.count, mp);
/*
* this logs the entire buffer, but the caller must write the header
* back to the buffer when it is finished modifying it.
Expand Down

0 comments on commit 634fd53

Please sign in to comment.