/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include /* * -------------------------------------------------------------------- * Bug Issue Id: #7512 * The bug time sequence: * 1. context #1, zfs_write assign a txg "n". * 2. In the same process, context #2, mmap page fault (which means the mm_sem * is hold) occurred, zfs_dirty_inode open a txg failed, and wait previous * txg "n" completed. * 3. context #1 call zfs_uiomove to write, however page fault is occurred in * zfs_uiomove, which means it needs mm_sem, but mm_sem is hold by * context #2, so it stuck and can't complete, then txg "n" will not * complete. * * So context #1 and context #2 trap into the "dead lock". * -------------------------------------------------------------------- */ #define NORMAL_WRITE_TH_NUM 2 #define MAX_WRITE_BYTES 262144000 static void * normal_writer(void *filename) { char *file_path = filename; int fd = -1; ssize_t write_num = 0; int page_size = getpagesize(); fd = open(file_path, O_RDWR | O_CREAT, 0777); if (fd == -1) { err(1, "failed to open %s", file_path); } char *buf = malloc(1); off_t bytes_written = 0; while (bytes_written < MAX_WRITE_BYTES) { write_num = write(fd, buf, 1); if (write_num == 0) { err(1, "write failed!"); break; } if ((bytes_written = lseek(fd, page_size, SEEK_CUR)) == -1) { err(1, "lseek failed on %s: %s", file_path, strerror(errno)); break; } } if (buf) { free(buf); } if (close(fd) != 0) err(1, "failed to close file"); return (NULL); } static void * map_writer(void *filename) { int fd = -1; int ret = 0; char *buf = NULL; int page_size = getpagesize(); int op_errno = 0; char *file_path = filename; while (1) { ret = access(file_path, F_OK); if (ret) { op_errno = errno; if (op_errno == ENOENT) { fd = open(file_path, O_RDWR | O_CREAT, 0777); if (fd == -1) { err(1, "open file failed"); } ret = ftruncate(fd, page_size); if (ret == -1) { err(1, "truncate file failed"); } } else { err(1, "access file failed!"); } } else { fd = open(file_path, O_RDWR, 0777); if (fd == -1) { err(1, "open file failed"); } } if ((buf = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { err(1, "map file failed"); } if (fd != -1) close(fd); char s[10] = {0, }; memcpy(buf, s, 10); ret = munmap(buf, page_size); if (ret != 0) { err(1, "unmap file failed"); } } } int main(int argc, char **argv) { pthread_t map_write_tid; pthread_t normal_write_tid[NORMAL_WRITE_TH_NUM]; int i = 0; if (argc != 3) { (void) printf("usage: %s " "\n", argv[0]); exit(1); } for (i = 0; i < NORMAL_WRITE_TH_NUM; i++) { if (pthread_create(&normal_write_tid[i], NULL, normal_writer, argv[1])) { err(1, "pthread_create normal_writer failed."); } } if (pthread_create(&map_write_tid, NULL, map_writer, argv[2])) { err(1, "pthread_create map_writer failed."); } /* NOTREACHED */ pthread_join(map_write_tid, NULL); return (0); }