diff --git a/src/mmap-rw-fault.c b/src/mmap-rw-fault.c
index 82f9d9781e06396cc10462a95ab989d8c775d86c..161d9f7983debd7409c3ae1f6d1e456957453983 100644
--- a/src/mmap-rw-fault.c
+++ b/src/mmap-rw-fault.c
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <errno.h>
 #include <err.h>
+#include <getopt.h>
 
 char *filename;
 unsigned int page_size;
@@ -109,11 +110,29 @@ static ssize_t do_write(int fd, const void *buf, size_t count, off_t offset)
 	return count2;
 }
 
+static void usage(const char *argv0)
+{
+	fprintf(stderr, "Usage: %s [-2] {filename}\n", argv0);
+	exit(2);
+}
+
 int main(int argc, char *argv[])
 {
-	if (argc != 2)
-		errx(1, "no test filename argument given");
-	filename = argv[1];
+	int opt, opt_2 = 0;
+
+	while ((opt = getopt(argc, argv, "2")) != -1) {
+		switch(opt) {
+		case '2':
+			opt_2 = 1;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	if (optind + 1 != argc)
+		usage(argv[0]);
+	filename = argv[optind];
 
 	page_size = ret = sysconf(_SC_PAGE_SIZE);
 	if (ret == -1)
@@ -179,6 +198,14 @@ int main(int argc, char *argv[])
 		errx(1, "pread (D_DIRECT) from hole is broken");
 	done();
 
+	if (opt_2) {
+		init('f', O_RDWR | O_DIRECT);
+		ret = do_write(fd, addr + page_size, page_size, page_size);
+		if (ret != page_size)
+			err(1, "pwrite %s (O_DIRECT): %ld != %u", filename, ret, page_size);
+		done();
+	}
+
 	if (unlink(filename))
 		err(1, "unlink %s", filename);
 
diff --git a/tests/generic/728 b/tests/generic/728
new file mode 100755
index 0000000000000000000000000000000000000000..13a88dc04f7d767b22c3d433d3f2e408d354e5fb
--- /dev/null
+++ b/tests/generic/728
@@ -0,0 +1,41 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023 Red Hat, Inc.  All Rights Reserved.
+#
+# FS QA Test 728
+#
+# Trigger page faults in the same file during read and write
+#
+# This is generic/647 with an additional test that writes a memory-mapped page
+# onto itself using direct I/O.
+#
+# The kernel will invalidate the page cache
+# before carrying out the write, so filesystems that fault in the target page before carrying out the direct I/O write will never make any progress.
+#
+. ./common/preamble
+_begin_fstest auto quick
+
+# Override the default cleanup function.
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+	rm -f $TEST_DIR/mmap-rw-fault.tmp
+}
+
+# Import common functions.
+. ./common/filter
+
+# real QA test starts here
+
+_supported_fs generic
+_require_test
+_require_odirect
+_require_test_program mmap-rw-fault
+
+echo "Silence is golden"
+
+$here/src/mmap-rw-fault -2 $TEST_DIR/mmap-rw-fault.tmp
+
+status=$?
+exit
diff --git a/tests/generic/728.out b/tests/generic/728.out
new file mode 100644
index 0000000000000000000000000000000000000000..ab39f45fe5da771d9029805e9b88e2f1fa6fe2d4
--- /dev/null
+++ b/tests/generic/728.out
@@ -0,0 +1,2 @@
+QA output created by 728
+Silence is golden