4 # Copyright (c) 2009 Peter Holm <pho@FreeBSD.org>
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 # There is a well-known problem in FreeBSD, caused by allowing page faults
32 # while doing filesystem data move to or from userspace during read(2) and
33 # write(2). The issue is that if the userspace address being read or write
34 # from/to is backed by the mapping of the same file we are doing i/o to,
37 # Test scenario by ups
39 [ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
43 sed '1,/^EOF/d' < $here/$0 > dl.c
48 old=`sysctl vm.old_msync | awk '{print $NF}'`
51 mkdir -p /tmp/dl.dir.$i
62 sysctl vm.old_msync=$old
67 #include <sys/types.h>
76 int prepareFile(char* filename,int* fdp);
77 int mapBuffer(char** bufferp,int fd1,int fd2);
78 int startIO(int fd,char *buffer);
82 #define FILESIZE (32*1024)
83 char wbuffer[FILESIZE];
85 /* Create a FILESIZE sized file - then remove file data from the cache*/
86 int prepareFile(char* filename,int* fdp)
93 fd = open(filename,O_CREAT | O_TRUNC | O_RDWR,S_IRWXU);
96 perror("Creating file");
100 len = write(fd,wbuffer,FILESIZE);
103 perror("Write failed");
110 perror("fsync failed");
114 addr = mmap(NULL,FILESIZE, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);
115 if (addr == MAP_FAILED)
117 perror("Mmap failed");
121 status = msync(addr,FILESIZE,MS_INVALIDATE | MS_SYNC);
124 perror("Msync failed");
128 munmap(addr,FILESIZE);
135 /* mmap a 2 page buffer - first page is from fd1, second page from fd2 */
136 int mapBuffer(char** bufferp,int fd1,int fd2)
141 addr = mmap(NULL,pagesize*2, PROT_READ | PROT_WRITE , MAP_SHARED, fd1, 0);
142 if (addr == MAP_FAILED)
144 perror("Mmap failed");
149 addr = mmap(buffer + pagesize,pagesize, PROT_READ | PROT_WRITE , MAP_FIXED |
152 if (addr == MAP_FAILED)
154 perror("Mmap2 failed");
162 int startIO(int fd,char *buffer)
165 len = write(fd,buffer,2*pagesize);
168 perror("write failed");
175 int main(int argc,char *argv[],char *envp[])
178 int fdA,fdB,fdDelayA,fdDelayB;
180 char *bufferA,*bufferB;
183 pagesize = getpagesize();
185 if ((prepareFile("A",&fdA))
186 || (prepareFile("B",&fdB))
187 || (prepareFile("DelayA",&fdDelayA))
188 || (prepareFile("DelayB",&fdDelayB))
189 || (mapBuffer(&bufferA,fdDelayA,fdB))
190 || (mapBuffer(&bufferB,fdDelayB,fdA)))
197 status = startIO(fdA,bufferA);
205 status = startIO(fdB,bufferB);