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