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 *
normal_writer(void * filename)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 *
map_writer(void * filename)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
main(int argc,char ** argv)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