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