diff mbox series

xfs: Test trashing of suspect inode chunks by xfs_repair

Message ID 20220530125156.1977338-1-chandan.babu@oracle.com (mailing list archive)
State New, archived
Headers show
Series xfs: Test trashing of suspect inode chunks by xfs_repair | expand

Commit Message

Chandan Babu R May 30, 2022, 12:51 p.m. UTC
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@oracle.com>
---
 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 mbox series

Patch

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