blob: be25c17645c69f0616b67cf13c898ea6c6b7220e (
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
|
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2014 Red Hat, Inc. All Rights Reserved.
#
# FS QA Test No. xfs/014
#
# Test the behavior of XFS dynamic speculative preallocation at ENOSPC and
# EDQUOT conditions. Speculative preallocation allocates post-EOF space to files
# as they are extended. This test creates conditions where an fs is near a space
# limit with lingering, relatively significant preallocations and verifies that
# new writers reclaim said preallocations rather than prematurely fail with
# ENOSPC/EDQUOT.
#
. ./common/preamble
_begin_fstest auto enospc quick quota prealloc
# Import common functions.
. ./common/filter
. ./common/quota
# Override the default cleanup function.
_cleanup()
{
cd /
umount $LOOP_MNT 2>/dev/null
_scratch_unmount 2>/dev/null
rm -f $tmp.*
}
# Create a file using a repeated open, extending write and close pattern. This
# causes the preallocation to persist after the file is closed. Preallocation
# will not be reclaimed unless the inode is evicted or we hit an allocation
# failure.
_spec_prealloc_file()
{
local file=$1
local prealloc_size=0
local i=0
# Now that we have background garbage collection processes that can be
# triggered by low space/quota conditions, it's possible that we won't
# succeed in creating a speculative preallocation on the first try.
for ((tries = 0; tries < 5 && prealloc_size == 0; tries++)); do
rm -f $file
# a few file extending open-write-close cycles should be enough
# to trigger the fs to retain preallocation. write 256k in 32k
# intervals to be sure
for i in $(seq 0 32768 262144); do
$XFS_IO_PROG -f -c "pwrite $i 32k" $file >> $seqres.full
done
# write a 4k aligned amount of data to keep the calculations
# simple
$XFS_IO_PROG -c "pwrite 0 128m" $file >> $seqres.full
size=`_get_filesize $file`
blocks=`stat -c "%b" $file`
blocksize=`stat -c "%B" $file`
prealloc_size=$((blocks * blocksize - size))
done
if [ $prealloc_size -eq 0 ]; then
echo "Warning: No speculative preallocation for $file after $tries iterations." \
"Check use of the allocsize= mount option."
fi
# keep a running total of how much preallocation we've created
TOTAL_PREALLOC=$((TOTAL_PREALLOC + prealloc_size))
}
_consume_free_space()
{
dir=$1
# allocate all but 10MB of available space
freesp=`$DF_PROG -m $dir | $AWK_PROG '/^\// { print $5 - 10 }'`
$XFS_IO_PROG -f -c "falloc 0 ${freesp}M" $dir/spc
}
# Create several files with preallocation and consume the remaining free space
# via fallocate to the put the fs at ENOSPC. Create a set of background writers
# to write into ENOSPC and cause the preallocation to be reclaimed and
# reallocated to the new writers.
_test_enospc()
{
dir=$1
rm -rf $dir/*
TOTAL_PREALLOC=0
for i in $(seq 0 3); do
_spec_prealloc_file $dir/pre$i
done
_consume_free_space $dir
# consume 1/2 of the current preallocation across the set of 4 writers
write_size=$((TOTAL_PREALLOC / 2 / 4))
for i in $(seq 0 3); do
touch $dir/file.$i
done
for i in $(seq 0 3); do
$XFS_IO_PROG -f -c "pwrite 0 $write_size" $dir/file.$i \
>> $seqres.full &
done
wait
}
# Create preallocations accounted by both user and group quotas. Set the
# associated quota hard limits to put them at EDQUOT. Verify that a new writer
# reclaims the preallocated space and proceeds without error.
_test_edquot()
{
dir=$1
rm -rf $dir/*
TOTAL_PREALLOC=0
_spec_prealloc_file $dir/user
chown $qa_user $dir/user
_spec_prealloc_file $dir/group
chgrp $qa_group $dir/group
# writing to a file under both quotas means both will be reclaimed on
# allocation failure
touch $dir/file
chown $qa_user $dir/file
chgrp $qa_group $dir/file
# put both quotas at EDQUOT
blks=`$XFS_QUOTA_PROG -xc "quota -u $qa_user" $dir | \
tail -n 1 | awk '{ print $2 }'`
$XFS_QUOTA_PROG -xc "limit -u bhard=${blks}k $qa_user" $dir
blks=`$XFS_QUOTA_PROG -xc "quota -g $qa_group" $dir | \
tail -n 1 | awk '{ print $2 }'`
$XFS_QUOTA_PROG -xc "limit -g bhard=${blks}k $qa_group" $dir
# each quota has a single file worth of preallocation to reclaim. leave
# some wiggle room and write to 1/3 the total.
write_size=$((TOTAL_PREALLOC / 3))
$XFS_IO_PROG -c "pwrite 0 $write_size" $dir/file >> $seqres.full
}
# real QA test starts here
_supported_fs xfs
_require_scratch
_require_xfs_io_command "falloc"
_require_loop
_require_quota
_require_user
_require_group
echo "Silence is golden."
_scratch_mkfs_xfs >> $seqres.full 2>&1
_scratch_mount
# make sure the background eofblocks scanner doesn't interfere
orig_sp_time=`cat /proc/sys/fs/xfs/speculative_prealloc_lifetime`
echo 9999 > /proc/sys/fs/xfs/speculative_prealloc_lifetime
LOOP_FILE=$SCRATCH_MNT/$seq.fs
LOOP_MNT=$SCRATCH_MNT/$seq.mnt
$MKFS_XFS_PROG -d "file=1,name=$LOOP_FILE,size=10g" >> $seqres.full 2>&1
mkdir -p $LOOP_MNT
mount -t xfs -o loop,uquota,gquota $LOOP_FILE $LOOP_MNT || \
_fail "Failed to mount loop fs."
_test_enospc $LOOP_MNT
_test_edquot $LOOP_MNT
umount $LOOP_MNT
echo $orig_sp_time > /proc/sys/fs/xfs/speculative_prealloc_lifetime
_scratch_unmount
status=0
exit
|