xref: /freebsd/tools/test/stress2/misc/mmap47.sh (revision 94a294e59d1772f316fef613b83e92f37294954c)
1*94a294e5SPeter Holm#!/bin/sh
2*94a294e5SPeter Holm
3*94a294e5SPeter Holm#
4*94a294e5SPeter Holm# Copyright (c) 2024 Peter Holm <pho@FreeBSD.org>
5*94a294e5SPeter Holm#
6*94a294e5SPeter Holm# SPDX-License-Identifier: BSD-2-Clause
7*94a294e5SPeter Holm#
8*94a294e5SPeter Holm
9*94a294e5SPeter Holm# Demonstrate issue described in:
10*94a294e5SPeter Holm# [Bug 276002] nfscl: data corruption using both copy_file_range and mmap'd I/O
11*94a294e5SPeter Holm
12*94a294e5SPeter Holm# This version only uses mapped read/write, read(2)/write(2) and ftruncate(2)
13*94a294e5SPeter Holm
14*94a294e5SPeter Holm# Issue seen:
15*94a294e5SPeter Holm
16*94a294e5SPeter Holm# 19:50:53 Start test of mmap47.sh
17*94a294e5SPeter Holm# 19:51:56, elapsed 0 days, 00:01.03
18*94a294e5SPeter Holm# 19:53:01, elapsed 0 days, 00:02.08
19*94a294e5SPeter Holm# 19:54:06, elapsed 0 days, 00:03.13
20*94a294e5SPeter Holm# 19:55:40, elapsed 0 days, 00:04.47
21*94a294e5SPeter Holm# 617c617
22*94a294e5SPeter Holm# < 0023200    80  81  82  83  84  85  86  87  88  89  8a  8b  8c  8d  8e  8f
23*94a294e5SPeter Holm# ---
24*94a294e5SPeter Holm# > 0023200    80  81  82  83  84  85  86  87  88  89  8a  8b  8c  8d  8e  ee
25*94a294e5SPeter Holm# 256 -rw-------  1 root wheel 262144 Mar  1 19:56 file
26*94a294e5SPeter Holm# 256 -rw-------  1 root wheel 262144 Mar  1 19:55 file.orig
27*94a294e5SPeter Holm# 19:56:44, elapsed 0 days, 00:05.51
28*94a294e5SPeter Holm# Failed with exit code 2 after 5 loops of mmap47.sh.
29*94a294e5SPeter Holm# 19:56 /usr/src/tools/test/stress2/misc $
30*94a294e5SPeter Holm
31*94a294e5SPeter Holm[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
32*94a294e5SPeter Holm. ../default.cfg
33*94a294e5SPeter Holmset -u
34*94a294e5SPeter Holmprog=$(basename "$0" .sh)
35*94a294e5SPeter Holmlog=/tmp/$prog.log
36*94a294e5SPeter Holmserial=/tmp/$prog.serial
37*94a294e5SPeter Holmgrep -q $mntpoint /etc/exports ||
38*94a294e5SPeter Holm    { echo "$mntpoint missing from /etc/exports"; exit 0; }
39*94a294e5SPeter Holmrpcinfo 2>/dev/null | grep -q mountd || exit 0
40*94a294e5SPeter Holm
41*94a294e5SPeter Holmcat > /tmp/$prog.c <<EOF
42*94a294e5SPeter Holm#include <sys/mman.h>
43*94a294e5SPeter Holm#include <sys/stat.h>
44*94a294e5SPeter Holm
45*94a294e5SPeter Holm#include <err.h>
46*94a294e5SPeter Holm#include <fcntl.h>
47*94a294e5SPeter Holm#include <pthread.h>
48*94a294e5SPeter Holm#include <stdio.h>
49*94a294e5SPeter Holm#include <stdlib.h>
50*94a294e5SPeter Holm#include <string.h>
51*94a294e5SPeter Holm#include <unistd.h>
52*94a294e5SPeter Holm
53*94a294e5SPeter Holmstatic off_t siz;
54*94a294e5SPeter Holmstatic pthread_mutex_t write_mutex;
55*94a294e5SPeter Holmstatic int fd, go;
56*94a294e5SPeter Holmstatic char *cp;
57*94a294e5SPeter Holm
58*94a294e5SPeter Holmstatic void *
59*94a294e5SPeter Holmmemread(void *arg __unused)
60*94a294e5SPeter Holm{
61*94a294e5SPeter Holm	int i;
62*94a294e5SPeter Holm	char c;
63*94a294e5SPeter Holm
64*94a294e5SPeter Holm	while (go == -1)
65*94a294e5SPeter Holm		usleep(50);
66*94a294e5SPeter Holm	while (go == 1) {
67*94a294e5SPeter Holm		i = arc4random() % siz;
68*94a294e5SPeter Holm		c = cp[i];
69*94a294e5SPeter Holm		if (c != 0x77) /* No unused vars here */
70*94a294e5SPeter Holm			usleep(arc4random() % 200);
71*94a294e5SPeter Holm	}
72*94a294e5SPeter Holm	return (0);
73*94a294e5SPeter Holm}
74*94a294e5SPeter Holm
75*94a294e5SPeter Holmstatic void *
76*94a294e5SPeter Holmmemwrite(void *arg __unused)
77*94a294e5SPeter Holm{
78*94a294e5SPeter Holm	int i;
79*94a294e5SPeter Holm	char c;
80*94a294e5SPeter Holm
81*94a294e5SPeter Holm	while (go == -1)
82*94a294e5SPeter Holm		usleep(50);
83*94a294e5SPeter Holm	while (go == 1) {
84*94a294e5SPeter Holm		i = arc4random() % siz;
85*94a294e5SPeter Holm		pthread_mutex_lock(&write_mutex);
86*94a294e5SPeter Holm		c = cp[i];
87*94a294e5SPeter Holm		cp[i] = 0xee;	/* This value seems to linger with NFS */
88*94a294e5SPeter Holm		cp[i] = c;
89*94a294e5SPeter Holm		pthread_mutex_unlock(&write_mutex);
90*94a294e5SPeter Holm		usleep(arc4random() % 200);
91*94a294e5SPeter Holm	}
92*94a294e5SPeter Holm	return (0);
93*94a294e5SPeter Holm}
94*94a294e5SPeter Holm
95*94a294e5SPeter Holmstatic void *
96*94a294e5SPeter Holmwr(void *arg __unused)
97*94a294e5SPeter Holm{
98*94a294e5SPeter Holm	off_t pos;
99*94a294e5SPeter Holm	int r, s;
100*94a294e5SPeter Holm	char buf[1024];
101*94a294e5SPeter Holm
102*94a294e5SPeter Holm	while (go == -1)
103*94a294e5SPeter Holm		usleep(50);
104*94a294e5SPeter Holm	while (go == 1) {
105*94a294e5SPeter Holm		s = arc4random() % sizeof(buf) + 1;
106*94a294e5SPeter Holm		pos = arc4random() % (siz - s);
107*94a294e5SPeter Holm		pthread_mutex_lock(&write_mutex);
108*94a294e5SPeter Holm		if (lseek(fd, pos, SEEK_SET) == -1)
109*94a294e5SPeter Holm			err(1, "lseek(%d)", (int)pos);
110*94a294e5SPeter Holm		if ((r = read(fd, buf, s)) != s) {
111*94a294e5SPeter Holm			fprintf(stderr, "r = %d, s = %d, pos = %d\n", r, s, (int)pos);
112*94a294e5SPeter Holm			err(1, "read():2");
113*94a294e5SPeter Holm		}
114*94a294e5SPeter Holm		if (lseek(fd, pos, SEEK_SET) == -1)
115*94a294e5SPeter Holm			err(1, "lseek(%d)", (int)pos);
116*94a294e5SPeter Holm		if (write(fd, buf, s) != s)
117*94a294e5SPeter Holm			err(1, "write()");
118*94a294e5SPeter Holm		pthread_mutex_unlock(&write_mutex);
119*94a294e5SPeter Holm		usleep(arc4random() % 200);
120*94a294e5SPeter Holm	}
121*94a294e5SPeter Holm	return (0);
122*94a294e5SPeter Holm}
123*94a294e5SPeter Holm
124*94a294e5SPeter Holm/* Both ftruncate() and fdatasync() triggers the problem */
125*94a294e5SPeter Holm
126*94a294e5SPeter Holmstatic void *
127*94a294e5SPeter Holmtr(void *arg __unused)
128*94a294e5SPeter Holm{
129*94a294e5SPeter Holm	while (go == -1)
130*94a294e5SPeter Holm		usleep(50);
131*94a294e5SPeter Holm	while (go == 1) {
132*94a294e5SPeter Holm#if 0
133*94a294e5SPeter Holm		if (ftruncate(fd, siz) == -1) /* No size change */
134*94a294e5SPeter Holm			err(1, "truncate)");
135*94a294e5SPeter Holm#else
136*94a294e5SPeter Holm		if (fdatasync(fd) == -1)
137*94a294e5SPeter Holm			err(1, "fdatasync()");
138*94a294e5SPeter Holm#endif
139*94a294e5SPeter Holm		usleep(arc4random() % 1000);
140*94a294e5SPeter Holm	}
141*94a294e5SPeter Holm	return (0);
142*94a294e5SPeter Holm}
143*94a294e5SPeter Holm
144*94a294e5SPeter Holmint
145*94a294e5SPeter Holmmain(int argc, char *argv[])
146*94a294e5SPeter Holm{
147*94a294e5SPeter Holm	struct stat st;
148*94a294e5SPeter Holm	pthread_t tp[31];
149*94a294e5SPeter Holm	int e, i, idx;
150*94a294e5SPeter Holm
151*94a294e5SPeter Holm	if (argc != 2) {
152*94a294e5SPeter Holm		fprintf(stderr, "Usage: %s <file>\n", argv[0]);
153*94a294e5SPeter Holm		exit(1);
154*94a294e5SPeter Holm	}
155*94a294e5SPeter Holm	if ((fd = open(argv[1], O_RDWR)) == -1)
156*94a294e5SPeter Holm		err(1, "open(%s)", argv[1]);
157*94a294e5SPeter Holm	if (fstat(fd, &st) == -1)
158*94a294e5SPeter Holm		err(1, "stat(%s)", argv[1]);
159*94a294e5SPeter Holm	siz = st.st_size;
160*94a294e5SPeter Holm	cp = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
161*94a294e5SPeter Holm	if (cp == MAP_FAILED)
162*94a294e5SPeter Holm		err(1, "mmap()");
163*94a294e5SPeter Holm
164*94a294e5SPeter Holm	go = -1;
165*94a294e5SPeter Holm	pthread_mutex_init(&write_mutex, NULL);
166*94a294e5SPeter Holm	idx = 0;
167*94a294e5SPeter Holm	for (i = 0; i < (int)(arc4random() % 10 + 1); i++) {
168*94a294e5SPeter Holm		if ((e = pthread_create(&tp[idx++], NULL, memread, NULL)) != 0)
169*94a294e5SPeter Holm			errc(1, e, "pthread_create");
170*94a294e5SPeter Holm	}
171*94a294e5SPeter Holm	for (i = 0; i < (int)(arc4random() % 10 + 1); i++) {
172*94a294e5SPeter Holm		if ((e = pthread_create(&tp[idx++], NULL, memwrite, NULL)) != 0)
173*94a294e5SPeter Holm			errc(1, e, "pthread_create");
174*94a294e5SPeter Holm	}
175*94a294e5SPeter Holm	for (i = 0; i < (int)(arc4random() % 10 + 1); i++) {
176*94a294e5SPeter Holm		if ((e = pthread_create(&tp[idx++], NULL, wr, NULL)) != 0)
177*94a294e5SPeter Holm			errc(1, e, "pthread_create");
178*94a294e5SPeter Holm	}
179*94a294e5SPeter Holm	if ((e = pthread_create(&tp[idx++], NULL, tr, NULL)) != 0)
180*94a294e5SPeter Holm		errc(1, e, "pthread_create");
181*94a294e5SPeter Holm
182*94a294e5SPeter Holm	sleep(1);
183*94a294e5SPeter Holm	go = 1;
184*94a294e5SPeter Holm	sleep(60);
185*94a294e5SPeter Holm	go = 0;
186*94a294e5SPeter Holm	for (i = 0; i < idx; i++)
187*94a294e5SPeter Holm		pthread_join(tp[i], NULL);
188*94a294e5SPeter Holm	if (munmap(cp, siz) == -1)
189*94a294e5SPeter Holm		err(1, "munmap()");
190*94a294e5SPeter Holm	close(fd);
191*94a294e5SPeter Holm}
192*94a294e5SPeter HolmEOF
193*94a294e5SPeter Holmmycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c -lpthread || exit 1
194*94a294e5SPeter Holm
195*94a294e5SPeter Holmmycc -o $serial -Wall -Wextra -O2 ../tools/serial.c || exit 1
196*94a294e5SPeter Holmmount | grep -q "on $mntpoint " && umount -f $mntpoint
197*94a294e5SPeter Holmmdconfig -l | grep -q md$mdstart && mdconfig -d -u $mdstart
198*94a294e5SPeter Holmmdconfig -s 5g -u $mdstart
199*94a294e5SPeter Holmnewfs -n $newfs_flags /dev/md$mdstart > /dev/null
200*94a294e5SPeter Holmmount /dev/md$mdstart $mntpoint
201*94a294e5SPeter Holm
202*94a294e5SPeter Holmmp2=${mntpoint}2
203*94a294e5SPeter Holmmkdir -p $mp2
204*94a294e5SPeter Holmmount | grep -q "on $mp2 " && umount -f $mp2
205*94a294e5SPeter Holmmount -t nfs -o retrycnt=3 127.0.0.1:$mntpoint $mp2 || exit 1
206*94a294e5SPeter Holmsleep .2
207*94a294e5SPeter Holm
208*94a294e5SPeter Holmhere=`pwd`
209*94a294e5SPeter Holmcd $mp2
210*94a294e5SPeter Holm$here/../testcases/swap/swap -t 5m -i 20 > /dev/null &
211*94a294e5SPeter Holmsleep 2
212*94a294e5SPeter Holm
213*94a294e5SPeter Holmsize=262144
214*94a294e5SPeter Holm$serial file $size
215*94a294e5SPeter Holmcp file file.orig
216*94a294e5SPeter Holm
217*94a294e5SPeter Holms=0
218*94a294e5SPeter Holm/tmp/$prog file || s=1
219*94a294e5SPeter Holm
220*94a294e5SPeter Holmwhile pgrep -q swap; do pkill swap; done
221*94a294e5SPeter Holmwait
222*94a294e5SPeter Holmif ! cmp -s file.orig file; then
223*94a294e5SPeter Holm	od -t x1 file.orig > /var/tmp/$prog.file1
224*94a294e5SPeter Holm	od -t x1 file      > /var/tmp/$prog.file2
225*94a294e5SPeter Holm	diff /var/tmp/$prog.file1 /var/tmp/$prog.file2 > $log
226*94a294e5SPeter Holm	head -20 $log
227*94a294e5SPeter Holm	rm /var/tmp/$prog.file1 /var/tmp/$prog.file2
228*94a294e5SPeter Holm	ls -ls file.orig file
229*94a294e5SPeter Holm	s=2
230*94a294e5SPeter Holmfi
231*94a294e5SPeter Holm
232*94a294e5SPeter Holmcd $here
233*94a294e5SPeter Holmumount $mp2
234*94a294e5SPeter Holmumount $mntpoint
235*94a294e5SPeter Holmmdconfig -d -u $mdstart
236*94a294e5SPeter Holmrm -f $serial /tmp/$prog /tmp/$prog.c $log
237*94a294e5SPeter Holmexit $s
238