mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
generic: test read around EOF
As posix standard, if the file offset is at or past the end of file,
no bytes are read, and read() returns zero. There was a bug, when
DIO read offset is just past the EOF a little, but in the same block
with EOF, read returns different negative values.
Kernel commit 74cedf9b6c60 ("direct-io: Fix negative return from dio
read beyond eof") and commit 2d4594acbf6d ("fix the regression from
"direct-io: Fix negative return from dio read beyond eof"") fixed
the bug.
This case reads from range within EOF, past EOF and at EOF, to make
sure the return value as expected, especially read from past/at EOF
returns 0.
[eguan: update commit log and comments about information of the
specific bug, adjust read_test param order (offset, count, ret) and
test description]
Signed-off-by: Zorro Lang <zlang@redhat.com>
Reviewed-by: Eryu Guan <eguan@redhat.com>
Signed-off-by: Eryu Guan <eguan@redhat.com>
This commit is contained in:
Executable
+163
@@ -0,0 +1,163 @@
|
||||
#! /bin/bash
|
||||
# FS QA Test 450
|
||||
#
|
||||
# Test read around EOF. If the file offset is at or past the end of file,
|
||||
# no bytes are read, and read() returns zero. There was a bug, when DIO
|
||||
# read offset is just past the EOF a little, but in the same block with
|
||||
# EOF, read returns different negative values.
|
||||
#
|
||||
# The following two kernel commits fixed this bug:
|
||||
# 74cedf9b6c60 direct-io: Fix negative return from dio read beyond eof
|
||||
# 2d4594acbf6d fix the regression from "direct-io: Fix negative return
|
||||
# from dio read beyond eof"
|
||||
#
|
||||
#-----------------------------------------------------------------------
|
||||
# Copyright (c) 2017 Red Hat, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it would be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#-----------------------------------------------------------------------
|
||||
#
|
||||
|
||||
seq=`basename $0`
|
||||
seqres=$RESULT_DIR/$seq
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here=`pwd`
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
cd /
|
||||
rm -f $tmp.*
|
||||
rm -f $tfile
|
||||
}
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common/rc
|
||||
|
||||
# remove previous $seqres.full before test
|
||||
rm -f $seqres.full
|
||||
|
||||
# real QA test starts here
|
||||
_supported_fs generic
|
||||
_supported_os Linux
|
||||
_require_test
|
||||
_require_odirect
|
||||
|
||||
tfile=$TEST_DIR/testfile_${seq}
|
||||
ssize=`_min_dio_alignment $TEST_DEV`
|
||||
bsize=`_get_block_size $TEST_DIR`
|
||||
|
||||
# let's focus on the specific bug that only happens when $ssize <= $bsize
|
||||
if [ $ssize -gt $((bsize/4)) ]; then
|
||||
_notrun "Only test on sector size < half of block size"
|
||||
fi
|
||||
|
||||
rm -f $tfile 2>/dev/null
|
||||
|
||||
# check xfs_io pread result, especially for
|
||||
# Param1: expected pread offset
|
||||
# Param2: expected pread count
|
||||
# Param3: expected pread return
|
||||
#
|
||||
# If any of above values are not as expected, the output keeps
|
||||
# using the real value
|
||||
check_xfs_io_read()
|
||||
{
|
||||
OFFSET=$1
|
||||
COUNT=$2
|
||||
RETURN=$3
|
||||
|
||||
$AWK_PROG -v ret="$RETURN" -v cnt="$COUNT" -v off="$OFFSET" '
|
||||
/read/{
|
||||
split($2, bytes, "/")
|
||||
|
||||
retval=bytes[1]
|
||||
count=bytes[2]
|
||||
offset=$NF
|
||||
|
||||
if(retval != ret || count != cnt || offset != off)
|
||||
printf("expect [%s,%s,%s], got [%s,%s,%s]\n", \
|
||||
off, cnt, ret, offset, count, retval)
|
||||
|
||||
next
|
||||
}
|
||||
'
|
||||
}
|
||||
|
||||
# +-------------------------------------------------------+
|
||||
# | block | block |
|
||||
# +-------------------------------------------------------+
|
||||
# | sect | sect | sect | sect | sect | sect | sect | sect |
|
||||
# |
|
||||
# EOF
|
||||
# |<--------------- move EOF -------------->| xxxxxxxxxxx |
|
||||
# [pread1]
|
||||
# [ pread2 ]
|
||||
# [pread3]
|
||||
# [pread4] ... [pread5]
|
||||
#
|
||||
# Run below steps with different $operation and $openflag
|
||||
#
|
||||
# 1) write 2 blocks (6 sectors) data to move EOF to the penultimate sector
|
||||
# 2) read (pread1) the first sector within EOF
|
||||
# 3) read (pread2) the second block contain EOF
|
||||
# 4) read (pread3) a sector at (after) EOF
|
||||
# 5) read (pread4) the last sector past EOF
|
||||
# 6) read (pread5) at far away from EOF
|
||||
#
|
||||
asize=$((bsize * 2))
|
||||
tsize=$((asize - ssize * 2))
|
||||
|
||||
read_test()
|
||||
{
|
||||
local of="$1"
|
||||
local op="buffer read"
|
||||
|
||||
if [ "$of" != "" ]; then
|
||||
op="direct read"
|
||||
fi
|
||||
|
||||
echo "$op the first sector within EOF"
|
||||
$XFS_IO_PROG $of -c "pread 0 $ssize" $tfile | \
|
||||
check_xfs_io_read 0 "$ssize" "$ssize"
|
||||
|
||||
echo "$op the second block contains EOF"
|
||||
$XFS_IO_PROG $of -c "pread $bsize $bsize" $tfile | \
|
||||
check_xfs_io_read "$bsize" "$bsize" "$((tsize - bsize))"
|
||||
|
||||
echo "$op a sector at (after) EOF"
|
||||
$XFS_IO_PROG $of -c "pread $tsize $ssize" $tfile | \
|
||||
check_xfs_io_read "$tsize" "$ssize" "0"
|
||||
|
||||
echo "$op the last sector past EOF"
|
||||
$XFS_IO_PROG $of -c "pread $((tsize + ssize)) $ssize" $tfile | \
|
||||
check_xfs_io_read "$((tsize + ssize))" "$ssize" "0"
|
||||
|
||||
echo "$op at far away from EOF"
|
||||
$XFS_IO_PROG $of -c "pread $((bsize * 100)) $ssize" $tfile | \
|
||||
check_xfs_io_read "$((bsize * 100))" "$ssize" "0"
|
||||
}
|
||||
|
||||
# Test buffer/direct I/O read
|
||||
$XFS_IO_PROG -ft -c "pwrite 0 ${tsize}" -c "fsync" $tfile >>$seqres.full
|
||||
for oflag in "" "-d"; do
|
||||
read_test "$oflag"
|
||||
done
|
||||
|
||||
# success, all done
|
||||
status=0
|
||||
exit
|
||||
@@ -0,0 +1,11 @@
|
||||
QA output created by 450
|
||||
buffer read the first sector within EOF
|
||||
buffer read the second block contains EOF
|
||||
buffer read a sector at (after) EOF
|
||||
buffer read the last sector past EOF
|
||||
buffer read at far away from EOF
|
||||
direct read the first sector within EOF
|
||||
direct read the second block contains EOF
|
||||
direct read a sector at (after) EOF
|
||||
direct read the last sector past EOF
|
||||
direct read at far away from EOF
|
||||
@@ -452,3 +452,4 @@
|
||||
447 auto quick clone
|
||||
448 auto quick rw
|
||||
449 auto quick acl enospc
|
||||
450 auto quick rw
|
||||
|
||||
Reference in New Issue
Block a user