generic: test for file loss after mix of rename, fsync and inode eviction
[xfstests-dev.git] / tests / generic / 450
1 #! /bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2017 Red Hat, Inc.  All Rights Reserved.
4 #
5 # FS QA Test 450
6 #
7 # Test read around EOF. If the file offset is at or past the end of file,
8 # no bytes are read, and read() returns zero. There was a bug, when DIO
9 # read offset is just past the EOF a little, but in the same block with
10 # EOF, read returns different negative values.
11 #
12 # The following two kernel commits fixed this bug:
13 # 74cedf9b6c60 direct-io: Fix negative return from dio read beyond eof
14 # 2d4594acbf6d fix the regression from "direct-io: Fix negative return
15 # from dio read beyond eof"
16 #
17 . ./common/preamble
18 _begin_fstest auto quick rw
19
20 # Override the default cleanup function.
21 _cleanup()
22 {
23         cd /
24         rm -f $tmp.*
25         rm -f $tfile
26 }
27
28 # Import common functions.
29
30 # real QA test starts here
31 _supported_fs generic
32 _require_test
33 _require_odirect
34
35 tfile=$TEST_DIR/testfile_${seq}
36 ssize=`_min_dio_alignment $TEST_DEV`
37 bsize=`_get_block_size $TEST_DIR`
38
39 # let's focus on the specific bug that only happens when $ssize <= $bsize
40 if [ $ssize -gt $((bsize/4)) ]; then
41         _notrun "Only test on sector size < half of block size"
42 fi
43
44 rm -f $tfile 2>/dev/null
45
46 # check xfs_io pread result, especially for
47 # Param1: expected pread offset
48 # Param2: expected pread count
49 # Param3: expected pread return
50 #
51 # If any of above values are not as expected, the output keeps
52 # using the real value
53 check_xfs_io_read()
54 {
55         OFFSET=$1
56         COUNT=$2
57         RETURN=$3
58
59         $AWK_PROG -v ret="$RETURN" -v cnt="$COUNT" -v off="$OFFSET" '
60                 /read/{
61                         split($2, bytes, "/")
62
63                         retval=bytes[1]
64                         count=bytes[2]
65                         offset=$NF
66
67                         if(retval != ret || count != cnt || offset != off)
68                                 printf("expect [%s,%s,%s], got [%s,%s,%s]\n", \
69                                         off, cnt, ret, offset, count, retval)
70
71                         next
72                 }
73         '
74 }
75
76 # +-------------------------------------------------------+
77 # |           block           |           block           |
78 # +-------------------------------------------------------+
79 # | sect | sect | sect | sect | sect | sect | sect | sect |
80 #                                           |
81 #                                          EOF
82 # |<--------------- move EOF -------------->| xxxxxxxxxxx |
83 # [pread1]
84 #                             [           pread2          ]
85 #                                           [pread3]
86 #                                                  [pread4]  ...  [pread5]
87 #
88 # Run below steps with different $operation and $openflag
89 #
90 # 1) write 2 blocks (6 sectors) data to move EOF to the penultimate sector
91 # 2) read (pread1) the first sector within EOF
92 # 3) read (pread2) the second block contain EOF
93 # 4) read (pread3) a sector at (after) EOF
94 # 5) read (pread4) the last sector past EOF
95 # 6) read (pread5) at far away from EOF
96 #
97 asize=$((bsize * 2))
98 tsize=$((asize - ssize * 2))
99
100 read_test()
101 {
102         local of="$1"
103         local op="buffer read"
104
105         if [ "$of" != "" ]; then
106                 op="direct read"
107         fi
108
109         echo "$op the first sector within EOF"
110         $XFS_IO_PROG $of -c "pread 0 $ssize" $tfile | \
111                 check_xfs_io_read 0 "$ssize" "$ssize"
112
113         echo "$op the second block contains EOF"
114         $XFS_IO_PROG $of -c "pread $bsize $bsize" $tfile | \
115                 check_xfs_io_read "$bsize" "$bsize" "$((tsize - bsize))"
116
117         echo "$op a sector at (after) EOF"
118         $XFS_IO_PROG $of -c "pread $tsize $ssize" $tfile | \
119                 check_xfs_io_read "$tsize" "$ssize" "0"
120
121         echo "$op the last sector past EOF"
122         $XFS_IO_PROG $of -c "pread $((tsize + ssize)) $ssize" $tfile | \
123                 check_xfs_io_read "$((tsize + ssize))" "$ssize" "0"
124
125         echo "$op at far away from EOF"
126         $XFS_IO_PROG $of -c "pread $((bsize * 100)) $ssize" $tfile | \
127                 check_xfs_io_read "$((bsize * 100))" "$ssize" "0"
128 }
129
130 # Test buffer/direct I/O read
131 $XFS_IO_PROG -ft -c "pwrite 0 ${tsize}" -c "fsync" $tfile >>$seqres.full
132 for oflag in "" "-d"; do
133         read_test "$oflag"
134 done
135
136 # success, all done
137 status=0
138 exit