#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2014 Red Hat, Inc. All Rights Reserved. # # FS QA Test No. xfs/010 # # Test xfs_repair of the free inode btree (finobt). Make a couple targeted # corruptions and verify that xfs_repair detects and repairs the filesystem to # a consistent state. # seq=`basename $0` seqres=$RESULT_DIR/$seq echo "QA output created by $seq" here=`pwd` tmp=/tmp/$$ status=1 # failure is the default! # get standard environment, filters and checks . ./common/rc . ./common/filter . ./common/repair _cleanup() { cd / _scratch_unmount 2>/dev/null rm -f $tmp.* } trap "_cleanup; exit \$status" 0 1 2 3 15 _sparse_inode_populate() { dir=$1 count=$2 for i in $(seq 0 $count) do touch $dir/$i done # Inode chunks are allocated 64 inodes at a time. If we remove 1 out of # every 32 we allocated above, we'll end up leaving an inode or two free # in each chunk. This ensures that most records are inserted into the # finobt. for i in $(seq 0 32 $count) do rm -f $dir/$i done } _filter_dbval() { awk '{ print $3 }' } _corrupt_finobt_records() { dev=$1 # determine the root block of the finobt free_root=`$XFS_DB_PROG -c "agi 0" -c "p free_root" $dev | _filter_dbval` # Corrupt a freecount value. This should never exceed 64. $XFS_DB_PROG -x -c "fsb $free_root" -c "type finobt" \ -c "write recs[1].freecount 70" $dev # Create a corrupted non-free record, which should never appear in the # finobt. $XFS_DB_PROG -x -c "fsb $free_root" -c "type finobt" \ -c "write recs[2].freecount 0" $dev $XFS_DB_PROG -x -c "fsb $free_root" -c "type finobt" \ -c "write recs[2].free 0" $dev } _corrupt_finobt_root() { dev=$1 # nuke the agi finobt root fields $XFS_DB_PROG -x \ -c "agi 0" \ -c "write -c free_root 0" \ -c "write -c free_level 0" \ $dev | grep -v "Allowing write of corrupted" } # real QA test starts here _supported_fs xfs _supported_os Linux _require_scratch _require_xfs_mkfs_finobt _require_xfs_finobt rm -f $seqres.full _scratch_mkfs_xfs "-m crc=1,finobt=1 -d agcount=2" | _filter_mkfs 2>$seqres.full # sparsely populate the fs such that we create records with free inodes _scratch_mount _sparse_inode_populate $SCRATCH_MNT 999 _scratch_unmount # corrupt some finobt records _corrupt_finobt_records $SCRATCH_DEV # repair should detect the inconsistencies _scratch_xfs_repair 2>&1 | _filter_repair _check_scratch_fs # nuke the finobt root, repair will have to regenerate from the inobt _corrupt_finobt_root $SCRATCH_DEV _scratch_xfs_repair 2>&1 | _filter_repair_lostblocks status=0 exit