xref: /freebsd/tools/test/stress2/misc/unionfs20.sh (revision 86db3c735dd999f75eab54d848fb8402e6689c80)
1*86db3c73SPeter Holm#!/bin/sh
2*86db3c73SPeter Holm
3*86db3c73SPeter Holm#
4*86db3c73SPeter Holm# Copyright (c) 2025 Peter Holm <pho@FreeBSD.org>
5*86db3c73SPeter Holm#
6*86db3c73SPeter Holm# SPDX-License-Identifier: BSD-2-Clause
7*86db3c73SPeter Holm#
8*86db3c73SPeter Holm
9*86db3c73SPeter Holm# Bug 289700 - unionfs: page fault in unionfs_find_node_status when closing a file within a socket's receive buffer
10*86db3c73SPeter Holm
11*86db3c73SPeter Holm# "Fatal trap 12: page fault while in kernel mode" seen:
12*86db3c73SPeter Holm# https://people.freebsd.org/~pho/stress/log/log0618.txt
13*86db3c73SPeter Holm
14*86db3c73SPeter Holm. ../default.cfg
15*86db3c73SPeter Holm
16*86db3c73SPeter Holmprog=$(basename "$0" .sh)
17*86db3c73SPeter Holmhere=`pwd`
18*86db3c73SPeter Holmlog=/tmp/$prog.log
19*86db3c73SPeter Holmmd1=$mdstart
20*86db3c73SPeter Holmmd2=$((md1 + 1))
21*86db3c73SPeter Holmmp1=/mnt$md1
22*86db3c73SPeter Holmmp2=/mnt$md2
23*86db3c73SPeter Holm
24*86db3c73SPeter Holmset -eu
25*86db3c73SPeter Holmmdconfig -l | grep -q md$md1 && mdconfig -d -u $md1
26*86db3c73SPeter Holmmdconfig -l | grep -q md$md2 && mdconfig -d -u $md2
27*86db3c73SPeter Holm
28*86db3c73SPeter Holmmdconfig -s 2g -u $md1
29*86db3c73SPeter Holmnewfs $newfs_flags /dev/md$md1 > /dev/null
30*86db3c73SPeter Holmmdconfig -s 2g -u $md2
31*86db3c73SPeter Holmnewfs $newfs_flags /dev/md$md2 > /dev/null
32*86db3c73SPeter Holm
33*86db3c73SPeter Holmmkdir -p $mp1 $mp2
34*86db3c73SPeter Holmmount /dev/md$md1 $mp1
35*86db3c73SPeter Holmmount /dev/md$md2 $mp2
36*86db3c73SPeter Holmmount -t unionfs -o noatime $mp1 $mp2
37*86db3c73SPeter Holmset +e
38*86db3c73SPeter Holm
39*86db3c73SPeter Holmcd /tmp
40*86db3c73SPeter Holmsed '1,/^EOF/d' < $here/$0 > $prog.c
41*86db3c73SPeter Holmmycc -o $prog -Wall -Wextra -O2 $prog.c
42*86db3c73SPeter Holmrm -f $prog.c
43*86db3c73SPeter Holm[ -d $RUNDIR ] || mkdir -p $RUNDIR
44*86db3c73SPeter Holmcd $RUNDIR
45*86db3c73SPeter Holm
46*86db3c73SPeter Holmn=3
47*86db3c73SPeter Holmfor i in `jot $n`; do
48*86db3c73SPeter Holm	mkdir $mp2/d$i
49*86db3c73SPeter Holmdone
50*86db3c73SPeter Holm(cd $here/../testcases/swap; ./swap -t 3m -i 20 -l 100 -h > /dev/null) &
51*86db3c73SPeter Holmsleep 2
52*86db3c73SPeter Holmfor i in `jot $n`; do
53*86db3c73SPeter Holm	(cd $mp2/d$i; /tmp/$prog) &
54*86db3c73SPeter Holmdone
55*86db3c73SPeter Holmwhile pgrep -q $prog; do sleep .5; done
56*86db3c73SPeter Holmwhile pkill swap; do :; done
57*86db3c73SPeter Holmwait
58*86db3c73SPeter Holm
59*86db3c73SPeter Holmcd $here
60*86db3c73SPeter Holmumount $mp2 # The unionfs mount
61*86db3c73SPeter Holmumount $mp2
62*86db3c73SPeter Holmumount $mp1
63*86db3c73SPeter Holm
64*86db3c73SPeter Holmmdconfig -d -u $md1
65*86db3c73SPeter Holmmdconfig -d -u $md2
66*86db3c73SPeter Holmrm -f /tmp/$prog
67*86db3c73SPeter Holmexit 0
68*86db3c73SPeter HolmEOF
69*86db3c73SPeter Holm#include <sys/param.h>
70*86db3c73SPeter Holm#include <sys/mman.h>
71*86db3c73SPeter Holm#include <sys/socket.h>
72*86db3c73SPeter Holm#include <sys/uio.h>
73*86db3c73SPeter Holm#include <sys/wait.h>
74*86db3c73SPeter Holm
75*86db3c73SPeter Holm#include <stdio.h>
76*86db3c73SPeter Holm#include <errno.h>
77*86db3c73SPeter Holm#include <err.h>
78*86db3c73SPeter Holm#include <stdlib.h>
79*86db3c73SPeter Holm#include <time.h>
80*86db3c73SPeter Holm#include <unistd.h>
81*86db3c73SPeter Holm#include <fcntl.h>
82*86db3c73SPeter Holm#include <poll.h>
83*86db3c73SPeter Holm#include <stdatomic.h>
84*86db3c73SPeter Holm#include <string.h>
85*86db3c73SPeter Holm
86*86db3c73SPeter Holm#define PARALLEL 2
87*86db3c73SPeter Holm#define SYNC 0
88*86db3c73SPeter Holm
89*86db3c73SPeter Holmstatic int debug;
90*86db3c73SPeter Holmstatic _Atomic(int) *share;
91*86db3c73SPeter Holm
92*86db3c73SPeter Holmint
93*86db3c73SPeter Holmsend_fd(int socket, int fd_to_send)
94*86db3c73SPeter Holm{
95*86db3c73SPeter Holm	struct cmsghdr *cmsg;
96*86db3c73SPeter Holm	struct msghdr msg = {0};
97*86db3c73SPeter Holm	struct iovec iov;
98*86db3c73SPeter Holm	char buf[1] = {0};  // dummy data
99*86db3c73SPeter Holm	char cmsgbuf[CMSG_SPACE(sizeof(fd_to_send))];
100*86db3c73SPeter Holm
101*86db3c73SPeter Holm	memset(cmsgbuf, 0, sizeof(cmsgbuf));
102*86db3c73SPeter Holm
103*86db3c73SPeter Holm	iov.iov_base = buf;
104*86db3c73SPeter Holm	iov.iov_len = sizeof(buf);
105*86db3c73SPeter Holm	msg.msg_iov = &iov;
106*86db3c73SPeter Holm	msg.msg_iovlen = 1;
107*86db3c73SPeter Holm
108*86db3c73SPeter Holm	msg.msg_control = cmsgbuf;
109*86db3c73SPeter Holm	msg.msg_controllen = sizeof(cmsgbuf);
110*86db3c73SPeter Holm
111*86db3c73SPeter Holm	cmsg = CMSG_FIRSTHDR(&msg);
112*86db3c73SPeter Holm	cmsg->cmsg_level = SOL_SOCKET;
113*86db3c73SPeter Holm	cmsg->cmsg_type = SCM_RIGHTS;
114*86db3c73SPeter Holm	cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send));
115*86db3c73SPeter Holm
116*86db3c73SPeter Holm	memcpy(CMSG_DATA(cmsg), &fd_to_send, sizeof(fd_to_send));
117*86db3c73SPeter Holm
118*86db3c73SPeter Holm	return (sendmsg(socket, &msg, 0));
119*86db3c73SPeter Holm}
120*86db3c73SPeter Holm
121*86db3c73SPeter Holmint
122*86db3c73SPeter Holmrecv_fd(int socket)
123*86db3c73SPeter Holm{
124*86db3c73SPeter Holm	struct cmsghdr *cmsg;
125*86db3c73SPeter Holm	struct msghdr msg = {0};
126*86db3c73SPeter Holm	struct iovec iov;
127*86db3c73SPeter Holm	char buf[1];
128*86db3c73SPeter Holm	int received_fd;
129*86db3c73SPeter Holm	char cmsgbuf[CMSG_SPACE(sizeof(received_fd))];
130*86db3c73SPeter Holm
131*86db3c73SPeter Holm	memset(cmsgbuf, 0, sizeof(cmsgbuf));
132*86db3c73SPeter Holm
133*86db3c73SPeter Holm	iov.iov_base = buf;
134*86db3c73SPeter Holm	iov.iov_len = sizeof(buf);
135*86db3c73SPeter Holm	msg.msg_iov = &iov;
136*86db3c73SPeter Holm	msg.msg_iovlen = 1;
137*86db3c73SPeter Holm
138*86db3c73SPeter Holm	msg.msg_control = cmsgbuf;
139*86db3c73SPeter Holm	msg.msg_controllen = sizeof(cmsgbuf);
140*86db3c73SPeter Holm
141*86db3c73SPeter Holm	if (recvmsg(socket, &msg, 0) < 0)
142*86db3c73SPeter Holm		err(1, "recvmsg()");
143*86db3c73SPeter Holm
144*86db3c73SPeter Holm	cmsg = CMSG_FIRSTHDR(&msg);
145*86db3c73SPeter Holm	if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(received_fd))) {
146*86db3c73SPeter Holm		fprintf(stderr, "No passed fd\n");
147*86db3c73SPeter Holm		return (-1);
148*86db3c73SPeter Holm	}
149*86db3c73SPeter Holm
150*86db3c73SPeter Holm	if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
151*86db3c73SPeter Holm		fprintf(stderr, "Invalid cmsg_level or cmsg_type\n");
152*86db3c73SPeter Holm		return (-1);
153*86db3c73SPeter Holm	}
154*86db3c73SPeter Holm
155*86db3c73SPeter Holm	memcpy(&received_fd, CMSG_DATA(cmsg), sizeof(received_fd));
156*86db3c73SPeter Holm	return (received_fd);
157*86db3c73SPeter Holm}
158*86db3c73SPeter Holm
159*86db3c73SPeter Holmint
160*86db3c73SPeter Holmmain(void)
161*86db3c73SPeter Holm{
162*86db3c73SPeter Holm	pid_t pid;
163*86db3c73SPeter Holm	time_t start;
164*86db3c73SPeter Holm	size_t len;
165*86db3c73SPeter Holm	int fd, pair[2], status;
166*86db3c73SPeter Holm
167*86db3c73SPeter Holm	fd  = -1;
168*86db3c73SPeter Holm	len = PAGE_SIZE;
169*86db3c73SPeter Holm	if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE,
170*86db3c73SPeter Holm	    MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
171*86db3c73SPeter Holm		err(1, "mmap");
172*86db3c73SPeter Holm
173*86db3c73SPeter Holm	if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, pair) == -1)
174*86db3c73SPeter Holm		err(1, "socketpair");
175*86db3c73SPeter Holm
176*86db3c73SPeter Holm	start = time(NULL);
177*86db3c73SPeter Holm	while (time(NULL) - start < 180) {
178*86db3c73SPeter Holm		share[SYNC] = 0;
179*86db3c73SPeter Holm		if ((pid = fork()) == -1)
180*86db3c73SPeter Holm			err(1, "fork");
181*86db3c73SPeter Holm		if (pid == 0) {
182*86db3c73SPeter Holm			close(pair[0]);
183*86db3c73SPeter Holm			atomic_fetch_add(&share[SYNC], 1);
184*86db3c73SPeter Holm			while (share[SYNC] != PARALLEL)
185*86db3c73SPeter Holm				usleep(1000);
186*86db3c73SPeter Holm			// Not calling recv_fd() triggers the issue
187*86db3c73SPeter Holm//			fd = recv_fd(pair[1]);
188*86db3c73SPeter Holm			if (debug)
189*86db3c73SPeter Holm				fprintf(stderr, "Received fd=%d\n", fd);
190*86db3c73SPeter Holm			_exit(0);
191*86db3c73SPeter Holm		}
192*86db3c73SPeter Holm		fd = open("foo", O_RDWR|O_CREAT|O_TRUNC, 0666);
193*86db3c73SPeter Holm		if (fd == -1)
194*86db3c73SPeter Holm			err(1, "open");
195*86db3c73SPeter Holm		if (debug)
196*86db3c73SPeter Holm			fprintf(stderr, "Sending fd=%d\n", fd);
197*86db3c73SPeter Holm		atomic_fetch_add(&share[SYNC], 1);
198*86db3c73SPeter Holm		while (share[SYNC] != PARALLEL)
199*86db3c73SPeter Holm			usleep(1000);
200*86db3c73SPeter Holm		send_fd(pair[0], fd);
201*86db3c73SPeter Holm		usleep(arc4random() % 1000);
202*86db3c73SPeter Holm		wait(&status);
203*86db3c73SPeter Holm		close(fd);
204*86db3c73SPeter Holm		unlink("foo");
205*86db3c73SPeter Holm	}
206*86db3c73SPeter Holm}
207