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 = 'z'; 70 while (1) { 71 write_num = write(fd, &buf, 1); 72 if (write_num == 0) { 73 err(1, "write failed!"); 74 break; 75 } 76 if (lseek(fd, page_size, SEEK_CUR) == -1) { 77 err(1, "lseek failed on %s: %s", file_path, 78 strerror(errno)); 79 break; 80 } 81 } 82 } 83 84 static void * 85 map_writer(void *filename) 86 { 87 int fd = -1; 88 int ret = 0; 89 char *buf = NULL; 90 int page_size = getpagesize(); 91 char *file_path = filename; 92 93 while (1) { 94 fd = open(file_path, O_RDWR); 95 if (fd == -1) { 96 if (errno == ENOENT) { 97 fd = open(file_path, O_RDWR | O_CREAT, 0777); 98 if (fd == -1) { 99 err(1, "open file failed"); 100 } 101 ret = ftruncate(fd, page_size); 102 if (ret == -1) { 103 err(1, "truncate file failed"); 104 } 105 } else { 106 err(1, "open file failed"); 107 } 108 } 109 110 if ((buf = mmap(NULL, page_size, PROT_READ | PROT_WRITE, 111 MAP_SHARED, fd, 0)) == MAP_FAILED) { 112 err(1, "map file failed"); 113 } 114 115 if (fd != -1) 116 close(fd); 117 118 char s[10] = {0, }; 119 memcpy(buf, s, 10); 120 ret = munmap(buf, page_size); 121 if (ret != 0) { 122 err(1, "unmap file failed"); 123 } 124 } 125 } 126 127 int 128 main(int argc, char **argv) 129 { 130 pthread_t map_write_tid; 131 pthread_t normal_write_tid[NORMAL_WRITE_TH_NUM]; 132 int i = 0; 133 134 if (argc != 3) { 135 (void) printf("usage: %s <normal write file name> " 136 "<map write file name>\n", argv[0]); 137 exit(1); 138 } 139 140 for (i = 0; i < NORMAL_WRITE_TH_NUM; i++) { 141 if (pthread_create(&normal_write_tid[i], NULL, normal_writer, 142 argv[1])) { 143 err(1, "pthread_create normal_writer failed."); 144 } 145 } 146 147 if (pthread_create(&map_write_tid, NULL, map_writer, argv[2])) { 148 err(1, "pthread_create map_writer failed."); 149 } 150 151 pthread_join(map_write_tid, NULL); 152 return (0); 153 } 154