summaryrefslogtreecommitdiff
path: root/common/repair
blob: 8945d0028c47a4d16c4b64407398c01a1bab3efc (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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
##/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
#
# Functions useful for xfs_repair tests

_zero_position()
{
	value=$1
	struct="$2"

	# set values for off/len variables provided by db
	eval `_scratch_xfs_db -r -c "$struct" -c stack | perl -ne '
		if (/byte offset (\d+), length (\d+)/) {
			print "offset=$1\nlength=$2\n"; exit
		}'`
	if [ -z "$offset" -o -z "$length" ]; then
		echo "cannot calculate offset ($offset) or length ($length)"
		exit
	fi
	length=`expr $length / 512`
	$here/src/devzero -v $value -b 1 -n $length -o $offset $SCRATCH_DEV \
		| perl -npe 's/\d\.\d\dKb/X.XXKb/g'
}

_filter_repair()
{
	perl -ne '
# for sb
/- agno = / && next;	# remove each AG line (variable number)
s/(pointer to) (\d+)/\1 INO/;
# Changed inode output in 5.5.0
s/sb root inode value /sb root inode /;
s/realtime bitmap inode value /realtime bitmap inode /;
s/realtime summary inode value /realtime summary inode /;
s/ino pointer to /inode pointer to /;
#
s/(sb root inode) (\d+)( \(NULLFSINO\))?/\1 INO/;
s/(realtime bitmap inode) (\d+)( \(NULLFSINO\))?/\1 INO/;
s/(realtime summary inode) (\d+)( \(NULLFSINO\))?/\1 INO/;
s/(inconsistent with calculated value) (\d+)/\1 INO/;
s/\.+(found)/\1/g;	# remove "searching" output
# for agf + agi
s/(bad length -{0,1}\d+ for ag. 0, should be) (\d+)/\1 LENGTH/;
s/(bad length # -{0,1}\d+ for ag. 0, should be) (\d+)/\1 LENGTH/;
s/(bad agbno) (\d+)/\1 AGBNO/g;
s/(max =) (\d+)/\1 MAX/g;
s/(bad levels) (\d+) (for [a-z]* root, agno) (\d+)/\1 LEVELS \3 AGNO/;
# for root inos
s/(on inode) (\d+)/\1 INO/g;
s/(imap claims a free inode) (\d+)/\1 INO/;
s/(imap claims in-use inode) (\d+)/\1 INO/;
s/(cleared root inode) (\d+)/\1 INO/;
s/(resetting inode) (\d+)/\1 INO/;
s/(disconnected dir inode) (\d+)/\1 INO/;
# for log
s/internal log/<TYPEOF> log/g;
s/external log on \S+/<TYPEOF> log/g;
# realtime subvol - remove this whole line if it appears
s/        - generate realtime summary info and bitmap...\n//g;
#
# new xfs repair output filters
#
s/\s+- creating \d+ worker thread\(s\)\n//g;
s/\s+- reporting progress in intervals of \d+ minutes\n//g;
s/\s+- \d+:\d\d:\d\d:.*\n//g;
# 3.1.0 extra accounting output
/^agf_/ && next; # remove agf counts
/^agi_/ && next; # remove agi counts
/^sb_/ && next; # remove sb counts
/^agi unlinked/ && next; # remove agi unlinked bucket warning
# crc enabled filesystem output
/XFS_CORRUPTION_ERROR/ && next;
/^bad uuid/ && next;
/^Metadata corruption detected/ && next;
/^Metadata CRC error detected/ && next;
/^agfl has bad CRC/ && next;
/^bad CRC for inode/ && next;
# finobt enabled filesystem output
s/(inode chunk) (\d+)\/(\d+)/AGNO\/INO/;
# sunit/swidth reset messages
s/^(Note - .*) were copied.*/\1 fields have been reset./;
s/^(Please) reset (with .*) if necessary/\1 set \2/;
# remove new unlinked inode test
/^bad next_unlinked/ && next;
# And make them generic so we dont depend on geometry
s/(stripe unit) \(.*\) (and width) \(.*\)/\1 (SU) \2 (SW)/;
# corrupt sb messages
s/(superblock) (\d+)/\1 AGNO/;
s/(AG \#)(\d+)/\1AGNO/;
s/(reset bad sb for ag) (\d+)/\1 AGNO/;
s/(unknown block state, ag )(\d+)(, blocks? )(\d+)/\1AGNO\3AGBNO/;
s/^Superblock has (bad magic number) 0x.*/\1/;
/^Note - quota info will be regenerated on next quota mount.$/ && next;
	print;'
}

# Filter out unknown block state messages that appear when rmap is enabled
# and we erase a btree root pointer (such that repair never finds the
# tree and fails to reconcile the metadata reverse mappings against the
# metadata).
_filter_repair_lostblocks() {
	_filter_repair | sed -e '/unknown block state, ag AGNO, blocks* AGBNO/d'
}

_filter_dd()
{
	grep -F -v records	# lose records in/out lines
}

# do some controlled corrupting & ensure repair recovers us
# 
_check_repair()
{
	value=$1
	structure="$2"

	#ensure the filesystem has been dirtied since last repair
	_scratch_mount
	POSIXLY_CORRECT=yes \
	dd if=/bin/bash of=$SCRATCH_MNT/sh 2>&1 |_filter_dd
	sync
	rm -f $SCRATCH_MNT/sh
	_scratch_unmount

	_zero_position $value "$structure"
	_scratch_xfs_repair 2>&1 | _filter_repair

	# some basic sanity checks...
	_check_scratch_fs
	_scratch_mount                                      #mount
	POSIXLY_CORRECT=yes \
	dd if=/bin/bash of=$SCRATCH_MNT/sh 2>&1 |_filter_dd   #open,write
	POSIXLY_CORRECT=yes \
	dd if=$SCRATCH_MNT/sh of=/dev/null 2>&1 |_filter_dd #read
	rm -f $SCRATCH_MNT/sh                               #unlink
	_scratch_unmount                                    #umount
}

# make sure this script returns success
/bin/true