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
open_file(const char * source)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
clone_file(int sfd,long long size,const char * dest)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 *
map_file(int fd,long long size)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
map_write(void * p,int fd)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
main(int argc,char ** argv)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