mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
generic: Test handling of private file mappings
Test handling of private file mappings in the kernel. Check that writes of only one thread / process are seen in each page and that none of these make it into the original file. Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Eryu Guan <eguan@redhat.com>
This commit is contained in:
+89
-32
@@ -70,6 +70,7 @@ long page_offs[THREADS];
|
||||
int use_wr[THREADS];
|
||||
int prefault = 0;
|
||||
int use_fork = 0;
|
||||
int use_private = 0;
|
||||
|
||||
uint64_t get_id(void)
|
||||
{
|
||||
@@ -90,24 +91,52 @@ void prefault_mapping(char *addr, long npages)
|
||||
}
|
||||
}
|
||||
|
||||
int verify_mapping(char *vastart, long npages, uint64_t *expect)
|
||||
{
|
||||
int errcnt = 0;
|
||||
int i;
|
||||
char *va;
|
||||
|
||||
for (va = vastart; npages > 0; va += page_size, npages--) {
|
||||
for (i = 0; i < THREADS; i++) {
|
||||
if (*(uint64_t*)(va + page_offs[i]) != expect[i]) {
|
||||
printf("ERROR: thread %d, "
|
||||
"offset %08lx, %08lx != %08lx\n", i,
|
||||
(va + page_offs[i] - vastart),
|
||||
*(uint64_t*)(va + page_offs[i]),
|
||||
expect[i]);
|
||||
errcnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return errcnt;
|
||||
}
|
||||
|
||||
void *pt_page_marker(void *args)
|
||||
{
|
||||
void **a = args;
|
||||
char *va = (char *)a[1];
|
||||
long npages = (long)a[2];
|
||||
long pgoff = (long)a[3];
|
||||
long i;
|
||||
long pgoff = page_offs[(long)a[3]];
|
||||
uint64_t tid = get_id();
|
||||
long errors = 0;
|
||||
|
||||
if (prefault && use_fork)
|
||||
prefault_mapping(va, npages);
|
||||
|
||||
va += pgoff;
|
||||
|
||||
/* mark pages */
|
||||
for (; npages > 0; va += page_size, npages--)
|
||||
*(uint64_t *)(va) = tid;
|
||||
for (i = 0; i < npages; i++)
|
||||
*(uint64_t *)(va + pgoff + i * page_size) = tid;
|
||||
|
||||
return NULL;
|
||||
if (use_private && use_fork) {
|
||||
uint64_t expect[THREADS] = {};
|
||||
|
||||
expect[(long)a[3]] = tid;
|
||||
errors = verify_mapping(va, npages, expect);
|
||||
}
|
||||
|
||||
return (void *)errors;
|
||||
} /* pt_page_marker() */
|
||||
|
||||
void *pt_write_marker(void *args)
|
||||
@@ -115,7 +144,7 @@ void *pt_write_marker(void *args)
|
||||
void **a = args;
|
||||
int fd = (long)a[0];
|
||||
long npages = (long)a[2];
|
||||
long pgoff = (long)a[3];
|
||||
long pgoff = page_offs[(long)a[3]];
|
||||
uint64_t tid = get_id();
|
||||
long i;
|
||||
|
||||
@@ -130,18 +159,18 @@ int test_this(int fd, loff_t sz)
|
||||
{
|
||||
long npages;
|
||||
char *vastart;
|
||||
char *va;
|
||||
void *targs[THREADS][4];
|
||||
pthread_t t[THREADS];
|
||||
uint64_t tid[THREADS];
|
||||
int errcnt;
|
||||
int errcnt = 0;
|
||||
int i;
|
||||
|
||||
npages = sz / page_size;
|
||||
printf("INFO: sz = %llu\n", (unsigned long long)sz);
|
||||
|
||||
/* mmap it */
|
||||
vastart = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
vastart = mmap(NULL, sz, PROT_READ | PROT_WRITE,
|
||||
use_private ? MAP_PRIVATE : MAP_SHARED, fd, 0);
|
||||
if (MAP_FAILED == vastart) {
|
||||
perror("mmap()");
|
||||
exit(20);
|
||||
@@ -155,7 +184,7 @@ int test_this(int fd, loff_t sz)
|
||||
targs[i][0] = (void *)(long)fd;
|
||||
targs[i][1] = vastart;
|
||||
targs[i][2] = (void *)npages;
|
||||
targs[i][3] = (void *)page_offs[i];
|
||||
targs[i][3] = (void *)(long)i;
|
||||
}
|
||||
|
||||
for (i = 0; i < THREADS; i++) {
|
||||
@@ -186,40 +215,58 @@ int test_this(int fd, loff_t sz)
|
||||
}
|
||||
/* Child? */
|
||||
if (!tid[i]) {
|
||||
void *ret;
|
||||
|
||||
if (use_wr[i])
|
||||
pt_write_marker(&targs[i]);
|
||||
ret = pt_write_marker(&targs[i]);
|
||||
else
|
||||
pt_page_marker(&targs[i]);
|
||||
exit(0);
|
||||
ret = pt_page_marker(&targs[i]);
|
||||
exit(ret ? 1 : 0);
|
||||
}
|
||||
printf("INFO: process %d created\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
/* wait for them to finish */
|
||||
for (i = 0; i < THREADS; i++)
|
||||
if (!use_fork)
|
||||
pthread_join(t[i], NULL);
|
||||
else
|
||||
waitpid(tid[i], NULL, 0);
|
||||
for (i = 0; i < THREADS; i++) {
|
||||
if (!use_fork) {
|
||||
void *status;
|
||||
|
||||
pthread_join(t[i], &status);
|
||||
if (status)
|
||||
errcnt++;
|
||||
} else {
|
||||
int status;
|
||||
|
||||
waitpid(tid[i], &status, 0);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
|
||||
errcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
/* check markers on each page */
|
||||
errcnt = 0;
|
||||
for (va = vastart; npages > 0; va += page_size, npages--) {
|
||||
for (i = 0; i < THREADS; i++) {
|
||||
if (*(uint64_t*)(va + page_offs[i]) != tid[i]) {
|
||||
printf("ERROR: thread %d, "
|
||||
"offset %08lx, %08lx != %08lx\n", i,
|
||||
(va + page_offs[i] - vastart),
|
||||
*(uint64_t*)(va + page_offs[i]), tid[i]);
|
||||
errcnt += 1;
|
||||
}
|
||||
/* For private mappings & fork we should see no writes happen */
|
||||
if (use_private && use_fork)
|
||||
for (i = 0; i < THREADS; i++)
|
||||
tid[i] = 0;
|
||||
errcnt = verify_mapping(vastart, npages, tid);
|
||||
munmap(vastart, sz);
|
||||
|
||||
if (use_private) {
|
||||
/* Check that no writes propagated into original file */
|
||||
for (i = 0; i < THREADS; i++)
|
||||
tid[i] = 0;
|
||||
vastart = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (vastart == MAP_FAILED) {
|
||||
perror("mmap()");
|
||||
exit(20);
|
||||
}
|
||||
errcnt += verify_mapping(vastart, npages, tid);
|
||||
munmap(vastart, sz);
|
||||
}
|
||||
|
||||
printf("INFO: %d error(s) detected\n", errcnt);
|
||||
|
||||
munmap(vastart, sz);
|
||||
|
||||
return errcnt;
|
||||
}
|
||||
@@ -242,7 +289,7 @@ int main(int argc, char **argv)
|
||||
for (i = 1; i < THREADS; i++)
|
||||
page_offs[i] = page_offs[i-1] + step;
|
||||
|
||||
while ((opt = getopt(argc, argv, "fwrF")) > 0) {
|
||||
while ((opt = getopt(argc, argv, "fwrFp")) > 0) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
/* ignore errors */
|
||||
@@ -260,6 +307,10 @@ int main(int argc, char **argv)
|
||||
/* create processes instead of threads */
|
||||
use_fork = 1;
|
||||
break;
|
||||
case 'p':
|
||||
/* Use private mappings for testing */
|
||||
use_private = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "ERROR: Unknown option character.\n");
|
||||
exit(1);
|
||||
@@ -267,10 +318,16 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (optind != argc - 2) {
|
||||
fprintf(stderr, "ERROR: usage: holetest [-fwrF] "
|
||||
fprintf(stderr, "ERROR: usage: holetest [-fwrFp] "
|
||||
"FILENAME FILESIZEinMB\n");
|
||||
exit(1);
|
||||
}
|
||||
if (use_private && use_wr[0]) {
|
||||
fprintf(stderr, "ERROR: Combinations of writes and private"
|
||||
"mappings not supported.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
path = argv[optind];
|
||||
sz = strtol(argv[optind + 1], &endch, 10);
|
||||
if (*endch || sz < 1) {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#! /bin/bash
|
||||
# FSQA Test No. 354
|
||||
#
|
||||
# Test races between private file mapping faults from racing processes or
|
||||
# threads
|
||||
#
|
||||
#-----------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2016 SUSE Linux Products GmbH. All Rights Reserved.
|
||||
# Author: Jan Kara <jack@suse.cz>
|
||||
#
|
||||
# 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"
|
||||
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 and checks
|
||||
. ./common/rc
|
||||
|
||||
# real QA test starts here
|
||||
_supported_fs generic
|
||||
_supported_os Linux
|
||||
_require_scratch
|
||||
_require_test_program "holetest"
|
||||
|
||||
rm -f $seqres.full
|
||||
|
||||
_scratch_mkfs >>$seqres.full 2>&1
|
||||
_scratch_mount
|
||||
|
||||
src/holetest -f -p $SCRATCH_MNT/testfile 16
|
||||
src/holetest -f -p $SCRATCH_MNT/testfile 256
|
||||
src/holetest -f -p -F $SCRATCH_MNT/testfile 16
|
||||
src/holetest -f -p -F $SCRATCH_MNT/testfile 256
|
||||
|
||||
status=0
|
||||
exit
|
||||
@@ -0,0 +1,73 @@
|
||||
QA output created by 354
|
||||
|
||||
INFO: zero-filled test...
|
||||
INFO: sz = 16777216
|
||||
INFO: thread 0 created
|
||||
INFO: thread 1 created
|
||||
INFO: 0 error(s) detected
|
||||
|
||||
INFO: posix_fallocate test...
|
||||
INFO: sz = 16777216
|
||||
INFO: thread 0 created
|
||||
INFO: thread 1 created
|
||||
INFO: 0 error(s) detected
|
||||
|
||||
INFO: ftruncate test...
|
||||
INFO: sz = 16777216
|
||||
INFO: thread 0 created
|
||||
INFO: thread 1 created
|
||||
INFO: 0 error(s) detected
|
||||
|
||||
INFO: zero-filled test...
|
||||
INFO: sz = 268435456
|
||||
INFO: thread 0 created
|
||||
INFO: thread 1 created
|
||||
INFO: 0 error(s) detected
|
||||
|
||||
INFO: posix_fallocate test...
|
||||
INFO: sz = 268435456
|
||||
INFO: thread 0 created
|
||||
INFO: thread 1 created
|
||||
INFO: 0 error(s) detected
|
||||
|
||||
INFO: ftruncate test...
|
||||
INFO: sz = 268435456
|
||||
INFO: thread 0 created
|
||||
INFO: thread 1 created
|
||||
INFO: 0 error(s) detected
|
||||
|
||||
INFO: zero-filled test...
|
||||
INFO: sz = 16777216
|
||||
INFO: process 0 created
|
||||
INFO: process 1 created
|
||||
INFO: 0 error(s) detected
|
||||
|
||||
INFO: posix_fallocate test...
|
||||
INFO: sz = 16777216
|
||||
INFO: process 0 created
|
||||
INFO: process 1 created
|
||||
INFO: 0 error(s) detected
|
||||
|
||||
INFO: ftruncate test...
|
||||
INFO: sz = 16777216
|
||||
INFO: process 0 created
|
||||
INFO: process 1 created
|
||||
INFO: 0 error(s) detected
|
||||
|
||||
INFO: zero-filled test...
|
||||
INFO: sz = 268435456
|
||||
INFO: process 0 created
|
||||
INFO: process 1 created
|
||||
INFO: 0 error(s) detected
|
||||
|
||||
INFO: posix_fallocate test...
|
||||
INFO: sz = 268435456
|
||||
INFO: process 0 created
|
||||
INFO: process 1 created
|
||||
INFO: 0 error(s) detected
|
||||
|
||||
INFO: ftruncate test...
|
||||
INFO: sz = 268435456
|
||||
INFO: process 0 created
|
||||
INFO: process 1 created
|
||||
INFO: 0 error(s) detected
|
||||
@@ -356,3 +356,4 @@
|
||||
351 blockdev quick rw
|
||||
352 auto clone
|
||||
353 auto quick clone
|
||||
354 auto
|
||||
|
||||
Reference in New Issue
Block a user