summaryrefslogtreecommitdiff
path: root/tests/xfs/010
blob: 16c08b8522eedddb90dab36048450fde1ea670b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/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.
#
. ./common/preamble
_begin_fstest auto quick repair

# Import common functions.
. ./common/filter
. ./common/repair

# Override the default cleanup function.
_cleanup()
{
	cd /
	_scratch_unmount 2>/dev/null
	rm -f $tmp.*
}

_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

_require_scratch
_require_xfs_mkfs_finobt
_require_xfs_finobt

_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

filter_finobt_repair() {
	sed -e '/^agi has bad CRC/d' \
	    -e '/^bad levels/d' \
	    -e '/^bad finobt block/d' | \
		_filter_repair_lostblocks
}

_scratch_xfs_repair 2>&1 | filter_finobt_repair

status=0
exit