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