When processing an uncertain inode chunk record, if xfs_repair loses 2 blocks worth of inodes or 25% of the inode chunk, it decides to ignore the chunk. Otherwise, xfs_repair adds a new chunk record to the certain inode tree, marking each inode as either free or used. However, before adding the new chunk record, xfs_repair has to check for the existance of a conflicting record. xfs_repair incorrectly checks for the conflicting record in the uncertain inode chunk tree. This check will succeed since the inode chunk record being processed was originally obtained from the uncertain inode chunk tree. Hence xfs_repair trashes such inodes. This test is for checking for the existance of this regression in xfs_repair. Signed-off-by: Chandan Babu R <chandan.babu@xxxxxxxxxx> --- tests/xfs/018 | 102 ++++++++++++++++++++++++++++++++++++++++++++++ tests/xfs/018.out | 6 +++ 2 files changed, 108 insertions(+) create mode 100755 tests/xfs/018 create mode 100644 tests/xfs/018.out diff --git a/tests/xfs/018 b/tests/xfs/018 new file mode 100755 index 00000000..780ae8f9 --- /dev/null +++ b/tests/xfs/018 @@ -0,0 +1,102 @@ +#! /bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2022 Oracle. All Rights Reserved. +# +# FS QA Test 018 +# +# When processing an uncertain inode chunk record, if xfs_repair loses 2 blocks +# worth of inodes or 25% of the inode chunk, it decides to ignore the +# chunk. Otherwise, xfs_repair adds a new chunk record to the certain inode +# tree, marking each inode as either free or used. However, before adding the +# new chunk record, xfs_repair has to check for the existance of a conflicting +# record. +# +# xfs_repair incorrectly checks for the conflicting record in the uncertain +# inode chunk tree. This check will succeed since the inode chunk record being +# processed was originally obtained from the uncertain inode chunk tree. Hence +# xfs_repair trashes such inodes. +# +# This test is for checking for the existance of this regression in xfs_repair. + +. ./common/preamble +_begin_fstest fuzzers + +# Override the default cleanup function. +_cleanup() +{ + cd / + rm -r -f $tmp.* +} + +# Import common functions. +. ./common/filter + +# real QA test starts here +_supported_fs xfs +_require_scratch_nocheck + +echo "Format and mount fs" + +# 1. Limit the number of AGs to 1 since we need to guarantee that all inodes are +# represented in a single Inobt. +# +# 2. For sparse inode chunks, xfs_repair can cause a suspect (e.g. incorrect CRC +# value) inode chunk to be ignored even if the verification of all inodes in +# chunk succeeds since the total number of inodes in the sparse inode chunk can +# be less than 25% of XFS_INODES_PER_CHUNK (i.e. 64). +_scratch_mkfs -d agcount=1 -i sparse=0 >> $seqres.full +_scratch_mount >> $seqres.full + +testdir=$SCRATCH_MNT/testdir + +mkdir $testdir + +bsize=$(_get_file_block_size $SCRATCH_MNT) + +# gdb -batch vmlinux -ex 'print /d &(((struct xfs_btree_block *)0)->bb_u)' +# $1 = 8 +# gdb -batch vmlinux -ex 'print sizeof(struct xfs_btree_block_shdr)' +# $1 = 48 +# +# Space used: 8 + 48 = 56 bytes +sblock_len=$((bsize - 56)) + +# gdb -batch vmlinux -ex 'print sizeof(struct xfs_inobt_rec)' +# $1 = 16 +nr_ino_chunks_per_block=$((sblock_len / 16)) + +nr_inode_chunks=$((nr_ino_chunks_per_block * 2)) + +nr_inodes=$((nr_inode_chunks * 64)) + +echo "Create Inobt with two fully populated leaves" +for i in $(seq 1 $nr_inodes); do + touch ${testdir}/${i} +done + +_scratch_unmount + +nr_levels=$(_scratch_xfs_db -c "agi 0" -c "p level") +nr_levels=${nr_levels##level = } + +echo "Number of levels in Inobt: $nr_levels" + +echo "Setting lsn field to zero" +_scratch_xfs_db -x -c "agi 0" -c "addr root" -c "addr ptrs[2]" \ + -c "fuzz -c lsn zeroes" >> $seqres.full + +echo "Try to repair filesystem" +_scratch_xfs_repair -o force_geometry >> $seqres.full 2>&1 + +_scratch_mount + +nr_inodes_found=$(ls -1 $testdir | wc -l) + +if [[ $nr_inodes != $nr_inodes_found ]]; then + echo "xfs_repair failed to revive all inodes: "\ + "Inodes expected = $nr_inodes; Inodes found = $nr_inodes_found" + exit 1 +fi + +status=0 +exit diff --git a/tests/xfs/018.out b/tests/xfs/018.out new file mode 100644 index 00000000..116e5f1e --- /dev/null +++ b/tests/xfs/018.out @@ -0,0 +1,6 @@ +QA output created by 018 +Format and mount fs +Create Inobt with two fully populated leaves +Number of levels in Inobt: 2 +Setting lsn field to zero +Try to repair filesystem -- 2.35.1