fstests.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Eryu Guan <guaneryu@gmail.com>
To: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: Christoph Hellwig <hch@infradead.org>, fstests <fstests@vger.kernel.org>
Subject: Re: [PATCH v2] generic: check reflink multiple mmap write
Date: Sun, 13 Oct 2019 20:11:37 +0800	[thread overview]
Message-ID: <20191013121134.GG2622@desktop> (raw)
In-Reply-To: <20191011214120.GI13097@magnolia>

On Fri, Oct 11, 2019 at 02:41:20PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Add a test to make sure that we can handle multiple memory mappings to a
> physical storage extent shared by multiple files, and that we can handle
> the copy on write operation without error.  Make sure we can also handle
> mappings at different offsets in the page cache.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> v2: test at different offsets
> ---
>  src/Makefile                |    2 -
>  src/mmap-write-concurrent.c |  155 +++++++++++++++++++++++++++++++++++++++++++

I added an entry in .gitignore file.

>  tests/generic/945           |  104 +++++++++++++++++++++++++++++
>  tests/generic/945.out       |   31 +++++++++
>  tests/generic/group         |    1 
>  5 files changed, 292 insertions(+), 1 deletion(-)
>  create mode 100644 src/mmap-write-concurrent.c
>  create mode 100755 tests/generic/945
>  create mode 100644 tests/generic/945.out
> 
> diff --git a/src/Makefile b/src/Makefile
> index ef7cfa63..5bc33e77 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_mmap_collision
> +	t_ofd_locks t_locks_execve t_mmap_collision mmap-write-concurrent
>  
>  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/mmap-write-concurrent.c b/src/mmap-write-concurrent.c
> new file mode 100644
> index 00000000..38364de8
> --- /dev/null
> +++ b/src/mmap-write-concurrent.c
> @@ -0,0 +1,155 @@
> +// SPDX-License-Identifier: GPL-2.0-or-newer
> +/*
> + * Copyright (c) 2019 Oracle.
> + * All Rights Reserved.
> + *
> + * Create writable mappings to multiple files and write them all to test
> + * concurrent mmap writes to the same shared blocks.
> + */
> +#include <sys/mman.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +struct file_info {
> +	char			*mapping;
> +	off_t			file_offset;
> +	off_t			file_length;
> +	int			fd;
> +};
> +
> +int
> +main(
> +	int			argc,
> +	char			*argv[])
> +{
> +	struct file_info	*fi;
> +	size_t			length;
> +	char			*endptr;
> +	unsigned int		nr_files;
> +	unsigned int		i;
> +	char			*buf;
> +	int			ret;
> +
> +	if (argc < 4) {
> +		printf("Usage: %s len offset file [offset file]...\n", argv[0]);
> +		return 1;
> +	}
> +
> +	/* Parse mwrite length. */
> +	errno = 0;
> +	length = strtoul(argv[1], &endptr, 0);
> +	if (errno) {
> +		perror(argv[1]);
> +		return 1;
> +	}
> +	if (*endptr != '\0') {
> +		fprintf(stderr, "%s: not a proper file length?\n", argv[2]);
> +		return 1;
> +	}
> +
> +	/* Allocate file info */
> +	nr_files = (argc - 2) / 2;
> +
> +	fi = calloc(nr_files, sizeof(struct file_info));
> +	if (!fi) {
> +		perror("calloc file info");
> +		return 1;
> +	}
> +
> +	buf = malloc(length);
> +	if (!buf) {
> +		perror("malloc buf");
> +		return 1;
> +	}
> +
> +	for (i = 0; i < nr_files; i++) {
> +		struct stat	statbuf;
> +		char		*offset = argv[((i + 1) * 2)];
> +		char		*fname = argv[((i + 1) * 2) + 1];
> +
> +		/* Open file, create mapping for the range we want. */
> +		fi[i].fd = open(fname, O_RDWR);
> +		if (fi[i].fd < 0) {
> +			perror(fname);
> +			return 1;
> +		}
> +
> +		/* Parse mwrite offset */
> +		errno = 0;
> +		fi[i].file_offset = strtoul(offset, &endptr, 0);
> +		if (errno) {
> +			perror(argv[1]);
> +			return 1;
> +		}
> +
> +		/* Remember file size */
> +		ret = fstat(fi[i].fd, &statbuf);
> +		if (ret) {
> +			perror(fname);
> +			return 1;
> +		}
> +		fi[i].file_length = statbuf.st_size;
> +
> +		if (fi[i].file_offset + length > fi[i].file_length) {
> +			fprintf(stderr, "%s: file must be %llu bytes\n",
> +				fname,
> +				(unsigned long long)fi[i].file_offset + length);
> +			return 1;
> +		}
> +
> +		/* Create the mapping */
> +		fi[i].mapping = mmap(NULL, fi[i].file_length,
> +				PROT_READ | PROT_WRITE, MAP_SHARED,
> +				fi[i].fd, 0);
> +		if (fi[i].mapping == MAP_FAILED) {
> +			perror(fname);
> +			return 1;
> +		}
> +
> +		/*
> +		 * Make sure the mapping for region we're going to write is
> +		 * already populated in the page cache.
> +		 */
> +		memcpy(buf, fi[i].mapping + fi[i].file_offset, length);
> +	}
> +
> +	/* Dirty the same region in each file to test COW. */
> +	for (i = 0; i < nr_files; i++) {
> +		memset(buf, 0x62 + i, length);
> +		memcpy(fi[i].mapping + fi[i].file_offset, buf, length);
> +	}
> +	for (i = 0; i < nr_files; i++) {
> +		ret = msync(fi[i].mapping, fi[i].file_offset + length, MS_SYNC);
> +		if (ret) {
> +			perror("msync");
> +			return 1;
> +		}
> +	}
> +
> +	/* Close everything. */
> +	for (i = 0; i < nr_files; i++) {
> +		ret = munmap(fi[i].mapping, fi[i].file_length);
> +		if (ret) {
> +			perror("munmap");
> +			return 1;
> +		}
> +
> +		ret = close(fi[i].fd);
> +		if (ret) {
> +			perror("close");
> +			return 1;
> +		}
> +	}
> +
> +	/* Free everything. */
> +	free(buf);
> +	free(fi);
> +
> +	return 0;
> +}
> diff --git a/tests/generic/945 b/tests/generic/945
> new file mode 100755
> index 00000000..38b5883c
> --- /dev/null
> +++ b/tests/generic/945
> @@ -0,0 +1,104 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0-or-newer
> +# Copyright (c) 2019, Oracle and/or its affiliates.  All Rights Reserved.
> +#
> +# FS QA Test No. 945
> +#
> +# Make sure that we can handle multiple mmap writers to the same file.
> +
> +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 -rf $tmp.* $testdir
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +. ./common/reflink
> +
> +# real QA test starts here
> +_supported_os Linux
> +_supported_fs generic
> +_require_command "$FILEFRAG_PROG" filefrag

Also added

_require_test_program "mmap-write-concurrent"

> +_require_test_reflink
> +_require_cp_reflink
> +
> +rm -f $seqres.full
> +
> +compare() {
> +	for i in $(seq 1 8); do
> +		md5sum $testdir/file$i | _filter_test_dir
> +		echo $testdir/file$i >> $seqres.full
> +		od -tx1 -Ad -c $testdir/file$i >> $seqres.full
> +	done
> +}
> +
> +testdir=$TEST_DIR/test-$seq
> +rm -rf $testdir
> +mkdir $testdir
> +
> +echo "Create the original files"
> +blksz=65536
> +filesz=$((blksz * 4))
> +_pwrite_byte 0x61 0 $filesz $testdir/file1 >> $seqres.full
> +_cp_reflink $testdir/file1 $testdir/file2 >> $seqres.full
> +_cp_reflink $testdir/file1 $testdir/file3 >> $seqres.full
> +_cp_reflink $testdir/file1 $testdir/file4 >> $seqres.full
> +_reflink_range $testdir/file1 0 $testdir/file5 $blksz $filesz >> $seqres.full
> +_reflink_range $testdir/file1 0 $testdir/file6 $((blksz * 2)) $filesz >> $seqres.full
> +_reflink_range $testdir/file1 0 $testdir/file7 $((blksz * 3)) $filesz >> $seqres.full
> +_reflink_range $testdir/file1 0 $testdir/file8 $((blksz * 4)) $filesz >> $seqres.full
> +_test_cycle_mount
> +
> +echo "Compare files before cow" | tee -a $seqres.full
> +compare
> +
> +echo "mwrite all copies" | tee -a $seqres.full
> +off=$(( (filesz / 2) - 168 ))
> +len=337
> +./src/mmap-write-concurrent $len \

And used "$here/src/mmap-write-concurrent .." here.

Thanks,
Eryu

> +		$off $testdir/file1 \
> +		$off $testdir/file2 \
> +		$off $testdir/file3 \
> +		$off $testdir/file4 \
> +		$((off + blksz)) $testdir/file5 \
> +		$((off + (blksz * 2))) $testdir/file6 \
> +		$((off + (blksz * 3))) $testdir/file7 \
> +		$((off + (blksz * 4))) $testdir/file8 \
> +		168 $testdir/file1 \
> +		$((blksz - 168)) $testdir/file2 \
> +		$((filesz - 777)) $testdir/file3 \
> +		$(((blksz * 3) - 168)) $testdir/file4 \
> +
> +
> +echo "Compare files before remount" | tee -a $seqres.full
> +compare
> +_test_cycle_mount
> +
> +echo "Compare files after remount" | tee -a $seqres.full
> +compare
> +
> +echo "Check for non-shared extents" | tee -a $seqres.full
> +$FILEFRAG_PROG -v $testdir/file1 $testdir/file2 $testdir/file3 $testdir/file4 \
> +		  $testdir/file5 $testdir/file6 $testdir/file7 $testdir/file8 \
> +		  | grep '^[[:space:]]*[0-9]*:' > $testdir/fiemap
> +cat $testdir/fiemap >> $seqres.full
> +grep -q 'shared' $testdir/fiemap || \
> +		echo "Expected to find shared extents"
> +
> +grep -q -v 'shared' $testdir/fiemap || \
> +		echo "Expected to find non-shared extents"
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/generic/945.out b/tests/generic/945.out
> new file mode 100644
> index 00000000..ad1e21ff
> --- /dev/null
> +++ b/tests/generic/945.out
> @@ -0,0 +1,31 @@
> +QA output created by 945
> +Create the original files
> +Compare files before cow
> +c946b71bb69c07daf25470742c967e7c  TEST_DIR/test-945/file1
> +c946b71bb69c07daf25470742c967e7c  TEST_DIR/test-945/file2
> +c946b71bb69c07daf25470742c967e7c  TEST_DIR/test-945/file3
> +c946b71bb69c07daf25470742c967e7c  TEST_DIR/test-945/file4
> +74e6b9b1a03fdf09293c089b002800f8  TEST_DIR/test-945/file5
> +c14f20b97155e3fc11a17532d02ad9df  TEST_DIR/test-945/file6
> +22eb46e0f4a3742c8d86346845b7bc80  TEST_DIR/test-945/file7
> +4d292f06cec9d3f1bece4822cd5ef532  TEST_DIR/test-945/file8
> +mwrite all copies
> +Compare files before remount
> +c1b46135a2620ae6da21bbfd4cbb3cba  TEST_DIR/test-945/file1
> +16f0bc0f97c42d2ad903c519095b8126  TEST_DIR/test-945/file2
> +eb71e3135ca2abf33bb9081e2b49a876  TEST_DIR/test-945/file3
> +2678dfcb77bed4dc29e19836bef82e5b  TEST_DIR/test-945/file4
> +2802d75dbee4f29d62124aa7b473edca  TEST_DIR/test-945/file5
> +acd58cf3d33ef905e26800a0e049223c  TEST_DIR/test-945/file6
> +1b68d203e5a1c1b45a9510bedcd1e126  TEST_DIR/test-945/file7
> +9479709b697ced2e3a57c17bc1b97373  TEST_DIR/test-945/file8
> +Compare files after remount
> +c1b46135a2620ae6da21bbfd4cbb3cba  TEST_DIR/test-945/file1
> +16f0bc0f97c42d2ad903c519095b8126  TEST_DIR/test-945/file2
> +eb71e3135ca2abf33bb9081e2b49a876  TEST_DIR/test-945/file3
> +2678dfcb77bed4dc29e19836bef82e5b  TEST_DIR/test-945/file4
> +2802d75dbee4f29d62124aa7b473edca  TEST_DIR/test-945/file5
> +acd58cf3d33ef905e26800a0e049223c  TEST_DIR/test-945/file6
> +1b68d203e5a1c1b45a9510bedcd1e126  TEST_DIR/test-945/file7
> +9479709b697ced2e3a57c17bc1b97373  TEST_DIR/test-945/file8
> +Check for non-shared extents
> diff --git a/tests/generic/group b/tests/generic/group
> index 4584667f..f77c5b21 100644
> --- a/tests/generic/group
> +++ b/tests/generic/group
> @@ -576,3 +576,4 @@
>  715 dangerous_norepair
>  716 dangerous_norepair
>  720 dangerous_norepair
> +945 auto quick rw clone

  reply	other threads:[~2019-10-13 12:11 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-10  4:14 [PATCH] generic: check reflink multiple mmap write Darrick J. Wong
2019-10-10  6:49 ` Christoph Hellwig
2019-10-11 21:41 ` [PATCH v2] " Darrick J. Wong
2019-10-13 12:11   ` Eryu Guan [this message]
2019-10-13 16:23     ` Darrick J. Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191013121134.GG2622@desktop \
    --to=guaneryu@gmail.com \
    --cc=darrick.wong@oracle.com \
    --cc=fstests@vger.kernel.org \
    --cc=hch@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).