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