xfs/007: fix regressions on V4 filesystems
[xfstests-dev.git] / tests / xfs / 014
1 #!/bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2014 Red Hat, Inc.  All Rights Reserved.
4 #
5 # FS QA Test No. xfs/014
6 #
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
12 # ENOSPC/EDQUOT.
13 #
14 . ./common/preamble
15 _begin_fstest auto enospc quick quota
16
17 # Import common functions.
18 . ./common/filter
19 . ./common/quota
20
21 # Override the default cleanup function.
22 _cleanup()
23 {
24         cd /
25         umount $LOOP_MNT 2>/dev/null
26         _scratch_unmount 2>/dev/null
27         rm -f $tmp.*
28 }
29
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
33 # failure.
34 _spec_prealloc_file()
35 {
36         file=$1
37
38         rm -f $file
39
40         # a few file extending open-write-close cycles should be enough to
41         # trigger the fs to retain preallocation. write 256k in 32k intervals to
42         # be sure
43         for i in $(seq 0 32768 262144); do
44                 $XFS_IO_PROG -f -c "pwrite $i 32k" $file >> $seqres.full
45         done
46
47         # write a 4k aligned amount of data to keep the calculations simple
48         $XFS_IO_PROG -c "pwrite 0 128m" $file >> $seqres.full
49
50         size=`_get_filesize $file`
51         blocks=`stat -c "%b" $file`
52         blocksize=`stat -c "%B" $file`
53
54         prealloc_size=$((blocks * blocksize - size))
55         if [ $prealloc_size -eq 0 ]; then
56                 echo "Warning: No speculative preallocation for $file." \
57                         "Check use of the allocsize= mount option."
58         fi
59
60         # keep a running total of how much preallocation we've created
61         TOTAL_PREALLOC=$((TOTAL_PREALLOC + prealloc_size))
62 }
63
64 _consume_free_space()
65 {
66         dir=$1
67
68         # allocate all but 10MB of available space
69         freesp=`$DF_PROG -m $dir | $AWK_PROG '/^\// { print $5 - 10 }'`
70         $XFS_IO_PROG -f -c "falloc 0 ${freesp}M" $dir/spc
71 }
72
73 # Create several files with preallocation and consume the remaining free space
74 # via fallocate to the put the fs at ENOSPC. Create a set of background writers
75 # to write into ENOSPC and cause the preallocation to be reclaimed and
76 # reallocated to the new writers.
77 _test_enospc()
78 {
79         dir=$1
80
81         rm -rf $dir/*
82
83         TOTAL_PREALLOC=0
84         for i in $(seq 0 3); do
85                 _spec_prealloc_file $dir/pre$i
86         done
87
88         _consume_free_space $dir
89
90         # consume 1/2 of the current preallocation across the set of 4 writers
91         write_size=$((TOTAL_PREALLOC / 2 / 4))
92         for i in $(seq 0 3); do
93                 touch $dir/file.$i
94         done
95         for i in $(seq 0 3); do
96                 $XFS_IO_PROG -f -c "pwrite 0 $write_size" $dir/file.$i \
97                         >> $seqres.full &
98         done
99
100         wait
101 }
102
103 # Create preallocations accounted by both user and group quotas. Set the
104 # associated quota hard limits to put them at EDQUOT. Verify that a new writer
105 # reclaims the preallocated space and proceeds without error.
106 _test_edquot()
107 {
108         dir=$1
109
110         rm -rf $dir/*
111
112         TOTAL_PREALLOC=0
113         _spec_prealloc_file $dir/user
114         chown $qa_user $dir/user
115
116         _spec_prealloc_file $dir/group
117         chgrp $qa_group $dir/group
118
119         # writing to a file under both quotas means both will be reclaimed on
120         # allocation failure
121         touch $dir/file
122         chown $qa_user $dir/file
123         chgrp $qa_group $dir/file
124
125         # put both quotas at EDQUOT
126         blks=`$XFS_QUOTA_PROG -xc "quota -u $qa_user" $dir | \
127                 tail -n 1 | awk '{ print $2 }'`
128         $XFS_QUOTA_PROG -xc "limit -u bhard=${blks}k $qa_user" $dir
129         blks=`$XFS_QUOTA_PROG -xc "quota -g $qa_group" $dir | \
130                 tail -n 1 | awk '{ print $2 }'`
131         $XFS_QUOTA_PROG -xc "limit -g bhard=${blks}k $qa_group" $dir
132
133         # each quota has a single file worth of preallocation to reclaim. leave
134         # some wiggle room and write to 1/3 the total.
135         write_size=$((TOTAL_PREALLOC / 3))
136         $XFS_IO_PROG -c "pwrite 0 $write_size" $dir/file >> $seqres.full
137 }
138
139 # real QA test starts here
140 _supported_fs xfs
141
142 _require_scratch
143 _require_xfs_io_command "falloc"
144 _require_loop
145 _require_quota
146 _require_user
147 _require_group
148
149 echo "Silence is golden."
150
151 _scratch_mkfs_xfs >> $seqres.full 2>&1
152 _scratch_mount
153
154 # make sure the background eofblocks scanner doesn't interfere
155 orig_sp_time=`cat /proc/sys/fs/xfs/speculative_prealloc_lifetime`
156 echo 9999 > /proc/sys/fs/xfs/speculative_prealloc_lifetime
157
158 LOOP_FILE=$SCRATCH_MNT/$seq.fs
159 LOOP_MNT=$SCRATCH_MNT/$seq.mnt
160
161 $MKFS_XFS_PROG -d "file=1,name=$LOOP_FILE,size=10g" >> $seqres.full 2>&1
162
163 mkdir -p $LOOP_MNT
164 mount -t xfs -o loop,uquota,gquota $LOOP_FILE $LOOP_MNT || \
165         _fail "Failed to mount loop fs."
166
167 _test_enospc $LOOP_MNT
168 _test_edquot $LOOP_MNT
169
170 umount $LOOP_MNT
171
172 echo $orig_sp_time > /proc/sys/fs/xfs/speculative_prealloc_lifetime
173
174 _scratch_unmount
175
176 status=0
177 exit