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# Variation of the datamove.sh scenario by not using "sysctl vm.old_msync=1"
32
33# Deadlock seen
34
35# Test scenario by ups
36
37here=`pwd`
38cd /tmp
39sed '1,/^EOF/d' < $here/$0 > dl.c
40cc -o dl -Wall dl.c
41rm -f dl.c
42
43for i in `jot 3`; do
44	$here/../testcases/swap/swap -t 10m -i 200 -h &
45	/tmp/dl
46	ps | grep swap | grep -v swap | awk '{print $1}' | xargs kill
47done
48rm -rf /tmp/dl
49exit 0
50EOF
51#include <err.h>
52#include <fcntl.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <sys/mman.h>
56#include <sys/stat.h>
57#include <sys/types.h>
58#include <sys/wait.h>
59#include <unistd.h>
60
61
62int	prepareFile(char *filename, int *fdp);
63int	mapBuffer  (char **bufferp, int fd1, int fd2);
64int	startIO    (int fd, char *buffer);
65
66int	pagesize;
67
68#define FILESIZE (32*1024)
69char	wbuffer   [FILESIZE];
70
71/* Create a FILESIZE sized file - then remove file data from the cache */
72int
73prepareFile(char *filename, int *fdp)
74{
75	int	fd;
76	int	len;
77	int	status;
78	void	*addr;
79
80	fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
81	if (fd == -1) {
82		perror("Creating file");
83		return fd;
84	}
85	len = write(fd, wbuffer, FILESIZE);
86	if (len < 0) {
87		perror("Write failed");
88		return 1;
89	}
90	status = fsync(fd);
91	if (status != 0) {
92		perror("fsync failed");
93		return 1;
94	}
95	addr = mmap(NULL, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
96	if (addr == MAP_FAILED) {
97		perror("Mmap failed");
98		return 1;
99	}
100	status = msync(addr, FILESIZE, MS_INVALIDATE | MS_SYNC);
101	if (status != 0) {
102		perror("Msync failed");
103		return 1;
104	}
105	if (munmap(addr, FILESIZE) == -1) {
106		perror("munmap failed");
107		return 1;
108	}
109
110	*fdp = fd;
111	return 0;
112}
113
114
115/* mmap a 2 page buffer - first page is from fd1, second page from fd2 */
116int
117mapBuffer(char **bufferp, int fd1, int fd2)
118{
119	void *addr;
120	char *buffer;
121
122	addr = mmap(NULL, pagesize * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd1, 0);
123	if (addr == MAP_FAILED) {
124		perror("Mmap failed");
125		return 1;
126	}
127	buffer = addr;
128	addr = mmap(buffer + pagesize, pagesize, PROT_READ | PROT_WRITE, MAP_FIXED |
129		    MAP_SHARED, fd2, 0);
130
131	if (addr == MAP_FAILED) {
132		perror("Mmap2 failed");
133		return 1;
134	}
135	*bufferp = buffer;
136	return 0;
137}
138
139void
140unmapBuffer(char *bufferp)
141{
142	if (munmap(bufferp, pagesize * 2) == -1)
143		err(1, "unmap 1. buffer");
144	if (munmap(bufferp + pagesize * 2, pagesize * 2) == -1)
145		err(1, "unmap 2. buffer");
146}
147
148int
149startIO(int fd, char *buffer)
150{
151	ssize_t	len;
152
153	len = write(fd, buffer, 2 * pagesize);
154	if (len == -1) {
155		perror("write failed");
156		return 1;
157	}
158	return 0;
159}
160
161
162int
163main(int argc, char *argv[], char *envp[])
164{
165
166	int	fdA, fdB, fdDelayA, fdDelayB;
167	int	status;
168	int	i;
169	char	*bufferA, *bufferB;
170	pid_t	pid;
171
172	pagesize = getpagesize();
173
174	for (i = 0; i < 1000; i++) {
175		if ((prepareFile("A", &fdA))
176		    || (prepareFile("B", &fdB))
177		    || (prepareFile("DelayA", &fdDelayA))
178		    || (prepareFile("DelayB", &fdDelayB))
179		    || (mapBuffer(&bufferA, fdDelayA, fdB))
180		    || (mapBuffer(&bufferB, fdDelayB, fdA)))
181			exit(1);
182
183		pid = fork();
184
185		if (pid == 0) {
186			status = startIO(fdA, bufferA);
187			exit(status);
188		}
189		if (pid == -1) {
190			perror("fork");
191			exit(1);
192		}
193		status = startIO(fdB, bufferB);
194		if (wait(&status) == -1)
195			err(1, "wait");
196
197		close(fdA);
198		close(fdB);
199		close(fdDelayA);
200		close(fdDelayB);
201		unmapBuffer(bufferA);
202		unmapBuffer(bufferB);
203		unlink("A");
204		unlink("B");
205		unlink("DelayA");
206		unlink("DelayB");
207	}
208	exit(status);
209
210}
211