generic: test MADV_POPULATE_READ with IO errors
[xfstests-dev.git] / tests / xfs / 010
1 #!/bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2014 Red Hat, Inc.  All Rights Reserved.
4 #
5 # FS QA Test No. xfs/010
6 #
7 # Test xfs_repair of the free inode btree (finobt). Make a couple targeted
8 # corruptions and verify that xfs_repair detects and repairs the filesystem to
9 # a consistent state.
10 #
11 . ./common/preamble
12 _begin_fstest auto quick repair
13
14 # Import common functions.
15 . ./common/filter
16 . ./common/repair
17
18 # Override the default cleanup function.
19 _cleanup()
20 {
21         cd /
22         _scratch_unmount 2>/dev/null
23         rm -f $tmp.*
24 }
25
26 _sparse_inode_populate()
27 {
28         dir=$1
29         count=$2
30
31         for i in $(seq 0 $count)
32         do
33                 touch $dir/$i
34         done
35
36         # Inode chunks are allocated 64 inodes at a time. If we remove 1 out of
37         # every 32 we allocated above, we'll end up leaving an inode or two free
38         # in each chunk. This ensures that most records are inserted into the
39         # finobt.
40         for i in $(seq 0 32 $count)
41         do
42                 rm -f $dir/$i
43         done
44 }
45
46 _filter_dbval()
47 {
48         awk '{ print $3 }'
49 }
50
51 _corrupt_finobt_records()
52 {
53         dev=$1
54
55         # determine the root block of the finobt
56         free_root=`$XFS_DB_PROG -c "agi 0" -c "p free_root" $dev |
57                         _filter_dbval`
58
59         # Corrupt a freecount value. This should never exceed 64.
60         $XFS_DB_PROG -x -c "fsb $free_root" -c "type finobt" \
61                 -c "write recs[1].freecount 70" $dev
62
63         # Create a corrupted non-free record, which should never appear in the
64         # finobt.
65         $XFS_DB_PROG -x -c "fsb $free_root" -c "type finobt" \
66                  -c "write recs[2].freecount 0" $dev
67         $XFS_DB_PROG -x -c "fsb $free_root" -c "type finobt" \
68                 -c "write recs[2].free 0" $dev
69 }
70
71 _corrupt_finobt_root()
72 {
73         dev=$1
74
75         # nuke the agi finobt root fields
76         $XFS_DB_PROG -x                         \
77                 -c "agi 0"                      \
78                 -c "write -c free_root 0"       \
79                 -c "write -c free_level 0"      \
80                 $dev | grep -v "Allowing write of corrupted"
81 }
82
83 # real QA test starts here
84 _supported_fs xfs
85
86 _require_scratch
87 _require_xfs_mkfs_finobt
88 _require_xfs_finobt
89
90 _scratch_mkfs_xfs "-m crc=1,finobt=1 -d agcount=2" | _filter_mkfs 2>$seqres.full
91
92 # sparsely populate the fs such that we create records with free inodes
93 _scratch_mount
94 _sparse_inode_populate $SCRATCH_MNT 999
95 _scratch_unmount
96
97 # corrupt some finobt records
98 _corrupt_finobt_records $SCRATCH_DEV
99
100 # repair should detect the inconsistencies
101 _scratch_xfs_repair 2>&1 | _filter_repair
102 _check_scratch_fs
103
104 # nuke the finobt root, repair will have to regenerate from the inobt
105 _corrupt_finobt_root $SCRATCH_DEV
106
107 filter_finobt_repair() {
108         sed -e '/^agi has bad CRC/d' \
109             -e '/^bad levels/d' \
110             -e '/^bad finobt block/d' | \
111                 _filter_repair_lostblocks
112 }
113
114 _scratch_xfs_repair 2>&1 | filter_finobt_repair
115
116 status=0
117 exit