1#!/bin/sh 2 3# 4# Copyright (c) 2014 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) / contigfree(9) test scenario. 30# Test allocation with 1GB 31 32# "panic: Bad link elm 0x6766fbc next->prev != elm" seen: 33# https://people.freebsd.org/~pho/stress/log/kostik1094.txt 34# Fixed by r331247 35 36[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 37[ -d /usr/src/sys ] || exit 0 38builddir=`sysctl kern.version | grep @ | sed 's/.*://'` 39[ -d "$builddir" ] && export KERNBUILDDIR=$builddir || exit 0 40export SYSDIR=`echo $builddir | sed 's#/sys.*#/sys#'` 41 42. ../default.cfg 43 44odir=`pwd` 45dir=/tmp/contigmalloc 46rm -rf $dir; mkdir -p $dir 47cat > $dir/ctest.c <<EOF 48#include <sys/param.h> 49#include <sys/syscall.h> 50 51#include <err.h> 52#include <stdio.h> 53#include <stdlib.h> 54#include <time.h> 55#include <unistd.h> 56 57#define MAXBUF (1LL * 1024 * 1024 * 1024) /* Max buffer size */ 58#define TALLOC 1 59#define TFREE 2 60 61void 62test(int argc, char *argv[]) 63{ 64 long mw, size; 65 int no, ps, res; 66 char *cp; 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 if (mw < MAXBUF / ps) { 77 fprintf(stderr, "max_user_wired too small for this test\n"); 78 exit (0); 79 } 80 size = round_page(MAXBUF); 81 res = syscall(no, TALLOC, &cp, &size); 82 if (res == -1) { 83 err(1, "contigmalloc(%lu MB) failed", 84 size / 1024 / 1024); 85 } else { 86#if defined(TEST) 87 fprintf(stderr, "contigmalloc(%lu pages) %luMB\n", 88 size / ps, size / 1024 / 1024); 89#endif 90 } 91 92 res = syscall(no, TFREE, &cp, &size); 93#if defined(TEST) 94 fprintf(stderr, "contigfree(%lu pages) %luMB\n", 95 size / ps, size / 1024 / 1024); 96#endif 97} 98 99int 100main(int argc, char *argv[]) 101{ 102 103 test(argc, argv); 104 105 return (0); 106} 107 108EOF 109mycc -o /tmp/ctest -Wall -Wextra -O0 -g $dir/ctest.c || exit 1 110rm $dir/ctest.c 111 112cd $dir 113cat > Makefile <<EOF 114KMOD= cmalloc 115SRCS= cmalloc.c 116 117.include <bsd.kmod.mk> 118EOF 119 120sed '1,/^EOF2/d' < $odir/$0 > cmalloc.c 121make || exit 1 122kldload $dir/cmalloc.ko || exit 1 123 124cd $odir 125mw=`sysctl -n vm.max_user_wired` || exit 1 126/tmp/ctest `sysctl -n debug.cmalloc_offset` $mw 2>&1 | tail -5 127kldunload $dir/cmalloc.ko 128rm -rf $dir /tmp/ctest 129exit 0 130 131EOF2 132#include <sys/param.h> 133#include <sys/kernel.h> 134#include <sys/malloc.h> 135#include <sys/module.h> 136#include <sys/proc.h> 137#include <sys/sysctl.h> 138#include <sys/sysent.h> 139#include <sys/sysproto.h> 140#include <sys/systm.h> 141 142#define TALLOC 1 143#define TFREE 2 144 145/* 146 * Hook up a syscall for contigmalloc testing. 147 */ 148 149struct cmalloc_args { 150 int a_op; 151 void *a_ptr; 152 void *a_size; 153}; 154 155static int 156cmalloc(struct thread *td, struct cmalloc_args *uap) 157{ 158 void *p; 159 unsigned long size; 160 int error; 161 162 error = copyin(uap->a_size, &size, sizeof(size)); 163 if (error != 0) { 164 return (error); 165 } 166 switch (uap->a_op) { 167 case TFREE: 168 error = copyin(uap->a_ptr, &p, sizeof(p)); 169 if (error == 0) { 170 if (p != NULL) 171 contigfree(p, size, M_TEMP); 172 } 173 return (error); 174 175 case TALLOC: 176 p = contigmalloc(size, M_TEMP, M_NOWAIT, 0ul, ~0ul, 4096, 0); 177 if (p != NULL) { 178 error = copyout(&p, uap->a_ptr, sizeof(p)); 179 return (error); 180 } 181 return (ENOMEM); 182 } 183 return (EINVAL); 184} 185 186/* 187 * The sysent for the new syscall 188 */ 189static struct sysent cmalloc_sysent = { 190 .sy_narg = 3, /* sy_narg */ 191 .sy_call = (sy_call_t *) cmalloc /* sy_call */ 192}; 193 194/* 195 * The offset in sysent where the syscall is allocated. 196 */ 197static int cmalloc_offset = NO_SYSCALL; 198 199SYSCTL_INT(_debug, OID_AUTO, cmalloc_offset, CTLFLAG_RD, &cmalloc_offset, 0, 200 "cmalloc syscall number"); 201 202/* 203 * The function called at load/unload. 204 */ 205 206static int 207cmalloc_load(struct module *module, int cmd, void *arg) 208{ 209 int error = 0; 210 211 switch (cmd) { 212 case MOD_LOAD : 213 break; 214 case MOD_UNLOAD : 215 break; 216 default : 217 error = EOPNOTSUPP; 218 break; 219 } 220 return (error); 221} 222 223SYSCALL_MODULE(cmalloc_syscall, &cmalloc_offset, &cmalloc_sysent, 224 cmalloc_load, NULL); 225