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 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 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 * 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 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 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