mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
ed8463509b
A simply reproducer from Frank Sorenson:
ftruncate(fd, 65012224)
io_prep_pwrite(iocbs[0], fd, buf[0], 1048576, 63963648);
io_prep_pwrite(iocbs[1], fd, buf[1], 1048576, 65012224);
io_submit(io_ctx, 1, &iocbs[0]);
io_submit(io_ctx, 1, &iocbs[1]);
io_getevents(io_ctx, 2, 2, events, NULL)
help to find an ext4 corruption:
**************** **************** ****************
* page 1 * * page 2 * * page 3 *
**************** **************** ****************
existing 0000000000000000 0000000000000000 0000000000000000
write 1 AAAAAAAAAAAAAA AA
write 2 BBBBBBBBBBBBBB BB
result 00AAAAAAAAAAAAAA 00BBBBBBBBBBBBBB BB00000000000000
desired 00AAAAAAAAAAAAAA AABBBBBBBBBBBBBB BB00000000000000
This issue remind us we might miss unaligned AIO test for long time.
We thought fsx cover this part, but looks like it's not. So this case
trys to cover unaligned direct AIO write test on file with different
initial truncate i_size.
The following patches fix the issue on xfs and ext4.
xfs: serialize unaligned dio writes against all other dio writes
ext4: Fix data corruption caused by unaligned direct AIO
Signed-off-by: Zorro Lang <zlang@redhat.com>
Reviewed-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
96 lines
2.9 KiB
Bash
Executable File
96 lines
2.9 KiB
Bash
Executable File
#! /bin/bash
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
# Copyright (c) 2019 Red Hat, Inc. All Rights Reserved.
|
|
#
|
|
# FS QA Test No. 538
|
|
#
|
|
# Non-block-aligned direct AIO write test with an initial truncate i_size.
|
|
#
|
|
# Uncover "ext4: Fix data corruption caused by unaligned direct AIO":
|
|
# (Ext4 needs to serialize unaligned direct AIO because the zeroing of
|
|
# partial blocks of two competing unaligned AIOs can result in data
|
|
# corruption.
|
|
#
|
|
# However it decides not to serialize if the potentially unaligned aio is
|
|
# past i_size with the rationale that no pending writes are possible past
|
|
# i_size. Unfortunately if the i_size is not block aligned and the second
|
|
# unaligned write lands past i_size, but still into the same block, it has
|
|
# the potential of corrupting the previous unaligned write to the same
|
|
# block.)
|
|
#
|
|
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.*
|
|
}
|
|
|
|
# get standard environment, filters and checks
|
|
. ./common/rc
|
|
. ./common/filter
|
|
|
|
# remove previous $seqres.full before test
|
|
rm -f $seqres.full
|
|
|
|
# real QA test starts here
|
|
_supported_fs generic
|
|
_supported_os Linux
|
|
_require_test
|
|
_require_aiodio aio-dio-write-verify
|
|
|
|
localfile=$TEST_DIR/${seq}-aio-dio-write-verify-testfile
|
|
diosize=`_min_dio_alignment $TEST_DEV`
|
|
blocksize=`_get_block_size $TEST_DIR`
|
|
bufsize=$((blocksize * 2))
|
|
truncsize=$((bufsize+diosize))
|
|
|
|
# Need smaller logical block size to do non-block-aligned test
|
|
if [ $diosize -ge $blocksize ];then
|
|
_notrun "Need device logical block size($diosize) < fs block size($blocksize)"
|
|
fi
|
|
|
|
rm -rf $localfile 2>/dev/null
|
|
# block-aligned aiodio write verification at first
|
|
$AIO_TEST -a size=$bufsize,off=0 -a size=$bufsize,off=$bufsize $localfile
|
|
|
|
# non-block-aligned aiodio write verification
|
|
# **************** **************** ****************
|
|
# * block 1&2 * * block 3&4 * * block 5&6 *
|
|
# **************** **************** ****************
|
|
# existing 0000000000000000 0000000000000000 0000000000000000
|
|
# truncate ---------------->|
|
|
# write 1 ZZZZZZZZZZZZZZZ Z
|
|
# write 2 |<---- ZZZZZZZZZZZZZZZ Z ---->|
|
|
#
|
|
# "Write 1" writes 2 blocks data at off=$diosize.
|
|
# "Write 2" seeks from 0 to "Write 1" end + block size, shift $diosize bytes each
|
|
# time, writes 2 blocksize data too.
|
|
# Verify there's not corruption each time.
|
|
i=0
|
|
while [ $((diosize * i)) -lt $((diosize + bufsize + blocksize)) ];do
|
|
position=$((diosize * i++))
|
|
# non-block-aligned AIO write on different i_size file
|
|
$AIO_TEST -t $truncsize -a size=$bufsize,off=$diosize \
|
|
-a size=$bufsize,off=$position \
|
|
$localfile
|
|
if [ $? -ne 0 ];then
|
|
echo "FAIL: [$truncsize, $bufsize, $diosize, $position]"
|
|
echo "-------------------------------------------------"
|
|
fi
|
|
rm -f $localfile
|
|
done
|
|
|
|
echo "Silence is golden"
|
|
|
|
# success, all done
|
|
status=0
|
|
exit
|