Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e400d27d authored by Dave Chinner's avatar Dave Chinner Committed by Ben Myers
Browse files

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>

(cherry picked from commit 5ae6e6a4)
parent 7c9950fd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -715,6 +715,7 @@ struct xfs_dir3_free_hdr {
	__be32			firstdb;	/* db of first entry */
	__be32			nvalid;		/* count of valid entries */
	__be32			nused;		/* count of used entries */
	__be32			pad;		/* 64 bit alignment. */
};

struct xfs_dir3_free {
+6 −7
Original line number Diff line number Diff line
@@ -263,18 +263,19 @@ xfs_dir3_free_get_buf(
	 * Initialize the new block to be empty, and remember
	 * its first slot as our empty slot.
	 */
	hdr.magic = XFS_DIR2_FREE_MAGIC;
	hdr.firstdb = 0;
	hdr.nused = 0;
	hdr.nvalid = 0;
	memset(bp->b_addr, 0, sizeof(struct xfs_dir3_free_hdr));
	memset(&hdr, 0, sizeof(hdr));

	if (xfs_sb_version_hascrc(&mp->m_sb)) {
		struct xfs_dir3_free_hdr *hdr3 = bp->b_addr;

		hdr.magic = XFS_DIR3_FREE_MAGIC;

		hdr3->hdr.blkno = cpu_to_be64(bp->b_bn);
		hdr3->hdr.owner = cpu_to_be64(dp->i_ino);
		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);
	*bpp = bp;
	return 0;
@@ -1921,8 +1922,6 @@ xfs_dir2_node_addname_int(
			 */
			freehdr.firstdb = (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) *
					xfs_dir3_free_max_bests(mp);
			free->hdr.nvalid = 0;
			free->hdr.nused = 0;
		} else {
			free = fbp->b_addr;
			bests = xfs_dir3_free_bests_p(mp, free);