| #! /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.) |
| # |
| . ./common/preamble |
| _begin_fstest auto quick aio |
| |
| # Import common functions. |
| . ./common/filter |
| |
| # real QA test starts here |
| _supported_fs generic |
| _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 |