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 <zlang@redhat.com>
Reviewed-by: Eryu Guan <guaneryu@gmail.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
This commit is contained in:
Zorro Lang
2021-05-21 16:01:45 +08:00
committed by Eryu Guan
parent 466ddbfd11
commit 8a9bc45111
6 changed files with 197 additions and 1 deletions
+1
View File
@@ -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
+2 -1
View File
@@ -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 \
+134
View File
@@ -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;
}
+57
View File
@@ -0,0 +1,57 @@
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2021 Red Hat Inc. All Rights Reserved.
#
# FS QA Test 638
#
# 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
+2
View File
@@ -0,0 +1,2 @@
QA output created by 638
Silence is golden
+1
View File
@@ -640,3 +640,4 @@
635 auto quick atime bigtime shutdown
636 auto quick swap
637 auto quick dir
638 auto quick rw