2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2014 Red Hat, Inc. All Rights Reserved.
5 # FS QA Test No. xfs/014
7 # Test the behavior of XFS dynamic speculative preallocation at ENOSPC and
8 # EDQUOT conditions. Speculative preallocation allocates post-EOF space to files
9 # as they are extended. This test creates conditions where an fs is near a space
10 # limit with lingering, relatively significant preallocations and verifies that
11 # new writers reclaim said preallocations rather than prematurely fail with
15 _begin_fstest auto enospc quick quota
17 # Import common functions.
21 # Override the default cleanup function.
25 umount $LOOP_MNT 2>/dev/null
26 _scratch_unmount 2>/dev/null
30 # Create a file using a repeated open, extending write and close pattern. This
31 # causes the preallocation to persist after the file is closed. Preallocation
32 # will not be reclaimed unless the inode is evicted or we hit an allocation
40 # Now that we have background garbage collection processes that can be
41 # triggered by low space/quota conditions, it's possible that we won't
42 # succeed in creating a speculative preallocation on the first try.
43 for ((tries = 0; tries < 5 && prealloc_size == 0; tries++)); do
46 # a few file extending open-write-close cycles should be enough
47 # to trigger the fs to retain preallocation. write 256k in 32k
48 # intervals to be sure
49 for i in $(seq 0 32768 262144); do
50 $XFS_IO_PROG -f -c "pwrite $i 32k" $file >> $seqres.full
53 # write a 4k aligned amount of data to keep the calculations
55 $XFS_IO_PROG -c "pwrite 0 128m" $file >> $seqres.full
57 size=`_get_filesize $file`
58 blocks=`stat -c "%b" $file`
59 blocksize=`stat -c "%B" $file`
61 prealloc_size=$((blocks * blocksize - size))
64 if [ $prealloc_size -eq 0 ]; then
65 echo "Warning: No speculative preallocation for $file after $tries iterations." \
66 "Check use of the allocsize= mount option."
69 # keep a running total of how much preallocation we've created
70 TOTAL_PREALLOC=$((TOTAL_PREALLOC + prealloc_size))
77 # allocate all but 10MB of available space
78 freesp=`$DF_PROG -m $dir | $AWK_PROG '/^\// { print $5 - 10 }'`
79 $XFS_IO_PROG -f -c "falloc 0 ${freesp}M" $dir/spc
82 # Create several files with preallocation and consume the remaining free space
83 # via fallocate to the put the fs at ENOSPC. Create a set of background writers
84 # to write into ENOSPC and cause the preallocation to be reclaimed and
85 # reallocated to the new writers.
93 for i in $(seq 0 3); do
94 _spec_prealloc_file $dir/pre$i
97 _consume_free_space $dir
99 # consume 1/2 of the current preallocation across the set of 4 writers
100 write_size=$((TOTAL_PREALLOC / 2 / 4))
101 for i in $(seq 0 3); do
104 for i in $(seq 0 3); do
105 $XFS_IO_PROG -f -c "pwrite 0 $write_size" $dir/file.$i \
112 # Create preallocations accounted by both user and group quotas. Set the
113 # associated quota hard limits to put them at EDQUOT. Verify that a new writer
114 # reclaims the preallocated space and proceeds without error.
122 _spec_prealloc_file $dir/user
123 chown $qa_user $dir/user
125 _spec_prealloc_file $dir/group
126 chgrp $qa_group $dir/group
128 # writing to a file under both quotas means both will be reclaimed on
131 chown $qa_user $dir/file
132 chgrp $qa_group $dir/file
134 # put both quotas at EDQUOT
135 blks=`$XFS_QUOTA_PROG -xc "quota -u $qa_user" $dir | \
136 tail -n 1 | awk '{ print $2 }'`
137 $XFS_QUOTA_PROG -xc "limit -u bhard=${blks}k $qa_user" $dir
138 blks=`$XFS_QUOTA_PROG -xc "quota -g $qa_group" $dir | \
139 tail -n 1 | awk '{ print $2 }'`
140 $XFS_QUOTA_PROG -xc "limit -g bhard=${blks}k $qa_group" $dir
142 # each quota has a single file worth of preallocation to reclaim. leave
143 # some wiggle room and write to 1/3 the total.
144 write_size=$((TOTAL_PREALLOC / 3))
145 $XFS_IO_PROG -c "pwrite 0 $write_size" $dir/file >> $seqres.full
148 # real QA test starts here
152 _require_xfs_io_command "falloc"
158 echo "Silence is golden."
160 _scratch_mkfs_xfs >> $seqres.full 2>&1
163 # make sure the background eofblocks scanner doesn't interfere
164 orig_sp_time=`cat /proc/sys/fs/xfs/speculative_prealloc_lifetime`
165 echo 9999 > /proc/sys/fs/xfs/speculative_prealloc_lifetime
167 LOOP_FILE=$SCRATCH_MNT/$seq.fs
168 LOOP_MNT=$SCRATCH_MNT/$seq.mnt
170 $MKFS_XFS_PROG -d "file=1,name=$LOOP_FILE,size=10g" >> $seqres.full 2>&1
173 mount -t xfs -o loop,uquota,gquota $LOOP_FILE $LOOP_MNT || \
174 _fail "Failed to mount loop fs."
176 _test_enospc $LOOP_MNT
177 _test_edquot $LOOP_MNT
181 echo $orig_sp_time > /proc/sys/fs/xfs/speculative_prealloc_lifetime