Commit 5ae6e6a4 authored by Dave Chinner's avatar Dave Chinner Committed by Ben Myers

xfs: fix dir3 freespace block corruption

When the directory freespace index grows to a second block (2017
4k data blocks in the directory), the initialisation of the second
new block header goes wrong. The write verifier fires a corruption
error indicating that the block number in the header is zero. This
was being tripped by xfs/110.

The problem is that the initialisation of the new block is done just
fine in xfs_dir3_free_get_buf(), but the caller then users a dirv2
structure to zero on-disk header fields that xfs_dir3_free_get_buf()
has already zeroed. These lined up with the block number in the dir
v3 header format.

While looking at this, I noticed that the struct xfs_dir3_free_hdr()
had 4 bytes of padding in it that wasn't defined as padding or being
zeroed by the initialisation. Add a pad field declaration and fully
zero the on disk and in-core headers in xfs_dir3_free_get_buf() so
that this is never an issue in the future. Note that this doesn't
change the on-disk layout, just makes the 32 bits of padding in the
layout explicit.
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarBen Myers <bpm@sgi.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 56c19e89
...@@ -715,6 +715,7 @@ struct xfs_dir3_free_hdr { ...@@ -715,6 +715,7 @@ struct xfs_dir3_free_hdr {
__be32 firstdb; /* db of first entry */ __be32 firstdb; /* db of first entry */
__be32 nvalid; /* count of valid entries */ __be32 nvalid; /* count of valid entries */
__be32 nused; /* count of used entries */ __be32 nused; /* count of used entries */
__be32 pad; /* 64 bit alignment. */
}; };
struct xfs_dir3_free { struct xfs_dir3_free {
......
...@@ -263,18 +263,19 @@ xfs_dir3_free_get_buf( ...@@ -263,18 +263,19 @@ xfs_dir3_free_get_buf(
* Initialize the new block to be empty, and remember * Initialize the new block to be empty, and remember
* its first slot as our empty slot. * its first slot as our empty slot.
*/ */
hdr.magic = XFS_DIR2_FREE_MAGIC; memset(bp->b_addr, 0, sizeof(struct xfs_dir3_free_hdr));
hdr.firstdb = 0; memset(&hdr, 0, sizeof(hdr));
hdr.nused = 0;
hdr.nvalid = 0;
if (xfs_sb_version_hascrc(&mp->m_sb)) { if (xfs_sb_version_hascrc(&mp->m_sb)) {
struct xfs_dir3_free_hdr *hdr3 = bp->b_addr; struct xfs_dir3_free_hdr *hdr3 = bp->b_addr;
hdr.magic = XFS_DIR3_FREE_MAGIC; hdr.magic = XFS_DIR3_FREE_MAGIC;
hdr3->hdr.blkno = cpu_to_be64(bp->b_bn); hdr3->hdr.blkno = cpu_to_be64(bp->b_bn);
hdr3->hdr.owner = cpu_to_be64(dp->i_ino); hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid); uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_uuid);
} } else
hdr.magic = XFS_DIR2_FREE_MAGIC;
xfs_dir3_free_hdr_to_disk(bp->b_addr, &hdr); xfs_dir3_free_hdr_to_disk(bp->b_addr, &hdr);
*bpp = bp; *bpp = bp;
return 0; return 0;
...@@ -1921,8 +1922,6 @@ xfs_dir2_node_addname_int( ...@@ -1921,8 +1922,6 @@ xfs_dir2_node_addname_int(
*/ */
freehdr.firstdb = (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) * freehdr.firstdb = (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) *
xfs_dir3_free_max_bests(mp); xfs_dir3_free_max_bests(mp);
free->hdr.nvalid = 0;
free->hdr.nused = 0;
} else { } else {
free = fbp->b_addr; free = fbp->b_addr;
bests = xfs_dir3_free_bests_p(mp, free); bests = xfs_dir3_free_bests_p(mp, free);
......
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