xref: /freebsd/tools/test/stress2/misc/mountu.sh (revision f126890a)
1#!/bin/sh
2
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6# Copyright (c) 2012 Peter Holm <pho@FreeBSD.org>
7# Copyright (c) 2019 Dell EMC Isilon
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions
11# are met:
12# 1. Redistributions of source code must retain the above copyright
13#    notice, this list of conditions and the following disclaimer.
14# 2. Redistributions in binary form must reproduce the above copyright
15#    notice, this list of conditions and the following disclaimer in the
16#    documentation and/or other materials provided with the distribution.
17#
18# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28# SUCH DAMAGE.
29#
30
31# Change mount point from rw to ro with a file mapped rw
32# Currently fails for NFS
33
34# Page fault seen:
35# https://people.freebsd.org/~pho/stress/log/mountu.txt
36# Fixed by: r285039.
37
38[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
39
40. ../default.cfg
41
42here=`pwd`
43cd /tmp
44sed '1,/^EOF/d' < $here/$0 > mountu.c
45mycc -o mountu -Wall -Wextra -O2 mountu.c || exit 1
46rm -f mountu.c
47
48pstat() {
49	local pid
50	pid=`ps ax | grep -v grep | grep /tmp/mountu | awk '{print $1}'`
51	[ -n "$pid" ] && procstat -v $pid
52}
53
54ck() {
55	if mount | grep $mntpoint | grep -q "read-only"; then
56		if pstat $!| awk "\$2 == \"$map\"" | grep -q " rw-"; then
57			echo
58			echo "$1 difference"
59			mount | grep $mntpoint
60			printf "RW mount mapping and RO mount mapping:\n%s\n" "$r"
61			pstat $! | awk "\$2 == \"$map\""
62			status=$((status + 1))
63		fi
64	else
65		echo "$1 mount point RO did not succeed"
66		mount | grep $mntpoint
67		status=$((status + 1))
68	fi
69}
70
71status=0
72file=$mntpoint/mountu.sh.file
73mapfile=/tmp/mountu.sh.map
74mount | grep -q "$mntpoint " && umount $mntpoint
75mdconfig -l | grep -q $mdstart && mdconfig -d -u $mdstart
76mdconfig -a -t swap -s 100m -u $mdstart
77gpart create -s bsd md$mdstart > /dev/null
78gpart add -t freebsd-ufs md$mdstart > /dev/null
79part=a
80newfs $newfs_flags md${mdstart}$part > /dev/null
81mount /dev/md${mdstart}$part $mntpoint
82chmod 777 $mntpoint
83
84# ufs
85exec 5>$mapfile
86/tmp/mountu UFS $file &
87pid=$!
88sleep 1
89map=`cat $mapfile`; rm $mapfile; exec 5>&-
90
91r=`pstat $! | awk "\\$2 == \"$map\""`
92mount -u -o ro $mntpoint 2>/dev/null || mount -fu -o ro $mntpoint
93ck UFS
94mount -u -o rw $mntpoint
95rm -f $file
96wait $pid
97s=$?
98[ $s -ne 139 ] && { echo "UFS exit status is $s"; status=1; }
99while mount | grep -q "$mntpoint "; do
100	umount $mntpoint || sleep 1
101done
102mdconfig -d -u $mdstart
103
104# nfs
105if ping -c 2 `echo $nfs_export | sed 's/:.*//'` > /dev/null 2>&1; then
106	mount -t nfs -o tcp -o retrycnt=3 -o intr,soft -o rw $nfs_export \
107	    $mntpoint
108	sleep .2
109	rm -f $file
110	/tmp/mountu NFS $file &
111	pid=$!
112	sleep 1
113
114	r=`pstat $! | awk "\\$2 == \"$map\""`
115	mount -u -o ro $mntpoint 2>/dev/null ||
116	    mount -fu -o ro $mntpoint 2>/dev/null
117	ck NFS
118	wait $pid
119	s=$?
120	[ $s -ne 139 ] && { echo "NFS exit status is $s"; status=1; }
121
122	mount -u -o rw $mntpoint 2>/dev/null
123	sleep .2
124	[ -f $file ] && rm -f $file
125	umount $mntpoint || umount $mntpoint
126fi
127
128# msdos
129if [ -x /sbin/mount_msdosfs ]; then
130	mdconfig -a -t swap -s 100m -u $mdstart
131	gpart create -s bsd md$mdstart > /dev/null
132	gpart add -t freebsd-ufs md$mdstart > /dev/null
133	part=a
134	newfs_msdos -F 16 -b 8192 /dev/md${mdstart}$part > /dev/null 2>&1
135	mount_msdosfs -m 777 /dev/md${mdstart}$part $mntpoint
136	/tmp/mountu MSDOS $file &
137	pid=$!
138
139	sleep 1
140	r=`pstat $! | awk "\\$2 == \"$map\""`
141	mount -u -o ro $mntpoint 2>/dev/null || mount -fu -o ro $mntpoint
142	ck MSDOS
143	wait $pid
144	s=$?
145	[ $s -ne 139 ] && { echo "MSDOS exit status is $s"; status=1; }
146	mount -u -o rw $mntpoint
147	rm -f $file
148
149	while mount | grep -q "$mntpoint "; do
150		umount $mntpoint || sleep 1
151	done
152	mdconfig -d -u $mdstart
153fi
154
155# tmpfs
156mount -t tmpfs null $mntpoint
157chmod 777 $mntpoint
158
159/tmp/mountu TMPFS $file &
160pid=$!
161
162sleep 1
163r=`pstat $! | awk "\\$2 == \"$map\""`
164mount -u -o ro $mntpoint 2>/dev/null || mount -fu -o ro $mntpoint
165ck TMPFS
166sleep 1
167mount -u -o rw $mntpoint
168rm -f $file
169wait $pid
170s=$?
171[ $s -ne 139 ] && { echo "TMPFS exit status is $s"; status=1; }
172while mount | grep -q "$mntpoint "; do
173	umount $mntpoint || sleep 1
174done
175
176rm -f /tmp/mountu
177exit 0
178EOF
179/* kib@ noted:
180   UFS/NFS/msdosfs reclaim vnode on rw->ro forced remount, and
181   change the type of the underying object to OBJT_DEAD, but leave
182   the pages on the object queue and installed in the page tables.
183   Applications can read/write already mapped pages, but cannot
184   page in new pages, cannot observe possible further modifications
185   to already mapped pages (if ro->rw remount happen later), and
186   their updates to pages are not flushed to file.
187
188   It is impossible to mimic this behaviour for tmpfs.
189 */
190#include <sys/param.h>
191#include <sys/mman.h>
192#include <sys/ucontext.h>
193
194#include <err.h>
195#include <errno.h>
196#include <fcntl.h>
197#include <pwd.h>
198#include <signal.h>
199#include <stdio.h>
200#include <stdlib.h>
201#include <string.h>
202#include <unistd.h>
203
204#define STARTADDR 0x0U
205#define ADRSPACE 0x0640000U
206
207static void
208sighandler(int signo, siginfo_t *si, void *uc1)
209{
210	ucontext_t *uc;
211
212	uc = uc1;
213	printf("SIG%s at %p, addr %p\n", sys_signame[signo], si->si_addr,
214#if defined(__i386__)
215	    (void *)uc->uc_mcontext.mc_eip);
216#else
217	    (void *)uc->uc_mcontext.mc_rip);
218#endif
219	exit(1);
220}
221
222int
223main(int argc __unused, char **argv)
224{
225	struct passwd *pw;
226	struct sigaction sa;
227	void *p;
228	size_t len;
229	int fd;
230	char *name, *path;
231	volatile char *c;
232
233	memset(&sa, 0, sizeof(sa));
234	sa.sa_sigaction = sighandler;
235	sa.sa_flags = SA_SIGINFO;
236	if (sigaction(SIGSEGV, &sa, NULL) == -1)
237		err(1, "sigaction(SIGSEGV)");
238	if (sigaction(SIGBUS, &sa, NULL) == -1)
239		err(1, "sigaction(SIGBUS)");
240
241	if ((pw = getpwnam("nobody")) == NULL)
242		err(1, "no such user: nobody");
243
244	if (setgroups(1, &pw->pw_gid) ||
245	    setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
246	    seteuid(pw->pw_uid) || setuid(pw->pw_uid))
247		err(1, "Can't drop privileges to \"nobody\"");
248	endpwent();
249
250	p = (void *)STARTADDR;
251	len = ADRSPACE;
252
253	name = argv[1];
254	path = argv[2];
255	if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0622)) == -1)
256		err(1,"open(%s)", path);
257	if (ftruncate(fd, len) == -1)
258		err(1, "ftruncate");
259	if ((p = mmap(p, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
260			MAP_FAILED) {
261		if (errno == ENOMEM) {
262			warn("mmap()");
263			return (1);
264		}
265		err(1, "mmap(1)");
266	}
267	dprintf(5, "%p\n", p);
268
269	for (c = p; (void *)c < p + len; c += PAGE_SIZE) {
270		*c = 1;
271	}
272
273	close(fd);
274	sleep(5);
275	fprintf(stderr, "%s: Late read start.\n", name);
276	for (c = p; (void *)c < p + len; c += PAGE_SIZE) {
277		*c;
278	}
279	fprintf(stderr, "%s: Late read complete.\n", name);
280
281	fprintf(stderr, "%s: Late write start.\n", name);
282	for (c = p; (void *)c < p + len; c += PAGE_SIZE) {
283		*c = 1;
284	}
285	fprintf(stderr, "%s: Late write complete.\n", name);
286
287	return (0);
288}
289