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: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Ben Myers <bpm@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
(cherry picked from commit 5ae6e6a401
)
This commit is contained in:
Родитель
7c9950fd2a
Коммит
e400d27d16
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче