summaryrefslogtreecommitdiff
path: root/tests/generic/251
blob: b7a15f91894fad6c9c1803d3eca4c6744056d290 (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
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright 2010 (C) Red Hat, Inc., Lukas Czerner <lczerner@redhat.com>
#
# FS QA Test No. 251
#
# This test was created in order to verify filesystem FITRIM implementation.
# By many concurrent copy and remove operations and checking that files
# does not change after copied into SCRATCH_MNT test if FITRIM implementation
# corrupts the filesystem (data/metadata).
#
. ./common/preamble
_begin_fstest ioctl trim auto

tmp=`mktemp -d`
trap "_cleanup; exit \$status" 0 1 3
trap "_destroy; exit \$status" 2 15
chpid=0
mypid=$$

# Import common functions.
. ./common/filter

# real QA test starts here
_supported_fs generic
_require_scratch
_scratch_mkfs >/dev/null 2>&1
_scratch_mount
_require_batched_discard $SCRATCH_MNT

# Override the default cleanup function.
_cleanup()
{
	rm -rf $tmp
}

_destroy()
{
	kill $pids $fstrim_pid 2> /dev/null
	wait $pids $fstrim_pid 2> /dev/null
	rm -rf $tmp
}

_destroy_fstrim()
{
	kill $fpid 2> /dev/null
	wait $fpid 2> /dev/null
}

_fail()
{
	echo "$1"
	kill $mypid 2> /dev/null
}

# Set FSTRIM_{MIN,MAX}_MINLEN to the lower and upper bounds of the -m(inlen)
# parameter to fstrim on the scratch filesystem.
set_minlen_constraints()
{
	local mmlen

	for ((mmlen = 100000; mmlen > 0; mmlen /= 2)); do
		$FSTRIM_PROG -l $(($mmlen*2))k -m ${mmlen}k $SCRATCH_MNT &> /dev/null && break
	done
	test $mmlen -gt 0 || \
		_notrun "could not determine maximum FSTRIM minlen param"
	FSTRIM_MAX_MINLEN=$mmlen

	for ((mmlen = 1; mmlen < FSTRIM_MAX_MINLEN; mmlen *= 2)); do
		$FSTRIM_PROG -l $(($mmlen*2))k -m ${mmlen}k $SCRATCH_MNT &> /dev/null && break
	done
	test $mmlen -le $FSTRIM_MAX_MINLEN || \
		_notrun "could not determine minimum FSTRIM minlen param"
	FSTRIM_MIN_MINLEN=$mmlen
}

# Set FSTRIM_{MIN,MAX}_LEN to the lower and upper bounds of the -l(ength)
# parameter to fstrim on the scratch filesystem.
set_length_constraints()
{
	local mmlen

	for ((mmlen = 100000; mmlen > 0; mmlen /= 2)); do
		$FSTRIM_PROG -l ${mmlen}k $SCRATCH_MNT &> /dev/null && break
	done
	test $mmlen -gt 0 || \
		_notrun "could not determine maximum FSTRIM length param"
	FSTRIM_MAX_LEN=$mmlen

	for ((mmlen = 1; mmlen < FSTRIM_MAX_LEN; mmlen *= 2)); do
		$FSTRIM_PROG -l ${mmlen}k $SCRATCH_MNT &> /dev/null && break
	done
	test $mmlen -le $FSTRIM_MAX_LEN || \
		_notrun "could not determine minimum FSTRIM length param"
	FSTRIM_MIN_LEN=$mmlen
}

##
# Background FSTRIM loop. We are trimming the device in the loop and for
# test coverage, we are doing whole device trim followed by several smaller
# trims.
##
fstrim_loop()
{
	set_minlen_constraints
	set_length_constraints
	echo "MINLEN max=$FSTRIM_MAX_MINLEN min=$FSTRIM_MIN_MINLEN" >> $seqres.full
	echo "LENGTH max=$FSTRIM_MAX_LEN min=$FSTRIM_MIN_LEN" >> $seqres.full

	trap "_destroy_fstrim; exit \$status" 2 15
	fsize=$(_discard_max_offset_kb "$SCRATCH_MNT" "$SCRATCH_DEV")

	while true ; do
		while true; do
			step=$((RANDOM*$RANDOM+4))
			test "$step" -ge "$FSTRIM_MIN_LEN" && break
		done
		while true; do
			minlen=$(( (RANDOM * (RANDOM % 2 + 1)) % FSTRIM_MAX_MINLEN ))
			test "$minlen" -ge "$FSTRIM_MIN_MINLEN" && break
		done

		start=$RANDOM
		if [ $((RANDOM%10)) -gt 7 ]; then
			$FSTRIM_PROG $SCRATCH_MNT &
			fpid=$!
			wait $fpid
		fi
		while [ $start -lt $fsize ] ; do
			$FSTRIM_PROG -m ${minlen}k -o ${start}k -l ${step}k $SCRATCH_MNT &
			fpid=$!
			wait $fpid
			start=$(( $start + $step ))
		done
	done
}

function check_sums() {
	(
	cd $SCRATCH_MNT/$p
	find -P . -xdev -type f -print0 | xargs -0 md5sum | sort -o $tmp/stress.$$.$p
	)

	diff $tmp/content.sums $tmp/stress.$$.$p
	if [ $? -ne 0 ]; then
		_fail "!!!Checksums has changed - Filesystem possibly corrupted!!!\n"
	fi
	rm -f $tmp/stress.$$.$p
}

function run_process() {
	local p=$1
	repeat=10

	sleep $((5*$p))s &
	export chpid=$! && wait $chpid &> /dev/null
	chpid=0

	while [ $repeat -gt 0 ]; do

		# Remove old directories.
		rm -rf $SCRATCH_MNT/$p
		export chpid=$! && wait $chpid &> /dev/null

		# Copy content -> partition.
		mkdir $SCRATCH_MNT/$p
		cp -axT $content/ $SCRATCH_MNT/$p/
		export chpid=$! && wait $chpid &> /dev/null

		check_sums
		repeat=$(( $repeat - 1 ))
	done
}

nproc=20

# Copy $here to the scratch fs and make coipes of the replica.  The fstests
# output (and hence $seqres.full) could be in $here, so we need to snapshot
# $here before computing file checksums.
content=$SCRATCH_MNT/orig
mkdir -p $content
cp -axT $here/ $content/

mkdir -p $tmp

(
cd $content
find -P . -xdev -type f -print0 | xargs -0 md5sum | sort -o $tmp/content.sums
)

echo -n "Running the test: "
pids=""
fstrim_loop &
fstrim_pid=$!
p=1
while [ $p -le $nproc ]; do
	run_process $p &
	pids="$pids $!"
	p=$(($p+1))
done
echo "done."

wait $pids
kill $fstrim_pid
wait $fstrim_pid

status=0

exit