xref: /freebsd/tools/test/stress2/misc/datamove.sh (revision d9a42747950146bf03cda7f6e25d219253f8a57a)
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
29# There is a well-known problem in FreeBSD, caused by allowing page faults
30# while doing filesystem data move to or from userspace during read(2) and
31# write(2). The issue is that if the userspace address being read or write
32# from/to is backed by the mapping of the same file we are doing i/o to,
33# we deadlock.
34
35# Test scenario by ups
36
37[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
38
39. ../default.cfg
40
41here=`pwd`
42cd /tmp
43sed '1,/^EOF/d' < $here/$0 > datamove.c
44mycc -o datamove -Wall datamove.c
45rm -f datamove.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/datamove.dir.$i
52	cd /tmp/datamove.dir.$i
53	/tmp/datamove &
54done
55cd /tmp
56for i in `jot $n`; do
57	wait
58done
59for i in `jot $n`; do
60	rm -rf /tmp/datamove.dir.$i
61done
62sysctl vm.old_msync=$old
63
64rm -rf /tmp/datamove
65exit 0
66EOF
67/*-
68 * Copyright (c) 2006, Stephan Uphoff <ups@freebsd.org>
69 * All rights reserved.
70 *
71 * Redistribution and use in source and binary forms, with or without
72 * modification, are permitted provided that the following conditions
73 * are met:
74 * 1. Redistributions of source code must retain the above copyright
75 *    notice unmodified, this list of conditions, and the following
76 *    disclaimer.
77 * 2. Redistributions in binary form must reproduce the above copyright
78 *    notice, this list of conditions and the following disclaimer in the
79 *    documentation and/or other materials provided with the distribution.
80 *
81 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
82 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
83 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
84 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
85 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
86 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
87 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
88 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
89 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
90 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
91 */
92
93#include <sys/types.h>
94#include <unistd.h>
95#include <sys/stat.h>
96#include <fcntl.h>
97#include <stdio.h>
98#include <stdlib.h>
99#include <sys/mman.h>
100
101int prepareFile(char* filename,int* fdp);
102int mapBuffer(char** bufferp,int fd1,int fd2);
103int startIO(int fd,char *buffer);
104
105int pagesize;
106
107#define FILESIZE (32*1024)
108char wbuffer[FILESIZE];
109
110/* Create a FILESIZE sized file - then remove file data from the cache*/
111int prepareFile(char* filename,int* fdp)
112{
113  int fd;
114  int len;
115  int status;
116  void *addr;
117
118  fd = open(filename,O_CREAT | O_TRUNC | O_RDWR,S_IRWXU);
119  if (fd == -1)
120    {
121      perror("Creating file");
122      return fd;
123    }
124
125  len = write(fd,wbuffer,FILESIZE);
126  if (len < 0)
127    {
128      perror("Write failed");
129      return 1;
130    }
131
132  status = fsync(fd);
133   if (status != 0)
134    {
135        perror("fsync failed");
136	return 1;
137    }
138
139  addr = mmap(NULL,FILESIZE, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);
140  if (addr == MAP_FAILED)
141    {
142      perror("Mmap failed");
143      return 1;
144    }
145
146  status = msync(addr,FILESIZE,MS_INVALIDATE | MS_SYNC);
147  if (status != 0)
148    {
149        perror("Msync failed");
150	return 1;
151    }
152
153  munmap(addr,FILESIZE);
154
155  *fdp = fd;
156  return 0;
157}
158
159/* mmap a 2 page buffer - first page is from fd1, second page from fd2 */
160int mapBuffer(char** bufferp,int fd1,int fd2)
161{
162  void* addr;
163  char *buffer;
164
165  addr = mmap(NULL,pagesize*2, PROT_READ | PROT_WRITE , MAP_SHARED, fd1, 0);
166  if (addr == MAP_FAILED)
167    {
168      perror("Mmap failed");
169      return 1;
170    }
171
172  buffer = addr;
173  addr = mmap(buffer + pagesize,pagesize, PROT_READ | PROT_WRITE , MAP_FIXED |
174      MAP_SHARED, fd2, 0);
175
176  if (addr == MAP_FAILED)
177    {
178      perror("Mmap2 failed");
179      return 1;
180    }
181  *bufferp = buffer;
182  return 0;
183}
184
185int startIO(int fd,char *buffer)
186{
187  ssize_t len;
188  len = write(fd,buffer,2*pagesize);
189  if (len == -1)
190    {
191      perror("write failed");
192      return 1;
193    }
194  return 0;
195}
196
197int main(void)
198{
199
200  int fdA,fdB,fdDelayA,fdDelayB;
201  int status;
202  char *bufferA,*bufferB;
203  pid_t pid;
204
205  pagesize = getpagesize();
206
207  if ((prepareFile("A",&fdA))
208      || (prepareFile("B",&fdB))
209      || (prepareFile("DelayA",&fdDelayA))
210      || (prepareFile("DelayB",&fdDelayB))
211      || (mapBuffer(&bufferA,fdDelayA,fdB))
212      || (mapBuffer(&bufferB,fdDelayB,fdA)))
213    exit(1);
214
215  pid = fork();
216
217  if (pid == 0)
218    {
219      status = startIO(fdA,bufferA);
220      exit(status);
221    }
222
223  if (pid == -1)
224    {
225      exit(1);
226    }
227  status = startIO(fdB,bufferB);
228  exit(status);
229
230}
231