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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #include <unistd.h> 29 #include <fcntl.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <sys/mman.h> 34 #include <pthread.h> 35 #include <errno.h> 36 #include <err.h> 37 38 /* 39 * -------------------------------------------------------------------- 40 * Bug Issue Id: #7512 41 * The bug time sequence: 42 * 1. context #1, zfs_write assign a txg "n". 43 * 2. In the same process, context #2, mmap page fault (which means the mm_sem 44 * is hold) occurred, zfs_dirty_inode open a txg failed, and wait previous 45 * txg "n" completed. 46 * 3. context #1 call zfs_uiomove to write, however page fault is occurred in 47 * zfs_uiomove, which means it needs mm_sem, but mm_sem is hold by 48 * context #2, so it stuck and can't complete, then txg "n" will not 49 * complete. 50 * 51 * So context #1 and context #2 trap into the "dead lock". 52 * -------------------------------------------------------------------- 53 */ 54 55 #define NORMAL_WRITE_TH_NUM 2 56 #define MAX_WRITE_BYTES 262144000 57 58 static void * 59 normal_writer(void *filename) 60 { 61 char *file_path = filename; 62 int fd = -1; 63 ssize_t write_num = 0; 64 int page_size = getpagesize(); 65 66 fd = open(file_path, O_RDWR | O_CREAT, 0777); 67 if (fd == -1) { 68 err(1, "failed to open %s", file_path); 69 } 70 71 char buf = 'z'; 72 off_t bytes_written = 0; 73 74 while (bytes_written < MAX_WRITE_BYTES) { 75 write_num = write(fd, &buf, 1); 76 if (write_num == 0) { 77 err(1, "write failed!"); 78 break; 79 } 80 if ((bytes_written = lseek(fd, page_size, SEEK_CUR)) == -1) { 81 err(1, "lseek failed on %s: %s", file_path, 82 strerror(errno)); 83 break; 84 } 85 } 86 87 if (close(fd) != 0) 88 err(1, "failed to close file"); 89 90 return (NULL); 91 } 92 93 static void * 94 map_writer(void *filename) 95 { 96 int fd = -1; 97 int ret = 0; 98 char *buf = NULL; 99 int page_size = getpagesize(); 100 char *file_path = filename; 101 102 while (1) { 103 fd = open(file_path, O_RDWR); 104 if (fd == -1) { 105 if (errno == ENOENT) { 106 fd = open(file_path, O_RDWR | O_CREAT, 0777); 107 if (fd == -1) { 108 err(1, "open file failed"); 109 } 110 ret = ftruncate(fd, page_size); 111 if (ret == -1) { 112 err(1, "truncate file failed"); 113 } 114 } else { 115 err(1, "open file failed"); 116 } 117 } 118 119 if ((buf = mmap(NULL, page_size, PROT_READ | PROT_WRITE, 120 MAP_SHARED, fd, 0)) == MAP_FAILED) { 121 err(1, "map file failed"); 122 } 123 124 if (fd != -1) 125 close(fd); 126 127 char s[10] = {0, }; 128 memcpy(buf, s, 10); 129 ret = munmap(buf, page_size); 130 if (ret != 0) { 131 err(1, "unmap file failed"); 132 } 133 } 134 } 135 136 int 137 main(int argc, char **argv) 138 { 139 pthread_t map_write_tid; 140 pthread_t normal_write_tid[NORMAL_WRITE_TH_NUM]; 141 int i = 0; 142 143 if (argc != 3) { 144 (void) printf("usage: %s <normal write file name> " 145 "<map write file name>\n", argv[0]); 146 exit(1); 147 } 148 149 for (i = 0; i < NORMAL_WRITE_TH_NUM; i++) { 150 if (pthread_create(&normal_write_tid[i], NULL, normal_writer, 151 argv[1])) { 152 err(1, "pthread_create normal_writer failed."); 153 } 154 } 155 156 if (pthread_create(&map_write_tid, NULL, map_writer, argv[2])) { 157 err(1, "pthread_create map_writer failed."); 158 } 159 160 pthread_join(map_write_tid, NULL); 161 return (0); 162 } 163