mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
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:
@@ -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
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Executable
+57
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
QA output created by 638
|
||||
Silence is golden
|
||||
@@ -640,3 +640,4 @@
|
||||
635 auto quick atime bigtime shutdown
|
||||
636 auto quick swap
|
||||
637 auto quick dir
|
||||
638 auto quick rw
|
||||
|
||||
Reference in New Issue
Block a user