generic: add regression test for stale mmap reads

This adds a regression test for the following kernel patch:

  dax: fix data corruption due to stale mmap reads

The above patch fixes an issue where users of DAX can suffer data
corruption from stale mmap reads via the following sequence:

- open an mmap over a 2MiB hole

- read from a 2MiB hole, faulting in a 2MiB zero page

- write to the hole with write(3p).  The write succeeds but we incorrectly
  leave the 2MiB zero page mapping intact.

- via the mmap, read the data that was just written.  Since the zero page
  mapping is still intact we read back zeroes instead of the new data.

Signed-off-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Reviewed-by: Eryu Guan <eguan@redhat.com>
Signed-off-by: Eryu Guan <eguan@redhat.com>
This commit is contained in:
Ross Zwisler
2017-04-26 12:05:31 -06:00
committed by Eryu Guan
parent accf20216c
commit bba1b1b2b9
6 changed files with 138 additions and 1 deletions
+1
View File
@@ -147,6 +147,7 @@
/src/renameat2
/src/t_rename_overwrite
/src/t_mmap_dio
/src/t_mmap_stale_pmd
# dmapi/ binaries
/dmapi/src/common/cmd/read_invis
+1 -1
View File
@@ -12,7 +12,7 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
godown resvtest writemod makeextents itrash rename \
multi_open_unlink dmiperf unwritten_sync genhashnames t_holes \
t_mmap_writev t_truncate_cmtime dirhash_collide t_rename_overwrite \
holetest t_truncate_self t_mmap_dio af_unix
holetest t_truncate_self t_mmap_dio af_unix t_mmap_stale_pmd
LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
+73
View File
@@ -0,0 +1,73 @@
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define MiB(a) ((a)*1024*1024)
void err_exit(char *op)
{
fprintf(stderr, "%s: %s\n", op, strerror(errno));
exit(1);
}
int main(int argc, char *argv[])
{
volatile int a __attribute__((__unused__));
char *buffer = "HELLO WORLD!";
char *data;
int fd, err, ret = 0;
if (argc < 2) {
printf("Usage: %s <pmem file>\n", basename(argv[0]));
exit(0);
}
fd = open(argv[1], O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
if (fd < 0)
err_exit("fd");
/*
* This allows us to map a huge zero page, and we do it at a non-zero
* offset for a little additional testing.
*/
ftruncate(fd, 0);
ftruncate(fd, MiB(4));
data = mmap(NULL, MiB(2), PROT_READ, MAP_SHARED, fd, MiB(2));
/*
* This faults in a 2MiB zero page to satisfy the read.
* 'a' is volatile so this read doesn't get optimized out.
*/
a = data[0];
pwrite(fd, buffer, strlen(buffer), MiB(2));
/*
* Try and use the mmap to read back the data we just wrote with
* pwrite(). If the kernel bug is present the mapping from the 2MiB
* zero page will still be intact, and we'll read back zeros instead.
*/
if (strncmp(buffer, data, strlen(buffer))) {
fprintf(stderr, "strncmp mismatch: '%s' vs '%s'\n", buffer,
data);
ret = 1;
}
err = munmap(data, MiB(2));
if (err < 0)
err_exit("munmap");
err = close(fd);
if (err < 0)
err_exit("close");
return ret;
}
+60
View File
@@ -0,0 +1,60 @@
#! /bin/bash
# FS QA Test 428
#
# This is a regression test for kernel patch:
# dax: fix data corruption due to stale mmap reads
# created by Ross Zwisler <ross.zwisler@linux.intel.com>
#
#-----------------------------------------------------------------------
# Copyright (c) 2017 Intel Corporation. All Rights Reserved.
#
# 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"
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
# Modify as appropriate.
_supported_fs generic
_supported_os Linux
_require_test
_require_test_program "t_mmap_stale_pmd"
# real QA test starts here
src/t_mmap_stale_pmd $TEST_DIR/testfile
# success, all done
echo "Silence is golden"
status=0
exit
+2
View File
@@ -0,0 +1,2 @@
QA output created by 428
Silence is golden
+1
View File
@@ -430,3 +430,4 @@
425 auto quick attr
426 auto quick exportfs
427 auto quick aio rw
428 auto quick