xref: /dragonfly/test/stress/stress2/misc/datamove.sh (revision 67640b13)
1#!/bin/sh
2
3#
4# Copyright (c) 2009 Peter Holm <pho@FreeBSD.org>
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
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.
15#
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
26# SUCH DAMAGE.
27#
28# $FreeBSD$
29#
30
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,
35# we deadlock.
36
37# Test scenario by ups
38
39[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
40
41here=`pwd`
42cd /tmp
43sed '1,/^EOF/d' < $here/$0 > dl.c
44cc -o dl -Wall dl.c
45rm -f dl.c
46
47n=5
48old=`sysctl vm.old_msync | awk '{print $NF}'`
49sysctl vm.old_msync=1
50for i in `jot $n`; do
51	mkdir -p /tmp/dl.dir.$i
52	cd /tmp/dl.dir.$i
53	/tmp/dl &
54done
55cd /tmp
56for i in `jot $n`; do
57	wait
58done
59for i in `jot $n`; do
60	rm -rf /tmp/dl.dir.$i
61done
62sysctl vm.old_msync=$old
63
64rm -rf /tmp/dl
65exit 0
66EOF
67#include <sys/types.h>
68#include <unistd.h>
69#include <sys/stat.h>
70#include <fcntl.h>
71#include <stdio.h>
72#include <stdlib.h>
73#include <sys/mman.h>
74
75
76int prepareFile(char* filename,int* fdp);
77int mapBuffer(char** bufferp,int fd1,int fd2);
78int startIO(int fd,char *buffer);
79
80int pagesize;
81
82#define FILESIZE (32*1024)
83char wbuffer[FILESIZE];
84
85/* Create a FILESIZE sized file - then remove file data from the cache*/
86int prepareFile(char* filename,int* fdp)
87{
88  int fd;
89  int len;
90  int status;
91  void *addr;
92
93  fd = open(filename,O_CREAT | O_TRUNC | O_RDWR,S_IRWXU);
94  if (fd == -1)
95    {
96      perror("Creating file");
97      return fd;
98    }
99
100  len = write(fd,wbuffer,FILESIZE);
101  if (len < 0)
102    {
103      perror("Write failed");
104      return 1;
105    }
106
107  status = fsync(fd);
108   if (status != 0)
109    {
110        perror("fsync failed");
111	return 1;
112    }
113
114  addr = mmap(NULL,FILESIZE, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);
115  if (addr == MAP_FAILED)
116    {
117      perror("Mmap failed");
118      return 1;
119    }
120
121  status = msync(addr,FILESIZE,MS_INVALIDATE | MS_SYNC);
122  if (status != 0)
123    {
124        perror("Msync failed");
125	return 1;
126    }
127
128  munmap(addr,FILESIZE);
129
130  *fdp = fd;
131  return 0;
132}
133
134
135/* mmap a 2 page buffer - first page is from fd1, second page from fd2 */
136int mapBuffer(char** bufferp,int fd1,int fd2)
137{
138  void* addr;
139  char *buffer;
140
141  addr = mmap(NULL,pagesize*2, PROT_READ | PROT_WRITE , MAP_SHARED, fd1, 0);
142  if (addr == MAP_FAILED)
143    {
144      perror("Mmap failed");
145      return 1;
146    }
147
148  buffer = addr;
149  addr = mmap(buffer + pagesize,pagesize, PROT_READ | PROT_WRITE , MAP_FIXED |
150MAP_SHARED, fd2, 0);
151
152  if (addr == MAP_FAILED)
153    {
154      perror("Mmap2 failed");
155      return 1;
156    }
157  *bufferp = buffer;
158  return 0;
159}
160
161
162int startIO(int fd,char *buffer)
163{
164  ssize_t len;
165  len = write(fd,buffer,2*pagesize);
166  if (len == -1)
167    {
168      perror("write failed");
169      return 1;
170    }
171  return 0;
172}
173
174
175int main(int argc,char *argv[],char *envp[])
176{
177
178  int fdA,fdB,fdDelayA,fdDelayB;
179  int status;
180  char *bufferA,*bufferB;
181  pid_t pid;
182
183  pagesize = getpagesize();
184
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)))
191    exit(1);
192
193  pid = fork();
194
195  if (pid == 0)
196    {
197      status = startIO(fdA,bufferA);
198      exit(status);
199    }
200
201  if (pid == -1)
202    {
203      exit(1);
204    }
205  status = startIO(fdB,bufferB);
206  exit(status);
207
208}
209