svn commit: r191969 - projects/stress2/misc
Peter Holm
pho at FreeBSD.org
Sun May 10 18:19:18 UTC 2009
Author: pho
Date: Sun May 10 18:19:16 2009
New Revision: 191969
URL: http://svn.freebsd.org/changeset/base/191969
Log:
Added test scenarios for page faults while doing filesystem data move to
or from userspace during read(2) and write(2)
Added:
projects/stress2/misc/datamove.sh (contents, props changed)
projects/stress2/misc/datamove2.sh (contents, props changed)
projects/stress2/misc/datamove3.sh (contents, props changed)
Added: projects/stress2/misc/datamove.sh
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/stress2/misc/datamove.sh Sun May 10 18:19:16 2009 (r191969)
@@ -0,0 +1,213 @@
+#!/bin/sh
+
+#
+# Copyright (c) 2009 Peter Holm <pho at FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+# There is a well-known problem in FreeBSD, caused by allowing page faults
+# while doing filesystem data move to or from userspace during read(2) and
+# write(2). The issue is that if the userspace address being read or write
+# from/to is backed by the mapping of the same file we are doing i/o to,
+# we deadlock.
+
+# Test scenario by ups
+
+[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
+
+here=`pwd`
+cd /tmp
+sed '1,/^EOF/d' < $here/$0 > dl.c
+cc -o dl -Wall dl.c
+rm -f dl.c
+
+n=5
+old=`sysctl vm.old_msync | awk '{print $NF}'`
+sysctl vm.old_msync=1
+for i in `jot $n`; do
+ mkdir -p /tmp/dl.dir.$i
+ cd /tmp/dl.dir.$i
+ /tmp/dl &
+done
+cd /tmp
+for i in `jot $n`; do
+ wait
+done
+for i in `jot $n`; do
+ rm -rf /tmp/dl.dir.$i
+done
+sysctl vm.old_msync=$old
+
+rm -rf /tmp/dl
+exit 0
+EOF
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+
+int prepareFile(char* filename,int* fdp);
+int mapBuffer(char** bufferp,int fd1,int fd2);
+int startIO(int fd,char *buffer);
+
+int pagesize;
+
+#define FILESIZE (32*1024)
+char wbuffer[FILESIZE];
+
+/* Create a FILESIZE sized file - then remove file data from the cache*/
+int prepareFile(char* filename,int* fdp)
+{
+ int fd;
+ int len;
+ int status;
+ void *addr;
+
+ fd = open(filename,O_CREAT | O_TRUNC | O_RDWR,S_IRWXU);
+ if (fd == -1)
+ {
+ perror("Creating file");
+ return fd;
+ }
+
+ len = write(fd,wbuffer,FILESIZE);
+ if (len < 0)
+ {
+ perror("Write failed");
+ return 1;
+ }
+
+ status = fsync(fd);
+ if (status != 0)
+ {
+ perror("fsync failed");
+ return 1;
+ }
+
+ addr = mmap(NULL,FILESIZE, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);
+ if (addr == MAP_FAILED)
+ {
+ perror("Mmap failed");
+ return 1;
+ }
+
+ status = msync(addr,FILESIZE,MS_INVALIDATE | MS_SYNC);
+ if (status != 0)
+ {
+ perror("Msync failed");
+ return 1;
+ }
+
+ munmap(addr,FILESIZE);
+
+ *fdp = fd;
+ return 0;
+}
+
+
+/* mmap a 2 page buffer - first page is from fd1, second page from fd2 */
+int mapBuffer(char** bufferp,int fd1,int fd2)
+{
+ void* addr;
+ char *buffer;
+
+ addr = mmap(NULL,pagesize*2, PROT_READ | PROT_WRITE , MAP_SHARED, fd1, 0);
+ if (addr == MAP_FAILED)
+ {
+ perror("Mmap failed");
+ return 1;
+ }
+
+ buffer = addr;
+ addr = mmap(buffer + pagesize,pagesize, PROT_READ | PROT_WRITE , MAP_FIXED |
+MAP_SHARED, fd2, 0);
+
+ if (addr == MAP_FAILED)
+ {
+ perror("Mmap2 failed");
+ return 1;
+ }
+ *bufferp = buffer;
+ return 0;
+}
+
+
+int startIO(int fd,char *buffer)
+{
+ ssize_t len;
+ len = write(fd,buffer,2*pagesize);
+ if (len == -1)
+ {
+ perror("write failed");
+ return 1;
+ }
+ return 0;
+}
+
+
+int main(int argc,char *argv[],char *envp[])
+{
+
+ int fdA,fdB,fdDelayA,fdDelayB;
+ int status;
+ char *bufferA,*bufferB;
+ pid_t pid;
+
+ pagesize = getpagesize();
+
+ if ((prepareFile("A",&fdA))
+ || (prepareFile("B",&fdB))
+ || (prepareFile("DelayA",&fdDelayA))
+ || (prepareFile("DelayB",&fdDelayB))
+ || (mapBuffer(&bufferA,fdDelayA,fdB))
+ || (mapBuffer(&bufferB,fdDelayB,fdA)))
+ exit(1);
+
+ pid = fork();
+
+ if (pid == 0)
+ {
+ status = startIO(fdA,bufferA);
+ exit(status);
+ }
+
+ if (pid == -1)
+ {
+ exit(1);
+ }
+ status = startIO(fdB,bufferB);
+ exit(status);
+
+}
+
+
+
+
+
Added: projects/stress2/misc/datamove2.sh
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/stress2/misc/datamove2.sh Sun May 10 18:19:16 2009 (r191969)
@@ -0,0 +1,210 @@
+#!/bin/sh
+
+#
+# Copyright (c) 2009 Peter Holm <pho at FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+# Variation of the datamove.sh scenario by not using "sysctl vm.old_msync=1"
+
+# Deadlock seen
+
+# Test scenario by ups
+
+here=`pwd`
+cd /tmp
+sed '1,/^EOF/d' < $here/$0 > dl.c
+cc -o dl -Wall dl.c
+rm -f dl.c
+
+for i in `jot 3`; do
+ $here/../testcases/swap/swap -t 10m -i 200 -h &
+ /tmp/dl
+ ps | grep swap | grep -v swap | awk '{print $1}' | xargs kill
+done
+rm -rf /tmp/dl
+exit 0
+EOF
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+
+int prepareFile(char *filename, int *fdp);
+int mapBuffer (char **bufferp, int fd1, int fd2);
+int startIO (int fd, char *buffer);
+
+int pagesize;
+
+#define FILESIZE (32*1024)
+char wbuffer [FILESIZE];
+
+/* Create a FILESIZE sized file - then remove file data from the cache */
+int
+prepareFile(char *filename, int *fdp)
+{
+ int fd;
+ int len;
+ int status;
+ void *addr;
+
+ fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
+ if (fd == -1) {
+ perror("Creating file");
+ return fd;
+ }
+ len = write(fd, wbuffer, FILESIZE);
+ if (len < 0) {
+ perror("Write failed");
+ return 1;
+ }
+ status = fsync(fd);
+ if (status != 0) {
+ perror("fsync failed");
+ return 1;
+ }
+ addr = mmap(NULL, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (addr == MAP_FAILED) {
+ perror("Mmap failed");
+ return 1;
+ }
+ status = msync(addr, FILESIZE, MS_INVALIDATE | MS_SYNC);
+ if (status != 0) {
+ perror("Msync failed");
+ return 1;
+ }
+ if (munmap(addr, FILESIZE) == -1) {
+ perror("munmap failed");
+ return 1;
+ }
+
+ *fdp = fd;
+ return 0;
+}
+
+
+/* mmap a 2 page buffer - first page is from fd1, second page from fd2 */
+int
+mapBuffer(char **bufferp, int fd1, int fd2)
+{
+ void *addr;
+ char *buffer;
+
+ addr = mmap(NULL, pagesize * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd1, 0);
+ if (addr == MAP_FAILED) {
+ perror("Mmap failed");
+ return 1;
+ }
+ buffer = addr;
+ addr = mmap(buffer + pagesize, pagesize, PROT_READ | PROT_WRITE, MAP_FIXED |
+ MAP_SHARED, fd2, 0);
+
+ if (addr == MAP_FAILED) {
+ perror("Mmap2 failed");
+ return 1;
+ }
+ *bufferp = buffer;
+ return 0;
+}
+
+void
+unmapBuffer(char *bufferp)
+{
+ if (munmap(bufferp, pagesize * 2) == -1)
+ err(1, "unmap 1. buffer");
+ if (munmap(bufferp + pagesize * 2, pagesize * 2) == -1)
+ err(1, "unmap 2. buffer");
+}
+
+int
+startIO(int fd, char *buffer)
+{
+ ssize_t len;
+
+ len = write(fd, buffer, 2 * pagesize);
+ if (len == -1) {
+ perror("write failed");
+ return 1;
+ }
+ return 0;
+}
+
+
+int
+main(int argc, char *argv[], char *envp[])
+{
+
+ int fdA, fdB, fdDelayA, fdDelayB;
+ int status;
+ int i;
+ char *bufferA, *bufferB;
+ pid_t pid;
+
+ pagesize = getpagesize();
+
+ for (i = 0; i < 1000; i++) {
+ if ((prepareFile("A", &fdA))
+ || (prepareFile("B", &fdB))
+ || (prepareFile("DelayA", &fdDelayA))
+ || (prepareFile("DelayB", &fdDelayB))
+ || (mapBuffer(&bufferA, fdDelayA, fdB))
+ || (mapBuffer(&bufferB, fdDelayB, fdA)))
+ exit(1);
+
+ pid = fork();
+
+ if (pid == 0) {
+ status = startIO(fdA, bufferA);
+ exit(status);
+ }
+ if (pid == -1) {
+ perror("fork");
+ exit(1);
+ }
+ status = startIO(fdB, bufferB);
+ if (wait(&status) == -1)
+ err(1, "wait");
+
+ close(fdA);
+ close(fdB);
+ close(fdDelayA);
+ close(fdDelayB);
+ unmapBuffer(bufferA);
+ unmapBuffer(bufferB);
+ unlink("A");
+ unlink("B");
+ unlink("DelayA");
+ unlink("DelayB");
+ }
+ exit(status);
+
+}
Added: projects/stress2/misc/datamove3.sh
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/stress2/misc/datamove3.sh Sun May 10 18:19:16 2009 (r191969)
@@ -0,0 +1,219 @@
+#!/bin/sh
+
+#
+# Copyright (c) 2009 Peter Holm <pho at FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+# Threaded variation of datamove.sh
+
+# Based on a test scenario by ups and suggestions by kib
+
+[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
+
+here=`pwd`
+cd /tmp
+sed '1,/^EOF/d' < $here/$0 > dl.c
+cc -o dl -Wall dl.c -lpthread
+rm -f dl.c
+
+n=5
+old=`sysctl vm.old_msync | awk '{print $NF}'`
+sysctl vm.old_msync=1
+for i in `jot $n`; do
+ mkdir -p /tmp/dl.dir.$i
+ cd /tmp/dl.dir.$i
+ /tmp/dl &
+done
+cd /tmp
+for i in `jot $n`; do
+ wait
+done
+for i in `jot $n`; do
+ rm -rf /tmp/dl.dir.$i
+done
+sysctl vm.old_msync=$old
+
+rm -rf /tmp/dl
+exit 0
+EOF
+#include <err.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+struct args {
+ char *bp;
+ int fd1;
+ int fd2;
+} a[2];
+
+int prepareFile(char *, int *);
+void * mapBuffer(void *);
+int startIO(int, char *);
+
+int pagesize;
+
+#define FILESIZE (32*1024)
+char wbuffer [FILESIZE];
+
+/* Create a FILESIZE sized file - then remove file data from the cache */
+int
+prepareFile(char *filename, int *fdp)
+{
+ int fd;
+ int len;
+ int status;
+ void *addr;
+
+ fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
+ if (fd == -1) {
+ perror("Creating file");
+ return fd;
+ }
+ len = write(fd, wbuffer, FILESIZE);
+ if (len < 0) {
+ perror("Write failed");
+ return 1;
+ }
+ status = fsync(fd);
+ if (status != 0) {
+ perror("fsync failed");
+ return 1;
+ }
+ addr = mmap(NULL, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (addr == MAP_FAILED) {
+ perror("Mmap failed");
+ return 1;
+ }
+ status = msync(addr, FILESIZE, MS_INVALIDATE | MS_SYNC);
+ if (status != 0) {
+ perror("Msync failed");
+ return 1;
+ }
+ munmap(addr, FILESIZE);
+
+ *fdp = fd;
+ return 0;
+}
+
+
+/* mmap a 2 page buffer - first page is from fd1, second page from fd2 */
+void *
+mapBuffer(void *ar)
+{
+ void *addr;
+ char *buffer;
+ int i;
+
+ i = (int )ar;
+ addr = mmap(NULL, pagesize * 2, PROT_READ | PROT_WRITE, MAP_SHARED, a[i].fd1, 0);
+ if (addr == MAP_FAILED) {
+ err(1, "Mmap failed");
+ }
+ buffer = addr;
+ addr = mmap(buffer + pagesize, pagesize, PROT_READ | PROT_WRITE, MAP_FIXED |
+ MAP_SHARED, a[i].fd2, 0);
+
+ if (addr == MAP_FAILED) {
+ err(1, "Mmap2 failed");
+ }
+ a[i].bp = buffer;
+ sleep(1);
+ return (NULL);
+}
+
+
+int
+startIO(int fd, char *buffer)
+{
+ ssize_t len;
+
+ len = write(fd, buffer, 2 * pagesize);
+ if (len == -1) {
+ warn("startIO(%d, %p): write failed", fd, buffer);
+ return 1;
+ }
+ return 0;
+}
+
+
+
+int
+main(int argc, char *argv[], char *envp[])
+{
+
+ int fdA, fdB, fdDelayA, fdDelayB;
+ int r, status;
+ char *bufferA, *bufferB;
+ pid_t pid;
+ pthread_t threads[2];
+
+ pagesize = getpagesize();
+
+ if ((prepareFile("A", &fdA))
+ || (prepareFile("B", &fdB))
+ || (prepareFile("DelayA", &fdDelayA))
+ || (prepareFile("DelayB", &fdDelayB)))
+ exit(1);
+
+ a[0].fd1 = fdDelayA;
+ a[0].fd2 = fdB;
+
+ a[1].fd1 = fdDelayB;
+ a[1].fd2 = fdA;
+
+ if ((r = pthread_create(&threads[0], NULL, mapBuffer, (void *)0)) != 0)
+ err(1, "pthread_create(): %s\n", strerror(r));
+ if ((r = pthread_create(&threads[1], NULL, mapBuffer, (void *)1)) != 0)
+ err(1, "pthread_create(): %s\n", strerror(r));
+
+ while (a[0].bp == NULL || a[1].bp == NULL)
+ pthread_yield();
+
+ bufferA = a[0].bp;
+ bufferB = a[1].bp;
+
+ pid = fork();
+
+ if (pid == 0) {
+ status = startIO(fdA, bufferA);
+ exit(status);
+ }
+ if (pid == -1) {
+ exit(1);
+ }
+ status = startIO(fdB, bufferB);
+ exit(status);
+
+}
More information about the svn-src-projects
mailing list