On Tue, Mar 12, 2019 at 06:12:08PM -0700, Darrick J. Wong wrote: > On Tue, Mar 12, 2019 at 05:19:44PM +0800, Zorro Lang wrote: > > 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_prep_pwrite(iocbs[2], fd, buf[2], 1048576, 66060800); > > io_prep_pwrite(iocbs[3], fd, buf[3], 1048576, 67109376); > > > > io_submit(io_ctx, 1, &iocbs[0]); > > io_submit(io_ctx, 1, &iocbs[1]); > > io_submit(io_ctx, 1, &iocbs[2]); > > io_submit(io_ctx, 1, &iocbs[3]); > > > > io_getevents(io_ctx, 4, 4, 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. > > > > Signed-off-by: Zorro Lang <zlang@xxxxxxxxxx> > > --- > > > > Hi, > > > > The aio-dio-write-verify.c nearly copy from aio-dio-eof-race.c, then change > > a few logic. I've changed aio-dio-eof-race.c several times, to fit different > > new AIO test cases. But this time I need to truncate the file, then it won't > > write at EOF. This against the motive of aio-dio-eof-race.c. So I think it's > > time to shift a new program to do more AIO write test. > > > > It's only my personal opinion :) > > > > Thanks, > > Zorro > > > > src/aio-dio-regress/aio-dio-write-verify.c | 223 +++++++++++++++++++++ > > tests/generic/999 | 71 +++++++ > > tests/generic/999.out | 2 + > > tests/generic/group | 1 + > > 4 files changed, 297 insertions(+) > > create mode 100644 src/aio-dio-regress/aio-dio-write-verify.c > > create mode 100755 tests/generic/999 > > create mode 100644 tests/generic/999.out > > > > diff --git a/src/aio-dio-regress/aio-dio-write-verify.c b/src/aio-dio-regress/aio-dio-write-verify.c > > new file mode 100644 > > index 00000000..402ddcdb > > --- /dev/null > > +++ b/src/aio-dio-regress/aio-dio-write-verify.c > > @@ -0,0 +1,223 @@ > > +// SPDX-License-Identifier: GPL-2.0+ > > +/* > > + * Copyright (C) 2019 Red Hat, Inc. All Rights reserved. > > + * > > + * AIO writes from a start offset on a truncated file, verify there's not > > + * data corruption. > > + */ > > +#include <sys/stat.h> > > +#include <sys/types.h> > > +#include <errno.h> [snip..] > > + /* truncate the file to a special size at first */ > > + if (tsize != 0) { > > + ftruncate(fd, tsize); > > + if (fd == -1) { > > Huh? ret = ftruncate(...); if (ret) ? Wow, my bad, that's totally a mistake. > > > + perror("ftruncate"); > > + return 1; > > + } > > + } > > + > > + err = posix_memalign(&buf, getpagesize(), buf_size); > > + if (err) { > > + fprintf(stderr, "error %s during %s\n", > > + strerror(err), > > + "posix_memalign"); > > + return 1; > > + } > > + cmp_buf = malloc(buf_size); > > + memset(cmp_buf, IO_PATTERN, buf_size); > > + > > + err = io_setup(5, &ctx); > > + if (err) { > > + fprintf(stderr, "error %s during %s\n", > > + strerror(err), > > + "io_setup"); > > + return 1; > > + } > > + > > + bytes = 0; > > + /* Keep extending until size_KB */ > > + while (bytes < size_KB * 1024) { > > + ssize_t sret; > > + int i; > > + > > + memset(buf, IO_PATTERN, buf_size); > > + > > + io_prep_pwrite(&iocb1, fd, buf, buf_size/2, \ > > + startoff + bytes + 0*buf_size/2); > > + io_prep_pwrite(&iocb2, fd, buf, buf_size/2, \ > > + startoff + bytes + 1*buf_size/2); > > + > > + err = io_submit(ctx, 2, iocbs); > > + if (err != 2) { > > + fprintf(stderr, "error %s during %s\n", > > + strerror(err), > > + "io_submit"); > > + return 1; > > + } > > + > > + err = io_getevents(ctx, 2, 2, evs, NULL); > > + if (err != 2) { > > + fprintf(stderr, "error %s during %s\n", > > + strerror(err), > > + "io_getevents"); > > + return 1; > > + } > > + > > + for (i = 0; i < err; i++) { > > + /* > > + * res is unsigned for some reason, so this is the best > > + * way to detect that it contains a negative errno. > > + */ > > + if (evs[i].res > buf_size / 2) { > > + fprintf(stderr, "pwrite: %s\n", > > + strerror(-evs[i].res)); > > + return 1; > > + } > > + } > > + fsync(fd); > > Ignoring the return value here... This operation is not a necessary step for the reproducer, so just try to do a sync, no matter the result. Hmm... should I remove it? > > --D > > > + > > + /* > > + * And then read it back, then compare with original content. > > + */ > > + sret = pread(fd, buf, buf_size, startoff + bytes); > > + if (sret == -1) { > > + perror("pread"); > > + return 1; > > + } else if (sret != buf_size) { > > + fprintf(stderr, "short read %zd was less than %zu\n", > > + sret, buf_size); > > + return 1; > > + } > > + if (memcmp(buf, cmp_buf, buf_size)) { > > + printf("Find corruption\n"); > > + dump_buffer(buf, 0, buf_size); > > + return 1; > > + } > > + > > + /* Calculate how many bytes we've written after pread */ > > + bytes += buf_size; > > + } > > + > > + return 0; > > +} > > diff --git a/tests/generic/999 b/tests/generic/999 > > new file mode 100755 > > index 00000000..6fcc593a > > --- /dev/null > > +++ b/tests/generic/999 > > @@ -0,0 +1,71 @@ > > +#! /bin/bash > > +# SPDX-License-Identifier: GPL-2.0 > > +# Copyright (c) 2019 Red Hat, Inc. All Rights Reserved. > > +# > > +# FS QA Test No. 999 > > +# > > +# Non-page-aligned direct AIO write test. AIO write from unalinged offset > > +# on a file with different initial truncate i_size. > > +# > > +# Uncover "ext4: Fix data corruption caused by unaligned direct AIO" > > +# > > +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 > > +_require_test_program "feature" > > + > > +localfile=$TEST_DIR/tst-aio-dio-testfile > > +diosize=`_min_dio_alignment $TEST_DEV` > > +pagesize=`src/feature -s` > > +bufsize=$((pagesize * 2)) > > +filesize=$((bufsize * 3 / 1024)) > > + > > +# Need smaller logical block size to do non-page-aligned test > > +if [ $diosize -ge $pagesize ];then > > + _notrun "Need device logical block size($diosize) < page size($pagesize)" > > +fi > > + > > +rm -rf $localfile 2>/dev/null > > +# page-aligned aiodio write verification at first > > +$AIO_TEST -s $((bufsize * 10)) -b $bufsize $localfile > > + > > +# non-page-aligned aiodio write verification > > +i=0 > > +while [ $((diosize * i)) -lt $bufsize ];do > > + truncsize=$((diosize * i++)) > > + # non-page-aligned AIO write on different i_size file > > + $AIO_TEST -s $filesize -b $bufsize -o $diosize -t $truncsize $localfile > > + if [ $? -ne 0 ];then > > + echo "[FAIL] $AIO_TEST -s $filesize -b $bufsize -o $diosize -t $truncsize $localfile" > > + fi > > +done > > + > > +echo "Silence is golden" > > + > > +# success, all done > > +status=0 > > +exit > > diff --git a/tests/generic/999.out b/tests/generic/999.out > > new file mode 100644 > > index 00000000..3b276ca8 > > --- /dev/null > > +++ b/tests/generic/999.out > > @@ -0,0 +1,2 @@ > > +QA output created by 999 > > +Silence is golden > > diff --git a/tests/generic/group b/tests/generic/group > > index 15227b67..b1f93d99 100644 > > --- a/tests/generic/group > > +++ b/tests/generic/group > > @@ -534,3 +534,4 @@ > > 529 auto quick attr > > 530 auto quick unlink > > 531 auto quick unlink > > +999 auto quick aio > > -- > > 2.17.2 > >