diff mbox series

xfstests: mmap and copy file data with page overlapping

Message ID 20210521080145.1692547-1-zlang@redhat.com (mailing list archive)
State New, archived
Headers show
Series xfstests: mmap and copy file data with page overlapping | expand

Commit Message

Zorro Lang May 21, 2021, 8:01 a.m. UTC
Mmap 2 pages of file, write 64 bytes to the first and second pages,
copy the data from the first page and then second page to the second
page offset with $pagesize - 64. Verify the data at the end.

       +-----------------------+
       |        (copy)         |
       |                       V
    +---------------+---------------+------------
    |AAAA| ........ |AAAA| ... |AAAA|AAAA|
    +---------------+---------------+------------
                       |            ^
                       |   (copy)   |
                       +------------+

This's also a regression test cover kernel commit: 4f06dd92b5d0
("fuse: fix write deadlock")

Signed-off-by: Zorro Lang <zlang@redhat.com>
---
 .gitignore                  |   1 +
 src/Makefile                |   3 +-
 src/t_mmap_writev_overlap.c | 134 ++++++++++++++++++++++++++++++++++++
 tests/generic/637           |  57 +++++++++++++++
 tests/generic/637.out       |   2 +
 tests/generic/group         |   1 +
 6 files changed, 197 insertions(+), 1 deletion(-)
 create mode 100644 src/t_mmap_writev_overlap.c
 create mode 100755 tests/generic/637
 create mode 100644 tests/generic/637.out
diff mbox series

Patch

diff --git a/.gitignore b/.gitignore
index 4cc9c807..1e56d7ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -142,6 +142,7 @@ 
 /src/t_mmap_stale_pmd
 /src/t_mmap_write_ro
 /src/t_mmap_writev
+/src/t_mmap_writev_overlap
 /src/t_mtab
 /src/t_ofd_locks
 /src/t_open_tmpfiles
diff --git a/src/Makefile b/src/Makefile
index cc0b9579..1279e4b9 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -17,7 +17,8 @@  TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
 	t_mmap_cow_race t_mmap_fallocate fsync-err t_mmap_write_ro \
 	t_ext4_dax_journal_corruption t_ext4_dax_inline_corruption \
 	t_ofd_locks t_mmap_collision mmap-write-concurrent \
-	t_get_file_time t_create_short_dirs t_create_long_dirs t_enospc
+	t_get_file_time t_create_short_dirs t_create_long_dirs t_enospc \
+	t_mmap_writev_overlap
 
 LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
 	preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
diff --git a/src/t_mmap_writev_overlap.c b/src/t_mmap_writev_overlap.c
new file mode 100644
index 00000000..e327e730
--- /dev/null
+++ b/src/t_mmap_writev_overlap.c
@@ -0,0 +1,134 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 RedHat Inc.  All Rights Reserved.
+ *
+ * mmap a file, alloc blocks, reading&writing blocks with overlapping. For example:
+ *
+ * |<--- block --->|<--- block --->|
+ *  len             len
+ * +---------------+---------------+
+ * |AAAA| ........ |AAAA| ........ |
+ * +---------------+---------------+
+ *    |               |
+ *    |               `------------+
+ *    `-----------------------+    |
+ *                            |    |
+ *                            V    V
+ * +---------------+---------------+----+
+ * |AAAA| ........ |AAAA| ... |AAAA|AAAA|
+ * +---------------+---------------+----+
+ */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+void usage(char *progname)
+{
+	fprintf(stderr, "usage: %s [-b blocksize ] [-c count] [-l length] filename\n"
+	        "\tmmap $count * $blocksize bytes memory, pwritev $length bytes in each block. blocksize=4096, count=2, length=12 by default.\n"
+                "e.g: %s -b 4096 -c 2 -l 12 filename\n",
+	        progname, progname);
+        exit(1);
+}
+
+int main(int argc, char **argv)
+{
+	char *filename = NULL;
+	size_t bsize = 4096;
+	size_t count = 2;
+	size_t length = 12;
+	int fd, i, c;
+	void *base;
+	char *buf, *cmp_buf;
+	struct iovec *iov;
+	int ret = 0;
+
+	while ((c = getopt(argc, argv, "b:l:c:")) != -1) {
+		char *endp;
+
+		switch (c) {
+		case 'b':
+			bsize = strtoul(optarg, &endp, 0);
+			break;
+		case 'c':
+			count = strtoul(optarg, &endp, 0);
+			break;
+		case 'l':
+			length = strtoul(optarg, &endp, 0);
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	if (optind == argc - 1)
+		filename = argv[optind];
+	else
+		usage(argv[0]);
+
+	if (length >= bsize) {
+		printf("-l length must be less than -b blocksize\n");
+		usage(argv[0]);
+	}
+
+	fd = open(filename, O_RDWR);
+	if (fd == -1) {
+		fprintf(stderr, "open %s failed:%s\n", filename, strerror(errno));
+		exit(1);
+	}
+	base = mmap(NULL, bsize * count, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+	if (base == MAP_FAILED) {
+		fprintf(stderr, "mmap failed %s\n", strerror(errno));
+		exit(1);
+	}
+
+	/* Write each of blocks */
+	buf = malloc(length);
+	memset(buf, 0xAA, length);
+	for (i=0; i<count; i++) {
+		ret = pwrite(fd, buf, length, i * bsize);
+		if (ret == -1) {
+			fprintf(stderr, "pwrite failed %s\n", strerror(errno));
+			exit(1);
+		}
+	}
+
+	/* Copy from the beginning of each blocks ... */
+	iov = malloc(sizeof(struct iovec) * count);
+	for (i=0; i<count; i++) {
+		iov[i].iov_base = base + i * bsize;
+		iov[i].iov_len  = length;
+	}
+	/* ... Write to the last block with offset ($bsize - $length) */
+	ret = pwritev(fd, iov, count, bsize * count - length);
+	if (ret == -1) {
+		fprintf(stderr, "pwritev failed %s\n", strerror(errno));
+		exit(1);
+	}
+
+	/* Verify data */
+	cmp_buf = malloc(length);
+	for (i=0; i<count; i++) {
+		ret = pread(fd, cmp_buf, length, bsize * count + (i - 1) * length);
+		if (ret == -1) {
+			fprintf(stderr, "pread failed %s\n", strerror(errno));
+			exit(1);
+		}
+		if (memcmp(buf, cmp_buf, length))
+			printf("Find corruption\n");
+	}
+
+	munmap(base, bsize * count);
+	free(buf);
+	free(cmp_buf);
+	free(iov);
+	close(fd);
+
+	return 0;
+}
diff --git a/tests/generic/637 b/tests/generic/637
new file mode 100755
index 00000000..dac2bf2c
--- /dev/null
+++ b/tests/generic/637
@@ -0,0 +1,57 @@ 
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2021 Red Hat Inc.  All Rights Reserved.
+#
+# FS QA Test 637
+#
+# This case mmaps several pages of a file, alloc pages, copy data with pages
+# overlapping, e.g:
+#       +-----------------------+
+#       |        (copy)         |
+#       |                       V
+#    +---------------+---------------+------------
+#    |AAAA| ........ |AAAA| ... |AAAA|AAAA|
+#    +---------------+---------------+------------
+#                       |            ^
+#                       |   (copy)   |
+#                       +------------+
+#
+# This's a regression test cover kernel commit:
+#   4f06dd92b5d0 ("fuse: fix write deadlock")
+#
+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
+_require_test
+_require_test_program "t_mmap_writev_overlap"
+
+pagesize=`getconf PAGE_SIZE`
+testfile=$TEST_DIR/mmap-writev-overlap
+$XFS_IO_PROG -f -c "truncate 0" $testfile
+$here/src/t_mmap_writev_overlap -b $pagesize -c 2 -l 64 $testfile
+
+echo "Silence is golden"
+# success, all done
+status=0
+exit
diff --git a/tests/generic/637.out b/tests/generic/637.out
new file mode 100644
index 00000000..55a3d825
--- /dev/null
+++ b/tests/generic/637.out
@@ -0,0 +1,2 @@ 
+QA output created by 637
+Silence is golden
diff --git a/tests/generic/group b/tests/generic/group
index 105763c4..b9614c69 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -639,3 +639,4 @@ 
 634 auto quick atime bigtime
 635 auto quick atime bigtime shutdown
 636 auto quick swap
+637 auto quick rw