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