1*61145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0 2716fd348SMartin Matuska /* 3716fd348SMartin Matuska * CDDL HEADER START 4716fd348SMartin Matuska * 5716fd348SMartin Matuska * The contents of this file are subject to the terms of the 6716fd348SMartin Matuska * Common Development and Distribution License (the "License"). 7716fd348SMartin Matuska * You may not use this file except in compliance with the License. 8716fd348SMartin Matuska * 9716fd348SMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 11716fd348SMartin Matuska * See the License for the specific language governing permissions 12716fd348SMartin Matuska * and limitations under the License. 13716fd348SMartin Matuska * 14716fd348SMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each 15716fd348SMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16716fd348SMartin Matuska * If applicable, add the following below this CDDL HEADER, with the 17716fd348SMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying 18716fd348SMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner] 19716fd348SMartin Matuska * 20716fd348SMartin Matuska * CDDL HEADER END 21716fd348SMartin Matuska */ 22716fd348SMartin Matuska 23716fd348SMartin Matuska /* 24716fd348SMartin Matuska * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 25716fd348SMartin Matuska * Use is subject to license terms. 26716fd348SMartin Matuska */ 27716fd348SMartin Matuska 28716fd348SMartin Matuska #include <unistd.h> 29716fd348SMartin Matuska #include <fcntl.h> 30716fd348SMartin Matuska #include <stdio.h> 31716fd348SMartin Matuska #include <stdlib.h> 32716fd348SMartin Matuska #include <string.h> 33716fd348SMartin Matuska #include <sys/mman.h> 34716fd348SMartin Matuska #include <pthread.h> 35716fd348SMartin Matuska #include <errno.h> 36716fd348SMartin Matuska #include <err.h> 37716fd348SMartin Matuska 38716fd348SMartin Matuska /* 39716fd348SMartin Matuska * -------------------------------------------------------------------- 40716fd348SMartin Matuska * Bug Issue Id: #7512 41716fd348SMartin Matuska * The bug time sequence: 42716fd348SMartin Matuska * 1. context #1, zfs_write assign a txg "n". 43716fd348SMartin Matuska * 2. In the same process, context #2, mmap page fault (which means the mm_sem 44716fd348SMartin Matuska * is hold) occurred, zfs_dirty_inode open a txg failed, and wait previous 45716fd348SMartin Matuska * txg "n" completed. 46716fd348SMartin Matuska * 3. context #1 call zfs_uiomove to write, however page fault is occurred in 47716fd348SMartin Matuska * zfs_uiomove, which means it needs mm_sem, but mm_sem is hold by 48716fd348SMartin Matuska * context #2, so it stuck and can't complete, then txg "n" will not 49716fd348SMartin Matuska * complete. 50716fd348SMartin Matuska * 51716fd348SMartin Matuska * So context #1 and context #2 trap into the "dead lock". 52716fd348SMartin Matuska * -------------------------------------------------------------------- 53716fd348SMartin Matuska */ 54716fd348SMartin Matuska 55716fd348SMartin Matuska #define NORMAL_WRITE_TH_NUM 2 5615f0b8c3SMartin Matuska #define MAX_WRITE_BYTES 262144000 57716fd348SMartin Matuska 58716fd348SMartin Matuska static void * 59716fd348SMartin Matuska normal_writer(void *filename) 60716fd348SMartin Matuska { 61716fd348SMartin Matuska char *file_path = filename; 62716fd348SMartin Matuska int fd = -1; 63716fd348SMartin Matuska ssize_t write_num = 0; 64716fd348SMartin Matuska int page_size = getpagesize(); 65716fd348SMartin Matuska 66716fd348SMartin Matuska fd = open(file_path, O_RDWR | O_CREAT, 0777); 67716fd348SMartin Matuska if (fd == -1) { 68716fd348SMartin Matuska err(1, "failed to open %s", file_path); 69716fd348SMartin Matuska } 70716fd348SMartin Matuska 71be181ee2SMartin Matuska char buf = 'z'; 7215f0b8c3SMartin Matuska off_t bytes_written = 0; 7315f0b8c3SMartin Matuska 7415f0b8c3SMartin Matuska while (bytes_written < MAX_WRITE_BYTES) { 75716fd348SMartin Matuska write_num = write(fd, &buf, 1); 76716fd348SMartin Matuska if (write_num == 0) { 77716fd348SMartin Matuska err(1, "write failed!"); 78716fd348SMartin Matuska break; 79716fd348SMartin Matuska } 8015f0b8c3SMartin Matuska if ((bytes_written = lseek(fd, page_size, SEEK_CUR)) == -1) { 81be181ee2SMartin Matuska err(1, "lseek failed on %s: %s", file_path, 82be181ee2SMartin Matuska strerror(errno)); 83be181ee2SMartin Matuska break; 84be181ee2SMartin Matuska } 85716fd348SMartin Matuska } 8615f0b8c3SMartin Matuska 8715f0b8c3SMartin Matuska if (close(fd) != 0) 8815f0b8c3SMartin Matuska err(1, "failed to close file"); 8915f0b8c3SMartin Matuska 9015f0b8c3SMartin Matuska return (NULL); 91716fd348SMartin Matuska } 92716fd348SMartin Matuska 93716fd348SMartin Matuska static void * 94716fd348SMartin Matuska map_writer(void *filename) 95716fd348SMartin Matuska { 96716fd348SMartin Matuska int fd = -1; 97716fd348SMartin Matuska int ret = 0; 98716fd348SMartin Matuska char *buf = NULL; 99716fd348SMartin Matuska int page_size = getpagesize(); 100716fd348SMartin Matuska char *file_path = filename; 101716fd348SMartin Matuska 102716fd348SMartin Matuska while (1) { 103dbd5678dSMartin Matuska fd = open(file_path, O_RDWR); 104dbd5678dSMartin Matuska if (fd == -1) { 105dbd5678dSMartin Matuska if (errno == ENOENT) { 106716fd348SMartin Matuska fd = open(file_path, O_RDWR | O_CREAT, 0777); 107716fd348SMartin Matuska if (fd == -1) { 108716fd348SMartin Matuska err(1, "open file failed"); 109716fd348SMartin Matuska } 110716fd348SMartin Matuska ret = ftruncate(fd, page_size); 111716fd348SMartin Matuska if (ret == -1) { 112716fd348SMartin Matuska err(1, "truncate file failed"); 113716fd348SMartin Matuska } 114716fd348SMartin Matuska } else { 115716fd348SMartin Matuska err(1, "open file failed"); 116716fd348SMartin Matuska } 117716fd348SMartin Matuska } 118716fd348SMartin Matuska 119716fd348SMartin Matuska if ((buf = mmap(NULL, page_size, PROT_READ | PROT_WRITE, 120716fd348SMartin Matuska MAP_SHARED, fd, 0)) == MAP_FAILED) { 121716fd348SMartin Matuska err(1, "map file failed"); 122716fd348SMartin Matuska } 123716fd348SMartin Matuska 124716fd348SMartin Matuska if (fd != -1) 125716fd348SMartin Matuska close(fd); 126716fd348SMartin Matuska 127716fd348SMartin Matuska char s[10] = {0, }; 128716fd348SMartin Matuska memcpy(buf, s, 10); 129716fd348SMartin Matuska ret = munmap(buf, page_size); 130716fd348SMartin Matuska if (ret != 0) { 131716fd348SMartin Matuska err(1, "unmap file failed"); 132716fd348SMartin Matuska } 133716fd348SMartin Matuska } 134716fd348SMartin Matuska } 135716fd348SMartin Matuska 136716fd348SMartin Matuska int 137716fd348SMartin Matuska main(int argc, char **argv) 138716fd348SMartin Matuska { 139716fd348SMartin Matuska pthread_t map_write_tid; 140716fd348SMartin Matuska pthread_t normal_write_tid[NORMAL_WRITE_TH_NUM]; 141716fd348SMartin Matuska int i = 0; 142716fd348SMartin Matuska 143716fd348SMartin Matuska if (argc != 3) { 144716fd348SMartin Matuska (void) printf("usage: %s <normal write file name> " 145716fd348SMartin Matuska "<map write file name>\n", argv[0]); 146716fd348SMartin Matuska exit(1); 147716fd348SMartin Matuska } 148716fd348SMartin Matuska 149716fd348SMartin Matuska for (i = 0; i < NORMAL_WRITE_TH_NUM; i++) { 150716fd348SMartin Matuska if (pthread_create(&normal_write_tid[i], NULL, normal_writer, 151716fd348SMartin Matuska argv[1])) { 152716fd348SMartin Matuska err(1, "pthread_create normal_writer failed."); 153716fd348SMartin Matuska } 154716fd348SMartin Matuska } 155716fd348SMartin Matuska 156716fd348SMartin Matuska if (pthread_create(&map_write_tid, NULL, map_writer, argv[2])) { 157716fd348SMartin Matuska err(1, "pthread_create map_writer failed."); 158716fd348SMartin Matuska } 159716fd348SMartin Matuska 160716fd348SMartin Matuska pthread_join(map_write_tid, NULL); 161716fd348SMartin Matuska return (0); 162716fd348SMartin Matuska } 163