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