1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * Redirecting driver; used to handle workstation console redirection. 31*7c478bd9Sstevel@tonic-gate * 32*7c478bd9Sstevel@tonic-gate * Redirects all I/O through a given device instance to the device designated 33*7c478bd9Sstevel@tonic-gate * as the current target, as given by the vnode associated with the first 34*7c478bd9Sstevel@tonic-gate * entry in the list of redirections for the given device instance. The 35*7c478bd9Sstevel@tonic-gate * implementation assumes that this vnode denotes a STREAMS device; this is 36*7c478bd9Sstevel@tonic-gate * perhaps a bug. 37*7c478bd9Sstevel@tonic-gate * 38*7c478bd9Sstevel@tonic-gate * Supports the SRIOCSREDIR ioctl for designating a new redirection target. 39*7c478bd9Sstevel@tonic-gate * The new target is added to the front of a list of potentially active 40*7c478bd9Sstevel@tonic-gate * designees. Should the device at the front of this list be closed, the new 41*7c478bd9Sstevel@tonic-gate * front entry assumes active duty. (Stated differently, redirection targets 42*7c478bd9Sstevel@tonic-gate * stack, except that it's possible for entries in the interior of the stack 43*7c478bd9Sstevel@tonic-gate * to go away.) 44*7c478bd9Sstevel@tonic-gate * 45*7c478bd9Sstevel@tonic-gate * Supports the SRIOCISREDIR ioctl for inquiring whether the descriptor given 46*7c478bd9Sstevel@tonic-gate * as argument is the current front of the redirection list associated with 47*7c478bd9Sstevel@tonic-gate * the descriptor on which the ioctl was issued. 48*7c478bd9Sstevel@tonic-gate * 49*7c478bd9Sstevel@tonic-gate * Every open instance of this driver corresponds to an instance of the 50*7c478bd9Sstevel@tonic-gate * underlying client driver. If the redirection stack would otherwise become 51*7c478bd9Sstevel@tonic-gate * empty, this device (designated by the wd_vp field of the wcd_data 52*7c478bd9Sstevel@tonic-gate * structure) is implicitly opened and added to the front of the list. Thus, 53*7c478bd9Sstevel@tonic-gate * there's always an active device for handling i/o through an open instance 54*7c478bd9Sstevel@tonic-gate * of this driver. 55*7c478bd9Sstevel@tonic-gate * 56*7c478bd9Sstevel@tonic-gate * XXX: Names -- many of the names in this driver and its companion STREAMS 57*7c478bd9Sstevel@tonic-gate * module still reflect its origins as the workstation console 58*7c478bd9Sstevel@tonic-gate * redirection driver. Ultimately, they should be changed to reflect the 59*7c478bd9Sstevel@tonic-gate * fact that this driver is potentially a general purpose redirection 60*7c478bd9Sstevel@tonic-gate * driver. In the meantime, the driver is still specialized to have a 61*7c478bd9Sstevel@tonic-gate * single client -- the workstation console driver -- and its file name 62*7c478bd9Sstevel@tonic-gate * remains iwscons.c to reflect that specialization. 63*7c478bd9Sstevel@tonic-gate * 64*7c478bd9Sstevel@tonic-gate * Proposed change: "iwscn" becomes either "dr" (for "streams redirecting 65*7c478bd9Sstevel@tonic-gate * driver") or "srm" (for "streams redirecting module"), as appropriate. 66*7c478bd9Sstevel@tonic-gate * 67*7c478bd9Sstevel@tonic-gate * XXX: Add mechanism for notifying a redirectee that it's no longer the 68*7c478bd9Sstevel@tonic-gate * current redirectee? (This in contrast to the current facility for 69*7c478bd9Sstevel@tonic-gate * letting it ask.) 70*7c478bd9Sstevel@tonic-gate */ 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 73*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 74*7c478bd9Sstevel@tonic-gate #include <sys/open.h> 75*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 76*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 77*7c478bd9Sstevel@tonic-gate #include <sys/signal.h> 78*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 79*7c478bd9Sstevel@tonic-gate #include <sys/user.h> 80*7c478bd9Sstevel@tonic-gate #include <sys/proc.h> 81*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 82*7c478bd9Sstevel@tonic-gate #include <sys/uio.h> 83*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 84*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 85*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 88*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 89*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 90*7c478bd9Sstevel@tonic-gate #include <sys/poll.h> 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate #include <sys/strredir.h> 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 97*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 98*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate static int iwscninfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 101*7c478bd9Sstevel@tonic-gate static int iwscnattach(dev_info_t *, ddi_attach_cmd_t); 102*7c478bd9Sstevel@tonic-gate static int iwscnopen(dev_t *, int, int, cred_t *); 103*7c478bd9Sstevel@tonic-gate static int iwscnclose(dev_t, int, int, cred_t *); 104*7c478bd9Sstevel@tonic-gate static int iwscnread(dev_t, struct uio *, cred_t *); 105*7c478bd9Sstevel@tonic-gate static int iwscnwrite(dev_t, struct uio *, cred_t *); 106*7c478bd9Sstevel@tonic-gate static int iwscnioctl(dev_t, int, intptr_t, int, cred_t *, int *); 107*7c478bd9Sstevel@tonic-gate static int iwscnpoll(dev_t, short, int, short *, struct pollhead **); 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate /* 110*7c478bd9Sstevel@tonic-gate * Private copy of devinfo pointer; iwscninfo uses it. 111*7c478bd9Sstevel@tonic-gate */ 112*7c478bd9Sstevel@tonic-gate static dev_info_t *iwscn_dip; 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate struct cb_ops iwscn_cb_ops = { 115*7c478bd9Sstevel@tonic-gate iwscnopen, /* open */ 116*7c478bd9Sstevel@tonic-gate iwscnclose, /* close */ 117*7c478bd9Sstevel@tonic-gate nodev, /* strategy */ 118*7c478bd9Sstevel@tonic-gate nodev, /* print */ 119*7c478bd9Sstevel@tonic-gate nodev, /* dump */ 120*7c478bd9Sstevel@tonic-gate iwscnread, /* read */ 121*7c478bd9Sstevel@tonic-gate iwscnwrite, /* write */ 122*7c478bd9Sstevel@tonic-gate iwscnioctl, /* ioctl */ 123*7c478bd9Sstevel@tonic-gate nodev, /* devmap */ 124*7c478bd9Sstevel@tonic-gate nodev, /* mmap */ 125*7c478bd9Sstevel@tonic-gate nodev, /* segmap */ 126*7c478bd9Sstevel@tonic-gate iwscnpoll, /* poll */ 127*7c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 128*7c478bd9Sstevel@tonic-gate 0, /* streamtab */ 129*7c478bd9Sstevel@tonic-gate D_NEW|D_MP /* Driver compatibility flag */ 130*7c478bd9Sstevel@tonic-gate }; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate struct dev_ops iwscn_ops = { 133*7c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 134*7c478bd9Sstevel@tonic-gate 0, /* refcnt */ 135*7c478bd9Sstevel@tonic-gate iwscninfo, /* info */ 136*7c478bd9Sstevel@tonic-gate nulldev, /* identify */ 137*7c478bd9Sstevel@tonic-gate nulldev, /* probe */ 138*7c478bd9Sstevel@tonic-gate iwscnattach, /* attach */ 139*7c478bd9Sstevel@tonic-gate nodev, /* detach */ 140*7c478bd9Sstevel@tonic-gate nodev, /* reset */ 141*7c478bd9Sstevel@tonic-gate &iwscn_cb_ops, /* driver operations */ 142*7c478bd9Sstevel@tonic-gate NULL /* bus operations */ 143*7c478bd9Sstevel@tonic-gate }; 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate static krwlock_t iwscn_lock; /* lock proecting almost everything here */ 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate /* 148*7c478bd9Sstevel@tonic-gate * A read/write lock was used to serialize reads,writes/opens,closes. 149*7c478bd9Sstevel@tonic-gate * Sometime the open would hang due to a pending read. The new lock 150*7c478bd9Sstevel@tonic-gate * iwscn_open_lock and the read lock are held in open to assure a single 151*7c478bd9Sstevel@tonic-gate * instance, while letting concurrent reads/writes to proceed. 152*7c478bd9Sstevel@tonic-gate */ 153*7c478bd9Sstevel@tonic-gate static kmutex_t iwscn_open_lock; /* Serializes opens */ 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate /* 156*7c478bd9Sstevel@tonic-gate * These next two fields, protected by iwscn_lock, pass the data to wcmopen() 157*7c478bd9Sstevel@tonic-gate * from the ioctl SRIOCSREDIR. wcmopen() uses the data only if the thread 158*7c478bd9Sstevel@tonic-gate * matches. This keeps other threads from interfering. 159*7c478bd9Sstevel@tonic-gate */ 160*7c478bd9Sstevel@tonic-gate extern kthread_id_t iwscn_thread; /* thread that is allowed to */ 161*7c478bd9Sstevel@tonic-gate /* push redirm */ 162*7c478bd9Sstevel@tonic-gate extern wcm_data_t *iwscn_wcm_data; /* allocated data for redirm */ 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate /* 165*7c478bd9Sstevel@tonic-gate * Forward declarations of private routines. 166*7c478bd9Sstevel@tonic-gate */ 167*7c478bd9Sstevel@tonic-gate static int srreset(wcd_data_t *, int, cred_t *); 168*7c478bd9Sstevel@tonic-gate static wcrlist_t *srrm(wcrlist_t **, vnode_t *, int); 169*7c478bd9Sstevel@tonic-gate static wcd_data_t *srilookup(minor_t); 170*7c478bd9Sstevel@tonic-gate static wcd_data_t *srialloc(minor_t); 171*7c478bd9Sstevel@tonic-gate static void sridealloc(wcd_data_t *); 172*7c478bd9Sstevel@tonic-gate static wcrlist_t *srpush(wcrlist_t **, vnode_t *); 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate /* 175*7c478bd9Sstevel@tonic-gate * The head of the list of open instances. 176*7c478bd9Sstevel@tonic-gate */ 177*7c478bd9Sstevel@tonic-gate static wcd_data_t *wcddata; 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate /* 180*7c478bd9Sstevel@tonic-gate * Currently, the only client of this driver is the workstation console 181*7c478bd9Sstevel@tonic-gate * driver. Thus, we can get away with hard-wiring a reference to it here. 182*7c478bd9Sstevel@tonic-gate * 183*7c478bd9Sstevel@tonic-gate * To handle multiple clients, the driver must be revised as follows. 184*7c478bd9Sstevel@tonic-gate * 1) Add a registration routine that clients can call to announce 185*7c478bd9Sstevel@tonic-gate * themselves to this driver. The routine should take as arguments the 186*7c478bd9Sstevel@tonic-gate * major device number of the corresponding instantiation of the 187*7c478bd9Sstevel@tonic-gate * redirecting driver and a pointer to its dedvnops ops vector. 188*7c478bd9Sstevel@tonic-gate * 2) Maintain a list (or perhaps hash array) or registered clients, 189*7c478bd9Sstevel@tonic-gate * recording for each the srvnops ops vector and a pointer to the list 190*7c478bd9Sstevel@tonic-gate * of open instances for that client. 191*7c478bd9Sstevel@tonic-gate * 3) Modify the driver entry points to use their dev argument to look up 192*7c478bd9Sstevel@tonic-gate * the proper instantiation, get the list of open instances, and then use 193*7c478bd9Sstevel@tonic-gate * that as they currently use the open instance list. 194*7c478bd9Sstevel@tonic-gate * 4) To allow clients to unload themselves, we probably need an unregister 195*7c478bd9Sstevel@tonic-gate * routine. This routine would have to cope with active open instances. 196*7c478bd9Sstevel@tonic-gate */ 197*7c478bd9Sstevel@tonic-gate extern srvnops_t wscons_srvnops; 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 200*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 201*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 202*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 203*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 204*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate /* 207*7c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 208*7c478bd9Sstevel@tonic-gate */ 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 211*7c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a pseudo driver */ 212*7c478bd9Sstevel@tonic-gate "Workstation Redirection driver 'iwscn' %I%", 213*7c478bd9Sstevel@tonic-gate &iwscn_ops, /* driver ops */ 214*7c478bd9Sstevel@tonic-gate }; 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 217*7c478bd9Sstevel@tonic-gate MODREV_1, 218*7c478bd9Sstevel@tonic-gate &modldrv, 219*7c478bd9Sstevel@tonic-gate NULL 220*7c478bd9Sstevel@tonic-gate }; 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate int 224*7c478bd9Sstevel@tonic-gate _init(void) 225*7c478bd9Sstevel@tonic-gate { 226*7c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 227*7c478bd9Sstevel@tonic-gate } 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate int 230*7c478bd9Sstevel@tonic-gate _fini(void) 231*7c478bd9Sstevel@tonic-gate { 232*7c478bd9Sstevel@tonic-gate return (EBUSY); 233*7c478bd9Sstevel@tonic-gate } 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate int 236*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 237*7c478bd9Sstevel@tonic-gate { 238*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate /* 242*7c478bd9Sstevel@tonic-gate * DDI glue routines. 243*7c478bd9Sstevel@tonic-gate */ 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 246*7c478bd9Sstevel@tonic-gate static int 247*7c478bd9Sstevel@tonic-gate iwscnattach(dev_info_t *devi, ddi_attach_cmd_t cmd) 248*7c478bd9Sstevel@tonic-gate { 249*7c478bd9Sstevel@tonic-gate static char been_here; 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate if (!been_here) { 252*7c478bd9Sstevel@tonic-gate been_here = 1; 253*7c478bd9Sstevel@tonic-gate rw_init(&iwscn_lock, NULL, RW_DEFAULT, NULL); 254*7c478bd9Sstevel@tonic-gate } 255*7c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "iwscn", S_IFCHR, 256*7c478bd9Sstevel@tonic-gate 0, DDI_PSEUDO, NULL) == DDI_FAILURE) { 257*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 258*7c478bd9Sstevel@tonic-gate return (-1); 259*7c478bd9Sstevel@tonic-gate } 260*7c478bd9Sstevel@tonic-gate iwscn_dip = devi; 261*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 265*7c478bd9Sstevel@tonic-gate static int 266*7c478bd9Sstevel@tonic-gate iwscninfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 267*7c478bd9Sstevel@tonic-gate { 268*7c478bd9Sstevel@tonic-gate int error; 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate switch (infocmd) { 271*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 272*7c478bd9Sstevel@tonic-gate if (iwscn_dip == NULL) { 273*7c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 274*7c478bd9Sstevel@tonic-gate } else { 275*7c478bd9Sstevel@tonic-gate *result = (void *)iwscn_dip; 276*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate break; 279*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 280*7c478bd9Sstevel@tonic-gate *result = (void *)0; 281*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 282*7c478bd9Sstevel@tonic-gate break; 283*7c478bd9Sstevel@tonic-gate default: 284*7c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate return (error); 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 291*7c478bd9Sstevel@tonic-gate static int 292*7c478bd9Sstevel@tonic-gate iwscnopen( 293*7c478bd9Sstevel@tonic-gate dev_t *devp, 294*7c478bd9Sstevel@tonic-gate int flag, 295*7c478bd9Sstevel@tonic-gate int state, /* should be OTYP_CHR */ 296*7c478bd9Sstevel@tonic-gate cred_t *cred) 297*7c478bd9Sstevel@tonic-gate { 298*7c478bd9Sstevel@tonic-gate minor_t unit = getminor(*devp); 299*7c478bd9Sstevel@tonic-gate wcd_data_t *wd; 300*7c478bd9Sstevel@tonic-gate int err = 0; 301*7c478bd9Sstevel@tonic-gate struct wcrlist *wwd; 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate if (state != OTYP_CHR) 304*7c478bd9Sstevel@tonic-gate return (ENXIO); 305*7c478bd9Sstevel@tonic-gate rw_enter(&iwscn_lock, RW_READER); 306*7c478bd9Sstevel@tonic-gate mutex_enter(&iwscn_open_lock); 307*7c478bd9Sstevel@tonic-gate if ((wd = srilookup(unit)) == NULL) { 308*7c478bd9Sstevel@tonic-gate vnode_t *vp; 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate /* 311*7c478bd9Sstevel@tonic-gate * First open for this instance; get a state structure for it. 312*7c478bd9Sstevel@tonic-gate */ 313*7c478bd9Sstevel@tonic-gate wd = srialloc(unit); 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate /* 316*7c478bd9Sstevel@tonic-gate * Call the client driver to obtain a held vnode for the 317*7c478bd9Sstevel@tonic-gate * underlying "real" device instance. 318*7c478bd9Sstevel@tonic-gate * 319*7c478bd9Sstevel@tonic-gate * XXX: There's wired in knowledge of the client driver here. 320*7c478bd9Sstevel@tonic-gate */ 321*7c478bd9Sstevel@tonic-gate err = wscons_srvnops.svn_get(unit, &vp); 322*7c478bd9Sstevel@tonic-gate if (err != 0) { 323*7c478bd9Sstevel@tonic-gate sridealloc(wd); 324*7c478bd9Sstevel@tonic-gate mutex_exit(&iwscn_open_lock); 325*7c478bd9Sstevel@tonic-gate rw_exit(&iwscn_lock); 326*7c478bd9Sstevel@tonic-gate return (err); 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate wd->wd_vp = vp; 329*7c478bd9Sstevel@tonic-gate } 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* 332*7c478bd9Sstevel@tonic-gate * Reinitalize the list if necessary. 333*7c478bd9Sstevel@tonic-gate * 334*7c478bd9Sstevel@tonic-gate * XXX: Is it possible for the list to empty completely while this 335*7c478bd9Sstevel@tonic-gate * instance is still open? If not, this if should be coalesced 336*7c478bd9Sstevel@tonic-gate * with the previous one. 337*7c478bd9Sstevel@tonic-gate */ 338*7c478bd9Sstevel@tonic-gate if (wd->wd_list == NULL) { 339*7c478bd9Sstevel@tonic-gate wcrlist_t *e = srpush(&wd->wd_list, wd->wd_vp); 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate /* 342*7c478bd9Sstevel@tonic-gate * There's no corresponding redirecting module instance for 343*7c478bd9Sstevel@tonic-gate * the underlying device. 344*7c478bd9Sstevel@tonic-gate */ 345*7c478bd9Sstevel@tonic-gate e->wl_data = NULL; 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate err = srreset(wd, flag, cred); 349*7c478bd9Sstevel@tonic-gate /* 350*7c478bd9Sstevel@tonic-gate * XXX cleanup the sig list. Hook for console driver. 351*7c478bd9Sstevel@tonic-gate */ 352*7c478bd9Sstevel@tonic-gate for (wwd = wd->wd_list; wwd != NULL; wwd = wwd->wl_next) { 353*7c478bd9Sstevel@tonic-gate ASSERT(wwd->wl_vp->v_stream != NULL); 354*7c478bd9Sstevel@tonic-gate str_cn_clean(wwd->wl_vp); 355*7c478bd9Sstevel@tonic-gate } 356*7c478bd9Sstevel@tonic-gate mutex_exit(&iwscn_open_lock); 357*7c478bd9Sstevel@tonic-gate rw_exit(&iwscn_lock); 358*7c478bd9Sstevel@tonic-gate return (err); 359*7c478bd9Sstevel@tonic-gate } 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 362*7c478bd9Sstevel@tonic-gate static int 363*7c478bd9Sstevel@tonic-gate iwscnclose( 364*7c478bd9Sstevel@tonic-gate dev_t dev, 365*7c478bd9Sstevel@tonic-gate int flag, 366*7c478bd9Sstevel@tonic-gate int state, /* should be OTYP_CHR */ 367*7c478bd9Sstevel@tonic-gate cred_t *cred) 368*7c478bd9Sstevel@tonic-gate { 369*7c478bd9Sstevel@tonic-gate wcd_data_t *wd; 370*7c478bd9Sstevel@tonic-gate int err = 0; 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate if (state != OTYP_CHR) 373*7c478bd9Sstevel@tonic-gate return (ENXIO); 374*7c478bd9Sstevel@tonic-gate rw_enter(&iwscn_lock, RW_WRITER); 375*7c478bd9Sstevel@tonic-gate wd = srilookup(getminor(dev)); 376*7c478bd9Sstevel@tonic-gate /* 377*7c478bd9Sstevel@tonic-gate * Remove all outstanding redirections for this instance. 378*7c478bd9Sstevel@tonic-gate */ 379*7c478bd9Sstevel@tonic-gate while (wd->wd_list != NULL) 380*7c478bd9Sstevel@tonic-gate (void) srrm(&wd->wd_list, wd->wd_list->wl_vp, 1); 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate /* 383*7c478bd9Sstevel@tonic-gate * Since this is the _last_ close, it's our last chance to close the 384*7c478bd9Sstevel@tonic-gate * underlying device. (Note that if someone else has the underlying 385*7c478bd9Sstevel@tonic-gate * workstation console device open, we won't get here, since 386*7c478bd9Sstevel@tonic-gate * spec_close will see s_count > 1.) 387*7c478bd9Sstevel@tonic-gate */ 388*7c478bd9Sstevel@tonic-gate while ((wd->wd_wsconsopen != 0) && (!err)) { 389*7c478bd9Sstevel@tonic-gate err = VOP_CLOSE(wd->wd_vp, flag, 1, (offset_t)0, cred); 390*7c478bd9Sstevel@tonic-gate if (!err) 391*7c478bd9Sstevel@tonic-gate wd->wd_wsconsopen--; 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate if (!err) 394*7c478bd9Sstevel@tonic-gate wd->wd_vp->v_stream = NULL; 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate /* 397*7c478bd9Sstevel@tonic-gate * We don't need the vnode that the client driver gave us any more. 398*7c478bd9Sstevel@tonic-gate * 399*7c478bd9Sstevel@tonic-gate * XXX: There's wired in knowledge of the client driver here. 400*7c478bd9Sstevel@tonic-gate */ 401*7c478bd9Sstevel@tonic-gate wscons_srvnops.svn_rele(wd->wd_unit, wd->wd_vp); 402*7c478bd9Sstevel@tonic-gate sridealloc(wd); 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate rw_exit(&iwscn_lock); 405*7c478bd9Sstevel@tonic-gate return (err); 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate static int 409*7c478bd9Sstevel@tonic-gate iwscnread(dev_t dev, uio_t *uio, cred_t *cred) 410*7c478bd9Sstevel@tonic-gate { 411*7c478bd9Sstevel@tonic-gate wcd_data_t *wd; 412*7c478bd9Sstevel@tonic-gate int error; 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate rw_enter(&iwscn_lock, RW_READER); 415*7c478bd9Sstevel@tonic-gate wd = srilookup(getminor(dev)); 416*7c478bd9Sstevel@tonic-gate error = strread(wd->wd_list->wl_vp, uio, cred); 417*7c478bd9Sstevel@tonic-gate rw_exit(&iwscn_lock); 418*7c478bd9Sstevel@tonic-gate return (error); 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate static int 422*7c478bd9Sstevel@tonic-gate iwscnwrite(dev_t dev, uio_t *uio, cred_t *cred) 423*7c478bd9Sstevel@tonic-gate { 424*7c478bd9Sstevel@tonic-gate wcd_data_t *wd; 425*7c478bd9Sstevel@tonic-gate int error; 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate rw_enter(&iwscn_lock, RW_READER); 428*7c478bd9Sstevel@tonic-gate wd = srilookup(getminor(dev)); 429*7c478bd9Sstevel@tonic-gate error = strwrite(wd->wd_list->wl_vp, uio, cred); 430*7c478bd9Sstevel@tonic-gate rw_exit(&iwscn_lock); 431*7c478bd9Sstevel@tonic-gate return (error); 432*7c478bd9Sstevel@tonic-gate } 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate static int 435*7c478bd9Sstevel@tonic-gate iwscnioctl(dev_t dev, int cmd, intptr_t arg, int flag, 436*7c478bd9Sstevel@tonic-gate cred_t *cred, int *rvalp) 437*7c478bd9Sstevel@tonic-gate { 438*7c478bd9Sstevel@tonic-gate wcd_data_t *wd; 439*7c478bd9Sstevel@tonic-gate int err = 0; 440*7c478bd9Sstevel@tonic-gate file_t *f; 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate switch (cmd) { 443*7c478bd9Sstevel@tonic-gate case SRIOCSREDIR: { 444*7c478bd9Sstevel@tonic-gate wcrlist_t *wlp; 445*7c478bd9Sstevel@tonic-gate wcm_data_t *mdp; 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate if (!rw_tryenter(&iwscn_lock, RW_WRITER)) { 448*7c478bd9Sstevel@tonic-gate return (EBUSY); 449*7c478bd9Sstevel@tonic-gate } 450*7c478bd9Sstevel@tonic-gate wd = srilookup(getminor(dev)); 451*7c478bd9Sstevel@tonic-gate /* 452*7c478bd9Sstevel@tonic-gate * Find the vnode corresponding to the file descriptor 453*7c478bd9Sstevel@tonic-gate * argument and verify that it names a stream. 454*7c478bd9Sstevel@tonic-gate */ 455*7c478bd9Sstevel@tonic-gate if ((f = getf((int)arg)) == NULL) { 456*7c478bd9Sstevel@tonic-gate err = EBADF; 457*7c478bd9Sstevel@tonic-gate break; 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate if (f->f_vnode->v_stream == NULL) { 460*7c478bd9Sstevel@tonic-gate err = ENOSTR; 461*7c478bd9Sstevel@tonic-gate releasef((int)arg); 462*7c478bd9Sstevel@tonic-gate break; 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate /* 465*7c478bd9Sstevel@tonic-gate * allocate the private data for redirmod, and pass it through 466*7c478bd9Sstevel@tonic-gate * a global to wcmopen(). This is all protected by iwscn_lock. 467*7c478bd9Sstevel@tonic-gate */ 468*7c478bd9Sstevel@tonic-gate mdp = kmem_alloc(sizeof (*mdp), KM_SLEEP); 469*7c478bd9Sstevel@tonic-gate iwscn_wcm_data = mdp; 470*7c478bd9Sstevel@tonic-gate iwscn_thread = curthread; 471*7c478bd9Sstevel@tonic-gate 472*7c478bd9Sstevel@tonic-gate /* 473*7c478bd9Sstevel@tonic-gate * Push a new instance of the redirecting module onto the 474*7c478bd9Sstevel@tonic-gate * stream, so that its close routine can notify us when the 475*7c478bd9Sstevel@tonic-gate * overall stream is closed. (In turn, we'll then remove it 476*7c478bd9Sstevel@tonic-gate * from the redirection list.) 477*7c478bd9Sstevel@tonic-gate */ 478*7c478bd9Sstevel@tonic-gate if ((err = VOP_IOCTL(f->f_vnode, I_PUSH, (intptr_t)"redirmod", 479*7c478bd9Sstevel@tonic-gate (FREAD | FKIOCTL), cred, rvalp)) != 0) { 480*7c478bd9Sstevel@tonic-gate iwscn_thread = NULL; 481*7c478bd9Sstevel@tonic-gate kmem_free(mdp, sizeof (*mdp)); 482*7c478bd9Sstevel@tonic-gate releasef((int)arg); 483*7c478bd9Sstevel@tonic-gate break; 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate iwscn_thread = NULL; /* clear authorization for wcmopen() */ 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate /* 488*7c478bd9Sstevel@tonic-gate * Push it onto the redirection stack. 489*7c478bd9Sstevel@tonic-gate */ 490*7c478bd9Sstevel@tonic-gate wlp = srpush(&wd->wd_list, f->f_vnode); 491*7c478bd9Sstevel@tonic-gate /* 492*7c478bd9Sstevel@tonic-gate * Fill in the redirecting module instance's private data with 493*7c478bd9Sstevel@tonic-gate * information to let it get to our redirection list when its 494*7c478bd9Sstevel@tonic-gate * close routine is called. Cross-link it with the 495*7c478bd9Sstevel@tonic-gate * redirection list entry. 496*7c478bd9Sstevel@tonic-gate */ 497*7c478bd9Sstevel@tonic-gate mdp->wm_wd = wd; 498*7c478bd9Sstevel@tonic-gate mdp->wm_entry = wlp; 499*7c478bd9Sstevel@tonic-gate wlp->wl_data = mdp; 500*7c478bd9Sstevel@tonic-gate releasef((int)arg); 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate break; 503*7c478bd9Sstevel@tonic-gate } 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate case SRIOCISREDIR: 506*7c478bd9Sstevel@tonic-gate rw_enter(&iwscn_lock, RW_READER); 507*7c478bd9Sstevel@tonic-gate wd = srilookup(getminor(dev)); 508*7c478bd9Sstevel@tonic-gate if ((f = getf((int)arg)) == NULL) { 509*7c478bd9Sstevel@tonic-gate err = EBADF; 510*7c478bd9Sstevel@tonic-gate break; 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate /* 513*7c478bd9Sstevel@tonic-gate * Return value is 1 if the argument descriptor is the current 514*7c478bd9Sstevel@tonic-gate * redirection target, and 0 otherwise. 515*7c478bd9Sstevel@tonic-gate */ 516*7c478bd9Sstevel@tonic-gate *rvalp = (f->f_vnode == wd->wd_list->wl_vp) ? 1 : 0; 517*7c478bd9Sstevel@tonic-gate releasef((int)arg); 518*7c478bd9Sstevel@tonic-gate break; 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate case I_POP: { 521*7c478bd9Sstevel@tonic-gate /* 522*7c478bd9Sstevel@tonic-gate * XXX - This is a big kludge the handles a deadlock case 523*7c478bd9Sstevel@tonic-gate * when we are trying to pop off the redirection 524*7c478bd9Sstevel@tonic-gate * module. Since this should only happen on a close 525*7c478bd9Sstevel@tonic-gate * of the device, and since it hangs the system, just 526*7c478bd9Sstevel@tonic-gate * do not allow a pop of the redirection module to happen. 527*7c478bd9Sstevel@tonic-gate * Popping other modules is allowed. 528*7c478bd9Sstevel@tonic-gate */ 529*7c478bd9Sstevel@tonic-gate struct stdata *stp; 530*7c478bd9Sstevel@tonic-gate char modname[FMNAMESZ + 1] = " "; 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate rw_enter(&iwscn_lock, RW_READER); 533*7c478bd9Sstevel@tonic-gate wd = srilookup(getminor(dev)); 534*7c478bd9Sstevel@tonic-gate (void) strioctl(wd->wd_list->wl_vp, I_LOOK, (intptr_t)modname, 535*7c478bd9Sstevel@tonic-gate flag, K_TO_K, cred, rvalp); 536*7c478bd9Sstevel@tonic-gate if (strcmp("redirmod", modname) == 0) { 537*7c478bd9Sstevel@tonic-gate if ((f = getf((int)arg)) == NULL) { 538*7c478bd9Sstevel@tonic-gate err = EBADF; 539*7c478bd9Sstevel@tonic-gate break; 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate if ((stp = f->f_vnode->v_stream) == NULL) { 542*7c478bd9Sstevel@tonic-gate err = ENOSTR; 543*7c478bd9Sstevel@tonic-gate releasef((int)arg); 544*7c478bd9Sstevel@tonic-gate break; 545*7c478bd9Sstevel@tonic-gate } 546*7c478bd9Sstevel@tonic-gate if (!(stp->sd_flag & STRCLOSE)) { 547*7c478bd9Sstevel@tonic-gate releasef((int)arg); 548*7c478bd9Sstevel@tonic-gate rw_exit(&iwscn_lock); 549*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Popping of redirection " 550*7c478bd9Sstevel@tonic-gate "module not allowed"); 551*7c478bd9Sstevel@tonic-gate return (EINVAL); 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate releasef((int)arg); 555*7c478bd9Sstevel@tonic-gate } 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate /* Process ioctl normally */ 558*7c478bd9Sstevel@tonic-gate err = strioctl(wd->wd_list->wl_vp, cmd, arg, flag, U_TO_K, 559*7c478bd9Sstevel@tonic-gate cred, rvalp); 560*7c478bd9Sstevel@tonic-gate break; 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate 563*7c478bd9Sstevel@tonic-gate default: 564*7c478bd9Sstevel@tonic-gate rw_enter(&iwscn_lock, RW_READER); 565*7c478bd9Sstevel@tonic-gate wd = srilookup(getminor(dev)); 566*7c478bd9Sstevel@tonic-gate err = strioctl(wd->wd_list->wl_vp, cmd, arg, flag, U_TO_K, 567*7c478bd9Sstevel@tonic-gate cred, rvalp); 568*7c478bd9Sstevel@tonic-gate break; 569*7c478bd9Sstevel@tonic-gate } 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate rw_exit(&iwscn_lock); 572*7c478bd9Sstevel@tonic-gate return (err); 573*7c478bd9Sstevel@tonic-gate } 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate static int 576*7c478bd9Sstevel@tonic-gate iwscnpoll( 577*7c478bd9Sstevel@tonic-gate dev_t dev, 578*7c478bd9Sstevel@tonic-gate short events, 579*7c478bd9Sstevel@tonic-gate int anyyet, 580*7c478bd9Sstevel@tonic-gate short *reventsp, 581*7c478bd9Sstevel@tonic-gate struct pollhead **phpp) 582*7c478bd9Sstevel@tonic-gate { 583*7c478bd9Sstevel@tonic-gate wcd_data_t *wd; 584*7c478bd9Sstevel@tonic-gate int error; 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate rw_enter(&iwscn_lock, RW_READER); 587*7c478bd9Sstevel@tonic-gate wd = srilookup(getminor(dev)); 588*7c478bd9Sstevel@tonic-gate error = strpoll(wd->wd_list->wl_vp->v_stream, events, anyyet, 589*7c478bd9Sstevel@tonic-gate reventsp, phpp); 590*7c478bd9Sstevel@tonic-gate rw_exit(&iwscn_lock); 591*7c478bd9Sstevel@tonic-gate return (error); 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate 595*7c478bd9Sstevel@tonic-gate /* 596*7c478bd9Sstevel@tonic-gate * Auxiliary routines. 597*7c478bd9Sstevel@tonic-gate */ 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate /* 600*7c478bd9Sstevel@tonic-gate * Additional public interfaces. 601*7c478bd9Sstevel@tonic-gate */ 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate /* 604*7c478bd9Sstevel@tonic-gate * Reset the current workstation console designee to the device denoted by the 605*7c478bd9Sstevel@tonic-gate * wl_vp field of the first entry in the redirection list. Called from 606*7c478bd9Sstevel@tonic-gate * iwscnopen and from the SRIOCSREDIR case of iwscnioctl, in both cases after 607*7c478bd9Sstevel@tonic-gate * the target vp has been set to its new value. 608*7c478bd9Sstevel@tonic-gate */ 609*7c478bd9Sstevel@tonic-gate static int 610*7c478bd9Sstevel@tonic-gate srreset(wcd_data_t *wd, int flag, cred_t *cred) 611*7c478bd9Sstevel@tonic-gate { 612*7c478bd9Sstevel@tonic-gate wcrlist_t *wlp; 613*7c478bd9Sstevel@tonic-gate int err = 0; 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&iwscn_lock) || MUTEX_HELD(&iwscn_open_lock)); 616*7c478bd9Sstevel@tonic-gate wlp = wd->wd_list; /* first entry */ 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate /* 619*7c478bd9Sstevel@tonic-gate * If we're reverting back to the workstation console, make sure it's 620*7c478bd9Sstevel@tonic-gate * open. 621*7c478bd9Sstevel@tonic-gate */ 622*7c478bd9Sstevel@tonic-gate if (wlp != NULL && wlp->wl_vp == wd->wd_vp) { 623*7c478bd9Sstevel@tonic-gate vnode_t *vp = wd->wd_vp; /* underlying device's vp */ 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate err = VOP_OPEN(&vp, flag, cred); 626*7c478bd9Sstevel@tonic-gate /* 627*7c478bd9Sstevel@tonic-gate * The underlying driver is not allowed to have cloned itself 628*7c478bd9Sstevel@tonic-gate * for this open. 629*7c478bd9Sstevel@tonic-gate */ 630*7c478bd9Sstevel@tonic-gate if (vp != wd->wd_vp) { 631*7c478bd9Sstevel@tonic-gate panic("srreset: Illegal clone"); 632*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate if (!err) 635*7c478bd9Sstevel@tonic-gate wd->wd_wsconsopen++; 636*7c478bd9Sstevel@tonic-gate } 637*7c478bd9Sstevel@tonic-gate return (err); 638*7c478bd9Sstevel@tonic-gate } 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate /* 641*7c478bd9Sstevel@tonic-gate * Remove vp from the redirection list rooted at *rwlp, should it be there. 642*7c478bd9Sstevel@tonic-gate * If zap is nonzero, deallocate the entry and remove dangling references to 643*7c478bd9Sstevel@tonic-gate * the it from the corresponding redirecting module instance's wcm_data 644*7c478bd9Sstevel@tonic-gate * structure. 645*7c478bd9Sstevel@tonic-gate * 646*7c478bd9Sstevel@tonic-gate * If the entry doesn't exist upon completion, return NULL; otherwise return a 647*7c478bd9Sstevel@tonic-gate * pointer to it. 648*7c478bd9Sstevel@tonic-gate */ 649*7c478bd9Sstevel@tonic-gate static wcrlist_t * 650*7c478bd9Sstevel@tonic-gate srrm(wcrlist_t **rwlp, vnode_t *vp, int zap) 651*7c478bd9Sstevel@tonic-gate { 652*7c478bd9Sstevel@tonic-gate wcrlist_t **delwlp; 653*7c478bd9Sstevel@tonic-gate wcrlist_t *wlp; 654*7c478bd9Sstevel@tonic-gate wcm_data_t *mdp; 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&iwscn_lock) || MUTEX_HELD(&iwscn_open_lock)); 657*7c478bd9Sstevel@tonic-gate for (delwlp = rwlp; (wlp = *delwlp) != NULL; delwlp = &wlp->wl_next) 658*7c478bd9Sstevel@tonic-gate if (wlp->wl_vp == vp) 659*7c478bd9Sstevel@tonic-gate break; 660*7c478bd9Sstevel@tonic-gate if (wlp == NULL) 661*7c478bd9Sstevel@tonic-gate return (NULL); 662*7c478bd9Sstevel@tonic-gate *delwlp = wlp->wl_next; 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate if (zap == 0) 665*7c478bd9Sstevel@tonic-gate return (wlp); 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate if (wlp->wl_vp == vp) 668*7c478bd9Sstevel@tonic-gate VN_RELE(vp); 669*7c478bd9Sstevel@tonic-gate /* 670*7c478bd9Sstevel@tonic-gate * Make sure there are no dangling references leading to the entry 671*7c478bd9Sstevel@tonic-gate * from the corresponding redirecting module instance. 672*7c478bd9Sstevel@tonic-gate */ 673*7c478bd9Sstevel@tonic-gate if ((mdp = wlp->wl_data) != NULL) { 674*7c478bd9Sstevel@tonic-gate mdp->wm_wd = NULL; 675*7c478bd9Sstevel@tonic-gate mdp->wm_entry = NULL; 676*7c478bd9Sstevel@tonic-gate } 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate kmem_free(wlp, sizeof (*wlp)); 679*7c478bd9Sstevel@tonic-gate return (NULL); 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate /* 683*7c478bd9Sstevel@tonic-gate * srpop - remove redirection because the target stream is being closed. 684*7c478bd9Sstevel@tonic-gate * Called from wcmclose(). 685*7c478bd9Sstevel@tonic-gate */ 686*7c478bd9Sstevel@tonic-gate void 687*7c478bd9Sstevel@tonic-gate srpop(wcm_data_t *mdp, int flag, cred_t *cred) 688*7c478bd9Sstevel@tonic-gate { 689*7c478bd9Sstevel@tonic-gate wcd_data_t *ddp; 690*7c478bd9Sstevel@tonic-gate 691*7c478bd9Sstevel@tonic-gate rw_enter(&iwscn_lock, RW_WRITER); 692*7c478bd9Sstevel@tonic-gate if ((ddp = mdp->wm_wd) != NULL) { 693*7c478bd9Sstevel@tonic-gate ASSERT(mdp->wm_entry != NULL); 694*7c478bd9Sstevel@tonic-gate (void) srrm(&ddp->wd_list, mdp->wm_entry->wl_vp, 1); 695*7c478bd9Sstevel@tonic-gate (void) srreset(ddp, flag, cred); 696*7c478bd9Sstevel@tonic-gate } 697*7c478bd9Sstevel@tonic-gate rw_exit(&iwscn_lock); 698*7c478bd9Sstevel@tonic-gate } 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate /* 701*7c478bd9Sstevel@tonic-gate * Routines for allocating, deallocating, and finding wcd_data structures. 702*7c478bd9Sstevel@tonic-gate * 703*7c478bd9Sstevel@tonic-gate * For a given instantiation of the driver, its open instance structures are 704*7c478bd9Sstevel@tonic-gate * linked together into a list, on the assumption that there will never be 705*7c478bd9Sstevel@tonic-gate * enough open instances to make search efficiency a serious concern. 706*7c478bd9Sstevel@tonic-gate */ 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate /* 709*7c478bd9Sstevel@tonic-gate * Look up the instance structure denoted by unit. 710*7c478bd9Sstevel@tonic-gate */ 711*7c478bd9Sstevel@tonic-gate static wcd_data_t * 712*7c478bd9Sstevel@tonic-gate srilookup(minor_t unit) 713*7c478bd9Sstevel@tonic-gate { 714*7c478bd9Sstevel@tonic-gate wcd_data_t *wd = wcddata; 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&iwscn_lock)); 717*7c478bd9Sstevel@tonic-gate for (; wd != NULL && wd->wd_unit != unit; wd = wd->wd_next) 718*7c478bd9Sstevel@tonic-gate continue; 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate return (wd); 721*7c478bd9Sstevel@tonic-gate } 722*7c478bd9Sstevel@tonic-gate 723*7c478bd9Sstevel@tonic-gate /* 724*7c478bd9Sstevel@tonic-gate * Allocate a wcd_data structure for the instance denoted by unit, link it in 725*7c478bd9Sstevel@tonic-gate * place, and return a pointer to it. If it's already allocated, simply 726*7c478bd9Sstevel@tonic-gate * return a pointer to it. 727*7c478bd9Sstevel@tonic-gate */ 728*7c478bd9Sstevel@tonic-gate static wcd_data_t * 729*7c478bd9Sstevel@tonic-gate srialloc(minor_t unit) 730*7c478bd9Sstevel@tonic-gate { 731*7c478bd9Sstevel@tonic-gate wcd_data_t *wdp; 732*7c478bd9Sstevel@tonic-gate wcd_data_t **wdpp; 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&iwscn_open_lock)); 735*7c478bd9Sstevel@tonic-gate for (wdpp = &wcddata; (wdp = *wdpp) != NULL; wdpp = &wdp->wd_next) { 736*7c478bd9Sstevel@tonic-gate if (unit < wdp->wd_unit) 737*7c478bd9Sstevel@tonic-gate break; 738*7c478bd9Sstevel@tonic-gate if (unit == wdp->wd_unit) { 739*7c478bd9Sstevel@tonic-gate /* Already allocated and in place. */ 740*7c478bd9Sstevel@tonic-gate return (wdp); 741*7c478bd9Sstevel@tonic-gate } 742*7c478bd9Sstevel@tonic-gate } 743*7c478bd9Sstevel@tonic-gate /* 744*7c478bd9Sstevel@tonic-gate * wdpp now points to the proper insertion point for unit's 745*7c478bd9Sstevel@tonic-gate * per-instance structure. 746*7c478bd9Sstevel@tonic-gate */ 747*7c478bd9Sstevel@tonic-gate wdp = kmem_zalloc(sizeof (*wdp), KM_SLEEP); 748*7c478bd9Sstevel@tonic-gate wdp->wd_unit = unit; 749*7c478bd9Sstevel@tonic-gate wdp->wd_next = *wdpp; 750*7c478bd9Sstevel@tonic-gate *wdpp = wdp; 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate return (wdp); 753*7c478bd9Sstevel@tonic-gate } 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate /* 756*7c478bd9Sstevel@tonic-gate * Deallocate the wcd_data structure denoted by wd and unlink it from the 757*7c478bd9Sstevel@tonic-gate * list of open instances. 758*7c478bd9Sstevel@tonic-gate */ 759*7c478bd9Sstevel@tonic-gate static void 760*7c478bd9Sstevel@tonic-gate sridealloc(wcd_data_t *wd) 761*7c478bd9Sstevel@tonic-gate { 762*7c478bd9Sstevel@tonic-gate wcd_data_t *wdp; 763*7c478bd9Sstevel@tonic-gate wcd_data_t **wdpp; 764*7c478bd9Sstevel@tonic-gate 765*7c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&iwscn_lock) || MUTEX_HELD(&iwscn_open_lock)); 766*7c478bd9Sstevel@tonic-gate for (wdpp = &wcddata; (wdp = *wdpp) != NULL; wdpp = &wdp->wd_next) 767*7c478bd9Sstevel@tonic-gate if (wd == wdp) 768*7c478bd9Sstevel@tonic-gate break; 769*7c478bd9Sstevel@tonic-gate if (wdp == NULL) { 770*7c478bd9Sstevel@tonic-gate /* 771*7c478bd9Sstevel@tonic-gate * Not there. This should probably be a panic. 772*7c478bd9Sstevel@tonic-gate */ 773*7c478bd9Sstevel@tonic-gate return; 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate *wdpp = wdp->wd_next; 776*7c478bd9Sstevel@tonic-gate kmem_free(wdp, sizeof (*wdp)); 777*7c478bd9Sstevel@tonic-gate } 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate /* 781*7c478bd9Sstevel@tonic-gate * Push vp onto the redirection list rooted at *wlpp. If it's already there, 782*7c478bd9Sstevel@tonic-gate * move it to the front position. Return a pointer to its list entry. 783*7c478bd9Sstevel@tonic-gate * 784*7c478bd9Sstevel@tonic-gate * N.B.: It is the caller's responsibility to initialize all fields in the 785*7c478bd9Sstevel@tonic-gate * entry other than the wl_next and wl_vp fields. 786*7c478bd9Sstevel@tonic-gate */ 787*7c478bd9Sstevel@tonic-gate static wcrlist_t * 788*7c478bd9Sstevel@tonic-gate srpush(wcrlist_t **wlpp, vnode_t *vp) 789*7c478bd9Sstevel@tonic-gate { 790*7c478bd9Sstevel@tonic-gate wcrlist_t *nwlp; 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&iwscn_lock) || MUTEX_HELD(&iwscn_open_lock)); 793*7c478bd9Sstevel@tonic-gate if ((nwlp = srrm(wlpp, vp, 0)) == NULL) { 794*7c478bd9Sstevel@tonic-gate nwlp = kmem_zalloc(sizeof (*nwlp), KM_SLEEP); 795*7c478bd9Sstevel@tonic-gate nwlp->wl_vp = vp; 796*7c478bd9Sstevel@tonic-gate /* 797*7c478bd9Sstevel@tonic-gate * The hold will prevent underlying device from closing 798*7c478bd9Sstevel@tonic-gate * while this vnode is still on the redirection list. 799*7c478bd9Sstevel@tonic-gate */ 800*7c478bd9Sstevel@tonic-gate VN_HOLD(vp); 801*7c478bd9Sstevel@tonic-gate } 802*7c478bd9Sstevel@tonic-gate nwlp->wl_next = *wlpp; 803*7c478bd9Sstevel@tonic-gate *wlpp = nwlp; 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate return (nwlp); 806*7c478bd9Sstevel@tonic-gate } 807