Files
apfstests/tests/generic/564
T
Amir Goldstein f60eeb9a21 generic: copy_file_range bounds test
Test that copy_file_range will return the correct errors for various
error conditions and boundary constraints.

This is a regression test for kernel commit:

  96e6e8f4a68d ("vfs: add missing checks to copy_file_range")

[Amir] Split out cross-device copy_range test and use only test dev.
Split out immutable/swapfile test cases to reduce the requirements to
run the bounds check to minimum and get coverage for more filesystems.
Remove the tests for read past EOF and write after chmod -r,
because we decided to stick with read(2)/write(2) semantics.
Add requirements needed for large size copy tests and fifo test.
Use existing char/block devices for char/block dev tests.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Eryu Guan <guaneryu@gmail.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
2019-07-22 00:41:30 +08:00

135 lines
3.8 KiB
Bash
Executable File

#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2018 Red Hat, Inc. All Rights Reserved.
#
# FS QA Test No. 564
#
# Exercise copy_file_range() syscall error conditions.
#
# This is a regression test for kernel commit:
# 96e6e8f4a68d ("vfs: add missing checks to copy_file_range")
#
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 7 15
_cleanup()
{
cd /
rm -rf $tmp.*
[ -z "$loopdev" ] || _destroy_loop_device $loopdev
}
# get standard environment, filters and checks
. ./common/rc
. ./common/filter
# real QA test starts here
_supported_os Linux
_supported_fs generic
rm -f $seqres.full
_require_test
_require_loop
#
# This test effectively requires xfs_io with these commits
# 2a42470b xfs_io: copy_file_range length is a size_t
# 1a05efba io: open pipes in non-blocking mode
#
# Without those commits test will hang on old kernel when copying
# very large size and when copying from a pipe.
#
# We require a new xfs_io feature of passing an open file as the
# copy source, as an indication that the test can run without hanging
# with large size argument and to avoid opening pipe in blocking mode.
#
_require_xfs_io_command "copy_range" "-f"
testdir="$TEST_DIR/test-$seq"
rm -rf $testdir
mkdir $testdir
rm -f $seqres.full
$XFS_IO_PROG -f -c "pwrite -S 0x61 0 128k" $testdir/file >> $seqres.full 2>&1
echo source range overlaps destination range in same file returns EINVAL
$XFS_IO_PROG -f -c "copy_range -s 32k -d 48k -l 32k $testdir/file" $testdir/file
echo
echo destination file O_RDONLY returns EBADF
$XFS_IO_PROG -f -r -c "copy_range -l 32k $testdir/file" $testdir/copy
echo
echo destination file O_APPEND returns EBADF
$XFS_IO_PROG -f -a -c "copy_range -l 32k $testdir/file" $testdir/copy
echo
echo source/destination as directory returns EISDIR
$XFS_IO_PROG -c "copy_range -l 32k $testdir/file" $testdir
$XFS_IO_PROG -f -c "copy_range -l 32k $testdir" $testdir/copy
echo
echo source/destination as blkdev returns EINVAL
$XFS_IO_PROG -f -c "truncate 128k" $testdir/img >> $seqres.full 2>&1
loopdev=`_create_loop_device $testdir/img`
$XFS_IO_PROG -c "copy_range -l 32k $testdir/file" $loopdev
$XFS_IO_PROG -f -c "copy_range -l 32k $loopdev" $testdir/copy
_destroy_loop_device $loopdev
loopdev=
echo
echo source/destination as chardev returns EINVAL
$XFS_IO_PROG -c "copy_range -l 32k $testdir/file" /dev/null
$XFS_IO_PROG -f -c "copy_range -l 32k /dev/zero" $testdir/copy
echo
echo source/destination as FIFO returns EINVAL
mkfifo $testdir/fifo
$XFS_IO_PROG -c "copy_range -l 32k $testdir/file" $testdir/fifo
# Pass input pipe as non-blocking open file to avoid old xfs_io (<4.20)
# opening the pipe in blocking mode and causing the test to hang
$XFS_IO_PROG -r -n -f -c "open $testdir/copy" -C "copy_range -l 32k -f 0" $testdir/fifo
max_off=$((8 * 2**60 - 65536 - 1))
min_off=65537
echo
echo length beyond 8EiB wraps around 0 returns EOVERFLOW
$XFS_IO_PROG -f -c "copy_range -l 10e -s $max_off $testdir/file" $testdir/copy
$XFS_IO_PROG -f -c "copy_range -l 10e -d $max_off $testdir/file" $testdir/copy
echo
echo source range beyond 8TiB returns 0
$XFS_IO_PROG -c "copy_range -s $max_off -l $min_off -d 0 $testdir/file" $testdir/copy
echo
echo destination range beyond 8TiB returns EFBIG
$XFS_IO_PROG -c "copy_range -l $min_off -s 0 -d $max_off $testdir/file" $testdir/copy
echo
echo destination larger than rlimit returns EFBIG
rm -f $testdir/copy
$XFS_IO_PROG -c "truncate 128k" $testdir/file
# need a wrapper so the "File size limit exceeded" error can be filtered
do_rlimit_copy()
{
$XFS_IO_PROG -f -c "copy_range -l 32k -s 0 -d 16m $testdir/file" $testdir/copy
}
ulimit -f $((8 * 1024))
ulimit -c 0
do_rlimit_copy 2>&1 | grep -o "File size limit exceeded"
ulimit -f unlimited
# success, all done
status=0
exit