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