generic: test MADV_POPULATE_READ with IO errors
[xfstests-dev.git] / tests / generic / 563
1 #! /bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2019 Red Hat, Inc.  All Rights Reserved.
4 #
5 # FS QA Test No. 563
6 #
7 # This test verifies that cgroup aware writeback properly accounts I/Os in
8 # various scenarios. We perform reads/writes from different combinations of
9 # cgroups and verify that pages are accounted against the group that brought
10 # them into cache.
11 #
12
13 . ./common/preamble
14 _begin_fstest auto quick
15
16 # Override the default cleanup function.
17 _cleanup()
18 {
19         cd /
20         rm -f $tmp.*
21
22         echo $$ > $cgdir/cgroup.procs
23         rmdir $cgdir/$seq-cg* > /dev/null 2>&1
24         umount $SCRATCH_MNT > /dev/null 2>&1
25         _destroy_loop_device $LOOP_DEV > /dev/null 2>&1
26 }
27
28 # Import common functions.
29 . ./common/filter
30 . ./common/cgroup2
31
32 # real QA test starts here
33
34 # Modify as appropriate.
35 _supported_fs generic
36 _require_scratch_nocheck
37 _require_cgroup2 io
38 _require_loop
39
40 # cgroup v2 writeback is only support on block devices so far
41 _require_block_device $SCRATCH_DEV
42
43 cgdir=$CGROUP2_PATH
44 iosize=$((1024 * 1024 * 8))
45
46 # Check cgroup read/write charges against expected values. Allow for some
47 # tolerance as different filesystems seem to account slightly differently.
48 check_cg()
49 {
50         cgroot=$1
51         cgname=$(basename $cgroot)
52         expectedread=$2
53         expectedwrite=$3
54         readtol=$4
55         writetol=$5
56         rbytes=0
57         wbytes=0
58
59         iobytes=`cat $cgroot/io.stat | grep $smajor:$sminor`
60         if [ $? == 0 ]; then
61                 rbytes=`echo $iobytes | awk '{ print $2 }' | \
62                         awk -F = '{ print $2 }'`
63                 wbytes=`echo $iobytes | awk '{ print $3 }' | \
64                         awk -F = '{ print $2 }'`
65         fi
66
67         _within_tolerance "read" $rbytes $expectedread $readtol -v
68         _within_tolerance "write" $wbytes $expectedwrite $writetol -v
69 }
70
71 # Move current process to another cgroup.
72 switch_cg()
73 {
74         mkdir -p $1
75         echo $$ > $1/cgroup.procs
76 }
77
78 # Reset cgroup state for a new test.
79 reset()
80 {
81         echo $$ > $cgdir/cgroup.procs
82         rmdir $cgdir/$seq-cg* > /dev/null 2>&1
83         $XFS_IO_PROG -fc "pwrite 0 $iosize" $SCRATCH_MNT/file \
84                 >> $seqres.full 2>&1
85         umount $SCRATCH_MNT || _fail "umount failed"
86         _mount $LOOP_DEV $SCRATCH_MNT || _fail "mount failed"
87         stat $SCRATCH_MNT/file > /dev/null
88 }
89
90 # cgroup I/O accounting doesn't work on partitions. Use a loop device to rule
91 # that out.
92 LOOP_DEV=$(_create_loop_device $SCRATCH_DEV)
93 smajor=$((0x`stat -L -c %t $LOOP_DEV`))
94 sminor=$((0x`stat -L -c %T $LOOP_DEV`))
95
96 _mkfs_dev $LOOP_DEV >> $seqres.full 2>&1
97 _mount $LOOP_DEV $SCRATCH_MNT || _fail "mount failed"
98
99 drop_io_cgroup=
100 grep -q -w io $cgdir/cgroup.subtree_control || drop_io_cgroup=1
101
102 echo "+io" > $cgdir/cgroup.subtree_control || _fail "subtree control"
103
104 # Read and write from a single group.
105 echo "read/write"
106 reset
107 switch_cg $cgdir/$seq-cg
108 $XFS_IO_PROG -c "pread 0 $iosize" -c "pwrite 0 $iosize" -c fsync \
109         $SCRATCH_MNT/file >> $seqres.full 2>&1
110 switch_cg $cgdir
111 $XFS_IO_PROG -c fsync $SCRATCH_MNT/file
112 check_cg $cgdir/$seq-cg $iosize $iosize 5% 5%
113
114 # Write from one cgroup then read and write from a second. Writes are charged to
115 # the first group and nothing to the second.
116 echo "write -> read/write"
117 reset
118 switch_cg $cgdir/$seq-cg
119 $XFS_IO_PROG -c "pwrite 0 $iosize" $SCRATCH_MNT/file >> $seqres.full 2>&1
120 switch_cg $cgdir/$seq-cg-2
121 $XFS_IO_PROG -c "pread 0 $iosize" -c "pwrite 0 $iosize" $SCRATCH_MNT/file \
122         >> $seqres.full 2>&1
123 switch_cg $cgdir
124 $XFS_IO_PROG -c fsync $SCRATCH_MNT/file
125 # Use a fixed value tolerance for the expected value of zero here
126 # because filesystems might perform a small number of metadata reads to
127 # complete the write. On ext2/3 with 1k block size, the read bytes is
128 # as large as 33792.
129 check_cg $cgdir/$seq-cg 0 $iosize 33792 5%
130 check_cg $cgdir/$seq-cg-2 0 0 0 0
131
132 # Read from one cgroup, read & write from a second. Both reads and writes are
133 # charged to the first group and nothing to the second.
134 echo "read -> read/write"
135 reset
136 switch_cg $cgdir/$seq-cg
137 $XFS_IO_PROG -c "pread 0 $iosize" $SCRATCH_MNT/file >> $seqres.full 2>&1
138 switch_cg $cgdir/$seq-cg-2
139 $XFS_IO_PROG -c "pread 0 $iosize" -c "pwrite 0 $iosize" $SCRATCH_MNT/file \
140         >> $seqres.full 2>&1
141 switch_cg $cgdir
142 $XFS_IO_PROG -c fsync $SCRATCH_MNT/file
143 check_cg $cgdir/$seq-cg $iosize $iosize 5% 5%
144 check_cg $cgdir/$seq-cg-2 0 0 0 0
145
146 if [ "$drop_io_cgroup" = 1 ]; then
147         echo "-io" > $cgdir/cgroup.subtree_control || _fail "subtree control"
148 fi
149
150 # success, all done
151 status=0
152 exit