On Mon, Apr 15, 2024 at 01:10:54AM -0700, Luis Chamberlain wrote: > mmap() POSIX compliance says we should zero fill data beyond a file > size up to page boundary, and issue a SIGBUS if we go beyond. While fsx > helps us test zero-fill sometimes, fsstress also let's us sometimes test > for SIGBUS however that is based on a random value and its not likley we > always test it. Dedicate a specic test for this to make testing for > this specific situation and to easily expand on other corner cases. > > Suggested-by: Matthew Wilcox <willy@xxxxxxxxxxxxx> > Signed-off-by: Luis Chamberlain <mcgrof@xxxxxxxxxx> > --- > > Does enough to get us to use to test this, however I'm aware of a bit > more polishing up to do: > > * maybe moving mread to common as generic/574 did it first > * sharing round_up_to_page_boundary() as well > > generic/574 is special, it was just testing for correctness of > integrity if we muck with mmap() however if you don't have verity > stuff available obviously you won't end up testing it. > > This generalizes mmap() zero-fill and SIGBUS corner case tests. > > I've tested so far only 4k and it works well there. For 16k bs on LBS > just the SIGBUS issue exists, I'll test smaller block sizes later like > 512, 1k, 2k as well. We'll fix triggering the SIBGUS when LBS is used, > we'll address that in the next iteration. > > Is this a worthy test as a generic test? > > common/filter | 6 ++ > tests/generic/740 | 231 ++++++++++++++++++++++++++++++++++++++++++ > tests/generic/740.out | 2 + > 3 files changed, 239 insertions(+) > create mode 100755 tests/generic/740 > create mode 100644 tests/generic/740.out > We could also extend the test to include mmap writes. I took the lazy approach here but I think we can make the code look prettier by adding some more functions that can do both mmap read and writes. diff --git a/tests/generic/740 b/tests/generic/740 index cbb82301..93663964 100755 --- a/tests/generic/740 +++ b/tests/generic/740 @@ -53,6 +53,25 @@ round_up_to_page_boundary() echo $(( (n + page_size - 1) & ~(page_size - 1) )) } +mwrite() +{ + local file=$1 + local map_len=$2 + local offset=$3 + local length=$4 + + # Some callers expect xfs_io to crash with SIGBUS due to the mread, + # causing the shell to print "Bus error" to stderr. To allow this + # message to be redirected, execute xfs_io in a new shell instance. + # However, for this to work reliably, we also need to prevent the new + # shell instance from optimizing out the fork and directly exec'ing + # xfs_io. The easiest way to do that is to append 'true' to the + # commands, so that xfs_io is no longer the last command the shell sees. + bash -c "trap '' SIGBUS; $XFS_IO_PROG $file \ + -c 'mmap -w 0 $map_len' \ + -c 'mwrite $offset $length'; true" +} + mread() { local file=$1 @@ -180,6 +199,12 @@ do_mmap_tests() _fail fi + # This should just work + mwrite $test_file $map_len 0 $map_len >> $seqres.full 2>$tmp.err + if [[ $? -ne 0 ]]; then + _fail + fi + # If we mmap() on the boundary but try to read beyond it just # fails, we don't get a SIGBUS $XFS_IO_PROG -r $test_file \ @@ -192,12 +217,29 @@ do_mmap_tests() _fail fi + $XFS_IO_PROG -w $test_file \ + -c "mmap -w 0 $map_len" \ + -c "mwrite 0 $((map_len + 10))" >> $seqres.full 2>$tmp.err + local mwrite_err=$? + if [[ $mwrite_err -eq 0 ]]; then + echo "mmap() to page boundary works as expected but writing beyond should fail" + echo "err: $?" + _fail + fi + # Now let's go beyond the allowed mmap() page boundary mread $test_file $((map_len + 10)) 0 $((map_len + 10)) >> $seqres.full 2>$tmp.err if ! grep -q 'Bus error' $tmp.err; then echo "Expected SIGBUS when mmap() reading beyond page boundary" _fail fi + + mwrite $test_file $((map_len + 10)) 0 $((map_len + 10)) >> $seqres.full 2>$tmp.err + if ! grep -q 'Bus error' $tmp.err; then + echo "Expected SIGBUS when mmap() writing beyond page boundary" + _fail + fi + local filelen_test=$(_get_filesize $test_file) if [[ "$filelen_test" != "$new_filelen" ]]; then echo "Expected file length: $new_filelen" -- Pankaj