1*1ec33855SPeter Holm#!/bin/sh 2*1ec33855SPeter Holm 3*1ec33855SPeter Holm# 4*1ec33855SPeter Holm# SPDX-License-Identifier: BSD-2-Clause 5*1ec33855SPeter Holm# 6*1ec33855SPeter Holm# Copyright (c) 2024 Peter Holm <pho@FreeBSD.org> 7*1ec33855SPeter Holm# 8*1ec33855SPeter Holm# Redistribution and use in source and binary forms, with or without 9*1ec33855SPeter Holm# modification, are permitted provided that the following conditions 10*1ec33855SPeter Holm# are met: 11*1ec33855SPeter Holm# 1. Redistributions of source code must retain the above copyright 12*1ec33855SPeter Holm# notice, this list of conditions and the following disclaimer. 13*1ec33855SPeter Holm# 2. Redistributions in binary form must reproduce the above copyright 14*1ec33855SPeter Holm# notice, this list of conditions and the following disclaimer in the 15*1ec33855SPeter Holm# documentation and/or other materials provided with the distribution. 16*1ec33855SPeter Holm# 17*1ec33855SPeter Holm# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*1ec33855SPeter Holm# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*1ec33855SPeter Holm# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*1ec33855SPeter Holm# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*1ec33855SPeter Holm# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*1ec33855SPeter Holm# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*1ec33855SPeter Holm# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*1ec33855SPeter Holm# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*1ec33855SPeter Holm# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*1ec33855SPeter Holm# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*1ec33855SPeter Holm# SUCH DAMAGE. 28*1ec33855SPeter Holm# 29*1ec33855SPeter Holm 30*1ec33855SPeter Holm# Demonstrate issue described in: 31*1ec33855SPeter Holm# [Bug 276002] nfscl: data corruption using both copy_file_range and mmap'd I/O 32*1ec33855SPeter Holm 33*1ec33855SPeter Holm[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 34*1ec33855SPeter Holm. ../default.cfg 35*1ec33855SPeter Holmset -u 36*1ec33855SPeter Holmprog=$(basename "$0" .sh) 37*1ec33855SPeter Holmlog=/tmp/$prog.log 38*1ec33855SPeter Holmgrep -q $mntpoint /etc/exports || 39*1ec33855SPeter Holm { echo "$mntpoint missing from /etc/exports"; exit 0; } 40*1ec33855SPeter Holm 41*1ec33855SPeter Holmcat > /tmp/$prog.c <<EOF 42*1ec33855SPeter Holm#include <sys/mman.h> 43*1ec33855SPeter Holm#include <sys/stat.h> 44*1ec33855SPeter Holm 45*1ec33855SPeter Holm#include <err.h> 46*1ec33855SPeter Holm#include <fcntl.h> 47*1ec33855SPeter Holm#include <pthread.h> 48*1ec33855SPeter Holm#include <stdio.h> 49*1ec33855SPeter Holm#include <stdlib.h> 50*1ec33855SPeter Holm#include <string.h> 51*1ec33855SPeter Holm#include <unistd.h> 52*1ec33855SPeter Holm 53*1ec33855SPeter Holmstatic off_t siz; 54*1ec33855SPeter Holmstatic pthread_mutex_t write_mutex; 55*1ec33855SPeter Holmstatic int fd, go; 56*1ec33855SPeter Holmstatic char *cp; 57*1ec33855SPeter Holm 58*1ec33855SPeter Holmstatic void * 59*1ec33855SPeter Holmmemread(void *arg __unused) 60*1ec33855SPeter Holm{ 61*1ec33855SPeter Holm int i; 62*1ec33855SPeter Holm char c; 63*1ec33855SPeter Holm 64*1ec33855SPeter Holm while (go == 1) { 65*1ec33855SPeter Holm i = arc4random() % siz; 66*1ec33855SPeter Holm c = cp[i]; 67*1ec33855SPeter Holm if (c != 0x77) /* No unused vars here */ 68*1ec33855SPeter Holm usleep(arc4random() % 400); 69*1ec33855SPeter Holm } 70*1ec33855SPeter Holm return (0); 71*1ec33855SPeter Holm} 72*1ec33855SPeter Holm 73*1ec33855SPeter Holmstatic void * 74*1ec33855SPeter Holmmemwrite(void *arg __unused) 75*1ec33855SPeter Holm{ 76*1ec33855SPeter Holm int i; 77*1ec33855SPeter Holm char c; 78*1ec33855SPeter Holm 79*1ec33855SPeter Holm while (go == 1) { 80*1ec33855SPeter Holm i = arc4random() % siz; 81*1ec33855SPeter Holm pthread_mutex_lock(&write_mutex); 82*1ec33855SPeter Holm c = cp[i]; 83*1ec33855SPeter Holm cp[i] = 0xee; /* This value seems to linger with NFS */ 84*1ec33855SPeter Holm cp[i] = c; 85*1ec33855SPeter Holm pthread_mutex_unlock(&write_mutex); 86*1ec33855SPeter Holm usleep(arc4random() % 400); 87*1ec33855SPeter Holm } 88*1ec33855SPeter Holm return (0); 89*1ec33855SPeter Holm} 90*1ec33855SPeter Holm 91*1ec33855SPeter Holmstatic void * 92*1ec33855SPeter Holmwr(void *arg __unused) 93*1ec33855SPeter Holm{ 94*1ec33855SPeter Holm off_t pos; 95*1ec33855SPeter Holm int r, s; 96*1ec33855SPeter Holm char buf[1024]; 97*1ec33855SPeter Holm 98*1ec33855SPeter Holm while (go == 1) { 99*1ec33855SPeter Holm s = arc4random() % sizeof(buf) + 1; 100*1ec33855SPeter Holm pos = arc4random() % (siz - s); 101*1ec33855SPeter Holm pthread_mutex_lock(&write_mutex); 102*1ec33855SPeter Holm if (lseek(fd, pos, SEEK_SET) == -1) 103*1ec33855SPeter Holm err(1, "lseek(%d)", (int)pos); 104*1ec33855SPeter Holm if ((r = read(fd, buf, s)) != s) { 105*1ec33855SPeter Holm fprintf(stderr, "r = %d, s = %d, pos = %d\n", r, s, (int)pos); 106*1ec33855SPeter Holm err(1, "read():2"); 107*1ec33855SPeter Holm } 108*1ec33855SPeter Holm if (lseek(fd, pos, SEEK_SET) == -1) 109*1ec33855SPeter Holm err(1, "lseek(%d)", (int)pos); 110*1ec33855SPeter Holm if (write(fd, buf, s) != s) 111*1ec33855SPeter Holm err(1, "write()"); 112*1ec33855SPeter Holm pthread_mutex_unlock(&write_mutex); 113*1ec33855SPeter Holm usleep(arc4random() % 400); 114*1ec33855SPeter Holm } 115*1ec33855SPeter Holm return (0); 116*1ec33855SPeter Holm} 117*1ec33855SPeter Holm 118*1ec33855SPeter Holmstatic void * 119*1ec33855SPeter Holms1(void *arg __unused) 120*1ec33855SPeter Holm{ 121*1ec33855SPeter Holm 122*1ec33855SPeter Holm while (go == 1) { 123*1ec33855SPeter Holm if (fdatasync(fd) == -1) 124*1ec33855SPeter Holm err(1, "fdatasync()"); 125*1ec33855SPeter Holm usleep(arc4random() % 1000); 126*1ec33855SPeter Holm } 127*1ec33855SPeter Holm return (0); 128*1ec33855SPeter Holm} 129*1ec33855SPeter Holm 130*1ec33855SPeter Holmstatic void * 131*1ec33855SPeter Holms2(void *arg __unused) 132*1ec33855SPeter Holm{ 133*1ec33855SPeter Holm 134*1ec33855SPeter Holm while (go == 1) { 135*1ec33855SPeter Holm if (fsync(fd) == -1) 136*1ec33855SPeter Holm err(1, "fdatasync()"); 137*1ec33855SPeter Holm usleep(arc4random() % 1000); 138*1ec33855SPeter Holm } 139*1ec33855SPeter Holm return (0); 140*1ec33855SPeter Holm} 141*1ec33855SPeter Holm 142*1ec33855SPeter Holmstatic void * 143*1ec33855SPeter Holmtr(void *arg __unused) 144*1ec33855SPeter Holm{ 145*1ec33855SPeter Holm int i, s; 146*1ec33855SPeter Holm char buf[1024]; 147*1ec33855SPeter Holm 148*1ec33855SPeter Holm memset(buf, 0x5a, sizeof(buf)); 149*1ec33855SPeter Holm while (go == 1) { 150*1ec33855SPeter Holm pthread_mutex_lock(&write_mutex); 151*1ec33855SPeter Holm if (lseek(fd, arc4random() % siz, SEEK_END) == -1) 152*1ec33855SPeter Holm err(1, "lseek() END"); 153*1ec33855SPeter Holm s = sizeof(buf); 154*1ec33855SPeter Holm for (i = 0; i < 50; i++) { 155*1ec33855SPeter Holm if (write(fd, buf, s) != s) 156*1ec33855SPeter Holm warn("write()"); 157*1ec33855SPeter Holm } 158*1ec33855SPeter Holm if (ftruncate(fd, siz) == -1) 159*1ec33855SPeter Holm err(1, "truncate()"); 160*1ec33855SPeter Holm pthread_mutex_unlock(&write_mutex); 161*1ec33855SPeter Holm usleep(arc4random() % 400); 162*1ec33855SPeter Holm } 163*1ec33855SPeter Holm return (0); 164*1ec33855SPeter Holm} 165*1ec33855SPeter Holm 166*1ec33855SPeter Holmint 167*1ec33855SPeter Holmmain(int argc, char *argv[]) 168*1ec33855SPeter Holm{ 169*1ec33855SPeter Holm struct stat st; 170*1ec33855SPeter Holm pthread_t tp[6]; 171*1ec33855SPeter Holm int e, i; 172*1ec33855SPeter Holm 173*1ec33855SPeter Holm if (argc != 2) { 174*1ec33855SPeter Holm fprintf(stderr, "Usage: %s <file>\n", argv[0]); 175*1ec33855SPeter Holm exit(1); 176*1ec33855SPeter Holm } 177*1ec33855SPeter Holm if ((fd = open(argv[1], O_RDWR)) == -1) 178*1ec33855SPeter Holm err(1, "open(%s)", argv[1]); 179*1ec33855SPeter Holm if (fstat(fd, &st) == -1) 180*1ec33855SPeter Holm err(1, "stat(%s)", argv[1]); 181*1ec33855SPeter Holm siz = st.st_size; 182*1ec33855SPeter Holm cp = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 183*1ec33855SPeter Holm if (cp == MAP_FAILED) 184*1ec33855SPeter Holm err(1, "mmap()"); 185*1ec33855SPeter Holm 186*1ec33855SPeter Holm go = 1; 187*1ec33855SPeter Holm pthread_mutex_init(&write_mutex, NULL); 188*1ec33855SPeter Holm if ((e = pthread_create(&tp[0], NULL, memwrite, NULL)) != 0) 189*1ec33855SPeter Holm errc(1, e, "pthread_create"); 190*1ec33855SPeter Holm if ((e = pthread_create(&tp[1], NULL, memread, NULL)) != 0) 191*1ec33855SPeter Holm errc(1, e, "pthread_create"); 192*1ec33855SPeter Holm if ((e = pthread_create(&tp[2], NULL, wr, NULL)) != 0) 193*1ec33855SPeter Holm errc(1, e, "pthread_create"); 194*1ec33855SPeter Holm if ((e = pthread_create(&tp[3], NULL, s1, NULL)) != 0) 195*1ec33855SPeter Holm errc(1, e, "pthread_create"); 196*1ec33855SPeter Holm if ((e = pthread_create(&tp[4], NULL, s2, NULL)) != 0) 197*1ec33855SPeter Holm errc(1, e, "pthread_create"); 198*1ec33855SPeter Holm if ((e = pthread_create(&tp[5], NULL, tr, NULL)) != 0) 199*1ec33855SPeter Holm errc(1, e, "pthread_create"); 200*1ec33855SPeter Holm 201*1ec33855SPeter Holm sleep(60); 202*1ec33855SPeter Holm go = 0; 203*1ec33855SPeter Holm for (i = 0; i < (int)(sizeof(tp) / sizeof(tp[0])); i++) 204*1ec33855SPeter Holm pthread_join(tp[i], NULL); 205*1ec33855SPeter Holm if (munmap(cp, siz) == -1) 206*1ec33855SPeter Holm err(1, "munmap()"); 207*1ec33855SPeter Holm close(fd); 208*1ec33855SPeter Holm} 209*1ec33855SPeter HolmEOF 210*1ec33855SPeter Holmmycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c -lpthread || exit 1 211*1ec33855SPeter Holm 212*1ec33855SPeter Holmmycc -o /tmp/serial -Wall -Wextra -O2 ../tools/serial.c || exit 1 213*1ec33855SPeter Holmmount | grep -q "on $mntpoint " && umount -f $mntpoint 214*1ec33855SPeter Holmmdconfig -l | grep -q md$mdstart && mdconfig -d -u $mdstart 215*1ec33855SPeter Holmmdconfig -s 5g -u $mdstart 216*1ec33855SPeter Holmnewfs -n $newfs_flags /dev/md$mdstart > /dev/null 217*1ec33855SPeter Holmmount /dev/md$mdstart $mntpoint 218*1ec33855SPeter Holm 219*1ec33855SPeter Holmmp2=${mntpoint}2 220*1ec33855SPeter Holmmkdir -p $mp2 221*1ec33855SPeter Holmmount | grep -q "on $mp2 " && umount -f $mp2 222*1ec33855SPeter Holmmount -t nfs 127.0.0.1:$mntpoint $mp2; s=$? 223*1ec33855SPeter Holmsleep .2 224*1ec33855SPeter Holm 225*1ec33855SPeter Holmhere=`pwd` 226*1ec33855SPeter Holmmount | grep $mntpoint 227*1ec33855SPeter Holmcd $mp2 228*1ec33855SPeter Holm$here/../testcases/swap/swap -t 5m -i 20 > /dev/null & 229*1ec33855SPeter Holmsleep 2 230*1ec33855SPeter Holm 231*1ec33855SPeter Holmsize=262144 232*1ec33855SPeter Holm/tmp/serial file $size 233*1ec33855SPeter Holmcp file file.orig 234*1ec33855SPeter Holm 235*1ec33855SPeter Holms=0 236*1ec33855SPeter Holm/tmp/$prog file || s=1 237*1ec33855SPeter Holm 238*1ec33855SPeter Holmwhile pgrep -q swap; do pkill swap; done 239*1ec33855SPeter Holmwait 240*1ec33855SPeter Holmif ! cmp -s file.orig file; then 241*1ec33855SPeter Holm od -t x1 file.orig > /var/tmp/$prog.file1 242*1ec33855SPeter Holm od -t x1 file > /var/tmp/$prog.file2 243*1ec33855SPeter Holm diff /var/tmp/$prog.file1 /var/tmp/$prog.file2 > $log 244*1ec33855SPeter Holm head -20 $log 245*1ec33855SPeter Holm rm /var/tmp/$prog.file1 /var/tmp/$prog.file2 246*1ec33855SPeter Holm ls -ls file.orig file 247*1ec33855SPeter Holm s=2 248*1ec33855SPeter Holmfi 249*1ec33855SPeter Holm 250*1ec33855SPeter Holmcd $here 251*1ec33855SPeter Holmumount $mp2 252*1ec33855SPeter Holmumount $mntpoint 253*1ec33855SPeter Holmmdconfig -d -u $mdstart 254*1ec33855SPeter Holmrm -f /tmp/serial /tmp/$prog /tmp/$prog.c $log 255*1ec33855SPeter Holmexit $s 256