summaryrefslogtreecommitdiff
path: root/tests/xfs/013
blob: 2d005753d10450aa718532f8f91127dae166b3ce (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
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2014 Red Hat, Inc.  All Rights Reserved.
#
# FS QA Test No. xfs/013
#
# Exercise the free inode btree (finobt). XFS allocates physical inodes in
# chunks of 64. Inode records with at least one free inode are stored in the
# finobt to optimize free inode lookup. This test runs a workload that creates
# and modifies a sparsely allocated set of inodes in combination with an
# fsstress workload.
#
. ./common/preamble
_begin_fstest auto metadata stress

# Import common functions.
. ./common/filter

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

filter_enospc() {
	sed -e '/^.*No space left on device.*/d'
}

_create()
{
	dir=$1
	count=$2

	mkdir -p $dir
	for i in $(seq 0 $count)
	do
		touch $dir/$i 2>&1 | filter_enospc
	done
}

_rand_replace()
{
	dir=$1
	count=$2

	# replace 5% of the dataset
	for i in $(seq 0 $((count / 20)))
	do
		file=$((RANDOM % count))
		rm -f $dir/$file
		touch $dir/$file 2>&1 | filter_enospc
	done
}

_cleaner()
{
	dir=$1
	iters=$2
	mindirs=$3

	iters=$((iters - mindirs))

	for i in $(seq 1 $iters)
	do
		need=$dir/dir$((i + mindirs))
		while [ ! -e $need ]
		do
			sleep 3
			if ! pgrep fsstress > /dev/null 2>&1; then
				echo "fsstress died?"
				return
			fi
		done

		rm -rf $dir/dir$i
	done
}

# real QA test starts here
_supported_fs xfs

_require_scratch
_require_xfs_mkfs_finobt
_require_xfs_finobt
_require_command "$KILLALL_PROG" killall

_scratch_mkfs_xfs "-m crc=1,finobt=1 -d agcount=2" | \
	_filter_mkfs 2>> $seqres.full
_scratch_mount

COUNT=20000	# number of files per directory
LOOPS=15	# last loop iteration
MINDIRS=2	# number of dirs for the cleaner to leave trailing behind the
		# most recent (no less than 2 to prevent an rm from trampling a
		# clone)

# create initial directory
_create $SCRATCH_MNT/dir1 $COUNT

# start background cleaner to remove old directories as new ones are created
_cleaner $SCRATCH_MNT $LOOPS $MINDIRS &

# start a background stress workload on the fs
$FSSTRESS_PROG -d $SCRATCH_MNT/fsstress -n 9999999 -p 2 -S t \
	>> $seqres.full 2>&1 &

# Each cycle clones the current directory and makes a random file replacement
# pass on the new directory. The directory is copied to the next using hard
# links. The replacement pass then randomly removes and replaces ~5% of the
# content in the directory. Files replaced as such are effectively marked to be
# freed by the background cleaner as it moves forward and removes all of the
# previous hard links to the inode. Over several iterations, this workload
# creates a sparsely located set of a free inodes across the set and uses the
# finobt to allocate new inodes for replacement.

for i in $(seq 1 $LOOPS)
do
	# hard link the content of the current directory to the next
	while ! test -d $SCRATCH_MNT/dir$((i+1)); do
		cp -Rl $SCRATCH_MNT/dir$i $SCRATCH_MNT/dir$((i+1)) 2>&1 | \
			filter_enospc
	done

	# do a random replacement of files in the new directory
	_rand_replace $SCRATCH_MNT/dir$((i+1)) $COUNT
done

$KILLALL_PROG fsstress
wait

# clean out the competing fsstress allocations, then everything else
rm -rf $SCRATCH_MNT/fsstress
rm -rf $SCRATCH_MNT/dir*

_scratch_unmount

status=0
exit