xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/cmd/mmapwrite.c (revision 716fd348e01c5f2ba125f878a634a753436c2994)
1*716fd348SMartin Matuska /*
2*716fd348SMartin Matuska  * CDDL HEADER START
3*716fd348SMartin Matuska  *
4*716fd348SMartin Matuska  * The contents of this file are subject to the terms of the
5*716fd348SMartin Matuska  * Common Development and Distribution License (the "License").
6*716fd348SMartin Matuska  * You may not use this file except in compliance with the License.
7*716fd348SMartin Matuska  *
8*716fd348SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*716fd348SMartin Matuska  * or http://www.opensolaris.org/os/licensing.
10*716fd348SMartin Matuska  * See the License for the specific language governing permissions
11*716fd348SMartin Matuska  * and limitations under the License.
12*716fd348SMartin Matuska  *
13*716fd348SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
14*716fd348SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*716fd348SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
16*716fd348SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
17*716fd348SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
18*716fd348SMartin Matuska  *
19*716fd348SMartin Matuska  * CDDL HEADER END
20*716fd348SMartin Matuska  */
21*716fd348SMartin Matuska 
22*716fd348SMartin Matuska /*
23*716fd348SMartin Matuska  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*716fd348SMartin Matuska  * Use is subject to license terms.
25*716fd348SMartin Matuska  */
26*716fd348SMartin Matuska 
27*716fd348SMartin Matuska #include <unistd.h>
28*716fd348SMartin Matuska #include <fcntl.h>
29*716fd348SMartin Matuska #include <stdio.h>
30*716fd348SMartin Matuska #include <stdlib.h>
31*716fd348SMartin Matuska #include <string.h>
32*716fd348SMartin Matuska #include <sys/mman.h>
33*716fd348SMartin Matuska #include <pthread.h>
34*716fd348SMartin Matuska #include <errno.h>
35*716fd348SMartin Matuska #include <err.h>
36*716fd348SMartin Matuska 
37*716fd348SMartin Matuska /*
38*716fd348SMartin Matuska  * --------------------------------------------------------------------
39*716fd348SMartin Matuska  * Bug Issue Id: #7512
40*716fd348SMartin Matuska  * The bug time sequence:
41*716fd348SMartin Matuska  * 1. context #1, zfs_write assign a txg "n".
42*716fd348SMartin Matuska  * 2. In the same process, context #2, mmap page fault (which means the mm_sem
43*716fd348SMartin Matuska  *    is hold) occurred, zfs_dirty_inode open a txg failed, and wait previous
44*716fd348SMartin Matuska  *    txg "n" completed.
45*716fd348SMartin Matuska  * 3. context #1 call zfs_uiomove to write, however page fault is occurred in
46*716fd348SMartin Matuska  *    zfs_uiomove, which means it needs mm_sem, but mm_sem is hold by
47*716fd348SMartin Matuska  *    context #2, so it stuck and can't complete, then txg "n" will not
48*716fd348SMartin Matuska  *    complete.
49*716fd348SMartin Matuska  *
50*716fd348SMartin Matuska  * So context #1 and context #2 trap into the "dead lock".
51*716fd348SMartin Matuska  * --------------------------------------------------------------------
52*716fd348SMartin Matuska  */
53*716fd348SMartin Matuska 
54*716fd348SMartin Matuska #define	NORMAL_WRITE_TH_NUM	2
55*716fd348SMartin Matuska 
56*716fd348SMartin Matuska static void *
57*716fd348SMartin Matuska normal_writer(void *filename)
58*716fd348SMartin Matuska {
59*716fd348SMartin Matuska 	char *file_path = filename;
60*716fd348SMartin Matuska 	int fd = -1;
61*716fd348SMartin Matuska 	ssize_t write_num = 0;
62*716fd348SMartin Matuska 	int page_size = getpagesize();
63*716fd348SMartin Matuska 
64*716fd348SMartin Matuska 	fd = open(file_path, O_RDWR | O_CREAT, 0777);
65*716fd348SMartin Matuska 	if (fd == -1) {
66*716fd348SMartin Matuska 		err(1, "failed to open %s", file_path);
67*716fd348SMartin Matuska 	}
68*716fd348SMartin Matuska 
69*716fd348SMartin Matuska 	char buf;
70*716fd348SMartin Matuska 	while (1) {
71*716fd348SMartin Matuska 		write_num = write(fd, &buf, 1);
72*716fd348SMartin Matuska 		if (write_num == 0) {
73*716fd348SMartin Matuska 			err(1, "write failed!");
74*716fd348SMartin Matuska 			break;
75*716fd348SMartin Matuska 		}
76*716fd348SMartin Matuska 		lseek(fd, page_size, SEEK_CUR);
77*716fd348SMartin Matuska 	}
78*716fd348SMartin Matuska }
79*716fd348SMartin Matuska 
80*716fd348SMartin Matuska static void *
81*716fd348SMartin Matuska map_writer(void *filename)
82*716fd348SMartin Matuska {
83*716fd348SMartin Matuska 	int fd = -1;
84*716fd348SMartin Matuska 	int ret = 0;
85*716fd348SMartin Matuska 	char *buf = NULL;
86*716fd348SMartin Matuska 	int page_size = getpagesize();
87*716fd348SMartin Matuska 	int op_errno = 0;
88*716fd348SMartin Matuska 	char *file_path = filename;
89*716fd348SMartin Matuska 
90*716fd348SMartin Matuska 	while (1) {
91*716fd348SMartin Matuska 		ret = access(file_path, F_OK);
92*716fd348SMartin Matuska 		if (ret) {
93*716fd348SMartin Matuska 			op_errno = errno;
94*716fd348SMartin Matuska 			if (op_errno == ENOENT) {
95*716fd348SMartin Matuska 				fd = open(file_path, O_RDWR | O_CREAT, 0777);
96*716fd348SMartin Matuska 				if (fd == -1) {
97*716fd348SMartin Matuska 					err(1, "open file failed");
98*716fd348SMartin Matuska 				}
99*716fd348SMartin Matuska 
100*716fd348SMartin Matuska 				ret = ftruncate(fd, page_size);
101*716fd348SMartin Matuska 				if (ret == -1) {
102*716fd348SMartin Matuska 					err(1, "truncate file failed");
103*716fd348SMartin Matuska 				}
104*716fd348SMartin Matuska 			} else {
105*716fd348SMartin Matuska 				err(1, "access file failed!");
106*716fd348SMartin Matuska 			}
107*716fd348SMartin Matuska 		} else {
108*716fd348SMartin Matuska 			fd = open(file_path, O_RDWR, 0777);
109*716fd348SMartin Matuska 			if (fd == -1) {
110*716fd348SMartin Matuska 				err(1, "open file failed");
111*716fd348SMartin Matuska 			}
112*716fd348SMartin Matuska 		}
113*716fd348SMartin Matuska 
114*716fd348SMartin Matuska 		if ((buf = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
115*716fd348SMartin Matuska 		    MAP_SHARED, fd, 0)) == MAP_FAILED) {
116*716fd348SMartin Matuska 			err(1, "map file failed");
117*716fd348SMartin Matuska 		}
118*716fd348SMartin Matuska 
119*716fd348SMartin Matuska 		if (fd != -1)
120*716fd348SMartin Matuska 			close(fd);
121*716fd348SMartin Matuska 
122*716fd348SMartin Matuska 		char s[10] = {0, };
123*716fd348SMartin Matuska 		memcpy(buf, s, 10);
124*716fd348SMartin Matuska 		ret = munmap(buf, page_size);
125*716fd348SMartin Matuska 		if (ret != 0) {
126*716fd348SMartin Matuska 			err(1, "unmap file failed");
127*716fd348SMartin Matuska 		}
128*716fd348SMartin Matuska 	}
129*716fd348SMartin Matuska }
130*716fd348SMartin Matuska 
131*716fd348SMartin Matuska int
132*716fd348SMartin Matuska main(int argc, char **argv)
133*716fd348SMartin Matuska {
134*716fd348SMartin Matuska 	pthread_t map_write_tid;
135*716fd348SMartin Matuska 	pthread_t normal_write_tid[NORMAL_WRITE_TH_NUM];
136*716fd348SMartin Matuska 	int i = 0;
137*716fd348SMartin Matuska 
138*716fd348SMartin Matuska 	if (argc != 3) {
139*716fd348SMartin Matuska 		(void) printf("usage: %s <normal write file name> "
140*716fd348SMartin Matuska 		    "<map write file name>\n", argv[0]);
141*716fd348SMartin Matuska 		exit(1);
142*716fd348SMartin Matuska 	}
143*716fd348SMartin Matuska 
144*716fd348SMartin Matuska 	for (i = 0; i < NORMAL_WRITE_TH_NUM; i++) {
145*716fd348SMartin Matuska 		if (pthread_create(&normal_write_tid[i], NULL, normal_writer,
146*716fd348SMartin Matuska 		    argv[1])) {
147*716fd348SMartin Matuska 			err(1, "pthread_create normal_writer failed.");
148*716fd348SMartin Matuska 		}
149*716fd348SMartin Matuska 	}
150*716fd348SMartin Matuska 
151*716fd348SMartin Matuska 	if (pthread_create(&map_write_tid, NULL, map_writer, argv[2])) {
152*716fd348SMartin Matuska 		err(1, "pthread_create map_writer failed.");
153*716fd348SMartin Matuska 	}
154*716fd348SMartin Matuska 
155*716fd348SMartin Matuska 	pthread_join(map_write_tid, NULL);
156*716fd348SMartin Matuska 	return (0);
157*716fd348SMartin Matuska }
158