xref: /freebsd/tools/test/stress2/misc/swap8.sh (revision c2b513335f688ac5657abc1bc40f6848988958d7)
1#!/bin/sh
2
3#
4# Copyright (c) 2026 Peter Holm <pho@FreeBSD.org>
5#
6# SPDX-License-Identifier: BSD-2-Clause
7#
8
9# sendfile over tmpfs
10
11# "panic: vm_page_assert_busied: page 0xfffffe000015fb88 not busy @ ../../../vm/vm_page.c:5845" seen
12# Triggered by: 72ddb6de1028 - main - unix: increase net.local.(stream|seqpacket).(recv|send)space to 64 KiB
13# Fixed by: d198ad51ea73 - main - swap_pager_getpages(): some pages from ma[] might be bogus
14
15[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
16[ `sysctl -n vm.swap_total` -eq 0 ] && exit 0
17
18. ../default.cfg
19
20prog=$(basename "$0" .sh)
21
22cat > /tmp/$prog.c <<EOF
23#include <sys/types.h>
24#include <sys/fcntl.h>
25#include <sys/mman.h>
26#include <sys/socket.h>
27#include <sys/stat.h>
28#include <sys/uio.h>
29#include <sys/wait.h>
30
31#include <err.h>
32#include <errno.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <unistd.h>
36
37static int use_sendfile = 1;
38
39int
40main(int argc, char *argv[])
41{
42	off_t rsize, wsize, pos;
43	ssize_t n;
44	struct stat st;
45	int from, pair[2], pid, status;
46	const char *from_name;
47	char *buf, *cp;
48
49	if (argc != 2)
50		errx(1, "Usage: %s from", argv[0]);
51	from_name = argv[1];
52
53	if ((from = open(from_name, O_RDONLY)) == -1)
54		err(1, "open read %s", from_name);
55
56	if (fstat(from, &st) == -1)
57		err(1, "stat %s", from_name);
58
59	if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
60		err(1, "socketpair");
61
62	pid = fork();
63	if (pid == -1)
64		err(1, "fork");
65	if (pid == 0) {	/* child */
66		setproctitle("reader");
67		close(pair[0]);
68		buf = malloc(st.st_size);
69		if (buf == NULL)
70			err(1, "malloc %jd", st.st_size);
71		pos = 0;
72		sleep(1);
73		for (;;) {
74			rsize = 413; /* arbitrary small block size */
75			if (rsize > st.st_size - pos)
76				rsize = st.st_size - pos;
77			n = read(pair[1], buf + pos, rsize);
78			if (n == -1)
79				err(1, "read()");
80			else if (n == 0)
81				errx(1, "Short read: Read %jd bytes out of %jd\n",
82					(intmax_t)pos, (intmax_t)st.st_size);
83			pos += n;
84			if (pos == st.st_size)
85				break;
86		}
87		close(pair[1]);
88		_exit(0);
89	}
90	setproctitle("writer");
91	close(pair[1]);
92
93	if (use_sendfile == 1) {
94		pos = 0;
95		for (;;) {
96			n = sendfile(from, pair[0], pos, st.st_size - pos,
97			    NULL, &wsize, 0);
98			if (n == -1) {
99				if (errno != EAGAIN)
100					err(1, "sendfile()");
101			}
102			if (wsize != st.st_size)
103				fprintf(stderr, "sendfile() wrote %jd bytes\n", (intmax_t)wsize);
104			pos += wsize;
105			if (pos == st.st_size)
106				break;
107		}
108	} else {
109		fprintf(stderr, "Not using sendfile().\n");
110		if ((cp = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, from, 0)) == MAP_FAILED)
111			err(1, "mmap");
112
113		if ((n = write(pair[0], cp, st.st_size)) == -1)
114			err(1, "write()");
115		if (n != st.st_size)
116			errx(1, "short write: %jd of %jd\n", (intmax_t)n, (intmax_t)st.st_size);
117		if (munmap(cp, st.st_size) == -1)
118			err(1, "munmap()");
119	}
120	if (waitpid(pid, &status, 0) != pid)
121		err(1, "waitpid()");
122	close(pair[0]);
123
124	return (status != 0);
125}
126EOF
127mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c || exit 1
128
129mount | grep -q "on $mntpoint " && umount -f $mntpoint
130mount -t tmpfs dummy $mntpoint || exit 1
131dd if=/dev/zero of=$mntpoint/file bs=1m count=1024 status=none # 1Gb
132
133../testcases/swap/swap -t 5m -i 40 > /dev/null 2>&1 &
134sleep 5
135/tmp/$prog $mntpoint/file
136while pkill swap; do :; done
137wait
138
139umount $mntpoint
140rm -f /tmp/$prog /tmp/$prog.c $diskimage
141exit 0
142