Skip to content

Commit

Permalink
update mmapwrite unittest.
Browse files Browse the repository at this point in the history
Signed-off-by: Grady Wong <grady.w@xtaotech.com>
  • Loading branch information
Grady Wong committed Oct 11, 2018
1 parent 9f7221f commit 8e221f6
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 44 deletions.
1 change: 1 addition & 0 deletions module/zfs/zfs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
else
#endif
if (uio_prefaultpages(MIN(n, max_blksz), uio)) {
ZFS_EXIT(zfsvfs);
return (SET_ERROR(EFAULT));
}

Expand Down
140 changes: 99 additions & 41 deletions tests/zfs-tests/cmd/mmapwrite/mmapwrite.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,74 +31,132 @@
#include <string.h>
#include <sys/mman.h>
#include <pthread.h>
#include <errno.h>
#include <err.h>

/*
* --------------------------------------------------------------------
* Bug Id: 5032643
* 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 need mm_sem, but mm_sem is hold by
* context #2, so it stuck and can't complete, then txg "n" will not
* complete.
*
* Simply writing to a file and mmaping that file at the same time can
* result in deadlock. Nothing perverse like writing from the file's
* own mapping is required.
* So context #1 and context #2 trap into the "dead lock".
* --------------------------------------------------------------------
*/

#define NORMAL_WRITE_TH_NUM 2

static void *
mapper(void *fdp)
normal_writer(void *filename)
{
void *addr;
int fd = *(int *)fdp;
char *file_path = filename;
int fd = -1;
ssize_t write_num = 0;
int page_size = getpagesize();

if ((addr =
mmap(0, 8192, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
perror("mmap");
exit(1);
fd = open(file_path, O_RDWR | O_CREAT, 0777);
if (fd == -1) {
err(1, "failed to open %s", file_path);
}
for (;;) {
if (mmap(addr, 8192, PROT_READ,
MAP_SHARED|MAP_FIXED, fd, 0) == MAP_FAILED) {
perror("mmap");
exit(1);

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);
}
/* NOTREACHED */
return ((void *)1);
}

int
main(int argc, char **argv)
static void *
map_writer(void *filename)
{
int fd;
char buf[1024];
pthread_t tid;
int fd = -1;
int ret = 0;
char *buf = NULL;
int page_size = getpagesize();
int op_errno = 0;
char *file_path = filename;

memset(buf, 'a', sizeof (buf));
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");
}

if (argc != 2) {
(void) printf("usage: %s <file name>\n", argv[0]);
exit(1);
}
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 ((fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666)) == -1) {
perror("open");
exit(1);
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");
}
}
}

(void) pthread_setconcurrency(2);
if (pthread_create(&tid, NULL, mapper, &fd) != 0) {
perror("pthread_create");
close(fd);
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 (;;) {
if (write(fd, buf, sizeof (buf)) == -1) {
perror("write");
close(fd);
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.");
}
}

close(fd);
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);
}
8 changes: 5 additions & 3 deletions tests/zfs-tests/tests/functional/mmap/mmap_write_001_pos.ksh
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,14 @@ if ! is_mp; then
fi

log_must chmod 777 $TESTDIR
mmapwrite $TESTDIR/test-write-file &
mmapwrite $TESTDIR/normal_write_file $TESTDIR/map_write_file &
PID_MMAPWRITE=$!
log_note "mmapwrite $TESTDIR/test-write-file pid: $PID_MMAPWRITE"
log_note "mmapwrite $TESTDIR/normal_write_file $TESTDIR/map_write_file"\
"pid: $PID_MMAPWRITE"
log_must sleep 30

log_must kill -9 $PID_MMAPWRITE
log_must ls -l $TESTDIR/test-write-file
log_must ls -l $TESTDIR/normal_write_file
log_must ls -l $TESTDIR/map_write_file

log_pass "write(2) a mmap(2)'ing file succeeded."

0 comments on commit 8e221f6

Please sign in to comment.