1#!/bin/sh 2 3# 4# Copyright (c) 2018 Dell EMC Isilon 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# Move files between two FSs using sendfile(2). 30# CG checksum errors reported. 31 32# Unrelated gpart page fault seen: 33# https://people.freebsd.org/~pho/stress/log/sendfile13.txt 34# Fixed by r329262 35 36. ../default.cfg 37[ `id -u` -ne 0 ] && echo "Must be root!" && exit 1 38 39dir=/tmp 40odir=`pwd` 41cd $dir 42sed '1,/^EOF/d' < $odir/$0 > $dir/sendfile13.c 43mycc -o sendfile13 -Wall -Wextra -O0 -g sendfile13.c || exit 1 44rm -f sendfile13.c 45cd $odir 46 47set -e 48size="$((`sysctl -n hw.usermem` / 2 / 1024 / 1024 / 1024))" 49size="$((size * 7 / 10))g" 50[ "$size" = "0g" ] && exit 0 51[ "$newfs_flags" = "-U" ] || exit 0 52newfs_flags="-j" 53 54mp1=$mntpoint 55mkdir -p $mp1 56md1=$mdstart 57mount | grep "on $mp1 " | grep -q /dev/md && umount -f $mp1 58[ -c /dev/md$md1 ] && mdconfig -d -u $md1 59mdconfig -a -t swap -s $size -u $md1 60newfs $newfs_flags -n md${md1} > /dev/null 2>&1 61mount /dev/md${md1} $mp1 62 63md2=$((mdstart + 1)) 64mp2=${mntpoint}$md2 65mkdir -p $mp2 66mount | grep "on $mp2 " | grep -q /dev/md && umount -f $mp2 67[ -c /dev/md$md2 ] && mdconfig -d -u $md2 68mdconfig -a -t swap -s $size -u $md2 69newfs $newfs_flags -n md${md2} > /dev/null 2>&1 70mount /dev/md${md2} $mp2 71set +e 72 73free=`df $mp1 | tail -1 | awk '{print $4}'` 74$dir/sendfile13 5432 $mp1 $mp2 $((free / 2)) & 75p1=$! 76$dir/sendfile13 5433 $mp2 $mp1 $((free / 2)) & 77p2=$! 78cd $odir 79s=0 80wait $p1; code=$? 81[ $code -ne 0 ] && { s=$code; echo "$p1 exit status $code"; } 82wait $p2; code=$? 83[ $code -ne 0 ] && { s=$code; echo "$p2 exit status $code"; } 84[ -f sendfile13.core -a $s -eq 0 ] && 85 { ls -l sendfile13.core; mv sendfile13.core /tmp; } 86cd $odir 87 88for i in `jot 6`; do 89 mount | grep -q "on $mp1 " || break 90 umount $mp1 && break || sleep 10 91 [ $i -eq 6 ] && 92 { echo FATAL; fstat -mf $mp1; exit 1; } 93done 94for i in `jot 6`; do 95 mount | grep -q "on $mp2 " || break 96 umount $mp2 && break || sleep 10 97 [ $i -eq 6 ] && 98 { echo FATAL; fstat -mf $mp2; exit 1; } 99done 100checkfs /dev/md${md1} || s=1 101checkfs /dev/md${md2} || s=1 102mdconfig -d -u $md1 || s=1 103mdconfig -d -u $md2 || s=1 104 105for i in `jot 6`; do 106 mount | grep -q "on $mp2 " || break 107 umount $mp2 && break || sleep 10 108 [ $i -eq 6 ] && 109 { echo FATAL; fstat -mf $mp2; exit 1; } 110done 111checkfs /dev/md${md2} || s=1 112 113rm -rf $dir/sendfile13 114exit $s 115 116EOF 117#include <sys/param.h> 118#include <sys/mman.h> 119#include <sys/socket.h> 120#include <sys/stat.h> 121#include <sys/wait.h> 122 123#include <netinet/in.h> 124 125#include <err.h> 126#include <fcntl.h> 127#include <netdb.h> 128#include <signal.h> 129#include <stdio.h> 130#include <stdlib.h> 131#include <string.h> 132#include <time.h> 133#include <unistd.h> 134 135#define BUFSIZE 8192 136#define MAXTHREADS 32 137 138static int files, port; 139static char *fromdir, *todir; 140 141static void 142create(char *path, size_t size) 143{ 144 size_t s; 145 int fd, i, ifd; 146 char *cp, file[128], help[128]; 147 148 i = 0; 149 while (size > 0) { 150 do { 151 s =arc4random() % size + 1; 152 } while (s > 1024 * 1024 * 1024); 153 size -= s; 154 sprintf(file, "%s/f%06d.%06d", path, getpid(), i++); 155 if ((ifd = open("/dev/zero", O_RDONLY)) == -1) 156 err(1, "open(/dev/zero)"); 157 if ((cp = mmap(0, s, PROT_READ, MAP_SHARED, ifd, 0)) == 158 (caddr_t) - 1) 159 err(1, "mmap error for input"); 160 if ((fd = open(file, O_WRONLY | O_CREAT, 0640)) == -1) 161 err(1, "create(%s)", file); 162 if (write(fd, cp, s) != (ssize_t)s) 163 err(1, "write(%s)", file); 164 munmap(cp, s); 165 close(fd); 166 close(ifd); 167 files++; 168 } 169 snprintf(help, sizeof(help), 170 "umount %s 2>&1 | grep -v 'Device busy'", path); 171 system(help); 172#if defined(DEBUG) 173 fprintf(stderr, "%d files created\n", files); 174#endif 175} 176 177static void 178server(void) 179{ 180 pid_t pid; 181 struct sigaction sa; 182 struct sockaddr_in inetaddr, inetpeer; 183 socklen_t len; 184 int tcpsock, msgsock; 185 int *buf, fd, idx, n, on, t __unused; 186 char ofile[128], nfile[128]; 187 188 sa.sa_handler = SIG_IGN; 189 sigemptyset(&sa.sa_mask); 190 sa.sa_flags = 0; 191 if (sigaction(SIGCHLD, &sa, 0) == -1) 192 err(1, "sigaction"); 193 194 on = 1; 195 if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 196 err(1, "socket(), %s:%d", __FILE__, __LINE__); 197 198 if (setsockopt(tcpsock, 199 SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) 200 err(1, "setsockopt(), %s:%d", __FILE__, __LINE__); 201 202 inetaddr.sin_family = AF_INET; 203 inetaddr.sin_addr.s_addr = INADDR_ANY; 204 inetaddr.sin_port = htons(port); 205 inetaddr.sin_len = sizeof(inetaddr); 206 207 if (bind(tcpsock, 208 (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) 209 err(1, "bind(), %s:%d", __FILE__, __LINE__); 210 211 if (listen(tcpsock, 5) < 0) 212 err(1, "listen(), %s:%d", __FILE__, __LINE__); 213 214 idx = 0; 215 len = sizeof(inetpeer); 216 for (;;) { 217 alarm(120); 218 if ((msgsock = accept(tcpsock, 219 (struct sockaddr *)&inetpeer, &len)) < 0) 220 err(1, "accept(), %s:%d", __FILE__, __LINE__); 221 222 if ((pid = fork()) == 0) { 223 alarm(120); 224 t = 0; 225 if ((buf = malloc(BUFSIZE)) == NULL) 226 err(1, "malloc(%d), %s:%d", BUFSIZE, 227 __FILE__, __LINE__); 228 229 sprintf(ofile, "%s/g%06d.%06d", todir, getpid(), 230 idx); 231 sprintf(nfile, "%s/n%06d.%06d", todir, getpid(), 232 idx); 233 if ((fd = open(ofile, O_RDWR | O_CREAT | O_TRUNC, 234 0640)) == -1) 235 err(1, "open(%s)", ofile); 236 237 for (;;) { 238 if ((n = read(msgsock, buf, BUFSIZE)) < 0) 239 err(1, "read(), %s:%d", __FILE__, 240 __LINE__); 241 t += n; 242 if (n == 0) break; 243 244 if ((write(fd, buf, n)) != n) 245 err(1, "write n=%d", n); 246 } 247 close(msgsock); 248 close(fd); 249 if (rename(ofile, nfile) != 0) 250 err(1, "rename(%s, %s)", ofile, nfile); 251 _exit(0); 252 } 253 close(msgsock); 254 if (++idx == files) 255 break; 256 } 257 258 _exit(0); 259} 260 261static void 262writer(char *inputFile) { 263 struct sockaddr_in inetaddr; 264 struct hostent *hostent; 265 struct stat statb; 266 off_t off = 0; 267 size_t size; 268 int i, fd, on, r, tcpsock; 269 270 alarm(120); 271 on = 1; 272 for (i = 1; i < 5; i++) { 273 if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 274 err(1, "socket(), %s:%d", __FILE__, __LINE__); 275 276 if (setsockopt(tcpsock, 277 SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) 278 err(1, "setsockopt(), %s:%d", __FILE__, __LINE__); 279 280 size = getpagesize(); 281 if (setsockopt(tcpsock, 282 SOL_SOCKET, SO_SNDBUF, (void *)&size, sizeof(size)) < 0) 283 err(1, "setsockopt(SO_SNDBUF), %s:%d", __FILE__, 284 __LINE__); 285 286 hostent = gethostbyname ("localhost"); 287 memcpy (&inetaddr.sin_addr.s_addr, hostent->h_addr, 288 sizeof (struct in_addr)); 289 290 inetaddr.sin_family = AF_INET; 291 inetaddr.sin_port = htons(port); 292 inetaddr.sin_len = sizeof(inetaddr); 293 294 r = connect(tcpsock, (struct sockaddr *) &inetaddr, 295 sizeof(inetaddr)); 296 if (r == 0) 297 break; 298 sleep(1); 299 close(tcpsock); 300 } 301 if (r < 0) 302 err(1, "connect(), %s:%d", __FILE__, __LINE__); 303 304 if (stat(inputFile, &statb) != 0) 305 err(1, "stat(%s)", inputFile); 306 307 if ((fd = open(inputFile, O_RDWR)) == -1) 308 err(1, "open(%s)", inputFile); 309 310 if (sendfile(fd, tcpsock, 0, statb.st_size, NULL, &off, 311 SF_NOCACHE) == -1) 312 warn("sendfile()"); 313 close(fd); 314 315 return; 316} 317 318static void 319move(int num) 320{ 321 char ifile[128]; 322 323 sprintf(ifile, "%s/f%06d.%06d", fromdir, getpid(), num); 324 writer(ifile); 325 326 if (unlink(ifile) != 0) 327 err(1, "unlink(%s)", ifile); 328} 329 330int 331main(int argc, char *argv[]) 332{ 333 pid_t spid; 334 size_t size; 335 int i, status; 336 337 if (argc != 5) { 338 fprintf(stderr, 339 "Usage %s <port> <from dir> <to dir> <size in k>", 340 argv[0]); 341 exit(1); 342 } 343 port = atoi(argv[1]); 344 fromdir = argv[2]; 345 if (chdir(fromdir) == -1) 346 err(1, "chdir(%s)", fromdir); 347 todir = argv[3]; 348 sscanf(argv[4], "%zd", &size); 349 size = size * 1024; 350 create(fromdir, size); 351 352 if ((spid = fork()) == 0) 353 server(); 354 355 for (i = 0; i < files; i++) { 356 move(i); 357 sleep(10); 358 } 359 if (waitpid(spid, &status, 0) != spid) 360 err(1, "waitpid"); 361 if (status != 0) { 362 if (WIFSIGNALED(status)) 363 fprintf(stderr, 364 "pid %d exit signal %d\n", 365 spid, WTERMSIG(status)); 366 } 367 368 return (status == 0 ? 0 : 1); 369} 370