xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/cmd/clone_mmap_write.c (revision b670c9bafc0e31c7609969bf374b2e80bdc00211)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or https://opensource.org/licenses/CDDL-1.0.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * This program clones the file, mmap it, and writes from the map into
25  * file. This scenario triggers a panic on Linux in dbuf_redirty(),
26  * which is fixed under PR#15656. On FreeBSD, the same test causes data
27  * corruption, which is fixed by PR#15665.
28  *
29  * It would be good to test for this scenario in ZTS. This program and
30  * issue was initially produced by @robn.
31  */
32 #ifndef _GNU_SOURCE
33 #define	_GNU_SOURCE
34 #endif
35 
36 #include <fcntl.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <sys/stat.h>
43 #include <sys/mman.h>
44 
45 #ifdef __FreeBSD__
46 #define	loff_t	off_t
47 #endif
48 
49 ssize_t
50 copy_file_range(int, loff_t *, int, loff_t *, size_t, unsigned int)
51     __attribute__((weak));
52 
53 static int
54 open_file(const char *source)
55 {
56 	int fd;
57 	if ((fd = open(source, O_RDWR | O_APPEND)) < 0) {
58 		(void) fprintf(stderr, "Error opening %s\n", source);
59 		exit(1);
60 	}
61 	sync();
62 	return (fd);
63 }
64 
65 static int
66 clone_file(int sfd, long long size, const char *dest)
67 {
68 	int dfd;
69 
70 	if ((dfd = open(dest, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
71 		(void) fprintf(stderr, "Error opening %s\n", dest);
72 		exit(1);
73 	}
74 
75 	if (copy_file_range(sfd, 0, dfd, 0, size, 0) < 0) {
76 		(void) fprintf(stderr, "copy_file_range failed\n");
77 		exit(1);
78 	}
79 
80 	return (dfd);
81 }
82 
83 static void *
84 map_file(int fd, long long size)
85 {
86 	void *p = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
87 	if (p == MAP_FAILED) {
88 		(void) fprintf(stderr, "mmap failed\n");
89 		exit(1);
90 	}
91 
92 	return (p);
93 }
94 
95 static void
96 map_write(void *p, int fd)
97 {
98 	if (pwrite(fd, p, 1024*128, 0) < 0) {
99 		(void) fprintf(stderr, "write failed\n");
100 		exit(1);
101 	}
102 }
103 
104 int
105 main(int argc, char **argv)
106 {
107 	int sfd, dfd;
108 	void *p;
109 	struct stat sb;
110 	if (argc != 3) {
111 		(void) printf("usage: %s <input source file> "
112 		    "<clone destination file>\n", argv[0]);
113 		exit(1);
114 	}
115 	sfd = open_file(argv[1]);
116 	if (fstat(sfd, &sb) == -1) {
117 		(void) fprintf(stderr, "fstat failed\n");
118 		exit(1);
119 	}
120 	dfd = clone_file(sfd, sb.st_size, argv[2]);
121 	p = map_file(dfd, sb.st_size);
122 	map_write(p, dfd);
123 	return (0);
124 }
125