summaryrefslogtreecommitdiff
path: root/common/ext4
blob: 3dcbfe17c994a6b7b5f00a0a86808a72f969a174 (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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#
# ext4 specific common functions
#

__generate_ext4_report_vars() {
	__generate_blockdev_report_vars TEST_LOGDEV
	__generate_blockdev_report_vars SCRATCH_LOGDEV
}

_setup_large_ext4_fs()
{
	local fs_size=$1
	local tmp_dir=/tmp/

	[ "$LARGE_SCRATCH_DEV" != yes ] && return 0
	[ -z "$SCRATCH_DEV_EMPTY_SPACE" ] && SCRATCH_DEV_EMPTY_SPACE=0
	[ $SCRATCH_DEV_EMPTY_SPACE -ge $fs_size ] && return 0

	# Default free space in the FS is 50GB, but you can specify more via
	# SCRATCH_DEV_EMPTY_SPACE
	local space_to_consume=$(($fs_size - 50*1024*1024*1024 - $SCRATCH_DEV_EMPTY_SPACE))

	# mount the filesystem and create 16TB - 4KB files until we consume
	# all the necessary space.
	_try_scratch_mount 2>&1 >$tmp_dir/mnt.err
	local status=$?
	if [ $status -ne 0 ]; then
		echo "mount failed"
		cat $tmp_dir/mnt.err >&2
		rm -f $tmp_dir/mnt.err
		return $status
	fi
	rm -f $tmp_dir/mnt.err

	local file_size=$((16*1024*1024*1024*1024 - 4096))
	local nfiles=0
	while [ $space_to_consume -gt $file_size ]; do

		xfs_io -F -f \
			-c "truncate $file_size" \
			-c "falloc -k 0 $file_size" \
			$SCRATCH_MNT/.use_space.$nfiles 2>&1
		status=$?
		if [ $status -ne 0 ]; then
			break;
		fi

		space_to_consume=$(( $space_to_consume - $file_size ))
		nfiles=$(($nfiles + 1))
	done

	# consume the remaining space.
	if [ $space_to_consume -gt 0 ]; then
		xfs_io -F -f \
			-c "truncate $space_to_consume" \
			-c "falloc -k 0 $space_to_consume" \
			$SCRATCH_MNT/.use_space.$nfiles 2>&1
		status=$?
	fi
	export NUM_SPACE_FILES=$nfiles

	_scratch_unmount
	if [ $status -ne 0 ]; then
		echo "large file prealloc failed"
		cat $tmp_dir/mnt.err >&2
		return $status
	fi
	return 0
}

_scratch_mkfs_ext4_opts()
{
	mkfs_opts=$*

	_scratch_options mkfs

	echo "$MKFS_EXT4_PROG $SCRATCH_OPTIONS $mkfs_opts"
}

_scratch_mkfs_ext4()
{
	local mkfs_cmd="`_scratch_mkfs_ext4_opts`"
	local mkfs_filter="grep -v -e ^Warning: -e \"^mke2fs \" | grep -v \"^$\""
	local tmp=`mktemp -u`
	local mkfs_status

	if [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ]; then
		$MKFS_EXT4_PROG -F -O journal_dev $MKFS_OPTIONS $* $SCRATCH_LOGDEV 2>$tmp.mkfserr 1>$tmp.mkfsstd
		mkjournal_status=$?

		if [ $mkjournal_status -ne 0 ]; then
			cat $tmp.mkfsstd
			cat $tmp.mkfserr >&2
			return $mkjournal_status
		fi
	fi

	_scratch_do_mkfs "$mkfs_cmd" "$mkfs_filter" $* 2>$tmp.mkfserr 1>$tmp.mkfsstd
	mkfs_status=$?

	if [ $mkfs_status -eq 0 -a "$LARGE_SCRATCH_DEV" = yes ]; then
		# manually parse the mkfs output to get the fs size in bytes
		local fs_size=`cat $tmp.mkfsstd | awk ' \
			/^Block size/ { split($2, a, "="); bs = a[2] ; } \
			/ inodes, / { blks = $3 } \
			/reserved for the super user/ { resv = $1 } \
			END { fssize = bs * blks - resv; print fssize }'`

		_setup_large_ext4_fs $fs_size
		mkfs_status=$?
	fi

	# output mkfs stdout and stderr
	cat $tmp.mkfsstd
	cat $tmp.mkfserr >&2
	rm -f $tmp.mkfserr $tmp.mkfsstd

	return $mkfs_status
}

_ext4_metadump()
{
	local device="$1"
	local dumpfile="$2"
	local compressopt="$3"

	test -n "$E2IMAGE_PROG" || _fail "e2image not installed"
	$E2IMAGE_PROG -Q "$device" "$dumpfile"
	[ "$compressopt" = "compress" ] && [ -n "$DUMP_COMPRESSOR" ] &&
		$DUMP_COMPRESSOR -f "$dumpfile" &>> "$seqres.full"
}

_ext4_mdrestore()
{
	local metadump="$1"
	local device="$2"
	shift; shift
	local options="$@"

	# If we're configured for compressed dumps and there isn't already an
	# uncompressed dump, see if we can use DUMP_COMPRESSOR to decompress
	# something.
	if [ ! -e "$metadump" ] && [ -n "$DUMP_COMPRESSOR" ]; then
		for compr in "$metadump".*; do
			[ -e "$compr" ] && $DUMP_COMPRESSOR -d -f -k "$compr" && break
		done
	fi
	test -r "$metadump" || return 1

	$E2IMAGE_PROG $options -r "${metadump}" "${SCRATCH_DEV}"
}

# this test requires the ext4 kernel support crc feature on scratch device
#
_require_scratch_ext4_crc()
{
	_scratch_mkfs_ext4 >/dev/null 2>&1
	dumpe2fs -h $SCRATCH_DEV 2> /dev/null | grep -q metadata_csum || _notrun "metadata_csum not supported by this filesystem"
	_try_scratch_mount >/dev/null 2>&1 \
	   || _notrun "Kernel doesn't support metadata_csum feature"
	_scratch_unmount
}

# Check whether the specified feature whether it is supported by
# mkfs.ext4 and the kernel.
_require_scratch_ext4_feature()
{
    if [ -z "$1" ]; then
        echo "Usage: _require_scratch_ext4_feature feature"
        exit 1
    fi
    $MKFS_EXT4_PROG -F $MKFS_OPTIONS -O "$1" \
		    $SCRATCH_DEV 512m >/dev/null 2>&1 \
	|| _notrun "mkfs.ext4 doesn't support $1 feature"
    _try_scratch_mount >/dev/null 2>&1 \
	|| _notrun "Kernel doesn't support the ext4 feature(s): $1"
    _scratch_unmount
}

# Disable extent zeroing for ext4 on the given device
_ext4_disable_extent_zeroout()
{
	local dev=${1:-$TEST_DEV}
	local sdev=`_short_dev $dev`

	[ -f /sys/fs/ext4/$sdev/extent_max_zeroout_kb ] && \
		echo 0 >/sys/fs/ext4/$sdev/extent_max_zeroout_kb
}

_require_scratch_richacl_ext4()
{
	_scratch_mkfs -O richacl >/dev/null 2>&1 \
		|| _notrun "can't mkfs $FSTYP with option -O richacl"
	_try_scratch_mount >/dev/null 2>&1 \
		|| _notrun "kernel doesn't support richacl feature on $FSTYP"
	_scratch_unmount
}

_scratch_ext4_options()
{
	local type=$1
	local log_opt=""

	case $type in
	mkfs)
		SCRATCH_OPTIONS="$SCRATCH_OPTIONS -F"
		log_opt="-J device=$SCRATCH_LOGDEV"
		;;
	mount)
		# As of kernel 5.19, the kernel mount option path parser only
		# accepts direct paths to block devices--the final path
		# component cannot be a symlink.
		log_opt="-o journal_path=$(realpath -q "$SCRATCH_LOGDEV")"
		;;
	esac
	[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
		SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${log_opt}"
}

# Get the inode flags for a particular inode number
_ext4_get_inum_iflags() {
	local dev="$1"
	local inumber="$2"

	debugfs -R "stat <${inumber}>" "${dev}" 2> /dev/null | \
			sed -n 's/^.*Flags: \([0-9a-fx]*\).*$/\1/p'
}