1#!/bin/sh 2 3# 4# Copyright (c) 2008 Peter Holm <pho@FreeBSD.org> 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# $FreeBSD$ 29# 30 31# Test scenario by kib@freebsd.org 32 33# Test of patch for Giant trick in cdevsw 34 35exit # Test moved to fpclone*.sh 36 37[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 38 39. ../default.cfg 40 41odir=`pwd` 42dir=$RUNDIR/tclone 43[ ! -d $dir ] && mkdir -p $dir 44 45cd $dir 46cat > Makefile <<EOF 47KMOD= tclone 48SRCS= tclone.c 49 50.include <bsd.kmod.mk> 51EOF 52 53sed '1,/^EOF2/d' < $odir/$0 > tclone.c 54make 55kldload $dir/tclone.ko 56 57cd $odir 58dd if=/dev/tclone bs=1m count=5k > /dev/null 2>&1 & 59 60export runRUNTIME=2m 61cd /home/pho/stress2; ./run.sh pty.cfg 62 63kldstat 64kldunload $dir/tclone.ko 65rm -rf $dir 66exit 67 68EOF2 69/* $FreeBSD$ */ 70 71#include <sys/param.h> 72#include <sys/systm.h> 73#include <sys/kernel.h> 74#include <sys/module.h> 75#include <sys/conf.h> 76#include <sys/uio.h> 77#include <sys/malloc.h> 78 79static d_open_t tclone_open; 80static d_close_t tclone_close; 81static d_read_t tclone_read; 82 83static struct cdevsw tclone_cdevsw = { 84 .d_open = tclone_open, 85 .d_close = tclone_close, 86 .d_read = tclone_read, 87 .d_name = "tclone", 88 .d_version = D_VERSION, 89 .d_flags = D_TRACKCLOSE|D_NEEDGIANT 90}; 91 92static eventhandler_tag tclone_ehtag; 93static struct clonedevs *tclone_clones; 94 95MALLOC_DEFINE(M_TCLONESC, "tclone memory", "tclone memory"); 96 97struct tclone_sc 98{ 99 int pos; 100}; 101 102static void 103tclone_clone(void *arg, struct ucred *cred, 104 char *name, int namelen, struct cdev **dev) 105{ 106 int i, clone; 107 108 if (*dev != NULL) 109 return; 110 if (strcmp(name, "tclone") != 0) 111 return; 112 113 clone = 0; 114 do { 115 i = clone_create(&tclone_clones, &tclone_cdevsw, 116 &clone, dev, 0); 117 if (i == 0) 118 clone++; 119 } while ((clone <= CLONE_UNITMASK) && (i == 0)); 120 121 if ((i != 0) && (clone <= CLONE_UNITMASK)) { 122 *dev = make_dev_credf(MAKEDEV_REF, 123 &tclone_cdevsw, unit2minor(clone), 124 cred, UID_ROOT, GID_WHEEL, 0666, 125 "tclone.%u", clone); 126 if (*dev != NULL) { 127 (*dev)->si_flags |= SI_CHEAPCLONE; 128 (*dev)->si_drv1 = (void *)1; 129 } 130 } 131} 132 133static int 134tclone_open(struct cdev *dev, int oflags, int devtype, d_thread_t *td) 135{ 136 int status; 137 138 if (!dev->si_drv2) { 139 /* only allow one open() of this file */ 140 dev->si_drv2 = malloc(sizeof(struct tclone_sc), M_TCLONESC, 141 M_WAITOK | M_ZERO); 142 status = 0; 143 } else 144 status = EBUSY; 145 146 if (status == 0) { 147 /* XXX Fix me? (clear of SI_CHEAPCLONE) */ 148 dev->si_flags &= ~SI_CHEAPCLONE; 149 } 150 151 return (status); 152} 153 154static int 155tclone_close(struct cdev *dev, int fflag, int devtype, d_thread_t *td) 156{ 157 void *x; 158 159 x = dev->si_drv2; 160 dev->si_drv2 = &tclone_cdevsw; 161 if (x != &tclone_cdevsw) 162 free(x, M_TCLONESC); 163 destroy_dev_sched(dev); 164 return (0); 165} 166 167static char rdata[] = "tclone sample data string\n"; 168 169static int 170tclone_read(struct cdev *dev, struct uio *uio, int ioflag) 171{ 172 struct tclone_sc *sc; 173 int rv, amnt; 174 175 sc = dev->si_drv2; 176 rv = 0; 177 while (uio->uio_resid > 0) { 178 amnt = MIN(uio->uio_resid, sizeof(rdata) - sc->pos); 179 rv = uiomove(rdata + sc->pos, amnt, uio); 180 if (rv != 0) 181 break; 182 sc->pos += amnt; 183 sc->pos %= sizeof(rdata); 184 } 185 return (rv); 186} 187 188static int 189tclone_modevent(module_t mod, int what, void *arg) 190{ 191 switch (what) { 192 case MOD_LOAD: 193 clone_setup(&tclone_clones); 194 tclone_ehtag = EVENTHANDLER_REGISTER(dev_clone, 195 tclone_clone, 0, 0); 196 if (tclone_ehtag == NULL) 197 return ENOMEM; 198 return(0); 199 200 case MOD_UNLOAD: 201 EVENTHANDLER_DEREGISTER(dev_clone, tclone_ehtag); 202 drain_dev_clone_events(); 203 clone_cleanup(&tclone_clones); 204 destroy_dev_drain(&tclone_cdevsw); 205 return (0); 206 default: 207 break; 208 } 209 210 return (0); 211} 212 213moduledata_t tclone_mdata = { 214 "tclone", 215 tclone_modevent, 216 NULL 217}; 218 219DECLARE_MODULE(tclone, tclone_mdata, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 220MODULE_VERSION(tclone, 1); 221