1#!/bin/sh 2 3# 4# Copyright (c) 2015 EMC Corp. 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28 29# contigmalloc(9) / free(9) test scenario. 30# Regression test for allocations >= 2 GiB. 31# "panic: vm_page_insert_after: mpred doesn't precede pindex" seen. 32# Fixed by r284207. 33 34[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 35[ -d /usr/src/sys ] || exit 0 36builddir=`sysctl kern.version | grep @ | sed 's/.*://'` 37[ -d "$builddir" ] && export KERNBUILDDIR=$builddir || exit 0 38export SYSDIR=`echo $builddir | sed 's#/sys.*#/sys#'` 39 40. ../default.cfg 41 42odir=`pwd` 43dir=/tmp/contigmalloc 44rm -rf $dir; mkdir -p $dir 45cat > $dir/ctest2.c <<EOF 46#include <sys/param.h> 47#include <sys/syscall.h> 48 49#include <err.h> 50#include <errno.h> 51#include <stdio.h> 52#include <stdlib.h> 53#include <unistd.h> 54 55#define TALLOC 1 56#define TFREE 2 57 58void *p; 59long size; 60int n; 61 62void 63test(int argc, char *argv[]) 64{ 65 long mw; 66 int no, ps, res; 67 68 if (argc == 3) { 69 no = atoi(argv[1]); 70 mw = atol(argv[2]); 71 } 72 if (argc != 3 || no == 0 || mw == 0) 73 errx(1, "Usage: %s <syscall number> <max wired>", argv[0]); 74 75 ps = getpagesize(); 76 size = mw / 100 * 80 * ps; /* Use 80% of vm.max_user_wired */ 77 while (size > 0) { 78 res = syscall(no, TALLOC, &p, &size); 79 if (res == -1) { 80 if (errno != ENOMEM) 81 warn("contigmalloc(%lu pages) failed", 82 size); 83 } else { 84#if defined(TEST) 85 fprintf(stderr, "pre contigmalloc(%lu pages): %lu MiB\n", 86 size, size * ps / 1024 / 1024); 87#endif 88 res = syscall(no, TFREE, &p, &size); 89#if defined(TEST) 90 fprintf(stderr, "free(%lu pages)\n", size); 91#endif 92 } 93 size /= 2; 94 } 95} 96 97int 98main(int argc, char *argv[]) 99{ 100 test(argc, argv); 101 102 return (0); 103} 104 105EOF 106mycc -o /tmp/ctest2 -Wall -Wextra -O0 -g $dir/ctest2.c || exit 1 107rm $dir/ctest2.c 108 109cd $dir 110cat > Makefile <<EOF 111KMOD= cmalloc2 112SRCS= cmalloc2.c 113 114.include <bsd.kmod.mk> 115EOF 116 117sed '1,/^EOF2/d' < $odir/$0 > cmalloc2.c 118make depend all || exit 1 119kldload $dir/cmalloc2.ko || exit 1 120 121cd $odir 122mw=$((`sysctl -n vm.max_user_wired` - \ 123 `sysctl -n vm.stats.vm.v_user_wire_count`)) || exit 1 124/tmp/ctest2 `sysctl -n debug.cmalloc_offset` $mw #2>&1 | tail -5 125kldunload $dir/cmalloc2.ko 126rm -rf $dir /tmp/ctest2 127exit 0 128 129EOF2 130#include <sys/param.h> 131#include <sys/kernel.h> 132#include <sys/malloc.h> 133#include <sys/module.h> 134#include <sys/proc.h> 135#include <sys/sysctl.h> 136#include <sys/sysent.h> 137#include <sys/sysproto.h> 138#include <sys/systm.h> 139 140#define TALLOC 1 141#define TFREE 2 142 143/* 144 * Hook up a syscall for contigmalloc testing. 145 */ 146 147struct cmalloc_args { 148 int a_op; 149 void *a_ptr; 150 void *a_size; 151}; 152 153static int 154cmalloc(struct thread *td, struct cmalloc_args *uap) 155{ 156 void *p; 157 unsigned long size; 158 int error; 159 160 error = copyin(uap->a_size, &size, sizeof(size)); 161 if (error != 0) { 162 return (error); 163 } 164 switch (uap->a_op) { 165 case TFREE: 166 error = copyin(uap->a_ptr, &p, sizeof(p)); 167 if (error == 0) 168 free(p, M_TEMP); 169 return (error); 170 171 case TALLOC: 172 p = contigmalloc(size, M_TEMP, M_NOWAIT, 0ul, ~0ul, 4096, 0); 173 if (p != NULL) { 174 error = copyout(&p, uap->a_ptr, sizeof(p)); 175 return (error); 176 } 177 return (ENOMEM); 178 } 179 return (EINVAL); 180} 181 182/* 183 * The sysent for the new syscall 184 */ 185static struct sysent cmalloc_sysent = { 186 .sy_narg = 3, /* sy_narg */ 187 .sy_call = (sy_call_t *) cmalloc /* sy_call */ 188}; 189 190/* 191 * The offset in sysent where the syscall is allocated. 192 */ 193static int cmalloc_offset = NO_SYSCALL; 194 195SYSCTL_INT(_debug, OID_AUTO, cmalloc_offset, CTLFLAG_RD, &cmalloc_offset, 0, 196 "cmalloc syscall number"); 197 198/* 199 * The function called at load/unload. 200 */ 201 202static int 203cmalloc_load(struct module *module, int cmd, void *arg) 204{ 205 int error = 0; 206 207 switch (cmd) { 208 case MOD_LOAD : 209 break; 210 case MOD_UNLOAD : 211 break; 212 default : 213 error = EOPNOTSUPP; 214 break; 215 } 216 return (error); 217} 218 219SYSCALL_MODULE(cmalloc_syscall, &cmalloc_offset, &cmalloc_sysent, 220 cmalloc_load, NULL); 221