163 lines
3.8 KiB
C
163 lines
3.8 KiB
C
|
/*
|
||
|
* 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 <unistd.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <sys/mman.h>
|
||
|
#include <pthread.h>
|
||
|
#include <errno.h>
|
||
|
#include <err.h>
|
||
|
|
||
|
/*
|
||
|
* --------------------------------------------------------------------
|
||
|
* 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 uiomove to write, however page fault is occurred in
|
||
|
* 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
|
||
|
|
||
|
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);
|
||
|
while (1) {
|
||
|
write_num = write(fd, buf, 1);
|
||
|
if (write_num == 0) {
|
||
|
err(1, "write failed!");
|
||
|
break;
|
||
|
}
|
||
|
lseek(fd, page_size, SEEK_CUR);
|
||
|
}
|
||
|
|
||
|
if (buf) {
|
||
|
free(buf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 <normal write file name>"
|
||
|
"<map write file name>\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);
|
||
|
}
|