From 8a9bc451112b5e6b62cee9d5630ea8fe7367097d Mon Sep 17 00:00:00 2001 From: Zorro Lang Date: Fri, 21 May 2021 16:01:45 +0800 Subject: [PATCH] generic: mmap and copy file data with page overlapping 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 Reviewed-by: Eryu Guan Signed-off-by: Eryu Guan --- .gitignore | 1 + src/Makefile | 3 +- src/t_mmap_writev_overlap.c | 134 ++++++++++++++++++++++++++++++++++++ tests/generic/638 | 57 +++++++++++++++ tests/generic/638.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/638 create mode 100644 tests/generic/638.out 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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