]> git.apps.os.sepia.ceph.com Git - xfstests-dev.git/commitdiff
dio: unwritten conversion bug tests
authorDarrick J. Wong <darrick.wong@oracle.com>
Tue, 2 Feb 2016 01:50:31 +0000 (17:50 -0800)
committerDarrick J. Wong <darrick.wong@oracle.com>
Fri, 12 Feb 2016 17:39:05 +0000 (09:39 -0800)
Check that we don't expose old disk contents when a directio write to
an unwritten extent fails due to IO errors.  This primarily affects
XFS and ext4.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
.gitignore
src/aio-dio-regress/aiocp.c [new file with mode: 0644]
tests/generic/250 [new file with mode: 0755]
tests/generic/250.out [new file with mode: 0644]
tests/generic/252 [new file with mode: 0755]
tests/generic/252.out [new file with mode: 0644]
tests/generic/group

index a6f47d3de60fcc8efb35f5db01dcfd4600794a3c..bbe7c1a94da5a1b5dbc1ec25a0f3745697e6c40a 100644 (file)
 /src/aio-dio-regress/aio-free-ring-with-bogus-nr-pages
 /src/aio-dio-regress/aio-io-setup-with-nonwritable-context-pointer
 /src/aio-dio-regress/aio-last-ref-held-by-io
+/src/aio-dio-regress/aiocp
 /src/aio-dio-regress/aiodio_sparse2
 /src/aio-dio-regress/aio-dio-eof-race
 /src/cloner
diff --git a/src/aio-dio-regress/aiocp.c b/src/aio-dio-regress/aiocp.c
new file mode 100644 (file)
index 0000000..1abff9c
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 2004 Daniel McNeil <daniel@osdl.org>
+ *               2004 Open Source Development Lab
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Module: .c
+ */
+
+/*
+ * Change History:
+ *
+ *
+ * version of copy command using async i/o
+ * From:       Stephen Hemminger <shemminger@osdl.org>
+ * Modified by Daniel McNeil <daniel@osdl.org> for testing aio.
+ *     - added -a alignment
+ *     - added -b blksize option 
+ *     _ added -s size option
+ *     - added -f open_flag option
+ *     - added -w (no write) option (reads from source only)
+ *     - added -n (num aio) option 
+ *     - added -z (zero dest) opton (writes zeros to dest only)
+ *     - added -D delay_ms option
+ *  - 2/2004  Marty Ridgeway (mridge@us.ibm.com) Changes to adapt to LTP
+ *
+ * Copy file by using a async I/O state machine.
+ * 1. Start read request
+ * 2. When read completes turn it into a write request
+ * 3. When write completes decrement counter and free resources
+ *
+ *
+ * Usage: aiocp [-b blksize] -n [num_aio] [-w] [-z] [-s filesize] 
+ *             [-f DIRECT|TRUNC|CREAT|SYNC|LARGEFILE] src dest
+ */
+
+//#define _GNU_SOURCE
+//#define DEBUG 1
+#undef DEBUG
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/select.h>
+
+#include <libaio.h>
+
+#define AIO_BLKSIZE    (64*1024)
+#define AIO_MAXIO      32
+
+static int aio_blksize = AIO_BLKSIZE;
+static int aio_maxio = AIO_MAXIO;
+
+static int busy = 0;           // # of I/O's in flight
+static int tocopy = 0;         // # of blocks left to copy
+static int srcfd;              // source fd
+static int dstfd = -1;         // destination file descriptor
+static const char *dstname = NULL;
+static const char *srcname = NULL;
+static int source_open_flag = O_RDONLY;        /* open flags on source file */
+static int dest_open_flag = O_WRONLY;  /* open flags on dest file */
+static int no_write;                   /* do not write */
+static int zero;                       /* write zero's only */
+
+static int debug;
+static int count_io_q_waits;   /* how many time io_queue_wait called */
+
+struct iocb **iocb_free;       /* array of pointers to iocb */
+int iocb_free_count;           /* current free count */
+int alignment = 512;           /* buffer alignment */
+
+struct timeval delay;          /* delay between i/o */
+
+int init_iocb(int n, int iosize)
+{
+       void *buf;
+       int i;
+
+       if ((iocb_free = malloc(n * sizeof(struct iocb *))) == 0) {
+               return -1;
+       }
+
+       for (i = 0; i < n; i++) {
+               if (!(iocb_free[i] = (struct iocb *) malloc(sizeof(struct iocb))))
+                       return -1;
+               if (posix_memalign(&buf, alignment, iosize))
+                       return -1;
+               if (debug > 1) {
+                       printf("buf allocated at 0x%p, align:%d\n",
+                                       buf, alignment);
+               }
+               if (zero) {
+                       /*
+                        * We are writing zero's to dstfd
+                        */
+                       memset(buf, 0, iosize);
+               }
+               io_prep_pread(iocb_free[i], -1, buf, iosize, 0);
+       }
+       iocb_free_count = i;
+       return 0;
+}
+
+struct iocb *alloc_iocb()
+{
+       if (!iocb_free_count)
+               return 0;
+       return iocb_free[--iocb_free_count];
+}
+
+void free_iocb(struct iocb *io)
+{
+       iocb_free[iocb_free_count++] = io;
+}
+
+/*
+ * io_wait_run() - wait for an io_event and then call the callback.
+ */
+int io_wait_run(io_context_t ctx, struct timespec *to)
+{
+       struct io_event events[aio_maxio];
+       struct io_event *ep;
+       int ret, n;
+
+       /*
+        * get up to aio_maxio events at a time.
+        */
+       ret = n = io_getevents(ctx, 1, aio_maxio, events, to);
+
+       /*
+        * Call the callback functions for each event.
+        */
+       for (ep = events; n-- > 0; ep++) {
+               io_callback_t cb = (io_callback_t)ep->data;
+               struct iocb *iocb = (struct iocb *)ep->obj;
+
+               cb(ctx, iocb, ep->res, ep->res2);
+       }
+       return ret;
+}
+
+/* Fatal error handler */
+static void io_error(const char *func, int rc)
+{
+       if (rc == -ENOSYS)
+               fprintf(stderr, "AIO not in this kernel\n");
+       else if (rc < 0)
+               fprintf(stderr, "%s: %s\n", func, strerror(-rc));
+       else
+               fprintf(stderr, "%s: error %d\n", func, rc);
+
+       if (dstfd > 0)
+               close(dstfd);
+       if (dstname && dest_open_flag & O_CREAT)
+               unlink(dstname);
+       exit(1);
+}
+
+/*
+ * Write complete callback.
+ * Adjust counts and free resources
+ */
+static void wr_done(io_context_t ctx, struct iocb *iocb, long res, long res2)
+{
+       if (res2 != 0) {
+               io_error("aio write", res2);
+       }
+       if (res != iocb->u.c.nbytes) {
+               fprintf(stderr, "write missed bytes expect %lu got %ld\n",
+                       iocb->u.c.nbytes, res2);
+               exit(1);
+       }
+       --tocopy;
+       --busy;
+       free_iocb(iocb);
+       if (debug)
+               write(2, "w", 1);
+}
+
+/*
+ * Read complete callback.
+ * Change read iocb into a write iocb and start it.
+ */
+static void rd_done(io_context_t ctx, struct iocb *iocb, long res, long res2)
+{
+       /* library needs accessors to look at iocb? */
+       int iosize = iocb->u.c.nbytes;
+       char *buf = iocb->u.c.buf;
+       off_t offset = iocb->u.c.offset;
+
+       if (res2 != 0)
+               io_error("aio read", res2);
+       if (res != iosize) {
+               fprintf(stderr, "read missing bytes expect %lu got %ld\n",
+                       iocb->u.c.nbytes, res);
+               exit(1);
+       }
+
+
+       /* turn read into write */
+       if (no_write) {
+               --tocopy;
+               --busy;
+               free_iocb(iocb);
+       } else {
+               io_prep_pwrite(iocb, dstfd, buf, iosize, offset);
+               io_set_callback(iocb, wr_done);
+               if (1 != (res = io_submit(ctx, 1, &iocb)))
+                       io_error("io_submit write", res);
+       }
+       if (debug)
+               write(2, "r", 1);
+       if (debug > 1)
+               printf("%d", iosize);
+}
+
+void usage()
+{
+       fprintf(stderr,
+               "Usage: aiocp [-a align] [-s size] [-b blksize] [-n num_io]"
+               " [-f open_flag] SOURCE DEST\n"
+               "This copies from SOURCE to DEST using AIO.\n\n"
+               "Usage: aiocp [options] -w SOURCE\n"
+               "This does sequential AIO reads (no writes).\n\n"
+               "Usage: aiocp [options] -z DEST\n"
+               "This does sequential AIO writes of zeros.\n");
+               
+       exit(1);
+}
+
+/*
+ * Scale value by kilo, mega, or giga.
+ */
+long long scale_by_kmg(long long value, char scale)
+{
+       switch (scale) {
+       case 'g':
+       case 'G':
+               value *= 1024;
+       case 'm':
+       case 'M':
+               value *= 1024;
+       case 'k':
+       case 'K':
+               value *= 1024;
+               break;
+       case '\0':
+               break;
+       default:
+               usage();
+               break;
+       }
+       return value;
+}
+
+int main(int argc, char *const *argv)
+{
+       struct stat st;
+       off_t length = 0, offset = 0;
+       io_context_t myctx;
+       int c;
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+
+       while ((c = getopt(argc, argv, "a:b:df:n:s:wzD:")) != -1) {
+               char *endp;
+
+               switch (c) {
+               case 'a':       /* alignment of data buffer */
+                       alignment = strtol(optarg, &endp, 0);
+                       alignment = (long)scale_by_kmg((long long)alignment,
+                                                       *endp);
+                       break;
+               case 'f':       /* use these open flags */
+                       if (strcmp(optarg, "LARGEFILE") == 0 ||
+                           strcmp(optarg, "O_LARGEFILE") == 0) {
+                               source_open_flag |= O_LARGEFILE;
+                               dest_open_flag |= O_LARGEFILE;
+                       } else if (strcmp(optarg, "TRUNC") == 0 ||
+                                  strcmp(optarg, "O_TRUNC") == 0) {
+                               dest_open_flag |= O_TRUNC;
+                       } else if (strcmp(optarg, "SYNC") == 0 ||
+                                  strcmp(optarg, "O_SYNC") == 0) {
+                               dest_open_flag |= O_SYNC | O_NONBLOCK;
+                       } else if (strcmp(optarg, "DIRECT") == 0 ||
+                                  strcmp(optarg, "O_DIRECT") == 0) {
+                               source_open_flag |= O_DIRECT;
+                               dest_open_flag |= O_DIRECT;
+                       } else if (strncmp(optarg, "CREAT", 5) == 0 ||
+                                  strncmp(optarg, "O_CREAT", 5) == 0) {
+                               dest_open_flag |= O_CREAT;
+                       }
+                       break;
+               case 'd':
+                       debug++;
+                       break;
+               case 'D':
+                       delay.tv_usec = atoi(optarg);
+                       break;
+               case 'b':       /* block size */
+                       aio_blksize = strtol(optarg, &endp, 0);
+                       aio_blksize = (long)scale_by_kmg((long long)aio_blksize, *endp);
+                       break;
+
+               case 'n':       /* num io */
+                       aio_maxio = strtol(optarg, &endp, 0);
+                       break;
+               case 's':       /* size to transfer */
+                       length = strtoll(optarg, &endp, 0);
+                       length = scale_by_kmg(length, *endp);
+                       break;
+               case 'w':       /* no write */
+                       no_write = 1;
+                       break;
+               case 'z':       /* write zero's */
+                       zero = 1;
+                       break;
+
+               default:
+                       usage();
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       
+#ifndef DEBUG
+       if (argc < 1) {
+               usage();
+       }
+#else
+    source_open_flag |= O_DIRECT;
+    dest_open_flag |= O_DIRECT;
+    aio_blksize = 1;
+    aio_maxio=1;
+    srcname = "junkdata";
+    dstname = "ff2";
+#endif
+       if (!zero) {
+#ifndef DEBUG
+               if ((srcfd = open(srcname = *argv, source_open_flag)) < 0) {
+#else
+                if ((srcfd = open(srcname, source_open_flag)) < 0) {
+#endif
+                       perror(srcname);
+                       exit(1);
+               }
+               argv++;
+               argc--;
+               if (fstat(srcfd, &st) < 0) {
+                       perror("fstat");
+                       exit(1);
+               }
+               if (length == 0)
+                       length = st.st_size;
+       }
+
+       if (!no_write) {
+               /*
+                * We are either copying or writing zeros to dstname
+                */
+#ifndef DEBUG
+               if (argc < 1) {
+                       usage();
+               }
+               if ((dstfd = open(dstname = *argv, dest_open_flag, 0666)) < 0) {
+#else
+            if ((dstfd = open(dstname, dest_open_flag, 0666)) < 0) {
+#endif
+                       perror(dstname);
+                       exit(1);
+               }
+               if (zero) {
+                       /*
+                        * get size of dest, if we are zeroing it.
+                        * TODO: handle devices.
+                        */
+                       if (fstat(dstfd, &st) < 0) {
+                               perror("fstat");
+                               exit(1);
+                       }
+                       if (length == 0)
+                               length = st.st_size;
+               }
+       }
+
+       /* initialize state machine */
+       memset(&myctx, 0, sizeof(myctx));
+       io_queue_init(aio_maxio, &myctx);
+       tocopy = howmany(length, aio_blksize);
+printf("tocopy=%d len=%d blk=%d\n", tocopy, length, aio_blksize);
+       if (init_iocb(aio_maxio, aio_blksize) < 0) {
+               fprintf(stderr, "Error allocating the i/o buffers\n");
+               exit(1);
+       }
+
+       while (tocopy > 0) {
+               int i, rc;
+               /* Submit as many reads as once as possible upto aio_maxio */
+               int n = MIN(MIN(aio_maxio - busy, aio_maxio),
+                               howmany(length - offset, aio_blksize));
+               if (n > 0) {
+                       struct iocb *ioq[n];
+
+                       for (i = 0; i < n; i++) {
+                               struct iocb *io = alloc_iocb();
+                               int iosize = MIN(length - offset, aio_blksize);
+
+                               if (zero) {
+                                       /*
+                                        * We are writing zero's to dstfd
+                                        */
+                                       io_prep_pwrite(io, dstfd, io->u.c.buf,
+                                                       iosize, offset);
+                                       io_set_callback(io, wr_done);
+                               } else {
+                                       io_prep_pread(io, srcfd, io->u.c.buf,
+                                                       iosize, offset);
+                                       io_set_callback(io, rd_done);
+                               }
+                               ioq[i] = io;
+                               offset += iosize;
+                       }
+
+                       rc = io_submit(myctx, n, ioq);
+                       if (rc < 0)
+                               io_error("io_submit", rc);
+
+                       busy += n;
+                       if (debug > 1)
+                               printf("io_submit(%d) busy:%d\n", n, busy);
+                       if (delay.tv_usec) {
+                               struct timeval t = delay;
+                               (void)select(0,0,0,0,&t);
+                       }
+               }
+
+               /*
+                * We have submitted all the i/o requests. Wait for at least one to complete
+                * and call the callbacks.
+                */
+               count_io_q_waits++;
+               rc = io_wait_run(myctx, 0);
+               if (rc < 0)
+                       io_error("io_wait_run", rc);
+
+               if (debug > 1) {
+                       printf("io_wait_run: rc == %d\n", rc);
+                       printf("busy:%d aio_maxio:%d tocopy:%d\n",
+                                       busy, aio_maxio, tocopy);
+               }
+       }
+
+       if (srcfd != -1)
+               close(srcfd);
+       if (dstfd != -1)
+               close(dstfd);
+       exit(0);
+}
+
+/* 
+ * Results look like:
+ * [alanm@toolbox ~/MOT3]$ ../taio -d kernel-source-2.4.8-0.4g.ppc.rpm abc
+ * rrrrrrrrrrrrrrrwwwrwrrwwrrwrwwrrwrwrwwrrwrwrrrrwwrwwwrrwrrrwwwwwwwwwwwwwwwww
+ * rrrrrrrrrrrrrrwwwrrwrwrwrwrrwwwwwwwwwwwwwwrrrrrrrrrrrrrrrrrrwwwwrwrwwrwrwrwr
+ * wrrrrrrrwwwwwwwwwwwwwrrrwrrrwrrwrwwwwwwwwwwrrrrwwrwrrrrrrrrrrrwwwwwwwwwwwrww
+ * wwwrrrrrrrrwwrrrwwrwrwrwwwrrrrrrrwwwrrwwwrrwrwwwwwwwwrrrrrrrwwwrrrrrrrwwwwww
+ * wwwwwwwrwrrrrrrrrwrrwrrwrrwrwrrrwrrrwrrrwrwwwwwwwwwwwwwwwwwwrrrwwwrrrrrrrrrr
+ * rrwrrrrrrwrrwwwwwwwwwwwwwwwwrwwwrrwrwwrrrrrrrrrrrrrrrrrrrwwwwwwwwwwwwwwwwwww
+ * rrrrrwrrwrwrwrrwrrrwwwwwwwwrrrrwrrrwrwwrwrrrwrrwrrrrwwwwwwwrwrwwwwrwwrrrwrrr
+ * rrrwwwwwwwrrrrwwrrrrrrrrrrrrwrwrrrrwwwwwwwwwwwwwwrwrrrrwwwwrwrrrrwrwwwrrrwww
+ * rwwrrrrrrrwrrrrrrrrrrrrwwwwrrrwwwrwrrwwwwwwwwwwwwwwwwwwwwwrrrrrrrwwwwwwwrw
+ */
diff --git a/tests/generic/250 b/tests/generic/250
new file mode 100755 (executable)
index 0000000..b0b175a
--- /dev/null
@@ -0,0 +1,100 @@
+#! /bin/bash
+# FS QA Test No. 250
+#
+# Create an unwritten extent, set up dm-error, try a DIO write, then
+# make sure we can't read back old disk contents.
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016, Oracle and/or its affiliates.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#-----------------------------------------------------------------------
+
+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 -rf $tmp.* $testdir
+    _dmerror_cleanup
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/dmerror
+
+# real QA test starts here
+_supported_os Linux
+_require_scratch
+_require_dm_target error
+_require_xfs_io_command "falloc"
+
+rm -f $seqres.full
+
+
+echo "Format and mount"
+$XFS_IO_PROG -d -c "pwrite -S 0x69 -b 1048576 0 $((64 * 1048576))" $SCRATCH_DEV >> $seqres.full
+_scratch_mkfs_sized $((64 * 1048576)) > $seqres.full 2>&1
+_dmerror_init
+_dmerror_mount >> $seqres.full 2>&1
+_dmerror_unmount
+_dmerror_mount
+
+testdir=$SCRATCH_MNT/test-$seq
+mkdir $testdir
+
+blksz=65536
+nr=640
+bufnr=128
+filesize=$((blksz * nr))
+bufsize=$((blksz * bufnr))
+
+_require_fs_space $SCRATCH_MNT $((filesize / 1024 * 5 / 4))
+
+echo "Create the original files"
+$XFS_IO_PROG -f -c "falloc 0 $filesize" $testdir/file2 >> $seqres.full
+_dmerror_unmount
+_dmerror_mount
+
+echo "Compare files"
+md5sum $testdir/file2 | _filter_scratch
+
+echo "CoW and unmount"
+$XFS_IO_PROG -f -c "pwrite -S 0x63 $bufsize 1" $testdir/file2 >> $seqres.full
+sync
+_dmerror_load_error_table
+$XFS_IO_PROG -d -f -c "pwrite -S 0x63 -b $bufsize 0 $filesize" $testdir/file2 >> $seqres.full
+_dmerror_load_working_table
+_dmerror_unmount
+_dmerror_mount
+
+echo "Compare files"
+md5sum $testdir/file2 | _filter_scratch
+
+echo "Check for damage"
+_dmerror_unmount
+_dmerror_cleanup
+_repair_scratch_fs >> $seqres.full
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/250.out b/tests/generic/250.out
new file mode 100644 (file)
index 0000000..710c80e
--- /dev/null
@@ -0,0 +1,10 @@
+QA output created by 250
+Format and mount
+Create the original files
+Compare files
+ec8bb3b24d5b0f1b5bdf8c8f0f541ee6  SCRATCH_MNT/test-250/file2
+CoW and unmount
+pwrite64: Input/output error
+Compare files
+3ed86318f4ff8da26c1c2a6e3041f9be  SCRATCH_MNT/test-250/file2
+Check for damage
diff --git a/tests/generic/252 b/tests/generic/252
new file mode 100755 (executable)
index 0000000..fc9a723
--- /dev/null
@@ -0,0 +1,103 @@
+#! /bin/bash
+# FS QA Test No. 252
+#
+# Create an unwritten extent, set up dm-error, try an AIO DIO write, then
+# make sure we can't read back old disk contents.
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2016, Oracle and/or its affiliates.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#-----------------------------------------------------------------------
+
+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 -rf $tmp.* $testdir $TEST_DIR/moo
+    _dmerror_cleanup
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/dmerror
+
+# real QA test starts here
+_supported_os Linux
+_require_scratch
+_require_dm_target error
+_require_xfs_io_command "falloc"
+_require_test_program "aio-dio-regress/aiocp"
+AIO_TEST="src/aio-dio-regress/aiocp"
+
+rm -f $seqres.full
+
+
+echo "Format and mount"
+$XFS_IO_PROG -d -c "pwrite -S 0x69 -b 1048576 0 $((64 * 1048576))" $SCRATCH_DEV >> $seqres.full
+_scratch_mkfs_sized $((64 * 1048576)) > $seqres.full 2>&1
+_dmerror_init
+_dmerror_mount >> $seqres.full 2>&1
+_dmerror_unmount
+_dmerror_mount
+
+testdir=$SCRATCH_MNT/test-$seq
+mkdir $testdir
+
+blksz=65536
+nr=640
+bufnr=128
+filesize=$((blksz * nr))
+bufsize=$((blksz * bufnr))
+
+_require_fs_space $SCRATCH_MNT $((filesize / 1024 * 5 / 4))
+
+echo "Create the original files"
+$XFS_IO_PROG -f -c "falloc 0 $filesize" $testdir/file2 >> $seqres.full
+_dmerror_unmount
+_dmerror_mount
+
+echo "Compare files"
+md5sum $testdir/file2 | _filter_scratch
+
+echo "CoW and unmount"
+$XFS_IO_PROG -f -c "pwrite -S 0x63 $bufsize 1" $testdir/file2 >> $seqres.full
+$XFS_IO_PROG -f -c "pwrite -S 0x63 -b $bufsize 0 $filesize" $TEST_DIR/moo >> $seqres.full
+sync
+_dmerror_load_error_table
+$AIO_TEST -f DIRECT -b $bufsize $TEST_DIR/moo $testdir/file2 >> $seqres.full
+_dmerror_load_working_table
+_dmerror_unmount
+_dmerror_mount
+
+echo "Compare files"
+md5sum $testdir/file2 | _filter_scratch
+
+echo "Check for damage"
+_dmerror_unmount
+_dmerror_cleanup
+_repair_scratch_fs >> $seqres.full
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/252.out b/tests/generic/252.out
new file mode 100644 (file)
index 0000000..3bc78c2
--- /dev/null
@@ -0,0 +1,10 @@
+QA output created by 252
+Format and mount
+Create the original files
+Compare files
+ec8bb3b24d5b0f1b5bdf8c8f0f541ee6  SCRATCH_MNT/test-252/file2
+CoW and unmount
+write missed bytes expect 8388608 got 0
+Compare files
+3ed86318f4ff8da26c1c2a6e3041f9be  SCRATCH_MNT/test-252/file2
+Check for damage
index 860ff4a575fb0cb383147e48bedc98228d2e10f8..0e4e7d32e90f7eb6ba1d6b4e3772ba03e28f9480 100644 (file)
 247 auto quick rw
 248 auto quick rw
 249 auto quick rw
+250 auto quick prealloc rw
 251 ioctl trim
+252 auto quick prealloc rw
 255 auto quick prealloc
 256 auto quick
 257 dir auto quick