This adds a regression test for the following series:
https://lists.01.org/pipermail/linux-nvdimm/2018-July/016842.html
which adds synchronization between DAX DMA in ext4 and truncate/hole-punch.
The intention of the test is to test those specific changes, but it runs
fine both with XFS and without DAX so I've put it in the generic tests
instead of ext4 and not restricted it to only DAX configurations.
When run with v4.18-rc4 + DAX + ext4, this test will hit the following
WARN_ON_ONCE() in dax_disassociate_entry():
WARN_ON_ONCE(trunc && page_ref_count(page) > 1);
If you change this to a WARN_ON() instead, you can see that each of the
four paths being exercised in this test hits that condition many times in
the one second that the subtest is being run.
Signed-off-by: Ross Zwisler
---
.gitignore | 1 +
src/Makefile | 2 +-
src/t_mmap_collision.c | 235 +
tests/generic/999 | 53 +++
tests/generic/999.out | 2 +
tests/generic/group| 1 +
6 files changed, 293 insertions(+), 1 deletion(-)
create mode 100644 src/t_mmap_collision.c
create mode 100755 tests/generic/999
create mode 100644 tests/generic/999.out
diff --git a/.gitignore b/.gitignore
index efc73a7c..ea1aac8a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -125,6 +125,7 @@
/src/t_holes
/src/t_immutable
/src/t_locks_execve
+/src/t_mmap_collision
/src/t_mmap_cow_race
/src/t_mmap_dio
/src/t_mmap_fallocate
diff --git a/src/Makefile b/src/Makefile
index 9e971bcc..41826585 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -16,7 +16,7 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
holetest t_truncate_self t_mmap_dio af_unix t_mmap_stale_pmd \
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_locks_execve
+ t_ofd_locks t_locks_execve t_mmap_collision
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_collision.c b/src/t_mmap_collision.c
new file mode 100644
index ..5f58d858
--- /dev/null
+++ b/src/t_mmap_collision.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018 Intel Corporation.
+ *
+ * As of kernel version 4.18-rc4, Linux has an issue with ext4+DAX where DMA
+ * and direct I/O operations aren't synchronized with respect to operations
+ * which can change the block mappings of an inode. This means that we can
+ * schedule an I/O for an inode and have the block mapping for that inode
+ * change before the I/O is actually complete. So, blocks which were once
+ * allocated to a given inode and then freed could still have I/O operations
+ * happening to them. If these blocks have also been reallocated to a
+ * different inode, this interaction can lead to data corruption.
+ *
+ * This test exercises four of the paths in ext4 which hit this issue.
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define PAGE(a) ((a)*0x1000)
+#define FILE_SIZE PAGE(4)
+
+void *dax_data;
+int nodax_fd;
+int dax_fd;
+bool done;
+
+#define err_exit(op) \
+{ \
+ fprintf(stderr, "%s %s: %s\n", __func__, op, strerror(errno));\
+ exit(1); \
+} \
+
+#if defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)
+void punch_hole_fn(void *ptr)
+{
+ ssize_t read;
+ int rc;
+
+ while (!done) {
+ read = 0;
+
+ do {
+ rc = pread(nodax_fd, dax_data + read, FILE_SIZE - read,
+ read);
+ if (rc > 0)
+ read += rc;
+ } while (rc > 0);
+
+ if (read != FILE_SIZE || rc != 0)
+ err_exit("pread");
+
+ rc = fallocate(dax_fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ 0, FILE_SIZE);
+ if (rc < 0)
+ err_exit("fallocate");
+
+ usleep(rand() % 1000);
+ }
+}
+#else
+void punch_hole_fn(void *ptr) { }
+#endif
+
+#if defined(FALLOC_FL_ZERO_RANGE) && defined(FALLOC_FL_KEEP_SIZE)
+void zero_range_fn(void *ptr)
+{
+ ssize_t read;
+ int rc;
+
+ while (!done) {
+ read = 0;
+
+ do {
+ rc = pread(nodax_fd, dax_data + read, FILE_SIZE - read,
+ read);
+ if (rc > 0)
+