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 2005 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 * modctl system call for loadable module support. 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/user.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/exec.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/reboot.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/sysconf.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/ddi_implfuncs.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/dc_ki.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/cladm.h> 55*7c478bd9Sstevel@tonic-gate #include <sys/dtrace.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/kdi.h> 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate #include <sys/devpolicy.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 60*7c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 61*7c478bd9Sstevel@tonic-gate #include <sys/devops.h> 62*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 63*7c478bd9Sstevel@tonic-gate #include <sys/hwconf.h> 64*7c478bd9Sstevel@tonic-gate #include <sys/callb.h> 65*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 66*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 67*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 68*7c478bd9Sstevel@tonic-gate #include <sys/sysevent.h> 69*7c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h> 70*7c478bd9Sstevel@tonic-gate #include <sys/instance.h> 71*7c478bd9Sstevel@tonic-gate #include <sys/modhash.h> 72*7c478bd9Sstevel@tonic-gate #include <sys/modhash_impl.h> 73*7c478bd9Sstevel@tonic-gate #include <sys/dacf_impl.h> 74*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 75*7c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 76*7c478bd9Sstevel@tonic-gate #include <sys/console.h> 77*7c478bd9Sstevel@tonic-gate #include <sys/policy.h> 78*7c478bd9Sstevel@tonic-gate #include <ipp/ipp_impl.h> 79*7c478bd9Sstevel@tonic-gate #include <sys/fs/dv_node.h> 80*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate static int mod_circdep(struct modctl *); 83*7c478bd9Sstevel@tonic-gate static int modinfo(modid_t, struct modinfo *); 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate static void mod_uninstall_all(void); 86*7c478bd9Sstevel@tonic-gate static int mod_getinfo(struct modctl *, struct modinfo *); 87*7c478bd9Sstevel@tonic-gate static struct modctl *allocate_modp(char *, char *); 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate static int mod_load(struct modctl *, int); 90*7c478bd9Sstevel@tonic-gate static void mod_unload(struct modctl *); 91*7c478bd9Sstevel@tonic-gate static int modinstall(struct modctl *); 92*7c478bd9Sstevel@tonic-gate static int moduninstall(struct modctl *); 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate static struct modctl *mod_hold_by_name_common(struct modctl *, char *); 95*7c478bd9Sstevel@tonic-gate static struct modctl *mod_hold_by_id(modid_t); 96*7c478bd9Sstevel@tonic-gate static struct modctl *mod_hold_next_by_id(modid_t); 97*7c478bd9Sstevel@tonic-gate static struct modctl *mod_hold_loaded_mod(struct modctl *, char *, int *); 98*7c478bd9Sstevel@tonic-gate static struct modctl *mod_hold_installed_mod(char *, int, int *); 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate static void mod_release(struct modctl *); 101*7c478bd9Sstevel@tonic-gate static void mod_make_requisite(struct modctl *, struct modctl *); 102*7c478bd9Sstevel@tonic-gate static int mod_install_requisites(struct modctl *); 103*7c478bd9Sstevel@tonic-gate static void check_esc_sequences(char *, char *); 104*7c478bd9Sstevel@tonic-gate static struct modctl *mod_hold_by_name_requisite(struct modctl *, char *); 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate /* 107*7c478bd9Sstevel@tonic-gate * module loading thread control structure. Calls to kobj_load_module()() are 108*7c478bd9Sstevel@tonic-gate * handled off to a separate thead using this structure. 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate struct loadmt { 111*7c478bd9Sstevel@tonic-gate ksema_t sema; 112*7c478bd9Sstevel@tonic-gate struct modctl *mp; 113*7c478bd9Sstevel@tonic-gate int usepath; 114*7c478bd9Sstevel@tonic-gate kthread_t *owner; 115*7c478bd9Sstevel@tonic-gate int retval; 116*7c478bd9Sstevel@tonic-gate }; 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate static void modload_thread(struct loadmt *); 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate kcondvar_t mod_cv; 121*7c478bd9Sstevel@tonic-gate kcondvar_t mod_uninstall_cv; /* Communication between swapper */ 122*7c478bd9Sstevel@tonic-gate /* and the uninstall daemon. */ 123*7c478bd9Sstevel@tonic-gate kmutex_t mod_lock; /* protects &modules insert linkage, */ 124*7c478bd9Sstevel@tonic-gate /* mod_busy, mod_want, and mod_ref. */ 125*7c478bd9Sstevel@tonic-gate /* blocking operations while holding */ 126*7c478bd9Sstevel@tonic-gate /* mod_lock should be avoided */ 127*7c478bd9Sstevel@tonic-gate kmutex_t mod_uninstall_lock; /* protects mod_uninstall_cv */ 128*7c478bd9Sstevel@tonic-gate kthread_id_t mod_aul_thread; 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate int isminiroot; /* set if running as miniroot */ 131*7c478bd9Sstevel@tonic-gate int modrootloaded; /* set after root driver and fs are loaded */ 132*7c478bd9Sstevel@tonic-gate int moddebug = 0x0; /* debug flags for module writers */ 133*7c478bd9Sstevel@tonic-gate int swaploaded; /* set after swap driver and fs are loaded */ 134*7c478bd9Sstevel@tonic-gate int bop_io_quiesced = 0; /* set when BOP I/O can no longer be used */ 135*7c478bd9Sstevel@tonic-gate int last_module_id; 136*7c478bd9Sstevel@tonic-gate clock_t mod_uninstall_interval = 0; 137*7c478bd9Sstevel@tonic-gate int ddi_modclose_unload = 1; /* 0 -> just decrement reference */ 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate struct devnames *devnamesp; 140*7c478bd9Sstevel@tonic-gate struct devnames orphanlist; 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate krwlock_t devinfo_tree_lock; /* obsolete, to be removed */ 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate #define MAJBINDFILE "/etc/name_to_major" 145*7c478bd9Sstevel@tonic-gate #define SYSBINDFILE "/etc/name_to_sysnum" 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate static char majbind[] = MAJBINDFILE; 148*7c478bd9Sstevel@tonic-gate static char sysbind[] = SYSBINDFILE; 149*7c478bd9Sstevel@tonic-gate static uint_t mod_autounload_key; /* for module autounload detection */ 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate extern int obpdebug; 152*7c478bd9Sstevel@tonic-gate extern int make_mbind(char *, int, char *, struct bind **); 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate #define DEBUGGER_PRESENT ((boothowto & RB_DEBUG) || (obpdebug != 0)) 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate static int minorperm_loaded = 0; 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate void 161*7c478bd9Sstevel@tonic-gate mod_setup(void) 162*7c478bd9Sstevel@tonic-gate { 163*7c478bd9Sstevel@tonic-gate struct sysent *callp; 164*7c478bd9Sstevel@tonic-gate int callnum, exectype; 165*7c478bd9Sstevel@tonic-gate int num_devs; 166*7c478bd9Sstevel@tonic-gate int i; 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate /* 169*7c478bd9Sstevel@tonic-gate * Initialize the list of loaded driver dev_ops. 170*7c478bd9Sstevel@tonic-gate * XXX - This must be done before reading the system file so that 171*7c478bd9Sstevel@tonic-gate * forceloads of drivers will work. 172*7c478bd9Sstevel@tonic-gate */ 173*7c478bd9Sstevel@tonic-gate num_devs = read_binding_file(majbind, mb_hashtab, make_mbind); 174*7c478bd9Sstevel@tonic-gate /* 175*7c478bd9Sstevel@tonic-gate * Since read_binding_file is common code, it doesn't enforce that all 176*7c478bd9Sstevel@tonic-gate * of the binding file entries have major numbers <= MAXMAJ32. Thus, 177*7c478bd9Sstevel@tonic-gate * ensure that we don't allocate some massive amount of space due to a 178*7c478bd9Sstevel@tonic-gate * bad entry. We can't have major numbers bigger than MAXMAJ32 179*7c478bd9Sstevel@tonic-gate * until file system support for larger major numbers exists. 180*7c478bd9Sstevel@tonic-gate */ 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate /* 183*7c478bd9Sstevel@tonic-gate * Leave space for expansion, but not more than L_MAXMAJ32 184*7c478bd9Sstevel@tonic-gate */ 185*7c478bd9Sstevel@tonic-gate devcnt = MIN(num_devs + 30, L_MAXMAJ32); 186*7c478bd9Sstevel@tonic-gate devopsp = kmem_alloc(devcnt * sizeof (struct dev_ops *), KM_SLEEP); 187*7c478bd9Sstevel@tonic-gate for (i = 0; i < devcnt; i++) 188*7c478bd9Sstevel@tonic-gate devopsp[i] = &mod_nodev_ops; 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate init_devnamesp(devcnt); 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate /* 193*7c478bd9Sstevel@tonic-gate * Sync up with the work that the stand-alone linker has already done. 194*7c478bd9Sstevel@tonic-gate */ 195*7c478bd9Sstevel@tonic-gate (void) kobj_sync(); 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate if (boothowto & RB_DEBUG) 198*7c478bd9Sstevel@tonic-gate kdi_dvec_modavail(); 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate make_aliases(mb_hashtab); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * Initialize streams device implementation structures. 204*7c478bd9Sstevel@tonic-gate */ 205*7c478bd9Sstevel@tonic-gate devimpl = kmem_zalloc(devcnt * sizeof (cdevsw_impl_t), KM_SLEEP); 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate /* 208*7c478bd9Sstevel@tonic-gate * If the cl_bootstrap module is present, 209*7c478bd9Sstevel@tonic-gate * we should be configured as a cluster. Loading this module 210*7c478bd9Sstevel@tonic-gate * will set "cluster_bootflags" to non-zero. 211*7c478bd9Sstevel@tonic-gate */ 212*7c478bd9Sstevel@tonic-gate (void) modload("misc", "cl_bootstrap"); 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate (void) read_binding_file(sysbind, sb_hashtab, make_mbind); 215*7c478bd9Sstevel@tonic-gate init_syscallnames(NSYSCALL); 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* 218*7c478bd9Sstevel@tonic-gate * Start up dynamic autoconfiguration framework (dacf). 219*7c478bd9Sstevel@tonic-gate */ 220*7c478bd9Sstevel@tonic-gate mod_hash_init(); 221*7c478bd9Sstevel@tonic-gate dacf_init(); 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate /* 224*7c478bd9Sstevel@tonic-gate * Start up IP policy framework (ipp). 225*7c478bd9Sstevel@tonic-gate */ 226*7c478bd9Sstevel@tonic-gate ipp_init(); 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate /* 229*7c478bd9Sstevel@tonic-gate * Allocate loadable native system call locks. 230*7c478bd9Sstevel@tonic-gate */ 231*7c478bd9Sstevel@tonic-gate for (callnum = 0, callp = sysent; callnum < NSYSCALL; 232*7c478bd9Sstevel@tonic-gate callnum++, callp++) { 233*7c478bd9Sstevel@tonic-gate if (LOADABLE_SYSCALL(callp)) { 234*7c478bd9Sstevel@tonic-gate if (mod_getsysname(callnum) != NULL) { 235*7c478bd9Sstevel@tonic-gate callp->sy_lock = 236*7c478bd9Sstevel@tonic-gate kobj_zalloc(sizeof (krwlock_t), KM_SLEEP); 237*7c478bd9Sstevel@tonic-gate rw_init(callp->sy_lock, NULL, RW_DEFAULT, NULL); 238*7c478bd9Sstevel@tonic-gate } else { 239*7c478bd9Sstevel@tonic-gate callp->sy_flags &= ~SE_LOADABLE; 240*7c478bd9Sstevel@tonic-gate callp->sy_callc = nosys; 241*7c478bd9Sstevel@tonic-gate } 242*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 243*7c478bd9Sstevel@tonic-gate } else { 244*7c478bd9Sstevel@tonic-gate /* 245*7c478bd9Sstevel@tonic-gate * Do some sanity checks on the sysent table 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate switch (callp->sy_flags & SE_RVAL_MASK) { 248*7c478bd9Sstevel@tonic-gate case SE_32RVAL1: 249*7c478bd9Sstevel@tonic-gate /* only r_val1 returned */ 250*7c478bd9Sstevel@tonic-gate case SE_32RVAL1 | SE_32RVAL2: 251*7c478bd9Sstevel@tonic-gate /* r_val1 and r_val2 returned */ 252*7c478bd9Sstevel@tonic-gate case SE_64RVAL: 253*7c478bd9Sstevel@tonic-gate /* 64-bit rval returned */ 254*7c478bd9Sstevel@tonic-gate break; 255*7c478bd9Sstevel@tonic-gate default: 256*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sysent[%d]: bad flags %x", 257*7c478bd9Sstevel@tonic-gate callnum, callp->sy_flags); 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate #endif 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 264*7c478bd9Sstevel@tonic-gate /* 265*7c478bd9Sstevel@tonic-gate * Allocate loadable system call locks for 32-bit compat syscalls 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate for (callnum = 0, callp = sysent32; callnum < NSYSCALL; 268*7c478bd9Sstevel@tonic-gate callnum++, callp++) { 269*7c478bd9Sstevel@tonic-gate if (LOADABLE_SYSCALL(callp)) { 270*7c478bd9Sstevel@tonic-gate if (mod_getsysname(callnum) != NULL) { 271*7c478bd9Sstevel@tonic-gate callp->sy_lock = 272*7c478bd9Sstevel@tonic-gate kobj_zalloc(sizeof (krwlock_t), KM_SLEEP); 273*7c478bd9Sstevel@tonic-gate rw_init(callp->sy_lock, NULL, RW_DEFAULT, NULL); 274*7c478bd9Sstevel@tonic-gate } else { 275*7c478bd9Sstevel@tonic-gate callp->sy_flags &= ~SE_LOADABLE; 276*7c478bd9Sstevel@tonic-gate callp->sy_callc = nosys; 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 279*7c478bd9Sstevel@tonic-gate } else { 280*7c478bd9Sstevel@tonic-gate /* 281*7c478bd9Sstevel@tonic-gate * Do some sanity checks on the sysent table 282*7c478bd9Sstevel@tonic-gate */ 283*7c478bd9Sstevel@tonic-gate switch (callp->sy_flags & SE_RVAL_MASK) { 284*7c478bd9Sstevel@tonic-gate case SE_32RVAL1: 285*7c478bd9Sstevel@tonic-gate /* only r_val1 returned */ 286*7c478bd9Sstevel@tonic-gate case SE_32RVAL1 | SE_32RVAL2: 287*7c478bd9Sstevel@tonic-gate /* r_val1 and r_val2 returned */ 288*7c478bd9Sstevel@tonic-gate case SE_64RVAL: 289*7c478bd9Sstevel@tonic-gate /* 64-bit rval returned */ 290*7c478bd9Sstevel@tonic-gate break; 291*7c478bd9Sstevel@tonic-gate default: 292*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sysent32[%d]: bad flags %x", 293*7c478bd9Sstevel@tonic-gate callnum, callp->sy_flags); 294*7c478bd9Sstevel@tonic-gate goto skip; 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate /* 298*7c478bd9Sstevel@tonic-gate * Cross-check the native and compatibility tables. 299*7c478bd9Sstevel@tonic-gate */ 300*7c478bd9Sstevel@tonic-gate if (callp->sy_callc == nosys || 301*7c478bd9Sstevel@tonic-gate sysent[callnum].sy_callc == nosys) 302*7c478bd9Sstevel@tonic-gate continue; 303*7c478bd9Sstevel@tonic-gate /* 304*7c478bd9Sstevel@tonic-gate * If only one or the other slot is loadable, then 305*7c478bd9Sstevel@tonic-gate * there's an error -- they should match! 306*7c478bd9Sstevel@tonic-gate */ 307*7c478bd9Sstevel@tonic-gate if ((callp->sy_callc == loadable_syscall) ^ 308*7c478bd9Sstevel@tonic-gate (sysent[callnum].sy_callc == loadable_syscall)) { 309*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sysent[%d] loadable?", 310*7c478bd9Sstevel@tonic-gate callnum); 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate /* 313*7c478bd9Sstevel@tonic-gate * This is more of a heuristic test -- if the 314*7c478bd9Sstevel@tonic-gate * system call returns two values in the 32-bit 315*7c478bd9Sstevel@tonic-gate * world, it should probably return two 32-bit 316*7c478bd9Sstevel@tonic-gate * values in the 64-bit world too. 317*7c478bd9Sstevel@tonic-gate */ 318*7c478bd9Sstevel@tonic-gate if (((callp->sy_flags & SE_32RVAL2) == 0) ^ 319*7c478bd9Sstevel@tonic-gate ((sysent[callnum].sy_flags & SE_32RVAL2) == 0)) { 320*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "sysent[%d] rval2 mismatch!", 321*7c478bd9Sstevel@tonic-gate callnum); 322*7c478bd9Sstevel@tonic-gate } 323*7c478bd9Sstevel@tonic-gate skip:; 324*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate } 327*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate /* 330*7c478bd9Sstevel@tonic-gate * Allocate loadable exec locks. (Assumes all execs are loadable) 331*7c478bd9Sstevel@tonic-gate */ 332*7c478bd9Sstevel@tonic-gate for (exectype = 0; exectype < nexectype; exectype++) { 333*7c478bd9Sstevel@tonic-gate execsw[exectype].exec_lock = 334*7c478bd9Sstevel@tonic-gate kobj_zalloc(sizeof (krwlock_t), KM_SLEEP); 335*7c478bd9Sstevel@tonic-gate rw_init(execsw[exectype].exec_lock, NULL, RW_DEFAULT, NULL); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate read_class_file(); 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate /* init thread specific structure for mod_uninstall_all */ 341*7c478bd9Sstevel@tonic-gate tsd_create(&mod_autounload_key, NULL); 342*7c478bd9Sstevel@tonic-gate } 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate static int 345*7c478bd9Sstevel@tonic-gate modctl_modload(int use_path, char *filename, int *rvp) 346*7c478bd9Sstevel@tonic-gate { 347*7c478bd9Sstevel@tonic-gate struct modctl *modp; 348*7c478bd9Sstevel@tonic-gate int retval = 0; 349*7c478bd9Sstevel@tonic-gate char *filenamep; 350*7c478bd9Sstevel@tonic-gate int modid; 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate filenamep = kmem_zalloc(MOD_MAXPATH, KM_SLEEP); 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate if (copyinstr(filename, filenamep, MOD_MAXPATH, 0)) { 355*7c478bd9Sstevel@tonic-gate retval = EFAULT; 356*7c478bd9Sstevel@tonic-gate goto out; 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate filenamep[MOD_MAXPATH - 1] = 0; 360*7c478bd9Sstevel@tonic-gate modp = mod_hold_installed_mod(filenamep, use_path, &retval); 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate if (modp == NULL) 363*7c478bd9Sstevel@tonic-gate goto out; 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate modp->mod_loadflags |= MOD_NOAUTOUNLOAD; 366*7c478bd9Sstevel@tonic-gate modid = modp->mod_id; 367*7c478bd9Sstevel@tonic-gate mod_release_mod(modp); 368*7c478bd9Sstevel@tonic-gate if (rvp != NULL && copyout(&modid, rvp, sizeof (modid)) != 0) 369*7c478bd9Sstevel@tonic-gate retval = EFAULT; 370*7c478bd9Sstevel@tonic-gate out: 371*7c478bd9Sstevel@tonic-gate kmem_free(filenamep, MOD_MAXPATH); 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate return (retval); 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate static int 377*7c478bd9Sstevel@tonic-gate modctl_modunload(modid_t id) 378*7c478bd9Sstevel@tonic-gate { 379*7c478bd9Sstevel@tonic-gate int rval = 0; 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate if (id == 0) { 382*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 383*7c478bd9Sstevel@tonic-gate /* 384*7c478bd9Sstevel@tonic-gate * Turn on mod_uninstall_daemon 385*7c478bd9Sstevel@tonic-gate */ 386*7c478bd9Sstevel@tonic-gate if (mod_uninstall_interval == 0) { 387*7c478bd9Sstevel@tonic-gate mod_uninstall_interval = 60; 388*7c478bd9Sstevel@tonic-gate modreap(); 389*7c478bd9Sstevel@tonic-gate return (rval); 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate #endif 392*7c478bd9Sstevel@tonic-gate mod_uninstall_all(); 393*7c478bd9Sstevel@tonic-gate } else { 394*7c478bd9Sstevel@tonic-gate (void) devfs_clean(ddi_root_node(), NULL, 0); 395*7c478bd9Sstevel@tonic-gate rval = modunload(id); 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate return (rval); 398*7c478bd9Sstevel@tonic-gate } 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate static int 401*7c478bd9Sstevel@tonic-gate modctl_modinfo(modid_t id, struct modinfo *umodi) 402*7c478bd9Sstevel@tonic-gate { 403*7c478bd9Sstevel@tonic-gate int retval; 404*7c478bd9Sstevel@tonic-gate struct modinfo modi; 405*7c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) 406*7c478bd9Sstevel@tonic-gate int nobase; 407*7c478bd9Sstevel@tonic-gate struct modinfo32 modi32; 408*7c478bd9Sstevel@tonic-gate #endif 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 411*7c478bd9Sstevel@tonic-gate if (copyin(umodi, &modi, sizeof (struct modinfo)) != 0) 412*7c478bd9Sstevel@tonic-gate return (EFAULT); 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 415*7c478bd9Sstevel@tonic-gate else { 416*7c478bd9Sstevel@tonic-gate bzero(&modi, sizeof (modi)); 417*7c478bd9Sstevel@tonic-gate if (copyin(umodi, &modi32, sizeof (struct modinfo32)) != 0) 418*7c478bd9Sstevel@tonic-gate return (EFAULT); 419*7c478bd9Sstevel@tonic-gate modi.mi_info = modi32.mi_info; 420*7c478bd9Sstevel@tonic-gate modi.mi_id = modi32.mi_id; 421*7c478bd9Sstevel@tonic-gate modi.mi_nextid = modi32.mi_nextid; 422*7c478bd9Sstevel@tonic-gate nobase = modi.mi_info & MI_INFO_NOBASE; 423*7c478bd9Sstevel@tonic-gate } 424*7c478bd9Sstevel@tonic-gate #endif 425*7c478bd9Sstevel@tonic-gate /* 426*7c478bd9Sstevel@tonic-gate * This flag is -only- for the kernels use. 427*7c478bd9Sstevel@tonic-gate */ 428*7c478bd9Sstevel@tonic-gate modi.mi_info &= ~MI_INFO_LINKAGE; 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate retval = modinfo(id, &modi); 431*7c478bd9Sstevel@tonic-gate if (retval) 432*7c478bd9Sstevel@tonic-gate return (retval); 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 435*7c478bd9Sstevel@tonic-gate if (copyout(&modi, umodi, sizeof (struct modinfo)) != 0) 436*7c478bd9Sstevel@tonic-gate retval = EFAULT; 437*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 438*7c478bd9Sstevel@tonic-gate } else { 439*7c478bd9Sstevel@tonic-gate int i; 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate if (!nobase && (uintptr_t)modi.mi_base > UINT32_MAX) 442*7c478bd9Sstevel@tonic-gate return (EOVERFLOW); 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate modi32.mi_info = modi.mi_info; 445*7c478bd9Sstevel@tonic-gate modi32.mi_state = modi.mi_state; 446*7c478bd9Sstevel@tonic-gate modi32.mi_id = modi.mi_id; 447*7c478bd9Sstevel@tonic-gate modi32.mi_nextid = modi.mi_nextid; 448*7c478bd9Sstevel@tonic-gate modi32.mi_base = (caddr32_t)(uintptr_t)modi.mi_base; 449*7c478bd9Sstevel@tonic-gate modi32.mi_size = modi.mi_size; 450*7c478bd9Sstevel@tonic-gate modi32.mi_rev = modi.mi_rev; 451*7c478bd9Sstevel@tonic-gate modi32.mi_loadcnt = modi.mi_loadcnt; 452*7c478bd9Sstevel@tonic-gate bcopy(modi.mi_name, modi32.mi_name, sizeof (modi32.mi_name)); 453*7c478bd9Sstevel@tonic-gate for (i = 0; i < MODMAXLINK32; i++) { 454*7c478bd9Sstevel@tonic-gate modi32.mi_msinfo[i].msi_p0 = modi.mi_msinfo[i].msi_p0; 455*7c478bd9Sstevel@tonic-gate bcopy(modi.mi_msinfo[i].msi_linkinfo, 456*7c478bd9Sstevel@tonic-gate modi32.mi_msinfo[i].msi_linkinfo, 457*7c478bd9Sstevel@tonic-gate sizeof (modi32.mi_msinfo[0].msi_linkinfo)); 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate if (copyout(&modi32, umodi, sizeof (struct modinfo32)) != 0) 460*7c478bd9Sstevel@tonic-gate retval = EFAULT; 461*7c478bd9Sstevel@tonic-gate #endif 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate return (retval); 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate /* 468*7c478bd9Sstevel@tonic-gate * Return the last major number in the range of permissible major numbers. 469*7c478bd9Sstevel@tonic-gate */ 470*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 471*7c478bd9Sstevel@tonic-gate static int 472*7c478bd9Sstevel@tonic-gate modctl_modreserve(modid_t id, int *data) 473*7c478bd9Sstevel@tonic-gate { 474*7c478bd9Sstevel@tonic-gate if (copyout(&devcnt, data, sizeof (devcnt)) != 0) 475*7c478bd9Sstevel@tonic-gate return (EFAULT); 476*7c478bd9Sstevel@tonic-gate return (0); 477*7c478bd9Sstevel@tonic-gate } 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate static int 480*7c478bd9Sstevel@tonic-gate modctl_add_major(int *data) 481*7c478bd9Sstevel@tonic-gate { 482*7c478bd9Sstevel@tonic-gate struct modconfig mc; 483*7c478bd9Sstevel@tonic-gate int i, rv; 484*7c478bd9Sstevel@tonic-gate struct aliases alias; 485*7c478bd9Sstevel@tonic-gate struct aliases *ap; 486*7c478bd9Sstevel@tonic-gate char name[MAXMODCONFNAME]; 487*7c478bd9Sstevel@tonic-gate char cname[MAXMODCONFNAME]; 488*7c478bd9Sstevel@tonic-gate char *drvname; 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate bzero(&mc, sizeof (struct modconfig)); 491*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 492*7c478bd9Sstevel@tonic-gate if (copyin(data, &mc, sizeof (struct modconfig)) != 0) 493*7c478bd9Sstevel@tonic-gate return (EFAULT); 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 496*7c478bd9Sstevel@tonic-gate else { 497*7c478bd9Sstevel@tonic-gate struct modconfig32 modc32; 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate if (copyin(data, &modc32, sizeof (struct modconfig32)) != 0) 500*7c478bd9Sstevel@tonic-gate return (EFAULT); 501*7c478bd9Sstevel@tonic-gate else { 502*7c478bd9Sstevel@tonic-gate bcopy(modc32.drvname, mc.drvname, 503*7c478bd9Sstevel@tonic-gate sizeof (modc32.drvname)); 504*7c478bd9Sstevel@tonic-gate bcopy(modc32.drvclass, mc.drvclass, 505*7c478bd9Sstevel@tonic-gate sizeof (modc32.drvclass)); 506*7c478bd9Sstevel@tonic-gate mc.major = modc32.major; 507*7c478bd9Sstevel@tonic-gate mc.num_aliases = modc32.num_aliases; 508*7c478bd9Sstevel@tonic-gate mc.ap = (struct aliases *)(uintptr_t)modc32.ap; 509*7c478bd9Sstevel@tonic-gate } 510*7c478bd9Sstevel@tonic-gate } 511*7c478bd9Sstevel@tonic-gate #endif 512*7c478bd9Sstevel@tonic-gate 513*7c478bd9Sstevel@tonic-gate /* 514*7c478bd9Sstevel@tonic-gate * If the driver is already in the mb_hashtab, and the name given 515*7c478bd9Sstevel@tonic-gate * doesn't match that driver's name, fail. Otherwise, pass, since 516*7c478bd9Sstevel@tonic-gate * we may be adding aliases. 517*7c478bd9Sstevel@tonic-gate */ 518*7c478bd9Sstevel@tonic-gate if ((drvname = mod_major_to_name(mc.major)) != NULL && 519*7c478bd9Sstevel@tonic-gate strcmp(drvname, mc.drvname) != 0) 520*7c478bd9Sstevel@tonic-gate return (EINVAL); 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate /* 523*7c478bd9Sstevel@tonic-gate * Add each supplied driver alias to mb_hashtab 524*7c478bd9Sstevel@tonic-gate */ 525*7c478bd9Sstevel@tonic-gate ap = mc.ap; 526*7c478bd9Sstevel@tonic-gate for (i = 0; i < mc.num_aliases; i++) { 527*7c478bd9Sstevel@tonic-gate bzero(&alias, sizeof (struct aliases)); 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 530*7c478bd9Sstevel@tonic-gate if (copyin(ap, &alias, sizeof (struct aliases)) != 0) 531*7c478bd9Sstevel@tonic-gate return (EFAULT); 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate if (alias.a_len > MAXMODCONFNAME) 534*7c478bd9Sstevel@tonic-gate return (EINVAL); 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate if (copyin(alias.a_name, name, alias.a_len) != 0) 537*7c478bd9Sstevel@tonic-gate return (EFAULT); 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate if (name[alias.a_len - 1] != '\0') 540*7c478bd9Sstevel@tonic-gate return (EINVAL); 541*7c478bd9Sstevel@tonic-gate } 542*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 543*7c478bd9Sstevel@tonic-gate else { 544*7c478bd9Sstevel@tonic-gate struct aliases32 al32; 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate bzero(&al32, sizeof (struct aliases32)); 547*7c478bd9Sstevel@tonic-gate if (copyin(ap, &al32, sizeof (struct aliases32)) != 0) 548*7c478bd9Sstevel@tonic-gate return (EFAULT); 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate if (al32.a_len > MAXMODCONFNAME) 551*7c478bd9Sstevel@tonic-gate return (EINVAL); 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate if (copyin((void *)(uintptr_t)al32.a_name, 554*7c478bd9Sstevel@tonic-gate name, al32.a_len) != 0) 555*7c478bd9Sstevel@tonic-gate return (EFAULT); 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate if (name[al32.a_len - 1] != '\0') 558*7c478bd9Sstevel@tonic-gate return (EINVAL); 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate alias.a_next = (void *)(uintptr_t)al32.a_next; 561*7c478bd9Sstevel@tonic-gate } 562*7c478bd9Sstevel@tonic-gate #endif 563*7c478bd9Sstevel@tonic-gate check_esc_sequences(name, cname); 564*7c478bd9Sstevel@tonic-gate (void) make_mbind(cname, mc.major, NULL, mb_hashtab); 565*7c478bd9Sstevel@tonic-gate ap = alias.a_next; 566*7c478bd9Sstevel@tonic-gate } 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate /* 569*7c478bd9Sstevel@tonic-gate * Try to establish an mbinding for mc.drvname, and add it to devnames. 570*7c478bd9Sstevel@tonic-gate * Add class if any after establishing the major number 571*7c478bd9Sstevel@tonic-gate */ 572*7c478bd9Sstevel@tonic-gate (void) make_mbind(mc.drvname, mc.major, NULL, mb_hashtab); 573*7c478bd9Sstevel@tonic-gate rv = make_devname(mc.drvname, mc.major); 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate if (rv == 0) { 576*7c478bd9Sstevel@tonic-gate if (mc.drvclass[0] != '\0') 577*7c478bd9Sstevel@tonic-gate add_class(mc.drvname, mc.drvclass); 578*7c478bd9Sstevel@tonic-gate (void) i_ddi_load_drvconf(mc.major); 579*7c478bd9Sstevel@tonic-gate i_ddi_bind_devs(); 580*7c478bd9Sstevel@tonic-gate i_ddi_di_cache_invalidate(KM_SLEEP); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate return (rv); 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate static int 586*7c478bd9Sstevel@tonic-gate modctl_rem_major(major_t major) 587*7c478bd9Sstevel@tonic-gate { 588*7c478bd9Sstevel@tonic-gate struct devnames *dnp; 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate if (major >= devcnt) 591*7c478bd9Sstevel@tonic-gate return (EINVAL); 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate /* mark devnames as removed */ 594*7c478bd9Sstevel@tonic-gate dnp = &devnamesp[major]; 595*7c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 596*7c478bd9Sstevel@tonic-gate if (dnp->dn_name == NULL || 597*7c478bd9Sstevel@tonic-gate (dnp->dn_flags & (DN_DRIVER_REMOVED | DN_TAKEN_GETUDEV))) { 598*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 599*7c478bd9Sstevel@tonic-gate return (EINVAL); 600*7c478bd9Sstevel@tonic-gate } 601*7c478bd9Sstevel@tonic-gate dnp->dn_flags |= DN_DRIVER_REMOVED; 602*7c478bd9Sstevel@tonic-gate pm_driver_removed(major); 603*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate (void) i_ddi_unload_drvconf(major); 606*7c478bd9Sstevel@tonic-gate i_ddi_unbind_devs(major); 607*7c478bd9Sstevel@tonic-gate i_ddi_di_cache_invalidate(KM_SLEEP); 608*7c478bd9Sstevel@tonic-gate return (0); 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate static struct vfs * 612*7c478bd9Sstevel@tonic-gate path_to_vfs(char *name) 613*7c478bd9Sstevel@tonic-gate { 614*7c478bd9Sstevel@tonic-gate vnode_t *vp; 615*7c478bd9Sstevel@tonic-gate struct vfs *vfsp; 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate if (lookupname(name, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) 618*7c478bd9Sstevel@tonic-gate return (NULL); 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate vfsp = vp->v_vfsp; 621*7c478bd9Sstevel@tonic-gate VN_RELE(vp); 622*7c478bd9Sstevel@tonic-gate return (vfsp); 623*7c478bd9Sstevel@tonic-gate } 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate static int 626*7c478bd9Sstevel@tonic-gate new_vfs_in_modpath() 627*7c478bd9Sstevel@tonic-gate { 628*7c478bd9Sstevel@tonic-gate static int n_modpath = 0; 629*7c478bd9Sstevel@tonic-gate static char *modpath_copy; 630*7c478bd9Sstevel@tonic-gate static struct pathvfs { 631*7c478bd9Sstevel@tonic-gate char *path; 632*7c478bd9Sstevel@tonic-gate struct vfs *vfsp; 633*7c478bd9Sstevel@tonic-gate } *pathvfs; 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate int i, new_vfs = 0; 636*7c478bd9Sstevel@tonic-gate char *tmp, *tmp1; 637*7c478bd9Sstevel@tonic-gate struct vfs *vfsp; 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate if (n_modpath != 0) { 640*7c478bd9Sstevel@tonic-gate for (i = 0; i < n_modpath; i++) { 641*7c478bd9Sstevel@tonic-gate vfsp = path_to_vfs(pathvfs[i].path); 642*7c478bd9Sstevel@tonic-gate if (vfsp != pathvfs[i].vfsp) { 643*7c478bd9Sstevel@tonic-gate pathvfs[i].vfsp = vfsp; 644*7c478bd9Sstevel@tonic-gate if (vfsp) 645*7c478bd9Sstevel@tonic-gate new_vfs = 1; 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate } 648*7c478bd9Sstevel@tonic-gate return (new_vfs); 649*7c478bd9Sstevel@tonic-gate } 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate /* 652*7c478bd9Sstevel@tonic-gate * First call, initialize the pathvfs structure 653*7c478bd9Sstevel@tonic-gate */ 654*7c478bd9Sstevel@tonic-gate modpath_copy = i_ddi_strdup(default_path, KM_SLEEP); 655*7c478bd9Sstevel@tonic-gate tmp = modpath_copy; 656*7c478bd9Sstevel@tonic-gate n_modpath = 1; 657*7c478bd9Sstevel@tonic-gate tmp1 = strchr(tmp, ' '); 658*7c478bd9Sstevel@tonic-gate while (tmp1) { 659*7c478bd9Sstevel@tonic-gate *tmp1 = '\0'; 660*7c478bd9Sstevel@tonic-gate n_modpath++; 661*7c478bd9Sstevel@tonic-gate tmp = tmp1 + 1; 662*7c478bd9Sstevel@tonic-gate tmp1 = strchr(tmp, ' '); 663*7c478bd9Sstevel@tonic-gate } 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate pathvfs = kmem_zalloc(n_modpath * sizeof (struct pathvfs), KM_SLEEP); 666*7c478bd9Sstevel@tonic-gate tmp = modpath_copy; 667*7c478bd9Sstevel@tonic-gate for (i = 0; i < n_modpath; i++) { 668*7c478bd9Sstevel@tonic-gate pathvfs[i].path = tmp; 669*7c478bd9Sstevel@tonic-gate vfsp = path_to_vfs(tmp); 670*7c478bd9Sstevel@tonic-gate pathvfs[i].vfsp = vfsp; 671*7c478bd9Sstevel@tonic-gate tmp += strlen(tmp) + 1; 672*7c478bd9Sstevel@tonic-gate } 673*7c478bd9Sstevel@tonic-gate return (1); /* always reread driver.conf the first time */ 674*7c478bd9Sstevel@tonic-gate } 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate static int modctl_load_drvconf(major_t major) 677*7c478bd9Sstevel@tonic-gate { 678*7c478bd9Sstevel@tonic-gate int ret; 679*7c478bd9Sstevel@tonic-gate 680*7c478bd9Sstevel@tonic-gate if (major != (major_t)-1) { 681*7c478bd9Sstevel@tonic-gate ret = i_ddi_load_drvconf(major); 682*7c478bd9Sstevel@tonic-gate if (ret == 0) 683*7c478bd9Sstevel@tonic-gate i_ddi_bind_devs(); 684*7c478bd9Sstevel@tonic-gate return (ret); 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate /* 688*7c478bd9Sstevel@tonic-gate * We are invoked to rescan new driver.conf files. It is 689*7c478bd9Sstevel@tonic-gate * only necessary if a new file system was mounted in the 690*7c478bd9Sstevel@tonic-gate * module_path. Because rescanning driver.conf files can 691*7c478bd9Sstevel@tonic-gate * take some time on older platforms (sun4m), the following 692*7c478bd9Sstevel@tonic-gate * code skips unnecessary driver.conf rescans to optimize 693*7c478bd9Sstevel@tonic-gate * boot performance. 694*7c478bd9Sstevel@tonic-gate */ 695*7c478bd9Sstevel@tonic-gate if (new_vfs_in_modpath()) { 696*7c478bd9Sstevel@tonic-gate (void) i_ddi_load_drvconf((major_t)-1); 697*7c478bd9Sstevel@tonic-gate /* 698*7c478bd9Sstevel@tonic-gate * If we are still initializing io subsystem, 699*7c478bd9Sstevel@tonic-gate * load drivers with ddi-forceattach property 700*7c478bd9Sstevel@tonic-gate */ 701*7c478bd9Sstevel@tonic-gate if (!i_ddi_io_initialized()) 702*7c478bd9Sstevel@tonic-gate i_ddi_forceattach_drivers(); 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate return (0); 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate static int 708*7c478bd9Sstevel@tonic-gate modctl_unload_drvconf(major_t major) 709*7c478bd9Sstevel@tonic-gate { 710*7c478bd9Sstevel@tonic-gate int ret; 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate if (major >= devcnt) 713*7c478bd9Sstevel@tonic-gate return (EINVAL); 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate ret = i_ddi_unload_drvconf(major); 716*7c478bd9Sstevel@tonic-gate if (ret != 0) 717*7c478bd9Sstevel@tonic-gate return (ret); 718*7c478bd9Sstevel@tonic-gate (void) i_ddi_unbind_devs(major); 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate return (0); 721*7c478bd9Sstevel@tonic-gate } 722*7c478bd9Sstevel@tonic-gate 723*7c478bd9Sstevel@tonic-gate static void 724*7c478bd9Sstevel@tonic-gate check_esc_sequences(char *str, char *cstr) 725*7c478bd9Sstevel@tonic-gate { 726*7c478bd9Sstevel@tonic-gate int i; 727*7c478bd9Sstevel@tonic-gate size_t len; 728*7c478bd9Sstevel@tonic-gate char *p; 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate len = strlen(str); 731*7c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++, str++, cstr++) { 732*7c478bd9Sstevel@tonic-gate if (*str != '\\') { 733*7c478bd9Sstevel@tonic-gate *cstr = *str; 734*7c478bd9Sstevel@tonic-gate } else { 735*7c478bd9Sstevel@tonic-gate p = str + 1; 736*7c478bd9Sstevel@tonic-gate /* 737*7c478bd9Sstevel@tonic-gate * we only handle octal escape sequences for SPACE 738*7c478bd9Sstevel@tonic-gate */ 739*7c478bd9Sstevel@tonic-gate if (*p++ == '0' && *p++ == '4' && *p == '0') { 740*7c478bd9Sstevel@tonic-gate *cstr = ' '; 741*7c478bd9Sstevel@tonic-gate str += 3; 742*7c478bd9Sstevel@tonic-gate } else { 743*7c478bd9Sstevel@tonic-gate *cstr = *str; 744*7c478bd9Sstevel@tonic-gate } 745*7c478bd9Sstevel@tonic-gate } 746*7c478bd9Sstevel@tonic-gate } 747*7c478bd9Sstevel@tonic-gate *cstr = 0; 748*7c478bd9Sstevel@tonic-gate } 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate static int 751*7c478bd9Sstevel@tonic-gate modctl_getmodpathlen(int *data) 752*7c478bd9Sstevel@tonic-gate { 753*7c478bd9Sstevel@tonic-gate int len; 754*7c478bd9Sstevel@tonic-gate len = strlen(default_path); 755*7c478bd9Sstevel@tonic-gate if (copyout(&len, data, sizeof (len)) != 0) 756*7c478bd9Sstevel@tonic-gate return (EFAULT); 757*7c478bd9Sstevel@tonic-gate return (0); 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate static int 761*7c478bd9Sstevel@tonic-gate modctl_getmodpath(char *data) 762*7c478bd9Sstevel@tonic-gate { 763*7c478bd9Sstevel@tonic-gate if (copyout(default_path, data, strlen(default_path) + 1) != 0) 764*7c478bd9Sstevel@tonic-gate return (EFAULT); 765*7c478bd9Sstevel@tonic-gate return (0); 766*7c478bd9Sstevel@tonic-gate } 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate static int 769*7c478bd9Sstevel@tonic-gate modctl_read_sysbinding_file(void) 770*7c478bd9Sstevel@tonic-gate { 771*7c478bd9Sstevel@tonic-gate (void) read_binding_file(sysbind, sb_hashtab, make_mbind); 772*7c478bd9Sstevel@tonic-gate return (0); 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate static int 776*7c478bd9Sstevel@tonic-gate modctl_getmaj(char *uname, uint_t ulen, int *umajorp) 777*7c478bd9Sstevel@tonic-gate { 778*7c478bd9Sstevel@tonic-gate char name[256]; 779*7c478bd9Sstevel@tonic-gate int retval; 780*7c478bd9Sstevel@tonic-gate major_t major; 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate if ((retval = copyinstr(uname, name, 783*7c478bd9Sstevel@tonic-gate (ulen < 256) ? ulen : 256, 0)) != 0) 784*7c478bd9Sstevel@tonic-gate return (retval); 785*7c478bd9Sstevel@tonic-gate if ((major = mod_name_to_major(name)) == (major_t)-1) 786*7c478bd9Sstevel@tonic-gate return (ENODEV); 787*7c478bd9Sstevel@tonic-gate if (copyout(&major, umajorp, sizeof (major_t)) != 0) 788*7c478bd9Sstevel@tonic-gate return (EFAULT); 789*7c478bd9Sstevel@tonic-gate return (0); 790*7c478bd9Sstevel@tonic-gate } 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate static int 793*7c478bd9Sstevel@tonic-gate modctl_getname(char *uname, uint_t ulen, int *umajorp) 794*7c478bd9Sstevel@tonic-gate { 795*7c478bd9Sstevel@tonic-gate char *name; 796*7c478bd9Sstevel@tonic-gate major_t major; 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate if (copyin(umajorp, &major, sizeof (major)) != 0) 799*7c478bd9Sstevel@tonic-gate return (EFAULT); 800*7c478bd9Sstevel@tonic-gate if ((name = mod_major_to_name(major)) == NULL) 801*7c478bd9Sstevel@tonic-gate return (ENODEV); 802*7c478bd9Sstevel@tonic-gate if ((strlen(name) + 1) > ulen) 803*7c478bd9Sstevel@tonic-gate return (ENOSPC); 804*7c478bd9Sstevel@tonic-gate return (copyoutstr(name, uname, ulen, NULL)); 805*7c478bd9Sstevel@tonic-gate } 806*7c478bd9Sstevel@tonic-gate 807*7c478bd9Sstevel@tonic-gate static int 808*7c478bd9Sstevel@tonic-gate modctl_devt2instance(dev_t dev, int *uinstancep) 809*7c478bd9Sstevel@tonic-gate { 810*7c478bd9Sstevel@tonic-gate int instance; 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate if ((instance = dev_to_instance(dev)) == -1) 813*7c478bd9Sstevel@tonic-gate return (EINVAL); 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate return (copyout(&instance, uinstancep, sizeof (int))); 816*7c478bd9Sstevel@tonic-gate } 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate /* 819*7c478bd9Sstevel@tonic-gate * Return the sizeof of the device id. 820*7c478bd9Sstevel@tonic-gate */ 821*7c478bd9Sstevel@tonic-gate static int 822*7c478bd9Sstevel@tonic-gate modctl_sizeof_devid(dev_t dev, uint_t *len) 823*7c478bd9Sstevel@tonic-gate { 824*7c478bd9Sstevel@tonic-gate uint_t sz; 825*7c478bd9Sstevel@tonic-gate ddi_devid_t devid; 826*7c478bd9Sstevel@tonic-gate 827*7c478bd9Sstevel@tonic-gate /* get device id */ 828*7c478bd9Sstevel@tonic-gate if (ddi_lyr_get_devid(dev, &devid) == DDI_FAILURE) 829*7c478bd9Sstevel@tonic-gate return (EINVAL); 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate sz = ddi_devid_sizeof(devid); 832*7c478bd9Sstevel@tonic-gate ddi_devid_free(devid); 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate /* copyout device id size */ 835*7c478bd9Sstevel@tonic-gate if (copyout(&sz, len, sizeof (sz)) != 0) 836*7c478bd9Sstevel@tonic-gate return (EFAULT); 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate return (0); 839*7c478bd9Sstevel@tonic-gate } 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate /* 842*7c478bd9Sstevel@tonic-gate * Return a copy of the device id. 843*7c478bd9Sstevel@tonic-gate */ 844*7c478bd9Sstevel@tonic-gate static int 845*7c478bd9Sstevel@tonic-gate modctl_get_devid(dev_t dev, uint_t len, ddi_devid_t udevid) 846*7c478bd9Sstevel@tonic-gate { 847*7c478bd9Sstevel@tonic-gate uint_t sz; 848*7c478bd9Sstevel@tonic-gate ddi_devid_t devid; 849*7c478bd9Sstevel@tonic-gate int err = 0; 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate /* get device id */ 852*7c478bd9Sstevel@tonic-gate if (ddi_lyr_get_devid(dev, &devid) == DDI_FAILURE) 853*7c478bd9Sstevel@tonic-gate return (EINVAL); 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate sz = ddi_devid_sizeof(devid); 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate /* Error if device id is larger than space allocated */ 858*7c478bd9Sstevel@tonic-gate if (sz > len) { 859*7c478bd9Sstevel@tonic-gate ddi_devid_free(devid); 860*7c478bd9Sstevel@tonic-gate return (ENOSPC); 861*7c478bd9Sstevel@tonic-gate } 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate /* copy out device id */ 864*7c478bd9Sstevel@tonic-gate if (copyout(devid, udevid, sz) != 0) 865*7c478bd9Sstevel@tonic-gate err = EFAULT; 866*7c478bd9Sstevel@tonic-gate ddi_devid_free(devid); 867*7c478bd9Sstevel@tonic-gate return (err); 868*7c478bd9Sstevel@tonic-gate } 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate /* 871*7c478bd9Sstevel@tonic-gate * return the /devices paths associated with the specified devid and 872*7c478bd9Sstevel@tonic-gate * minor name. 873*7c478bd9Sstevel@tonic-gate */ 874*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 875*7c478bd9Sstevel@tonic-gate static int 876*7c478bd9Sstevel@tonic-gate modctl_devid2paths(ddi_devid_t udevid, char *uminor_name, uint_t flag, 877*7c478bd9Sstevel@tonic-gate size_t *ulensp, char *upaths) 878*7c478bd9Sstevel@tonic-gate { 879*7c478bd9Sstevel@tonic-gate ddi_devid_t devid = NULL; 880*7c478bd9Sstevel@tonic-gate int devid_len; 881*7c478bd9Sstevel@tonic-gate char *minor_name = NULL; 882*7c478bd9Sstevel@tonic-gate dev_info_t *dip = NULL; 883*7c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmdp; 884*7c478bd9Sstevel@tonic-gate char *path = NULL; 885*7c478bd9Sstevel@tonic-gate int ulens; 886*7c478bd9Sstevel@tonic-gate int lens; 887*7c478bd9Sstevel@tonic-gate int len; 888*7c478bd9Sstevel@tonic-gate dev_t *devlist = NULL; 889*7c478bd9Sstevel@tonic-gate int ndevs; 890*7c478bd9Sstevel@tonic-gate int i; 891*7c478bd9Sstevel@tonic-gate int ret = 0; 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate /* 894*7c478bd9Sstevel@tonic-gate * If upaths is NULL then we are only computing the amount of space 895*7c478bd9Sstevel@tonic-gate * needed to hold the paths and returning the value in *ulensp. If we 896*7c478bd9Sstevel@tonic-gate * are copying out paths then we get the amount of space allocated by 897*7c478bd9Sstevel@tonic-gate * the caller. If the actual space needed for paths is larger, or 898*7c478bd9Sstevel@tonic-gate * things are changing out from under us, then we return EAGAIN. 899*7c478bd9Sstevel@tonic-gate */ 900*7c478bd9Sstevel@tonic-gate if (upaths) { 901*7c478bd9Sstevel@tonic-gate if (ulensp == NULL) 902*7c478bd9Sstevel@tonic-gate return (EINVAL); 903*7c478bd9Sstevel@tonic-gate if (copyin(ulensp, &ulens, sizeof (ulens)) != 0) 904*7c478bd9Sstevel@tonic-gate return (EFAULT); 905*7c478bd9Sstevel@tonic-gate } 906*7c478bd9Sstevel@tonic-gate 907*7c478bd9Sstevel@tonic-gate /* 908*7c478bd9Sstevel@tonic-gate * copyin enough of the devid to determine the length then 909*7c478bd9Sstevel@tonic-gate * reallocate and copy in the entire devid. 910*7c478bd9Sstevel@tonic-gate */ 911*7c478bd9Sstevel@tonic-gate devid_len = ddi_devid_sizeof(NULL); 912*7c478bd9Sstevel@tonic-gate devid = kmem_alloc(devid_len, KM_SLEEP); 913*7c478bd9Sstevel@tonic-gate if (copyin(udevid, devid, devid_len)) { 914*7c478bd9Sstevel@tonic-gate ret = EFAULT; 915*7c478bd9Sstevel@tonic-gate goto out; 916*7c478bd9Sstevel@tonic-gate } 917*7c478bd9Sstevel@tonic-gate len = devid_len; 918*7c478bd9Sstevel@tonic-gate devid_len = ddi_devid_sizeof(devid); 919*7c478bd9Sstevel@tonic-gate kmem_free(devid, len); 920*7c478bd9Sstevel@tonic-gate devid = kmem_alloc(devid_len, KM_SLEEP); 921*7c478bd9Sstevel@tonic-gate if (copyin(udevid, devid, devid_len)) { 922*7c478bd9Sstevel@tonic-gate ret = EFAULT; 923*7c478bd9Sstevel@tonic-gate goto out; 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate /* copyin the minor name if specified. */ 927*7c478bd9Sstevel@tonic-gate minor_name = uminor_name; 928*7c478bd9Sstevel@tonic-gate if ((minor_name != DEVID_MINOR_NAME_ALL) && 929*7c478bd9Sstevel@tonic-gate (minor_name != DEVID_MINOR_NAME_ALL_CHR) && 930*7c478bd9Sstevel@tonic-gate (minor_name != DEVID_MINOR_NAME_ALL_BLK)) { 931*7c478bd9Sstevel@tonic-gate minor_name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 932*7c478bd9Sstevel@tonic-gate if (copyinstr(uminor_name, minor_name, MAXPATHLEN, 0)) { 933*7c478bd9Sstevel@tonic-gate ret = EFAULT; 934*7c478bd9Sstevel@tonic-gate goto out; 935*7c478bd9Sstevel@tonic-gate } 936*7c478bd9Sstevel@tonic-gate } 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate /* 939*7c478bd9Sstevel@tonic-gate * Use existing function to resolve the devid into a devlist. 940*7c478bd9Sstevel@tonic-gate * 941*7c478bd9Sstevel@tonic-gate * NOTE: there is a loss of spectype information in the current 942*7c478bd9Sstevel@tonic-gate * ddi_lyr_devid_to_devlist implementation. We work around this by not 943*7c478bd9Sstevel@tonic-gate * passing down DEVID_MINOR_NAME_ALL here, but reproducing all minor 944*7c478bd9Sstevel@tonic-gate * node forms in the loop processing the devlist below. It would be 945*7c478bd9Sstevel@tonic-gate * best if at some point the use of this interface here was replaced 946*7c478bd9Sstevel@tonic-gate * with a path oriented call. 947*7c478bd9Sstevel@tonic-gate */ 948*7c478bd9Sstevel@tonic-gate if (ddi_lyr_devid_to_devlist(devid, 949*7c478bd9Sstevel@tonic-gate (minor_name == DEVID_MINOR_NAME_ALL) ? 950*7c478bd9Sstevel@tonic-gate DEVID_MINOR_NAME_ALL_CHR : minor_name, 951*7c478bd9Sstevel@tonic-gate &ndevs, &devlist) != DDI_SUCCESS) { 952*7c478bd9Sstevel@tonic-gate ret = EINVAL; 953*7c478bd9Sstevel@tonic-gate goto out; 954*7c478bd9Sstevel@tonic-gate } 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate /* 957*7c478bd9Sstevel@tonic-gate * loop over the devlist, converting each devt to a path and doing 958*7c478bd9Sstevel@tonic-gate * a copyout of the path and computation of the amount of space 959*7c478bd9Sstevel@tonic-gate * needed to hold all the paths 960*7c478bd9Sstevel@tonic-gate */ 961*7c478bd9Sstevel@tonic-gate path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 962*7c478bd9Sstevel@tonic-gate for (i = 0, lens = 0; i < ndevs; i++) { 963*7c478bd9Sstevel@tonic-gate 964*7c478bd9Sstevel@tonic-gate /* find the dip associated with the dev_t */ 965*7c478bd9Sstevel@tonic-gate if ((dip = e_ddi_hold_devi_by_dev(devlist[i], 0)) == NULL) 966*7c478bd9Sstevel@tonic-gate continue; 967*7c478bd9Sstevel@tonic-gate 968*7c478bd9Sstevel@tonic-gate /* loop over all the minor nodes, skipping ones we don't want */ 969*7c478bd9Sstevel@tonic-gate for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) { 970*7c478bd9Sstevel@tonic-gate if ((dmdp->ddm_dev != devlist[i]) || 971*7c478bd9Sstevel@tonic-gate (dmdp->type != DDM_MINOR)) 972*7c478bd9Sstevel@tonic-gate continue; 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate if ((minor_name != DEVID_MINOR_NAME_ALL) && 975*7c478bd9Sstevel@tonic-gate (minor_name != DEVID_MINOR_NAME_ALL_CHR) && 976*7c478bd9Sstevel@tonic-gate (minor_name != DEVID_MINOR_NAME_ALL_BLK) && 977*7c478bd9Sstevel@tonic-gate strcmp(minor_name, dmdp->ddm_name)) 978*7c478bd9Sstevel@tonic-gate continue; 979*7c478bd9Sstevel@tonic-gate else { 980*7c478bd9Sstevel@tonic-gate if ((minor_name == DEVID_MINOR_NAME_ALL_CHR) && 981*7c478bd9Sstevel@tonic-gate (dmdp->ddm_spec_type != S_IFCHR)) 982*7c478bd9Sstevel@tonic-gate continue; 983*7c478bd9Sstevel@tonic-gate if ((minor_name == DEVID_MINOR_NAME_ALL_BLK) && 984*7c478bd9Sstevel@tonic-gate (dmdp->ddm_spec_type != S_IFBLK)) 985*7c478bd9Sstevel@tonic-gate continue; 986*7c478bd9Sstevel@tonic-gate } 987*7c478bd9Sstevel@tonic-gate 988*7c478bd9Sstevel@tonic-gate /* XXX need ddi_pathname_minor(dmdp, path); interface */ 989*7c478bd9Sstevel@tonic-gate if (ddi_dev_pathname(dmdp->ddm_dev, dmdp->ddm_spec_type, 990*7c478bd9Sstevel@tonic-gate path) != DDI_SUCCESS) { 991*7c478bd9Sstevel@tonic-gate ret = EAGAIN; 992*7c478bd9Sstevel@tonic-gate goto out; 993*7c478bd9Sstevel@tonic-gate } 994*7c478bd9Sstevel@tonic-gate len = strlen(path) + 1; 995*7c478bd9Sstevel@tonic-gate *(path + len) = '\0'; /* set double termination */ 996*7c478bd9Sstevel@tonic-gate lens += len; 997*7c478bd9Sstevel@tonic-gate 998*7c478bd9Sstevel@tonic-gate /* copyout the path with double terminations */ 999*7c478bd9Sstevel@tonic-gate if (upaths) { 1000*7c478bd9Sstevel@tonic-gate if (lens > ulens) { 1001*7c478bd9Sstevel@tonic-gate ret = EAGAIN; 1002*7c478bd9Sstevel@tonic-gate goto out; 1003*7c478bd9Sstevel@tonic-gate } 1004*7c478bd9Sstevel@tonic-gate if (copyout(path, upaths, len + 1)) { 1005*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1006*7c478bd9Sstevel@tonic-gate goto out; 1007*7c478bd9Sstevel@tonic-gate } 1008*7c478bd9Sstevel@tonic-gate upaths += len; 1009*7c478bd9Sstevel@tonic-gate } 1010*7c478bd9Sstevel@tonic-gate } 1011*7c478bd9Sstevel@tonic-gate ddi_release_devi(dip); 1012*7c478bd9Sstevel@tonic-gate dip = NULL; 1013*7c478bd9Sstevel@tonic-gate } 1014*7c478bd9Sstevel@tonic-gate lens++; /* add one for double termination */ 1015*7c478bd9Sstevel@tonic-gate 1016*7c478bd9Sstevel@tonic-gate /* copy out the amount of space needed to hold the paths */ 1017*7c478bd9Sstevel@tonic-gate if (ulensp && copyout(&lens, ulensp, sizeof (lens))) { 1018*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1019*7c478bd9Sstevel@tonic-gate goto out; 1020*7c478bd9Sstevel@tonic-gate } 1021*7c478bd9Sstevel@tonic-gate ret = 0; 1022*7c478bd9Sstevel@tonic-gate 1023*7c478bd9Sstevel@tonic-gate out: if (dip) 1024*7c478bd9Sstevel@tonic-gate ddi_release_devi(dip); 1025*7c478bd9Sstevel@tonic-gate if (path) 1026*7c478bd9Sstevel@tonic-gate kmem_free(path, MAXPATHLEN); 1027*7c478bd9Sstevel@tonic-gate if (devlist) 1028*7c478bd9Sstevel@tonic-gate ddi_lyr_free_devlist(devlist, ndevs); 1029*7c478bd9Sstevel@tonic-gate if (minor_name && 1030*7c478bd9Sstevel@tonic-gate (minor_name != DEVID_MINOR_NAME_ALL) && 1031*7c478bd9Sstevel@tonic-gate (minor_name != DEVID_MINOR_NAME_ALL_CHR) && 1032*7c478bd9Sstevel@tonic-gate (minor_name != DEVID_MINOR_NAME_ALL_BLK)) 1033*7c478bd9Sstevel@tonic-gate kmem_free(minor_name, MAXPATHLEN); 1034*7c478bd9Sstevel@tonic-gate if (devid) 1035*7c478bd9Sstevel@tonic-gate kmem_free(devid, devid_len); 1036*7c478bd9Sstevel@tonic-gate return (ret); 1037*7c478bd9Sstevel@tonic-gate } 1038*7c478bd9Sstevel@tonic-gate 1039*7c478bd9Sstevel@tonic-gate /* 1040*7c478bd9Sstevel@tonic-gate * Return the size of the minor name. 1041*7c478bd9Sstevel@tonic-gate */ 1042*7c478bd9Sstevel@tonic-gate static int 1043*7c478bd9Sstevel@tonic-gate modctl_sizeof_minorname(dev_t dev, int spectype, uint_t *len) 1044*7c478bd9Sstevel@tonic-gate { 1045*7c478bd9Sstevel@tonic-gate uint_t sz; 1046*7c478bd9Sstevel@tonic-gate char *name; 1047*7c478bd9Sstevel@tonic-gate 1048*7c478bd9Sstevel@tonic-gate /* get the minor name */ 1049*7c478bd9Sstevel@tonic-gate if (ddi_lyr_get_minor_name(dev, spectype, &name) == DDI_FAILURE) 1050*7c478bd9Sstevel@tonic-gate return (EINVAL); 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate sz = strlen(name) + 1; 1053*7c478bd9Sstevel@tonic-gate kmem_free(name, sz); 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate /* copy out the size of the minor name */ 1056*7c478bd9Sstevel@tonic-gate if (copyout(&sz, len, sizeof (sz)) != 0) 1057*7c478bd9Sstevel@tonic-gate return (EFAULT); 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate return (0); 1060*7c478bd9Sstevel@tonic-gate } 1061*7c478bd9Sstevel@tonic-gate 1062*7c478bd9Sstevel@tonic-gate /* 1063*7c478bd9Sstevel@tonic-gate * Return the minor name. 1064*7c478bd9Sstevel@tonic-gate */ 1065*7c478bd9Sstevel@tonic-gate static int 1066*7c478bd9Sstevel@tonic-gate modctl_get_minorname(dev_t dev, int spectype, uint_t len, char *uname) 1067*7c478bd9Sstevel@tonic-gate { 1068*7c478bd9Sstevel@tonic-gate uint_t sz; 1069*7c478bd9Sstevel@tonic-gate char *name; 1070*7c478bd9Sstevel@tonic-gate int err = 0; 1071*7c478bd9Sstevel@tonic-gate 1072*7c478bd9Sstevel@tonic-gate /* get the minor name */ 1073*7c478bd9Sstevel@tonic-gate if (ddi_lyr_get_minor_name(dev, spectype, &name) == DDI_FAILURE) 1074*7c478bd9Sstevel@tonic-gate return (EINVAL); 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate sz = strlen(name) + 1; 1077*7c478bd9Sstevel@tonic-gate 1078*7c478bd9Sstevel@tonic-gate /* Error if the minor name is larger than the space allocated */ 1079*7c478bd9Sstevel@tonic-gate if (sz > len) { 1080*7c478bd9Sstevel@tonic-gate kmem_free(name, sz); 1081*7c478bd9Sstevel@tonic-gate return (ENOSPC); 1082*7c478bd9Sstevel@tonic-gate } 1083*7c478bd9Sstevel@tonic-gate 1084*7c478bd9Sstevel@tonic-gate /* copy out the minor name */ 1085*7c478bd9Sstevel@tonic-gate if (copyout(name, uname, sz) != 0) 1086*7c478bd9Sstevel@tonic-gate err = EFAULT; 1087*7c478bd9Sstevel@tonic-gate kmem_free(name, sz); 1088*7c478bd9Sstevel@tonic-gate return (err); 1089*7c478bd9Sstevel@tonic-gate } 1090*7c478bd9Sstevel@tonic-gate 1091*7c478bd9Sstevel@tonic-gate /* 1092*7c478bd9Sstevel@tonic-gate * Return the size of the devfspath name. 1093*7c478bd9Sstevel@tonic-gate */ 1094*7c478bd9Sstevel@tonic-gate static int 1095*7c478bd9Sstevel@tonic-gate modctl_devfspath_len(dev_t dev, int spectype, uint_t *len) 1096*7c478bd9Sstevel@tonic-gate { 1097*7c478bd9Sstevel@tonic-gate uint_t sz; 1098*7c478bd9Sstevel@tonic-gate char *name; 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate /* get the path name */ 1101*7c478bd9Sstevel@tonic-gate name = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1102*7c478bd9Sstevel@tonic-gate if (ddi_dev_pathname(dev, spectype, name) == DDI_FAILURE) { 1103*7c478bd9Sstevel@tonic-gate kmem_free(name, MAXPATHLEN); 1104*7c478bd9Sstevel@tonic-gate return (EINVAL); 1105*7c478bd9Sstevel@tonic-gate } 1106*7c478bd9Sstevel@tonic-gate 1107*7c478bd9Sstevel@tonic-gate sz = strlen(name) + 1; 1108*7c478bd9Sstevel@tonic-gate kmem_free(name, MAXPATHLEN); 1109*7c478bd9Sstevel@tonic-gate 1110*7c478bd9Sstevel@tonic-gate /* copy out the size of the path name */ 1111*7c478bd9Sstevel@tonic-gate if (copyout(&sz, len, sizeof (sz)) != 0) 1112*7c478bd9Sstevel@tonic-gate return (EFAULT); 1113*7c478bd9Sstevel@tonic-gate 1114*7c478bd9Sstevel@tonic-gate return (0); 1115*7c478bd9Sstevel@tonic-gate } 1116*7c478bd9Sstevel@tonic-gate 1117*7c478bd9Sstevel@tonic-gate /* 1118*7c478bd9Sstevel@tonic-gate * Return the devfspath name. 1119*7c478bd9Sstevel@tonic-gate */ 1120*7c478bd9Sstevel@tonic-gate static int 1121*7c478bd9Sstevel@tonic-gate modctl_devfspath(dev_t dev, int spectype, uint_t len, char *uname) 1122*7c478bd9Sstevel@tonic-gate { 1123*7c478bd9Sstevel@tonic-gate uint_t sz; 1124*7c478bd9Sstevel@tonic-gate char *name; 1125*7c478bd9Sstevel@tonic-gate int err = 0; 1126*7c478bd9Sstevel@tonic-gate 1127*7c478bd9Sstevel@tonic-gate /* get the path name */ 1128*7c478bd9Sstevel@tonic-gate name = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1129*7c478bd9Sstevel@tonic-gate if (ddi_dev_pathname(dev, spectype, name) == DDI_FAILURE) { 1130*7c478bd9Sstevel@tonic-gate kmem_free(name, MAXPATHLEN); 1131*7c478bd9Sstevel@tonic-gate return (EINVAL); 1132*7c478bd9Sstevel@tonic-gate } 1133*7c478bd9Sstevel@tonic-gate 1134*7c478bd9Sstevel@tonic-gate sz = strlen(name) + 1; 1135*7c478bd9Sstevel@tonic-gate 1136*7c478bd9Sstevel@tonic-gate /* Error if the path name is larger than the space allocated */ 1137*7c478bd9Sstevel@tonic-gate if (sz > len) { 1138*7c478bd9Sstevel@tonic-gate kmem_free(name, MAXPATHLEN); 1139*7c478bd9Sstevel@tonic-gate return (ENOSPC); 1140*7c478bd9Sstevel@tonic-gate } 1141*7c478bd9Sstevel@tonic-gate 1142*7c478bd9Sstevel@tonic-gate /* copy out the path name */ 1143*7c478bd9Sstevel@tonic-gate if (copyout(name, uname, sz) != 0) 1144*7c478bd9Sstevel@tonic-gate err = EFAULT; 1145*7c478bd9Sstevel@tonic-gate kmem_free(name, MAXPATHLEN); 1146*7c478bd9Sstevel@tonic-gate return (err); 1147*7c478bd9Sstevel@tonic-gate } 1148*7c478bd9Sstevel@tonic-gate 1149*7c478bd9Sstevel@tonic-gate static int 1150*7c478bd9Sstevel@tonic-gate modctl_get_fbname(char *path) 1151*7c478bd9Sstevel@tonic-gate { 1152*7c478bd9Sstevel@tonic-gate extern dev_t fbdev; 1153*7c478bd9Sstevel@tonic-gate char *pathname = NULL; 1154*7c478bd9Sstevel@tonic-gate int rval = 0; 1155*7c478bd9Sstevel@tonic-gate 1156*7c478bd9Sstevel@tonic-gate /* make sure fbdev is set before we plunge in */ 1157*7c478bd9Sstevel@tonic-gate if (fbdev == NODEV) 1158*7c478bd9Sstevel@tonic-gate return (ENODEV); 1159*7c478bd9Sstevel@tonic-gate 1160*7c478bd9Sstevel@tonic-gate pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1161*7c478bd9Sstevel@tonic-gate if ((rval = ddi_dev_pathname(fbdev, S_IFCHR, 1162*7c478bd9Sstevel@tonic-gate pathname)) == DDI_SUCCESS) { 1163*7c478bd9Sstevel@tonic-gate if (copyout(pathname, path, strlen(pathname)+1) != 0) { 1164*7c478bd9Sstevel@tonic-gate rval = EFAULT; 1165*7c478bd9Sstevel@tonic-gate } 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate kmem_free(pathname, MAXPATHLEN); 1168*7c478bd9Sstevel@tonic-gate return (rval); 1169*7c478bd9Sstevel@tonic-gate } 1170*7c478bd9Sstevel@tonic-gate 1171*7c478bd9Sstevel@tonic-gate /* 1172*7c478bd9Sstevel@tonic-gate * modctl_reread_dacf() 1173*7c478bd9Sstevel@tonic-gate * Reread the dacf rules database from the named binding file. 1174*7c478bd9Sstevel@tonic-gate * If NULL is specified, pass along the NULL, it means 'use the default'. 1175*7c478bd9Sstevel@tonic-gate */ 1176*7c478bd9Sstevel@tonic-gate static int 1177*7c478bd9Sstevel@tonic-gate modctl_reread_dacf(char *path) 1178*7c478bd9Sstevel@tonic-gate { 1179*7c478bd9Sstevel@tonic-gate int rval = 0; 1180*7c478bd9Sstevel@tonic-gate char *filename, *filenamep; 1181*7c478bd9Sstevel@tonic-gate 1182*7c478bd9Sstevel@tonic-gate filename = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1183*7c478bd9Sstevel@tonic-gate 1184*7c478bd9Sstevel@tonic-gate if (path == NULL) { 1185*7c478bd9Sstevel@tonic-gate filenamep = NULL; 1186*7c478bd9Sstevel@tonic-gate } else { 1187*7c478bd9Sstevel@tonic-gate if (copyinstr(path, filename, MAXPATHLEN, 0) != 0) { 1188*7c478bd9Sstevel@tonic-gate rval = EFAULT; 1189*7c478bd9Sstevel@tonic-gate goto out; 1190*7c478bd9Sstevel@tonic-gate } 1191*7c478bd9Sstevel@tonic-gate filenamep = filename; 1192*7c478bd9Sstevel@tonic-gate filenamep[MAXPATHLEN - 1] = '\0'; 1193*7c478bd9Sstevel@tonic-gate } 1194*7c478bd9Sstevel@tonic-gate 1195*7c478bd9Sstevel@tonic-gate rval = read_dacf_binding_file(filenamep); 1196*7c478bd9Sstevel@tonic-gate out: 1197*7c478bd9Sstevel@tonic-gate kmem_free(filename, MAXPATHLEN); 1198*7c478bd9Sstevel@tonic-gate return (rval); 1199*7c478bd9Sstevel@tonic-gate } 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1202*7c478bd9Sstevel@tonic-gate static int 1203*7c478bd9Sstevel@tonic-gate modctl_modevents(int subcmd, uintptr_t a2, uintptr_t a3, uintptr_t a4, 1204*7c478bd9Sstevel@tonic-gate uint_t flag) 1205*7c478bd9Sstevel@tonic-gate { 1206*7c478bd9Sstevel@tonic-gate int error = 0; 1207*7c478bd9Sstevel@tonic-gate char *filenamep; 1208*7c478bd9Sstevel@tonic-gate 1209*7c478bd9Sstevel@tonic-gate switch (subcmd) { 1210*7c478bd9Sstevel@tonic-gate 1211*7c478bd9Sstevel@tonic-gate case MODEVENTS_FLUSH: 1212*7c478bd9Sstevel@tonic-gate /* flush all currently queued events */ 1213*7c478bd9Sstevel@tonic-gate log_sysevent_flushq(subcmd, flag); 1214*7c478bd9Sstevel@tonic-gate break; 1215*7c478bd9Sstevel@tonic-gate 1216*7c478bd9Sstevel@tonic-gate case MODEVENTS_SET_DOOR_UPCALL_FILENAME: 1217*7c478bd9Sstevel@tonic-gate /* 1218*7c478bd9Sstevel@tonic-gate * bind door_upcall to filename 1219*7c478bd9Sstevel@tonic-gate * this should only be done once per invocation 1220*7c478bd9Sstevel@tonic-gate * of the event daemon. 1221*7c478bd9Sstevel@tonic-gate */ 1222*7c478bd9Sstevel@tonic-gate 1223*7c478bd9Sstevel@tonic-gate filenamep = kmem_zalloc(MOD_MAXPATH, KM_SLEEP); 1224*7c478bd9Sstevel@tonic-gate 1225*7c478bd9Sstevel@tonic-gate if (copyinstr((char *)a2, filenamep, MOD_MAXPATH, 0)) { 1226*7c478bd9Sstevel@tonic-gate error = EFAULT; 1227*7c478bd9Sstevel@tonic-gate } else { 1228*7c478bd9Sstevel@tonic-gate error = log_sysevent_filename(filenamep); 1229*7c478bd9Sstevel@tonic-gate } 1230*7c478bd9Sstevel@tonic-gate kmem_free(filenamep, MOD_MAXPATH); 1231*7c478bd9Sstevel@tonic-gate break; 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate case MODEVENTS_GETDATA: 1234*7c478bd9Sstevel@tonic-gate error = log_sysevent_copyout_data((sysevent_id_t *)a2, 1235*7c478bd9Sstevel@tonic-gate (size_t)a3, (caddr_t)a4); 1236*7c478bd9Sstevel@tonic-gate break; 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate case MODEVENTS_FREEDATA: 1239*7c478bd9Sstevel@tonic-gate error = log_sysevent_free_data((sysevent_id_t *)a2); 1240*7c478bd9Sstevel@tonic-gate break; 1241*7c478bd9Sstevel@tonic-gate case MODEVENTS_POST_EVENT: 1242*7c478bd9Sstevel@tonic-gate error = log_usr_sysevent((sysevent_t *)a2, (uint32_t)a3, 1243*7c478bd9Sstevel@tonic-gate (sysevent_id_t *)a4); 1244*7c478bd9Sstevel@tonic-gate break; 1245*7c478bd9Sstevel@tonic-gate case MODEVENTS_REGISTER_EVENT: 1246*7c478bd9Sstevel@tonic-gate error = log_sysevent_register((char *)a2, (char *)a3, 1247*7c478bd9Sstevel@tonic-gate (se_pubsub_t *)a4); 1248*7c478bd9Sstevel@tonic-gate break; 1249*7c478bd9Sstevel@tonic-gate default: 1250*7c478bd9Sstevel@tonic-gate error = EINVAL; 1251*7c478bd9Sstevel@tonic-gate } 1252*7c478bd9Sstevel@tonic-gate 1253*7c478bd9Sstevel@tonic-gate return (error); 1254*7c478bd9Sstevel@tonic-gate } 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate static void 1257*7c478bd9Sstevel@tonic-gate free_mperm(mperm_t *mp) 1258*7c478bd9Sstevel@tonic-gate { 1259*7c478bd9Sstevel@tonic-gate int len; 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate if (mp->mp_minorname) { 1262*7c478bd9Sstevel@tonic-gate len = strlen(mp->mp_minorname) + 1; 1263*7c478bd9Sstevel@tonic-gate kmem_free(mp->mp_minorname, len); 1264*7c478bd9Sstevel@tonic-gate } 1265*7c478bd9Sstevel@tonic-gate kmem_free(mp, sizeof (mperm_t)); 1266*7c478bd9Sstevel@tonic-gate } 1267*7c478bd9Sstevel@tonic-gate 1268*7c478bd9Sstevel@tonic-gate #define MP_NO_DRV_ERR \ 1269*7c478bd9Sstevel@tonic-gate "/etc/minor_perm: no driver for %s\n" 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate #define MP_EMPTY_MINOR \ 1272*7c478bd9Sstevel@tonic-gate "/etc/minor_perm: empty minor name for driver %s\n" 1273*7c478bd9Sstevel@tonic-gate 1274*7c478bd9Sstevel@tonic-gate #define MP_NO_MINOR \ 1275*7c478bd9Sstevel@tonic-gate "/etc/minor_perm: no minor matching %s for driver %s\n" 1276*7c478bd9Sstevel@tonic-gate 1277*7c478bd9Sstevel@tonic-gate /* 1278*7c478bd9Sstevel@tonic-gate * Remove mperm entry with matching minorname 1279*7c478bd9Sstevel@tonic-gate */ 1280*7c478bd9Sstevel@tonic-gate static void 1281*7c478bd9Sstevel@tonic-gate rem_minorperm(major_t major, char *drvname, mperm_t *mp, int is_clone) 1282*7c478bd9Sstevel@tonic-gate { 1283*7c478bd9Sstevel@tonic-gate mperm_t **mp_head; 1284*7c478bd9Sstevel@tonic-gate mperm_t *freemp = NULL; 1285*7c478bd9Sstevel@tonic-gate struct devnames *dnp = &devnamesp[major]; 1286*7c478bd9Sstevel@tonic-gate mperm_t **wildmp; 1287*7c478bd9Sstevel@tonic-gate 1288*7c478bd9Sstevel@tonic-gate ASSERT(mp->mp_minorname && strlen(mp->mp_minorname) > 0); 1289*7c478bd9Sstevel@tonic-gate 1290*7c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 1291*7c478bd9Sstevel@tonic-gate if (strcmp(mp->mp_minorname, "*") == 0) { 1292*7c478bd9Sstevel@tonic-gate wildmp = ((is_clone == 0) ? 1293*7c478bd9Sstevel@tonic-gate &dnp->dn_mperm_wild : &dnp->dn_mperm_clone); 1294*7c478bd9Sstevel@tonic-gate if (*wildmp) 1295*7c478bd9Sstevel@tonic-gate freemp = *wildmp; 1296*7c478bd9Sstevel@tonic-gate *wildmp = NULL; 1297*7c478bd9Sstevel@tonic-gate } else { 1298*7c478bd9Sstevel@tonic-gate mp_head = &dnp->dn_mperm; 1299*7c478bd9Sstevel@tonic-gate while (*mp_head) { 1300*7c478bd9Sstevel@tonic-gate if (strcmp((*mp_head)->mp_minorname, 1301*7c478bd9Sstevel@tonic-gate mp->mp_minorname) != 0) { 1302*7c478bd9Sstevel@tonic-gate mp_head = &(*mp_head)->mp_next; 1303*7c478bd9Sstevel@tonic-gate continue; 1304*7c478bd9Sstevel@tonic-gate } 1305*7c478bd9Sstevel@tonic-gate /* remove the entry */ 1306*7c478bd9Sstevel@tonic-gate freemp = *mp_head; 1307*7c478bd9Sstevel@tonic-gate *mp_head = freemp->mp_next; 1308*7c478bd9Sstevel@tonic-gate break; 1309*7c478bd9Sstevel@tonic-gate } 1310*7c478bd9Sstevel@tonic-gate } 1311*7c478bd9Sstevel@tonic-gate if (freemp) { 1312*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MINORPERM) { 1313*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "< %s %s 0%o %d %d\n", 1314*7c478bd9Sstevel@tonic-gate drvname, freemp->mp_minorname, 1315*7c478bd9Sstevel@tonic-gate freemp->mp_mode & 0777, 1316*7c478bd9Sstevel@tonic-gate freemp->mp_uid, freemp->mp_gid); 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate free_mperm(freemp); 1319*7c478bd9Sstevel@tonic-gate } else { 1320*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MINORPERM) { 1321*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, MP_NO_MINOR, 1322*7c478bd9Sstevel@tonic-gate drvname, mp->mp_minorname); 1323*7c478bd9Sstevel@tonic-gate } 1324*7c478bd9Sstevel@tonic-gate } 1325*7c478bd9Sstevel@tonic-gate 1326*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 1327*7c478bd9Sstevel@tonic-gate } 1328*7c478bd9Sstevel@tonic-gate 1329*7c478bd9Sstevel@tonic-gate /* 1330*7c478bd9Sstevel@tonic-gate * Add minor perm entry 1331*7c478bd9Sstevel@tonic-gate */ 1332*7c478bd9Sstevel@tonic-gate static void 1333*7c478bd9Sstevel@tonic-gate add_minorperm(major_t major, char *drvname, mperm_t *mp, int is_clone) 1334*7c478bd9Sstevel@tonic-gate { 1335*7c478bd9Sstevel@tonic-gate mperm_t **mp_head; 1336*7c478bd9Sstevel@tonic-gate mperm_t *freemp = NULL; 1337*7c478bd9Sstevel@tonic-gate struct devnames *dnp = &devnamesp[major]; 1338*7c478bd9Sstevel@tonic-gate mperm_t **wildmp; 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate ASSERT(mp->mp_minorname && strlen(mp->mp_minorname) > 0); 1341*7c478bd9Sstevel@tonic-gate 1342*7c478bd9Sstevel@tonic-gate /* 1343*7c478bd9Sstevel@tonic-gate * Note that update_drv replace semantics require 1344*7c478bd9Sstevel@tonic-gate * replacing matching entries with the new permissions. 1345*7c478bd9Sstevel@tonic-gate */ 1346*7c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 1347*7c478bd9Sstevel@tonic-gate if (strcmp(mp->mp_minorname, "*") == 0) { 1348*7c478bd9Sstevel@tonic-gate wildmp = ((is_clone == 0) ? 1349*7c478bd9Sstevel@tonic-gate &dnp->dn_mperm_wild : &dnp->dn_mperm_clone); 1350*7c478bd9Sstevel@tonic-gate if (*wildmp) 1351*7c478bd9Sstevel@tonic-gate freemp = *wildmp; 1352*7c478bd9Sstevel@tonic-gate *wildmp = mp; 1353*7c478bd9Sstevel@tonic-gate } else { 1354*7c478bd9Sstevel@tonic-gate mperm_t *p, *v = NULL; 1355*7c478bd9Sstevel@tonic-gate for (p = dnp->dn_mperm; p; v = p, p = p->mp_next) { 1356*7c478bd9Sstevel@tonic-gate if (strcmp(p->mp_minorname, mp->mp_minorname) == 0) { 1357*7c478bd9Sstevel@tonic-gate if (v == NULL) 1358*7c478bd9Sstevel@tonic-gate dnp->dn_mperm = mp; 1359*7c478bd9Sstevel@tonic-gate else 1360*7c478bd9Sstevel@tonic-gate v->mp_next = mp; 1361*7c478bd9Sstevel@tonic-gate mp->mp_next = p->mp_next; 1362*7c478bd9Sstevel@tonic-gate freemp = p; 1363*7c478bd9Sstevel@tonic-gate goto replaced; 1364*7c478bd9Sstevel@tonic-gate } 1365*7c478bd9Sstevel@tonic-gate } 1366*7c478bd9Sstevel@tonic-gate if (p == NULL) { 1367*7c478bd9Sstevel@tonic-gate mp_head = &dnp->dn_mperm; 1368*7c478bd9Sstevel@tonic-gate if (*mp_head == NULL) { 1369*7c478bd9Sstevel@tonic-gate *mp_head = mp; 1370*7c478bd9Sstevel@tonic-gate } else { 1371*7c478bd9Sstevel@tonic-gate mp->mp_next = *mp_head; 1372*7c478bd9Sstevel@tonic-gate *mp_head = mp; 1373*7c478bd9Sstevel@tonic-gate } 1374*7c478bd9Sstevel@tonic-gate } 1375*7c478bd9Sstevel@tonic-gate } 1376*7c478bd9Sstevel@tonic-gate replaced: 1377*7c478bd9Sstevel@tonic-gate if (freemp) { 1378*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MINORPERM) { 1379*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "< %s %s 0%o %d %d\n", 1380*7c478bd9Sstevel@tonic-gate drvname, freemp->mp_minorname, 1381*7c478bd9Sstevel@tonic-gate freemp->mp_mode & 0777, 1382*7c478bd9Sstevel@tonic-gate freemp->mp_uid, freemp->mp_gid); 1383*7c478bd9Sstevel@tonic-gate } 1384*7c478bd9Sstevel@tonic-gate free_mperm(freemp); 1385*7c478bd9Sstevel@tonic-gate } 1386*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MINORPERM) { 1387*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "> %s %s 0%o %d %d\n", 1388*7c478bd9Sstevel@tonic-gate drvname, mp->mp_minorname, mp->mp_mode & 0777, 1389*7c478bd9Sstevel@tonic-gate mp->mp_uid, mp->mp_gid); 1390*7c478bd9Sstevel@tonic-gate } 1391*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 1392*7c478bd9Sstevel@tonic-gate } 1393*7c478bd9Sstevel@tonic-gate 1394*7c478bd9Sstevel@tonic-gate 1395*7c478bd9Sstevel@tonic-gate static int 1396*7c478bd9Sstevel@tonic-gate process_minorperm(int cmd, nvlist_t *nvl) 1397*7c478bd9Sstevel@tonic-gate { 1398*7c478bd9Sstevel@tonic-gate char *minor; 1399*7c478bd9Sstevel@tonic-gate major_t major; 1400*7c478bd9Sstevel@tonic-gate mperm_t *mp; 1401*7c478bd9Sstevel@tonic-gate nvpair_t *nvp; 1402*7c478bd9Sstevel@tonic-gate char *name; 1403*7c478bd9Sstevel@tonic-gate int is_clone; 1404*7c478bd9Sstevel@tonic-gate major_t minmaj; 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate ASSERT(cmd == MODLOADMINORPERM || 1407*7c478bd9Sstevel@tonic-gate cmd == MODADDMINORPERM || cmd == MODREMMINORPERM); 1408*7c478bd9Sstevel@tonic-gate 1409*7c478bd9Sstevel@tonic-gate nvp = NULL; 1410*7c478bd9Sstevel@tonic-gate while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 1411*7c478bd9Sstevel@tonic-gate name = nvpair_name(nvp); 1412*7c478bd9Sstevel@tonic-gate 1413*7c478bd9Sstevel@tonic-gate is_clone = 0; 1414*7c478bd9Sstevel@tonic-gate (void) nvpair_value_string(nvp, &minor); 1415*7c478bd9Sstevel@tonic-gate major = ddi_name_to_major(name); 1416*7c478bd9Sstevel@tonic-gate if (major != (major_t)-1) { 1417*7c478bd9Sstevel@tonic-gate mp = kmem_zalloc(sizeof (*mp), KM_SLEEP); 1418*7c478bd9Sstevel@tonic-gate if (minor == NULL || strlen(minor) == 0) { 1419*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MINORPERM) { 1420*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, MP_EMPTY_MINOR, name); 1421*7c478bd9Sstevel@tonic-gate } 1422*7c478bd9Sstevel@tonic-gate minor = "*"; 1423*7c478bd9Sstevel@tonic-gate } 1424*7c478bd9Sstevel@tonic-gate 1425*7c478bd9Sstevel@tonic-gate /* 1426*7c478bd9Sstevel@tonic-gate * The minor name of a node using the clone 1427*7c478bd9Sstevel@tonic-gate * driver must be the driver name. To avoid 1428*7c478bd9Sstevel@tonic-gate * multiple searches, we map entries in the form 1429*7c478bd9Sstevel@tonic-gate * clone:<driver> to <driver>:*. This also allows us 1430*7c478bd9Sstevel@tonic-gate * to filter out some of the litter in /etc/minor_perm. 1431*7c478bd9Sstevel@tonic-gate * Minor perm alias entries where the name is not 1432*7c478bd9Sstevel@tonic-gate * the driver kept on the clone list itself. 1433*7c478bd9Sstevel@tonic-gate * This all seems very fragile as a driver could 1434*7c478bd9Sstevel@tonic-gate * be introduced with an existing alias name. 1435*7c478bd9Sstevel@tonic-gate */ 1436*7c478bd9Sstevel@tonic-gate if (strcmp(name, "clone") == 0) { 1437*7c478bd9Sstevel@tonic-gate minmaj = ddi_name_to_major(minor); 1438*7c478bd9Sstevel@tonic-gate if (minmaj != (major_t)-1) { 1439*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MINORPERM) { 1440*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 1441*7c478bd9Sstevel@tonic-gate "mapping %s:%s to %s:*\n", 1442*7c478bd9Sstevel@tonic-gate name, minor, minor); 1443*7c478bd9Sstevel@tonic-gate } 1444*7c478bd9Sstevel@tonic-gate major = minmaj; 1445*7c478bd9Sstevel@tonic-gate name = minor; 1446*7c478bd9Sstevel@tonic-gate minor = "*"; 1447*7c478bd9Sstevel@tonic-gate is_clone = 1; 1448*7c478bd9Sstevel@tonic-gate } 1449*7c478bd9Sstevel@tonic-gate } 1450*7c478bd9Sstevel@tonic-gate 1451*7c478bd9Sstevel@tonic-gate if (mp) { 1452*7c478bd9Sstevel@tonic-gate mp->mp_minorname = 1453*7c478bd9Sstevel@tonic-gate i_ddi_strdup(minor, KM_SLEEP); 1454*7c478bd9Sstevel@tonic-gate } 1455*7c478bd9Sstevel@tonic-gate } else { 1456*7c478bd9Sstevel@tonic-gate mp = NULL; 1457*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MINORPERM) { 1458*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, MP_NO_DRV_ERR, name); 1459*7c478bd9Sstevel@tonic-gate } 1460*7c478bd9Sstevel@tonic-gate } 1461*7c478bd9Sstevel@tonic-gate 1462*7c478bd9Sstevel@tonic-gate /* mode */ 1463*7c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(nvl, nvp); 1464*7c478bd9Sstevel@tonic-gate ASSERT(strcmp(nvpair_name(nvp), "mode") == 0); 1465*7c478bd9Sstevel@tonic-gate if (mp) 1466*7c478bd9Sstevel@tonic-gate (void) nvpair_value_int32(nvp, (int *)&mp->mp_mode); 1467*7c478bd9Sstevel@tonic-gate /* uid */ 1468*7c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(nvl, nvp); 1469*7c478bd9Sstevel@tonic-gate ASSERT(strcmp(nvpair_name(nvp), "uid") == 0); 1470*7c478bd9Sstevel@tonic-gate if (mp) 1471*7c478bd9Sstevel@tonic-gate (void) nvpair_value_int32(nvp, &mp->mp_uid); 1472*7c478bd9Sstevel@tonic-gate /* gid */ 1473*7c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(nvl, nvp); 1474*7c478bd9Sstevel@tonic-gate ASSERT(strcmp(nvpair_name(nvp), "gid") == 0); 1475*7c478bd9Sstevel@tonic-gate if (mp) { 1476*7c478bd9Sstevel@tonic-gate (void) nvpair_value_int32(nvp, &mp->mp_gid); 1477*7c478bd9Sstevel@tonic-gate 1478*7c478bd9Sstevel@tonic-gate if (cmd == MODREMMINORPERM) { 1479*7c478bd9Sstevel@tonic-gate rem_minorperm(major, name, mp, is_clone); 1480*7c478bd9Sstevel@tonic-gate free_mperm(mp); 1481*7c478bd9Sstevel@tonic-gate } else { 1482*7c478bd9Sstevel@tonic-gate add_minorperm(major, name, mp, is_clone); 1483*7c478bd9Sstevel@tonic-gate } 1484*7c478bd9Sstevel@tonic-gate } 1485*7c478bd9Sstevel@tonic-gate } 1486*7c478bd9Sstevel@tonic-gate 1487*7c478bd9Sstevel@tonic-gate if (cmd == MODLOADMINORPERM) 1488*7c478bd9Sstevel@tonic-gate minorperm_loaded = 1; 1489*7c478bd9Sstevel@tonic-gate 1490*7c478bd9Sstevel@tonic-gate /* 1491*7c478bd9Sstevel@tonic-gate * Reset permissions of cached dv_nodes 1492*7c478bd9Sstevel@tonic-gate */ 1493*7c478bd9Sstevel@tonic-gate (void) devfs_reset_perm(DV_RESET_PERM); 1494*7c478bd9Sstevel@tonic-gate 1495*7c478bd9Sstevel@tonic-gate return (0); 1496*7c478bd9Sstevel@tonic-gate } 1497*7c478bd9Sstevel@tonic-gate 1498*7c478bd9Sstevel@tonic-gate static int 1499*7c478bd9Sstevel@tonic-gate modctl_minorperm(int cmd, char *usrbuf, size_t buflen) 1500*7c478bd9Sstevel@tonic-gate { 1501*7c478bd9Sstevel@tonic-gate int error; 1502*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 1503*7c478bd9Sstevel@tonic-gate char *buf = kmem_alloc(buflen, KM_SLEEP); 1504*7c478bd9Sstevel@tonic-gate 1505*7c478bd9Sstevel@tonic-gate if ((error = ddi_copyin(usrbuf, buf, buflen, 0)) != 0) { 1506*7c478bd9Sstevel@tonic-gate kmem_free(buf, buflen); 1507*7c478bd9Sstevel@tonic-gate return (error); 1508*7c478bd9Sstevel@tonic-gate } 1509*7c478bd9Sstevel@tonic-gate 1510*7c478bd9Sstevel@tonic-gate error = nvlist_unpack(buf, buflen, &nvl, KM_SLEEP); 1511*7c478bd9Sstevel@tonic-gate kmem_free(buf, buflen); 1512*7c478bd9Sstevel@tonic-gate if (error) 1513*7c478bd9Sstevel@tonic-gate return (error); 1514*7c478bd9Sstevel@tonic-gate 1515*7c478bd9Sstevel@tonic-gate error = process_minorperm(cmd, nvl); 1516*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 1517*7c478bd9Sstevel@tonic-gate return (error); 1518*7c478bd9Sstevel@tonic-gate } 1519*7c478bd9Sstevel@tonic-gate 1520*7c478bd9Sstevel@tonic-gate struct walk_args { 1521*7c478bd9Sstevel@tonic-gate char *wa_drvname; 1522*7c478bd9Sstevel@tonic-gate list_t wa_pathlist; 1523*7c478bd9Sstevel@tonic-gate }; 1524*7c478bd9Sstevel@tonic-gate 1525*7c478bd9Sstevel@tonic-gate struct path_elem { 1526*7c478bd9Sstevel@tonic-gate char *pe_dir; 1527*7c478bd9Sstevel@tonic-gate char *pe_nodename; 1528*7c478bd9Sstevel@tonic-gate list_node_t pe_node; 1529*7c478bd9Sstevel@tonic-gate int pe_dirlen; 1530*7c478bd9Sstevel@tonic-gate }; 1531*7c478bd9Sstevel@tonic-gate 1532*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1533*7c478bd9Sstevel@tonic-gate static int 1534*7c478bd9Sstevel@tonic-gate modctl_inst_walker(const char *path, in_node_t *np, in_drv_t *dp, void *arg) 1535*7c478bd9Sstevel@tonic-gate { 1536*7c478bd9Sstevel@tonic-gate struct walk_args *wargs = (struct walk_args *)arg; 1537*7c478bd9Sstevel@tonic-gate struct path_elem *pe; 1538*7c478bd9Sstevel@tonic-gate char *nodename; 1539*7c478bd9Sstevel@tonic-gate 1540*7c478bd9Sstevel@tonic-gate if (strcmp(dp->ind_driver_name, wargs->wa_drvname) != 0) 1541*7c478bd9Sstevel@tonic-gate return (INST_WALK_CONTINUE); 1542*7c478bd9Sstevel@tonic-gate 1543*7c478bd9Sstevel@tonic-gate pe = kmem_zalloc(sizeof (*pe), KM_SLEEP); 1544*7c478bd9Sstevel@tonic-gate pe->pe_dir = i_ddi_strdup((char *)path, KM_SLEEP); 1545*7c478bd9Sstevel@tonic-gate pe->pe_dirlen = strlen(pe->pe_dir) + 1; 1546*7c478bd9Sstevel@tonic-gate ASSERT(strrchr(pe->pe_dir, '/') != NULL); 1547*7c478bd9Sstevel@tonic-gate nodename = strrchr(pe->pe_dir, '/'); 1548*7c478bd9Sstevel@tonic-gate *nodename++ = 0; 1549*7c478bd9Sstevel@tonic-gate pe->pe_nodename = nodename; 1550*7c478bd9Sstevel@tonic-gate list_insert_tail(&wargs->wa_pathlist, pe); 1551*7c478bd9Sstevel@tonic-gate 1552*7c478bd9Sstevel@tonic-gate return (INST_WALK_CONTINUE); 1553*7c478bd9Sstevel@tonic-gate } 1554*7c478bd9Sstevel@tonic-gate 1555*7c478bd9Sstevel@tonic-gate static int 1556*7c478bd9Sstevel@tonic-gate modctl_remdrv_cleanup(const char *u_drvname) 1557*7c478bd9Sstevel@tonic-gate { 1558*7c478bd9Sstevel@tonic-gate struct walk_args *wargs; 1559*7c478bd9Sstevel@tonic-gate struct path_elem *pe; 1560*7c478bd9Sstevel@tonic-gate char *drvname; 1561*7c478bd9Sstevel@tonic-gate int err, rval = 0; 1562*7c478bd9Sstevel@tonic-gate 1563*7c478bd9Sstevel@tonic-gate drvname = kmem_alloc(MAXMODCONFNAME, KM_SLEEP); 1564*7c478bd9Sstevel@tonic-gate if ((err = copyinstr(u_drvname, drvname, MAXMODCONFNAME, 0))) { 1565*7c478bd9Sstevel@tonic-gate kmem_free(drvname, MAXMODCONFNAME); 1566*7c478bd9Sstevel@tonic-gate return (err); 1567*7c478bd9Sstevel@tonic-gate } 1568*7c478bd9Sstevel@tonic-gate 1569*7c478bd9Sstevel@tonic-gate /* 1570*7c478bd9Sstevel@tonic-gate * First go through the instance database. For each 1571*7c478bd9Sstevel@tonic-gate * instance of a device bound to the driver being 1572*7c478bd9Sstevel@tonic-gate * removed, remove any underlying devfs attribute nodes. 1573*7c478bd9Sstevel@tonic-gate * 1574*7c478bd9Sstevel@tonic-gate * This is a two-step process. First we go through 1575*7c478bd9Sstevel@tonic-gate * the instance data itself, constructing a list of 1576*7c478bd9Sstevel@tonic-gate * the nodes discovered. The second step is then 1577*7c478bd9Sstevel@tonic-gate * to find and remove any devfs attribute nodes 1578*7c478bd9Sstevel@tonic-gate * for the instances discovered in the first step. 1579*7c478bd9Sstevel@tonic-gate * The two-step process avoids any difficulties 1580*7c478bd9Sstevel@tonic-gate * which could arise by holding the instance data 1581*7c478bd9Sstevel@tonic-gate * lock with simultaneous devfs operations. 1582*7c478bd9Sstevel@tonic-gate */ 1583*7c478bd9Sstevel@tonic-gate wargs = kmem_zalloc(sizeof (*wargs), KM_SLEEP); 1584*7c478bd9Sstevel@tonic-gate 1585*7c478bd9Sstevel@tonic-gate wargs->wa_drvname = drvname; 1586*7c478bd9Sstevel@tonic-gate list_create(&wargs->wa_pathlist, 1587*7c478bd9Sstevel@tonic-gate sizeof (struct path_elem), offsetof(struct path_elem, pe_node)); 1588*7c478bd9Sstevel@tonic-gate 1589*7c478bd9Sstevel@tonic-gate (void) e_ddi_walk_instances(modctl_inst_walker, (void *)wargs); 1590*7c478bd9Sstevel@tonic-gate 1591*7c478bd9Sstevel@tonic-gate for (pe = list_head(&wargs->wa_pathlist); pe != NULL; 1592*7c478bd9Sstevel@tonic-gate pe = list_next(&wargs->wa_pathlist, pe)) { 1593*7c478bd9Sstevel@tonic-gate err = devfs_remdrv_cleanup((const char *)pe->pe_dir, 1594*7c478bd9Sstevel@tonic-gate (const char *)pe->pe_nodename); 1595*7c478bd9Sstevel@tonic-gate if (rval == 0) 1596*7c478bd9Sstevel@tonic-gate rval = err; 1597*7c478bd9Sstevel@tonic-gate } 1598*7c478bd9Sstevel@tonic-gate 1599*7c478bd9Sstevel@tonic-gate while ((pe = list_head(&wargs->wa_pathlist)) != NULL) { 1600*7c478bd9Sstevel@tonic-gate list_remove(&wargs->wa_pathlist, pe); 1601*7c478bd9Sstevel@tonic-gate kmem_free(pe->pe_dir, pe->pe_dirlen); 1602*7c478bd9Sstevel@tonic-gate kmem_free(pe, sizeof (*pe)); 1603*7c478bd9Sstevel@tonic-gate } 1604*7c478bd9Sstevel@tonic-gate kmem_free(wargs, sizeof (*wargs)); 1605*7c478bd9Sstevel@tonic-gate 1606*7c478bd9Sstevel@tonic-gate /* 1607*7c478bd9Sstevel@tonic-gate * Pseudo nodes aren't recorded in the instance database 1608*7c478bd9Sstevel@tonic-gate * so any such nodes need to be handled separately. 1609*7c478bd9Sstevel@tonic-gate */ 1610*7c478bd9Sstevel@tonic-gate err = devfs_remdrv_cleanup("pseudo", (const char *)drvname); 1611*7c478bd9Sstevel@tonic-gate if (rval == 0) 1612*7c478bd9Sstevel@tonic-gate rval = err; 1613*7c478bd9Sstevel@tonic-gate 1614*7c478bd9Sstevel@tonic-gate kmem_free(drvname, MAXMODCONFNAME); 1615*7c478bd9Sstevel@tonic-gate return (rval); 1616*7c478bd9Sstevel@tonic-gate } 1617*7c478bd9Sstevel@tonic-gate 1618*7c478bd9Sstevel@tonic-gate static int 1619*7c478bd9Sstevel@tonic-gate modctl_allocpriv(const char *name) 1620*7c478bd9Sstevel@tonic-gate { 1621*7c478bd9Sstevel@tonic-gate char *pstr = kmem_alloc(PRIVNAME_MAX, KM_SLEEP); 1622*7c478bd9Sstevel@tonic-gate int error; 1623*7c478bd9Sstevel@tonic-gate 1624*7c478bd9Sstevel@tonic-gate if ((error = copyinstr(name, pstr, PRIVNAME_MAX, 0))) { 1625*7c478bd9Sstevel@tonic-gate kmem_free(pstr, PRIVNAME_MAX); 1626*7c478bd9Sstevel@tonic-gate return (error); 1627*7c478bd9Sstevel@tonic-gate } 1628*7c478bd9Sstevel@tonic-gate error = priv_getbyname(pstr, PRIV_ALLOC); 1629*7c478bd9Sstevel@tonic-gate if (error < 0) 1630*7c478bd9Sstevel@tonic-gate error = -error; 1631*7c478bd9Sstevel@tonic-gate else 1632*7c478bd9Sstevel@tonic-gate error = 0; 1633*7c478bd9Sstevel@tonic-gate kmem_free(pstr, PRIVNAME_MAX); 1634*7c478bd9Sstevel@tonic-gate return (error); 1635*7c478bd9Sstevel@tonic-gate } 1636*7c478bd9Sstevel@tonic-gate 1637*7c478bd9Sstevel@tonic-gate /*ARGSUSED5*/ 1638*7c478bd9Sstevel@tonic-gate int 1639*7c478bd9Sstevel@tonic-gate modctl(int cmd, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, 1640*7c478bd9Sstevel@tonic-gate uintptr_t a5) 1641*7c478bd9Sstevel@tonic-gate { 1642*7c478bd9Sstevel@tonic-gate int error = EINVAL; 1643*7c478bd9Sstevel@tonic-gate dev_t dev; 1644*7c478bd9Sstevel@tonic-gate 1645*7c478bd9Sstevel@tonic-gate if (secpolicy_modctl(CRED(), cmd) != 0) 1646*7c478bd9Sstevel@tonic-gate return (set_errno(EPERM)); 1647*7c478bd9Sstevel@tonic-gate 1648*7c478bd9Sstevel@tonic-gate switch (cmd) { 1649*7c478bd9Sstevel@tonic-gate case MODLOAD: /* load a module */ 1650*7c478bd9Sstevel@tonic-gate error = modctl_modload((int)a1, (char *)a2, (int *)a3); 1651*7c478bd9Sstevel@tonic-gate break; 1652*7c478bd9Sstevel@tonic-gate 1653*7c478bd9Sstevel@tonic-gate case MODUNLOAD: /* unload a module */ 1654*7c478bd9Sstevel@tonic-gate error = modctl_modunload((modid_t)a1); 1655*7c478bd9Sstevel@tonic-gate break; 1656*7c478bd9Sstevel@tonic-gate 1657*7c478bd9Sstevel@tonic-gate case MODINFO: /* get module status */ 1658*7c478bd9Sstevel@tonic-gate error = modctl_modinfo((modid_t)a1, (struct modinfo *)a2); 1659*7c478bd9Sstevel@tonic-gate break; 1660*7c478bd9Sstevel@tonic-gate 1661*7c478bd9Sstevel@tonic-gate case MODRESERVED: /* get last major number in range */ 1662*7c478bd9Sstevel@tonic-gate error = modctl_modreserve((modid_t)a1, (int *)a2); 1663*7c478bd9Sstevel@tonic-gate break; 1664*7c478bd9Sstevel@tonic-gate 1665*7c478bd9Sstevel@tonic-gate case MODSETMINIROOT: /* we are running in miniroot */ 1666*7c478bd9Sstevel@tonic-gate isminiroot = 1; 1667*7c478bd9Sstevel@tonic-gate error = 0; 1668*7c478bd9Sstevel@tonic-gate break; 1669*7c478bd9Sstevel@tonic-gate 1670*7c478bd9Sstevel@tonic-gate case MODADDMAJBIND: /* read major binding file */ 1671*7c478bd9Sstevel@tonic-gate error = modctl_add_major((int *)a2); 1672*7c478bd9Sstevel@tonic-gate break; 1673*7c478bd9Sstevel@tonic-gate 1674*7c478bd9Sstevel@tonic-gate case MODGETPATHLEN: /* get modpath length */ 1675*7c478bd9Sstevel@tonic-gate error = modctl_getmodpathlen((int *)a2); 1676*7c478bd9Sstevel@tonic-gate break; 1677*7c478bd9Sstevel@tonic-gate 1678*7c478bd9Sstevel@tonic-gate case MODGETPATH: /* get modpath */ 1679*7c478bd9Sstevel@tonic-gate error = modctl_getmodpath((char *)a2); 1680*7c478bd9Sstevel@tonic-gate break; 1681*7c478bd9Sstevel@tonic-gate 1682*7c478bd9Sstevel@tonic-gate case MODREADSYSBIND: /* read system call binding file */ 1683*7c478bd9Sstevel@tonic-gate error = modctl_read_sysbinding_file(); 1684*7c478bd9Sstevel@tonic-gate break; 1685*7c478bd9Sstevel@tonic-gate 1686*7c478bd9Sstevel@tonic-gate case MODGETMAJBIND: /* get major number for named device */ 1687*7c478bd9Sstevel@tonic-gate error = modctl_getmaj((char *)a1, (uint_t)a2, (int *)a3); 1688*7c478bd9Sstevel@tonic-gate break; 1689*7c478bd9Sstevel@tonic-gate 1690*7c478bd9Sstevel@tonic-gate case MODGETNAME: /* get name of device given major number */ 1691*7c478bd9Sstevel@tonic-gate error = modctl_getname((char *)a1, (uint_t)a2, (int *)a3); 1692*7c478bd9Sstevel@tonic-gate break; 1693*7c478bd9Sstevel@tonic-gate 1694*7c478bd9Sstevel@tonic-gate case MODDEVT2INSTANCE: 1695*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 1696*7c478bd9Sstevel@tonic-gate dev = (dev_t)a1; 1697*7c478bd9Sstevel@tonic-gate } 1698*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1699*7c478bd9Sstevel@tonic-gate else { 1700*7c478bd9Sstevel@tonic-gate dev = expldev(a1); 1701*7c478bd9Sstevel@tonic-gate } 1702*7c478bd9Sstevel@tonic-gate #endif 1703*7c478bd9Sstevel@tonic-gate error = modctl_devt2instance(dev, (int *)a2); 1704*7c478bd9Sstevel@tonic-gate break; 1705*7c478bd9Sstevel@tonic-gate 1706*7c478bd9Sstevel@tonic-gate case MODSIZEOF_DEVID: /* sizeof device id of device given dev_t */ 1707*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 1708*7c478bd9Sstevel@tonic-gate dev = (dev_t)a1; 1709*7c478bd9Sstevel@tonic-gate } 1710*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1711*7c478bd9Sstevel@tonic-gate else { 1712*7c478bd9Sstevel@tonic-gate dev = expldev(a1); 1713*7c478bd9Sstevel@tonic-gate } 1714*7c478bd9Sstevel@tonic-gate #endif 1715*7c478bd9Sstevel@tonic-gate error = modctl_sizeof_devid(dev, (uint_t *)a2); 1716*7c478bd9Sstevel@tonic-gate break; 1717*7c478bd9Sstevel@tonic-gate 1718*7c478bd9Sstevel@tonic-gate case MODGETDEVID: /* get device id of device given dev_t */ 1719*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 1720*7c478bd9Sstevel@tonic-gate dev = (dev_t)a1; 1721*7c478bd9Sstevel@tonic-gate } 1722*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1723*7c478bd9Sstevel@tonic-gate else { 1724*7c478bd9Sstevel@tonic-gate dev = expldev(a1); 1725*7c478bd9Sstevel@tonic-gate } 1726*7c478bd9Sstevel@tonic-gate #endif 1727*7c478bd9Sstevel@tonic-gate error = modctl_get_devid(dev, (uint_t)a2, (ddi_devid_t)a3); 1728*7c478bd9Sstevel@tonic-gate break; 1729*7c478bd9Sstevel@tonic-gate 1730*7c478bd9Sstevel@tonic-gate case MODSIZEOF_MINORNAME: /* sizeof minor nm of dev_t/spectype */ 1731*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 1732*7c478bd9Sstevel@tonic-gate error = modctl_sizeof_minorname((dev_t)a1, (int)a2, 1733*7c478bd9Sstevel@tonic-gate (uint_t *)a3); 1734*7c478bd9Sstevel@tonic-gate } 1735*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1736*7c478bd9Sstevel@tonic-gate else { 1737*7c478bd9Sstevel@tonic-gate error = modctl_sizeof_minorname(expldev(a1), (int)a2, 1738*7c478bd9Sstevel@tonic-gate (uint_t *)a3); 1739*7c478bd9Sstevel@tonic-gate } 1740*7c478bd9Sstevel@tonic-gate 1741*7c478bd9Sstevel@tonic-gate #endif 1742*7c478bd9Sstevel@tonic-gate break; 1743*7c478bd9Sstevel@tonic-gate 1744*7c478bd9Sstevel@tonic-gate case MODGETMINORNAME: /* get minor name of dev_t and spec type */ 1745*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 1746*7c478bd9Sstevel@tonic-gate error = modctl_get_minorname((dev_t)a1, (int)a2, 1747*7c478bd9Sstevel@tonic-gate (uint_t)a3, (char *)a4); 1748*7c478bd9Sstevel@tonic-gate } 1749*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1750*7c478bd9Sstevel@tonic-gate else { 1751*7c478bd9Sstevel@tonic-gate error = modctl_get_minorname(expldev(a1), (int)a2, 1752*7c478bd9Sstevel@tonic-gate (uint_t)a3, (char *)a4); 1753*7c478bd9Sstevel@tonic-gate } 1754*7c478bd9Sstevel@tonic-gate #endif 1755*7c478bd9Sstevel@tonic-gate break; 1756*7c478bd9Sstevel@tonic-gate 1757*7c478bd9Sstevel@tonic-gate case MODGETDEVFSPATH_LEN: /* sizeof path nm of dev_t/spectype */ 1758*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 1759*7c478bd9Sstevel@tonic-gate error = modctl_devfspath_len((dev_t)a1, (int)a2, 1760*7c478bd9Sstevel@tonic-gate (uint_t *)a3); 1761*7c478bd9Sstevel@tonic-gate } 1762*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1763*7c478bd9Sstevel@tonic-gate else { 1764*7c478bd9Sstevel@tonic-gate error = modctl_devfspath_len(expldev(a1), (int)a2, 1765*7c478bd9Sstevel@tonic-gate (uint_t *)a3); 1766*7c478bd9Sstevel@tonic-gate } 1767*7c478bd9Sstevel@tonic-gate 1768*7c478bd9Sstevel@tonic-gate #endif 1769*7c478bd9Sstevel@tonic-gate break; 1770*7c478bd9Sstevel@tonic-gate 1771*7c478bd9Sstevel@tonic-gate case MODGETDEVFSPATH: /* get path name of dev_t and spec type */ 1772*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 1773*7c478bd9Sstevel@tonic-gate error = modctl_devfspath((dev_t)a1, (int)a2, 1774*7c478bd9Sstevel@tonic-gate (uint_t)a3, (char *)a4); 1775*7c478bd9Sstevel@tonic-gate } 1776*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1777*7c478bd9Sstevel@tonic-gate else { 1778*7c478bd9Sstevel@tonic-gate error = modctl_devfspath(expldev(a1), (int)a2, 1779*7c478bd9Sstevel@tonic-gate (uint_t)a3, (char *)a4); 1780*7c478bd9Sstevel@tonic-gate } 1781*7c478bd9Sstevel@tonic-gate #endif 1782*7c478bd9Sstevel@tonic-gate break; 1783*7c478bd9Sstevel@tonic-gate 1784*7c478bd9Sstevel@tonic-gate 1785*7c478bd9Sstevel@tonic-gate case MODEVENTS: 1786*7c478bd9Sstevel@tonic-gate error = modctl_modevents((int)a1, a2, a3, a4, (uint_t)a5); 1787*7c478bd9Sstevel@tonic-gate break; 1788*7c478bd9Sstevel@tonic-gate 1789*7c478bd9Sstevel@tonic-gate case MODGETFBNAME: /* get the framebuffer name */ 1790*7c478bd9Sstevel@tonic-gate error = modctl_get_fbname((char *)a1); 1791*7c478bd9Sstevel@tonic-gate break; 1792*7c478bd9Sstevel@tonic-gate 1793*7c478bd9Sstevel@tonic-gate case MODREREADDACF: /* reread dacf rule database from given file */ 1794*7c478bd9Sstevel@tonic-gate error = modctl_reread_dacf((char *)a1); 1795*7c478bd9Sstevel@tonic-gate break; 1796*7c478bd9Sstevel@tonic-gate 1797*7c478bd9Sstevel@tonic-gate case MODLOADDRVCONF: /* load driver.conf file for major */ 1798*7c478bd9Sstevel@tonic-gate error = modctl_load_drvconf((major_t)a1); 1799*7c478bd9Sstevel@tonic-gate break; 1800*7c478bd9Sstevel@tonic-gate 1801*7c478bd9Sstevel@tonic-gate case MODUNLOADDRVCONF: /* unload driver.conf file for major */ 1802*7c478bd9Sstevel@tonic-gate error = modctl_unload_drvconf((major_t)a1); 1803*7c478bd9Sstevel@tonic-gate break; 1804*7c478bd9Sstevel@tonic-gate 1805*7c478bd9Sstevel@tonic-gate case MODREMMAJBIND: /* remove a major binding */ 1806*7c478bd9Sstevel@tonic-gate error = modctl_rem_major((major_t)a1); 1807*7c478bd9Sstevel@tonic-gate break; 1808*7c478bd9Sstevel@tonic-gate 1809*7c478bd9Sstevel@tonic-gate case MODDEVID2PATHS: /* get paths given devid */ 1810*7c478bd9Sstevel@tonic-gate error = modctl_devid2paths((ddi_devid_t)a1, (char *)a2, 1811*7c478bd9Sstevel@tonic-gate (uint_t)a3, (size_t *)a4, (char *)a5); 1812*7c478bd9Sstevel@tonic-gate break; 1813*7c478bd9Sstevel@tonic-gate 1814*7c478bd9Sstevel@tonic-gate case MODSETDEVPOLICY: /* establish device policy */ 1815*7c478bd9Sstevel@tonic-gate error = devpolicy_load((int)a1, (size_t)a2, (devplcysys_t *)a3); 1816*7c478bd9Sstevel@tonic-gate break; 1817*7c478bd9Sstevel@tonic-gate 1818*7c478bd9Sstevel@tonic-gate case MODGETDEVPOLICY: /* get device policy */ 1819*7c478bd9Sstevel@tonic-gate error = devpolicy_get((int *)a1, (size_t)a2, 1820*7c478bd9Sstevel@tonic-gate (devplcysys_t *)a3); 1821*7c478bd9Sstevel@tonic-gate break; 1822*7c478bd9Sstevel@tonic-gate 1823*7c478bd9Sstevel@tonic-gate case MODALLOCPRIV: 1824*7c478bd9Sstevel@tonic-gate error = modctl_allocpriv((const char *)a1); 1825*7c478bd9Sstevel@tonic-gate break; 1826*7c478bd9Sstevel@tonic-gate 1827*7c478bd9Sstevel@tonic-gate case MODGETDEVPOLICYBYNAME: 1828*7c478bd9Sstevel@tonic-gate error = devpolicy_getbyname((size_t)a1, 1829*7c478bd9Sstevel@tonic-gate (devplcysys_t *)a2, (char *)a3); 1830*7c478bd9Sstevel@tonic-gate break; 1831*7c478bd9Sstevel@tonic-gate 1832*7c478bd9Sstevel@tonic-gate case MODCLEANUP: 1833*7c478bd9Sstevel@tonic-gate e_devid_cache_cleanup(); 1834*7c478bd9Sstevel@tonic-gate error = 0; 1835*7c478bd9Sstevel@tonic-gate break; 1836*7c478bd9Sstevel@tonic-gate 1837*7c478bd9Sstevel@tonic-gate case MODLOADMINORPERM: 1838*7c478bd9Sstevel@tonic-gate case MODADDMINORPERM: 1839*7c478bd9Sstevel@tonic-gate case MODREMMINORPERM: 1840*7c478bd9Sstevel@tonic-gate error = modctl_minorperm(cmd, (char *)a1, (size_t)a2); 1841*7c478bd9Sstevel@tonic-gate break; 1842*7c478bd9Sstevel@tonic-gate 1843*7c478bd9Sstevel@tonic-gate case MODREMDRVCLEANUP: 1844*7c478bd9Sstevel@tonic-gate error = modctl_remdrv_cleanup((const char *)a1); 1845*7c478bd9Sstevel@tonic-gate break; 1846*7c478bd9Sstevel@tonic-gate 1847*7c478bd9Sstevel@tonic-gate default: 1848*7c478bd9Sstevel@tonic-gate error = EINVAL; 1849*7c478bd9Sstevel@tonic-gate break; 1850*7c478bd9Sstevel@tonic-gate } 1851*7c478bd9Sstevel@tonic-gate 1852*7c478bd9Sstevel@tonic-gate return (error ? set_errno(error) : 0); 1853*7c478bd9Sstevel@tonic-gate } 1854*7c478bd9Sstevel@tonic-gate 1855*7c478bd9Sstevel@tonic-gate /* 1856*7c478bd9Sstevel@tonic-gate * Calls to kobj_load_module()() are handled off to this routine in a 1857*7c478bd9Sstevel@tonic-gate * separate thread. 1858*7c478bd9Sstevel@tonic-gate */ 1859*7c478bd9Sstevel@tonic-gate static void 1860*7c478bd9Sstevel@tonic-gate modload_thread(struct loadmt *ltp) 1861*7c478bd9Sstevel@tonic-gate { 1862*7c478bd9Sstevel@tonic-gate /* load the module and signal the creator of this thread */ 1863*7c478bd9Sstevel@tonic-gate kmutex_t cpr_lk; 1864*7c478bd9Sstevel@tonic-gate callb_cpr_t cpr_i; 1865*7c478bd9Sstevel@tonic-gate 1866*7c478bd9Sstevel@tonic-gate mutex_init(&cpr_lk, NULL, MUTEX_DEFAULT, NULL); 1867*7c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cpr_i, &cpr_lk, callb_generic_cpr, "modload"); 1868*7c478bd9Sstevel@tonic-gate /* borrow the devi lock from thread which invoked us */ 1869*7c478bd9Sstevel@tonic-gate pm_borrow_lock(ltp->owner); 1870*7c478bd9Sstevel@tonic-gate ltp->retval = kobj_load_module(ltp->mp, ltp->usepath); 1871*7c478bd9Sstevel@tonic-gate pm_return_lock(); 1872*7c478bd9Sstevel@tonic-gate sema_v(<p->sema); 1873*7c478bd9Sstevel@tonic-gate mutex_enter(&cpr_lk); 1874*7c478bd9Sstevel@tonic-gate CALLB_CPR_EXIT(&cpr_i); 1875*7c478bd9Sstevel@tonic-gate mutex_destroy(&cpr_lk); 1876*7c478bd9Sstevel@tonic-gate thread_exit(); 1877*7c478bd9Sstevel@tonic-gate } 1878*7c478bd9Sstevel@tonic-gate 1879*7c478bd9Sstevel@tonic-gate /* 1880*7c478bd9Sstevel@tonic-gate * load a module, adding a reference if caller specifies rmodp. If rmodp 1881*7c478bd9Sstevel@tonic-gate * is specified then an errno is returned, otherwise a module index is 1882*7c478bd9Sstevel@tonic-gate * returned (-1 on error). 1883*7c478bd9Sstevel@tonic-gate */ 1884*7c478bd9Sstevel@tonic-gate static int 1885*7c478bd9Sstevel@tonic-gate modrload(char *subdir, char *filename, struct modctl **rmodp) 1886*7c478bd9Sstevel@tonic-gate { 1887*7c478bd9Sstevel@tonic-gate struct modctl *modp; 1888*7c478bd9Sstevel@tonic-gate size_t size; 1889*7c478bd9Sstevel@tonic-gate char *fullname; 1890*7c478bd9Sstevel@tonic-gate int retval = EINVAL; 1891*7c478bd9Sstevel@tonic-gate int id = -1; 1892*7c478bd9Sstevel@tonic-gate struct _buf *buf; 1893*7c478bd9Sstevel@tonic-gate 1894*7c478bd9Sstevel@tonic-gate if (rmodp) 1895*7c478bd9Sstevel@tonic-gate *rmodp = NULL; /* avoid garbage */ 1896*7c478bd9Sstevel@tonic-gate 1897*7c478bd9Sstevel@tonic-gate if (subdir != NULL) { 1898*7c478bd9Sstevel@tonic-gate /* 1899*7c478bd9Sstevel@tonic-gate * refuse / in filename to prevent "../" escapes. 1900*7c478bd9Sstevel@tonic-gate */ 1901*7c478bd9Sstevel@tonic-gate if (strchr(filename, '/') != NULL) 1902*7c478bd9Sstevel@tonic-gate return (rmodp ? retval : id); 1903*7c478bd9Sstevel@tonic-gate 1904*7c478bd9Sstevel@tonic-gate /* 1905*7c478bd9Sstevel@tonic-gate * allocate enough space for <subdir>/<filename><NULL> 1906*7c478bd9Sstevel@tonic-gate */ 1907*7c478bd9Sstevel@tonic-gate size = strlen(subdir) + strlen(filename) + 2; 1908*7c478bd9Sstevel@tonic-gate fullname = kmem_zalloc(size, KM_SLEEP); 1909*7c478bd9Sstevel@tonic-gate (void) sprintf(fullname, "%s/%s", subdir, filename); 1910*7c478bd9Sstevel@tonic-gate } else { 1911*7c478bd9Sstevel@tonic-gate fullname = filename; 1912*7c478bd9Sstevel@tonic-gate } 1913*7c478bd9Sstevel@tonic-gate 1914*7c478bd9Sstevel@tonic-gate /* 1915*7c478bd9Sstevel@tonic-gate * Verify that that module in question actually exists on disk. 1916*7c478bd9Sstevel@tonic-gate * Otherwise, modload_now will succeed if (for example) modload 1917*7c478bd9Sstevel@tonic-gate * is requested for sched/nfs if fs/nfs is already loaded, and 1918*7c478bd9Sstevel@tonic-gate * sched/nfs doesn't exist. 1919*7c478bd9Sstevel@tonic-gate */ 1920*7c478bd9Sstevel@tonic-gate if (modrootloaded && swaploaded) { 1921*7c478bd9Sstevel@tonic-gate if ((buf = kobj_open_path(fullname, 1, 1)) == 1922*7c478bd9Sstevel@tonic-gate (struct _buf *)-1) { 1923*7c478bd9Sstevel@tonic-gate retval = ENOENT; 1924*7c478bd9Sstevel@tonic-gate goto done; 1925*7c478bd9Sstevel@tonic-gate } 1926*7c478bd9Sstevel@tonic-gate kobj_close_file(buf); 1927*7c478bd9Sstevel@tonic-gate } 1928*7c478bd9Sstevel@tonic-gate 1929*7c478bd9Sstevel@tonic-gate modp = mod_hold_installed_mod(fullname, 1, &retval); 1930*7c478bd9Sstevel@tonic-gate if (modp != NULL) { 1931*7c478bd9Sstevel@tonic-gate id = modp->mod_id; 1932*7c478bd9Sstevel@tonic-gate if (rmodp) { 1933*7c478bd9Sstevel@tonic-gate /* add mod_ref and return *rmodp */ 1934*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 1935*7c478bd9Sstevel@tonic-gate modp->mod_ref++; 1936*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 1937*7c478bd9Sstevel@tonic-gate *rmodp = modp; 1938*7c478bd9Sstevel@tonic-gate } 1939*7c478bd9Sstevel@tonic-gate mod_release_mod(modp); 1940*7c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(CPU, sys, modload, 1); 1941*7c478bd9Sstevel@tonic-gate } 1942*7c478bd9Sstevel@tonic-gate 1943*7c478bd9Sstevel@tonic-gate done: if (subdir != NULL) 1944*7c478bd9Sstevel@tonic-gate kmem_free(fullname, size); 1945*7c478bd9Sstevel@tonic-gate return (rmodp ? retval : id); 1946*7c478bd9Sstevel@tonic-gate } 1947*7c478bd9Sstevel@tonic-gate 1948*7c478bd9Sstevel@tonic-gate /* 1949*7c478bd9Sstevel@tonic-gate * This is the primary kernel interface to load a module. It loads and 1950*7c478bd9Sstevel@tonic-gate * installs the named module. It does not hold mod_ref of the module, so 1951*7c478bd9Sstevel@tonic-gate * a module unload attempt can occur at any time - it is up to the 1952*7c478bd9Sstevel@tonic-gate * _fini/mod_remove implementation to determine if unload will succeed. 1953*7c478bd9Sstevel@tonic-gate */ 1954*7c478bd9Sstevel@tonic-gate int 1955*7c478bd9Sstevel@tonic-gate modload(char *subdir, char *filename) 1956*7c478bd9Sstevel@tonic-gate { 1957*7c478bd9Sstevel@tonic-gate return (modrload(subdir, filename, NULL)); 1958*7c478bd9Sstevel@tonic-gate } 1959*7c478bd9Sstevel@tonic-gate 1960*7c478bd9Sstevel@tonic-gate /* 1961*7c478bd9Sstevel@tonic-gate * Load a module. 1962*7c478bd9Sstevel@tonic-gate */ 1963*7c478bd9Sstevel@tonic-gate int 1964*7c478bd9Sstevel@tonic-gate modloadonly(char *subdir, char *filename) 1965*7c478bd9Sstevel@tonic-gate { 1966*7c478bd9Sstevel@tonic-gate struct modctl *modp; 1967*7c478bd9Sstevel@tonic-gate char *fullname; 1968*7c478bd9Sstevel@tonic-gate size_t size; 1969*7c478bd9Sstevel@tonic-gate int id, retval; 1970*7c478bd9Sstevel@tonic-gate 1971*7c478bd9Sstevel@tonic-gate if (subdir != NULL) { 1972*7c478bd9Sstevel@tonic-gate /* 1973*7c478bd9Sstevel@tonic-gate * allocate enough space for <subdir>/<filename><NULL> 1974*7c478bd9Sstevel@tonic-gate */ 1975*7c478bd9Sstevel@tonic-gate size = strlen(subdir) + strlen(filename) + 2; 1976*7c478bd9Sstevel@tonic-gate fullname = kmem_zalloc(size, KM_SLEEP); 1977*7c478bd9Sstevel@tonic-gate (void) sprintf(fullname, "%s/%s", subdir, filename); 1978*7c478bd9Sstevel@tonic-gate } else { 1979*7c478bd9Sstevel@tonic-gate fullname = filename; 1980*7c478bd9Sstevel@tonic-gate } 1981*7c478bd9Sstevel@tonic-gate 1982*7c478bd9Sstevel@tonic-gate modp = mod_hold_loaded_mod(NULL, fullname, &retval); 1983*7c478bd9Sstevel@tonic-gate if (modp) { 1984*7c478bd9Sstevel@tonic-gate id = modp->mod_id; 1985*7c478bd9Sstevel@tonic-gate mod_release_mod(modp); 1986*7c478bd9Sstevel@tonic-gate } 1987*7c478bd9Sstevel@tonic-gate 1988*7c478bd9Sstevel@tonic-gate if (subdir != NULL) 1989*7c478bd9Sstevel@tonic-gate kmem_free(fullname, size); 1990*7c478bd9Sstevel@tonic-gate 1991*7c478bd9Sstevel@tonic-gate if (retval == 0) 1992*7c478bd9Sstevel@tonic-gate return (id); 1993*7c478bd9Sstevel@tonic-gate return (-1); 1994*7c478bd9Sstevel@tonic-gate } 1995*7c478bd9Sstevel@tonic-gate 1996*7c478bd9Sstevel@tonic-gate /* 1997*7c478bd9Sstevel@tonic-gate * Try to uninstall and unload a module, removing a reference if caller 1998*7c478bd9Sstevel@tonic-gate * specifies rmodp. 1999*7c478bd9Sstevel@tonic-gate */ 2000*7c478bd9Sstevel@tonic-gate static int 2001*7c478bd9Sstevel@tonic-gate modunrload(modid_t id, struct modctl **rmodp, int unload) 2002*7c478bd9Sstevel@tonic-gate { 2003*7c478bd9Sstevel@tonic-gate struct modctl *modp; 2004*7c478bd9Sstevel@tonic-gate int retval; 2005*7c478bd9Sstevel@tonic-gate 2006*7c478bd9Sstevel@tonic-gate if (rmodp) 2007*7c478bd9Sstevel@tonic-gate *rmodp = NULL; /* avoid garbage */ 2008*7c478bd9Sstevel@tonic-gate 2009*7c478bd9Sstevel@tonic-gate if ((modp = mod_hold_by_id((modid_t)id)) == NULL) 2010*7c478bd9Sstevel@tonic-gate return (EINVAL); 2011*7c478bd9Sstevel@tonic-gate 2012*7c478bd9Sstevel@tonic-gate if (rmodp) { 2013*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 2014*7c478bd9Sstevel@tonic-gate modp->mod_ref--; 2015*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2016*7c478bd9Sstevel@tonic-gate *rmodp = modp; 2017*7c478bd9Sstevel@tonic-gate } 2018*7c478bd9Sstevel@tonic-gate 2019*7c478bd9Sstevel@tonic-gate if (unload) { 2020*7c478bd9Sstevel@tonic-gate retval = moduninstall(modp); 2021*7c478bd9Sstevel@tonic-gate if (retval == 0) { 2022*7c478bd9Sstevel@tonic-gate mod_unload(modp); 2023*7c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(CPU, sys, modunload, 1); 2024*7c478bd9Sstevel@tonic-gate } else if (retval == EALREADY) 2025*7c478bd9Sstevel@tonic-gate retval = 0; /* already unloaded, not an error */ 2026*7c478bd9Sstevel@tonic-gate } else 2027*7c478bd9Sstevel@tonic-gate retval = 0; 2028*7c478bd9Sstevel@tonic-gate 2029*7c478bd9Sstevel@tonic-gate mod_release_mod(modp); 2030*7c478bd9Sstevel@tonic-gate return (retval); 2031*7c478bd9Sstevel@tonic-gate } 2032*7c478bd9Sstevel@tonic-gate 2033*7c478bd9Sstevel@tonic-gate /* 2034*7c478bd9Sstevel@tonic-gate * Uninstall and unload a module. 2035*7c478bd9Sstevel@tonic-gate */ 2036*7c478bd9Sstevel@tonic-gate int 2037*7c478bd9Sstevel@tonic-gate modunload(modid_t id) 2038*7c478bd9Sstevel@tonic-gate { 2039*7c478bd9Sstevel@tonic-gate return (modunrload(id, NULL, 1)); 2040*7c478bd9Sstevel@tonic-gate } 2041*7c478bd9Sstevel@tonic-gate 2042*7c478bd9Sstevel@tonic-gate /* 2043*7c478bd9Sstevel@tonic-gate * Return status of a loaded module. 2044*7c478bd9Sstevel@tonic-gate */ 2045*7c478bd9Sstevel@tonic-gate static int 2046*7c478bd9Sstevel@tonic-gate modinfo(modid_t id, struct modinfo *modinfop) 2047*7c478bd9Sstevel@tonic-gate { 2048*7c478bd9Sstevel@tonic-gate struct modctl *modp; 2049*7c478bd9Sstevel@tonic-gate modid_t mid; 2050*7c478bd9Sstevel@tonic-gate int i; 2051*7c478bd9Sstevel@tonic-gate 2052*7c478bd9Sstevel@tonic-gate mid = modinfop->mi_id; 2053*7c478bd9Sstevel@tonic-gate if (modinfop->mi_info & MI_INFO_ALL) { 2054*7c478bd9Sstevel@tonic-gate while ((modp = mod_hold_next_by_id(mid++)) != NULL) { 2055*7c478bd9Sstevel@tonic-gate if ((modinfop->mi_info & MI_INFO_CNT) || 2056*7c478bd9Sstevel@tonic-gate modp->mod_installed) 2057*7c478bd9Sstevel@tonic-gate break; 2058*7c478bd9Sstevel@tonic-gate mod_release_mod(modp); 2059*7c478bd9Sstevel@tonic-gate } 2060*7c478bd9Sstevel@tonic-gate if (modp == NULL) 2061*7c478bd9Sstevel@tonic-gate return (EINVAL); 2062*7c478bd9Sstevel@tonic-gate } else { 2063*7c478bd9Sstevel@tonic-gate modp = mod_hold_by_id(id); 2064*7c478bd9Sstevel@tonic-gate if (modp == NULL) 2065*7c478bd9Sstevel@tonic-gate return (EINVAL); 2066*7c478bd9Sstevel@tonic-gate if (!(modinfop->mi_info & MI_INFO_CNT) && 2067*7c478bd9Sstevel@tonic-gate (modp->mod_installed == 0)) { 2068*7c478bd9Sstevel@tonic-gate mod_release_mod(modp); 2069*7c478bd9Sstevel@tonic-gate return (EINVAL); 2070*7c478bd9Sstevel@tonic-gate } 2071*7c478bd9Sstevel@tonic-gate } 2072*7c478bd9Sstevel@tonic-gate 2073*7c478bd9Sstevel@tonic-gate modinfop->mi_rev = 0; 2074*7c478bd9Sstevel@tonic-gate modinfop->mi_state = 0; 2075*7c478bd9Sstevel@tonic-gate for (i = 0; i < MODMAXLINK; i++) { 2076*7c478bd9Sstevel@tonic-gate modinfop->mi_msinfo[i].msi_p0 = -1; 2077*7c478bd9Sstevel@tonic-gate modinfop->mi_msinfo[i].msi_linkinfo[0] = 0; 2078*7c478bd9Sstevel@tonic-gate } 2079*7c478bd9Sstevel@tonic-gate if (modp->mod_loaded) { 2080*7c478bd9Sstevel@tonic-gate modinfop->mi_state = MI_LOADED; 2081*7c478bd9Sstevel@tonic-gate kobj_getmodinfo(modp->mod_mp, modinfop); 2082*7c478bd9Sstevel@tonic-gate } 2083*7c478bd9Sstevel@tonic-gate if (modp->mod_installed) { 2084*7c478bd9Sstevel@tonic-gate modinfop->mi_state |= MI_INSTALLED; 2085*7c478bd9Sstevel@tonic-gate 2086*7c478bd9Sstevel@tonic-gate (void) mod_getinfo(modp, modinfop); 2087*7c478bd9Sstevel@tonic-gate } 2088*7c478bd9Sstevel@tonic-gate 2089*7c478bd9Sstevel@tonic-gate modinfop->mi_id = modp->mod_id; 2090*7c478bd9Sstevel@tonic-gate modinfop->mi_loadcnt = modp->mod_loadcnt; 2091*7c478bd9Sstevel@tonic-gate (void) strcpy(modinfop->mi_name, modp->mod_modname); 2092*7c478bd9Sstevel@tonic-gate 2093*7c478bd9Sstevel@tonic-gate mod_release_mod(modp); 2094*7c478bd9Sstevel@tonic-gate return (0); 2095*7c478bd9Sstevel@tonic-gate } 2096*7c478bd9Sstevel@tonic-gate 2097*7c478bd9Sstevel@tonic-gate static char mod_stub_err[] = "mod_hold_stub: Couldn't load stub module %s"; 2098*7c478bd9Sstevel@tonic-gate static char no_err[] = "No error function for weak stub %s"; 2099*7c478bd9Sstevel@tonic-gate 2100*7c478bd9Sstevel@tonic-gate /* 2101*7c478bd9Sstevel@tonic-gate * used by the stubs themselves to load and hold a module. 2102*7c478bd9Sstevel@tonic-gate * Returns 0 if the module is successfully held; 2103*7c478bd9Sstevel@tonic-gate * the stub needs to call mod_release_stub(). 2104*7c478bd9Sstevel@tonic-gate * -1 if the stub should just call the err_fcn. 2105*7c478bd9Sstevel@tonic-gate * Note that this code is stretched out so that we avoid subroutine calls 2106*7c478bd9Sstevel@tonic-gate * and optimize for the most likely case. That is, the case where the 2107*7c478bd9Sstevel@tonic-gate * module is loaded and installed and not held. In that case we just inc 2108*7c478bd9Sstevel@tonic-gate * the mod_ref count and continue. 2109*7c478bd9Sstevel@tonic-gate */ 2110*7c478bd9Sstevel@tonic-gate int 2111*7c478bd9Sstevel@tonic-gate mod_hold_stub(struct mod_stub_info *stub) 2112*7c478bd9Sstevel@tonic-gate { 2113*7c478bd9Sstevel@tonic-gate struct modctl *mp; 2114*7c478bd9Sstevel@tonic-gate struct mod_modinfo *mip; 2115*7c478bd9Sstevel@tonic-gate 2116*7c478bd9Sstevel@tonic-gate mip = stub->mods_modinfo; 2117*7c478bd9Sstevel@tonic-gate 2118*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 2119*7c478bd9Sstevel@tonic-gate 2120*7c478bd9Sstevel@tonic-gate /* we do mod_hold_by_modctl inline for speed */ 2121*7c478bd9Sstevel@tonic-gate 2122*7c478bd9Sstevel@tonic-gate mod_check_again: 2123*7c478bd9Sstevel@tonic-gate if ((mp = mip->mp) != NULL) { 2124*7c478bd9Sstevel@tonic-gate if (mp->mod_busy == 0) { 2125*7c478bd9Sstevel@tonic-gate if (mp->mod_installed) { 2126*7c478bd9Sstevel@tonic-gate /* increment the reference count */ 2127*7c478bd9Sstevel@tonic-gate mp->mod_ref++; 2128*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_ref && mp->mod_installed); 2129*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2130*7c478bd9Sstevel@tonic-gate return (0); 2131*7c478bd9Sstevel@tonic-gate } else { 2132*7c478bd9Sstevel@tonic-gate mp->mod_busy = 1; 2133*7c478bd9Sstevel@tonic-gate mp->mod_inprogress_thread = 2134*7c478bd9Sstevel@tonic-gate (curthread == NULL ? 2135*7c478bd9Sstevel@tonic-gate (kthread_id_t)-1 : curthread); 2136*7c478bd9Sstevel@tonic-gate } 2137*7c478bd9Sstevel@tonic-gate } else { 2138*7c478bd9Sstevel@tonic-gate /* 2139*7c478bd9Sstevel@tonic-gate * wait one time and then go see if someone 2140*7c478bd9Sstevel@tonic-gate * else has resolved the stub (set mip->mp). 2141*7c478bd9Sstevel@tonic-gate */ 2142*7c478bd9Sstevel@tonic-gate if (mod_hold_by_modctl(mp, 2143*7c478bd9Sstevel@tonic-gate MOD_WAIT_ONCE | MOD_LOCK_HELD)) 2144*7c478bd9Sstevel@tonic-gate goto mod_check_again; 2145*7c478bd9Sstevel@tonic-gate 2146*7c478bd9Sstevel@tonic-gate /* 2147*7c478bd9Sstevel@tonic-gate * what we have now may have been unloaded!, in 2148*7c478bd9Sstevel@tonic-gate * that case, mip->mp will be NULL, we'll hit this 2149*7c478bd9Sstevel@tonic-gate * module and load again.. 2150*7c478bd9Sstevel@tonic-gate */ 2151*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "mod_hold_stub should have blocked"); 2152*7c478bd9Sstevel@tonic-gate } 2153*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2154*7c478bd9Sstevel@tonic-gate } else { 2155*7c478bd9Sstevel@tonic-gate /* first time we've hit this module */ 2156*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2157*7c478bd9Sstevel@tonic-gate mp = mod_hold_by_name(mip->modm_module_name); 2158*7c478bd9Sstevel@tonic-gate mip->mp = mp; 2159*7c478bd9Sstevel@tonic-gate } 2160*7c478bd9Sstevel@tonic-gate 2161*7c478bd9Sstevel@tonic-gate /* 2162*7c478bd9Sstevel@tonic-gate * If we are here, it means that the following conditions 2163*7c478bd9Sstevel@tonic-gate * are satisfied. 2164*7c478bd9Sstevel@tonic-gate * 2165*7c478bd9Sstevel@tonic-gate * mip->mp != NULL 2166*7c478bd9Sstevel@tonic-gate * this thread has set the mp->mod_busy = 1 2167*7c478bd9Sstevel@tonic-gate * mp->mod_installed = 0 2168*7c478bd9Sstevel@tonic-gate * 2169*7c478bd9Sstevel@tonic-gate */ 2170*7c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 2171*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_busy == 1); 2172*7c478bd9Sstevel@tonic-gate 2173*7c478bd9Sstevel@tonic-gate if (mp->mod_installed == 0) { 2174*7c478bd9Sstevel@tonic-gate /* Module not loaded, if weak stub don't load it */ 2175*7c478bd9Sstevel@tonic-gate if (stub->mods_flag & MODS_WEAK) { 2176*7c478bd9Sstevel@tonic-gate if (stub->mods_errfcn == NULL) { 2177*7c478bd9Sstevel@tonic-gate mod_release_mod(mp); 2178*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, no_err, 2179*7c478bd9Sstevel@tonic-gate mip->modm_module_name); 2180*7c478bd9Sstevel@tonic-gate } 2181*7c478bd9Sstevel@tonic-gate } else { 2182*7c478bd9Sstevel@tonic-gate /* Not a weak stub so load the module */ 2183*7c478bd9Sstevel@tonic-gate 2184*7c478bd9Sstevel@tonic-gate if (mod_load(mp, 1) != 0 || modinstall(mp) != 0) { 2185*7c478bd9Sstevel@tonic-gate /* 2186*7c478bd9Sstevel@tonic-gate * If mod_load() was successful 2187*7c478bd9Sstevel@tonic-gate * and modinstall() failed, then 2188*7c478bd9Sstevel@tonic-gate * unload the module. 2189*7c478bd9Sstevel@tonic-gate */ 2190*7c478bd9Sstevel@tonic-gate if (mp->mod_loaded) 2191*7c478bd9Sstevel@tonic-gate mod_unload(mp); 2192*7c478bd9Sstevel@tonic-gate 2193*7c478bd9Sstevel@tonic-gate mod_release_mod(mp); 2194*7c478bd9Sstevel@tonic-gate if (stub->mods_errfcn == NULL) { 2195*7c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, mod_stub_err, 2196*7c478bd9Sstevel@tonic-gate mip->modm_module_name); 2197*7c478bd9Sstevel@tonic-gate } else { 2198*7c478bd9Sstevel@tonic-gate return (-1); 2199*7c478bd9Sstevel@tonic-gate } 2200*7c478bd9Sstevel@tonic-gate } 2201*7c478bd9Sstevel@tonic-gate } 2202*7c478bd9Sstevel@tonic-gate } 2203*7c478bd9Sstevel@tonic-gate 2204*7c478bd9Sstevel@tonic-gate /* 2205*7c478bd9Sstevel@tonic-gate * At this point module is held and loaded. Release 2206*7c478bd9Sstevel@tonic-gate * the mod_busy and mod_inprogress_thread before 2207*7c478bd9Sstevel@tonic-gate * returning. We actually call mod_release() here so 2208*7c478bd9Sstevel@tonic-gate * that if another stub wants to access this module, 2209*7c478bd9Sstevel@tonic-gate * it can do so. mod_ref is incremented before mod_release() 2210*7c478bd9Sstevel@tonic-gate * is called to prevent someone else from snatching the 2211*7c478bd9Sstevel@tonic-gate * module from this thread. 2212*7c478bd9Sstevel@tonic-gate */ 2213*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 2214*7c478bd9Sstevel@tonic-gate mp->mod_ref++; 2215*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_ref && 2216*7c478bd9Sstevel@tonic-gate (mp->mod_loaded || (stub->mods_flag & MODS_WEAK))); 2217*7c478bd9Sstevel@tonic-gate mod_release(mp); 2218*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2219*7c478bd9Sstevel@tonic-gate return (0); 2220*7c478bd9Sstevel@tonic-gate } 2221*7c478bd9Sstevel@tonic-gate 2222*7c478bd9Sstevel@tonic-gate void 2223*7c478bd9Sstevel@tonic-gate mod_release_stub(struct mod_stub_info *stub) 2224*7c478bd9Sstevel@tonic-gate { 2225*7c478bd9Sstevel@tonic-gate struct modctl *mp = stub->mods_modinfo->mp; 2226*7c478bd9Sstevel@tonic-gate 2227*7c478bd9Sstevel@tonic-gate /* inline mod_release_mod */ 2228*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 2229*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_ref && 2230*7c478bd9Sstevel@tonic-gate (mp->mod_loaded || (stub->mods_flag & MODS_WEAK))); 2231*7c478bd9Sstevel@tonic-gate mp->mod_ref--; 2232*7c478bd9Sstevel@tonic-gate if (mp->mod_want) { 2233*7c478bd9Sstevel@tonic-gate mp->mod_want = 0; 2234*7c478bd9Sstevel@tonic-gate cv_broadcast(&mod_cv); 2235*7c478bd9Sstevel@tonic-gate } 2236*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2237*7c478bd9Sstevel@tonic-gate } 2238*7c478bd9Sstevel@tonic-gate 2239*7c478bd9Sstevel@tonic-gate static struct modctl * 2240*7c478bd9Sstevel@tonic-gate mod_hold_loaded_mod(struct modctl *dep, char *filename, int *status) 2241*7c478bd9Sstevel@tonic-gate { 2242*7c478bd9Sstevel@tonic-gate struct modctl *modp; 2243*7c478bd9Sstevel@tonic-gate int retval; 2244*7c478bd9Sstevel@tonic-gate 2245*7c478bd9Sstevel@tonic-gate /* 2246*7c478bd9Sstevel@tonic-gate * Hold the module. 2247*7c478bd9Sstevel@tonic-gate */ 2248*7c478bd9Sstevel@tonic-gate modp = mod_hold_by_name_requisite(dep, filename); 2249*7c478bd9Sstevel@tonic-gate if (modp) { 2250*7c478bd9Sstevel@tonic-gate retval = mod_load(modp, 1); 2251*7c478bd9Sstevel@tonic-gate if (retval != 0) { 2252*7c478bd9Sstevel@tonic-gate mod_release_mod(modp); 2253*7c478bd9Sstevel@tonic-gate modp = NULL; 2254*7c478bd9Sstevel@tonic-gate } 2255*7c478bd9Sstevel@tonic-gate *status = retval; 2256*7c478bd9Sstevel@tonic-gate } else { 2257*7c478bd9Sstevel@tonic-gate *status = ENOSPC; 2258*7c478bd9Sstevel@tonic-gate } 2259*7c478bd9Sstevel@tonic-gate 2260*7c478bd9Sstevel@tonic-gate /* 2261*7c478bd9Sstevel@tonic-gate * if dep is not NULL, clear the module dependency information. 2262*7c478bd9Sstevel@tonic-gate * This information is set in mod_hold_by_name_common(). 2263*7c478bd9Sstevel@tonic-gate */ 2264*7c478bd9Sstevel@tonic-gate if (dep != NULL && dep->mod_requisite_loading != NULL) { 2265*7c478bd9Sstevel@tonic-gate ASSERT(dep->mod_busy); 2266*7c478bd9Sstevel@tonic-gate dep->mod_requisite_loading = NULL; 2267*7c478bd9Sstevel@tonic-gate } 2268*7c478bd9Sstevel@tonic-gate 2269*7c478bd9Sstevel@tonic-gate return (modp); 2270*7c478bd9Sstevel@tonic-gate } 2271*7c478bd9Sstevel@tonic-gate 2272*7c478bd9Sstevel@tonic-gate /* 2273*7c478bd9Sstevel@tonic-gate * hold, load, and install the named module 2274*7c478bd9Sstevel@tonic-gate */ 2275*7c478bd9Sstevel@tonic-gate static struct modctl * 2276*7c478bd9Sstevel@tonic-gate mod_hold_installed_mod(char *name, int usepath, int *r) 2277*7c478bd9Sstevel@tonic-gate { 2278*7c478bd9Sstevel@tonic-gate struct modctl *modp; 2279*7c478bd9Sstevel@tonic-gate int retval; 2280*7c478bd9Sstevel@tonic-gate 2281*7c478bd9Sstevel@tonic-gate /* 2282*7c478bd9Sstevel@tonic-gate * Hold the module. 2283*7c478bd9Sstevel@tonic-gate */ 2284*7c478bd9Sstevel@tonic-gate modp = mod_hold_by_name(name); 2285*7c478bd9Sstevel@tonic-gate if (modp) { 2286*7c478bd9Sstevel@tonic-gate retval = mod_load(modp, usepath); 2287*7c478bd9Sstevel@tonic-gate if (retval != 0) { 2288*7c478bd9Sstevel@tonic-gate mod_release_mod(modp); 2289*7c478bd9Sstevel@tonic-gate modp = NULL; 2290*7c478bd9Sstevel@tonic-gate *r = retval; 2291*7c478bd9Sstevel@tonic-gate } else { 2292*7c478bd9Sstevel@tonic-gate if ((*r = modinstall(modp)) != 0) { 2293*7c478bd9Sstevel@tonic-gate /* 2294*7c478bd9Sstevel@tonic-gate * We loaded it, but failed to _init() it. 2295*7c478bd9Sstevel@tonic-gate * Be kind to developers -- force it 2296*7c478bd9Sstevel@tonic-gate * out of memory now so that the next 2297*7c478bd9Sstevel@tonic-gate * attempt to use the module will cause 2298*7c478bd9Sstevel@tonic-gate * a reload. See 1093793. 2299*7c478bd9Sstevel@tonic-gate */ 2300*7c478bd9Sstevel@tonic-gate mod_unload(modp); 2301*7c478bd9Sstevel@tonic-gate mod_release_mod(modp); 2302*7c478bd9Sstevel@tonic-gate modp = NULL; 2303*7c478bd9Sstevel@tonic-gate } 2304*7c478bd9Sstevel@tonic-gate } 2305*7c478bd9Sstevel@tonic-gate } else { 2306*7c478bd9Sstevel@tonic-gate *r = ENOSPC; 2307*7c478bd9Sstevel@tonic-gate } 2308*7c478bd9Sstevel@tonic-gate return (modp); 2309*7c478bd9Sstevel@tonic-gate } 2310*7c478bd9Sstevel@tonic-gate 2311*7c478bd9Sstevel@tonic-gate static char mod_excl_msg[] = 2312*7c478bd9Sstevel@tonic-gate "module %s(%s) is EXCLUDED and will not be loaded\n"; 2313*7c478bd9Sstevel@tonic-gate static char mod_init_msg[] = "loadmodule:%s(%s): _init() error %d\n"; 2314*7c478bd9Sstevel@tonic-gate 2315*7c478bd9Sstevel@tonic-gate /* 2316*7c478bd9Sstevel@tonic-gate * This routine is needed for dependencies. Users specify dependencies 2317*7c478bd9Sstevel@tonic-gate * by declaring a character array initialized to filenames of dependents. 2318*7c478bd9Sstevel@tonic-gate * So the code that handles dependents deals with filenames (and not 2319*7c478bd9Sstevel@tonic-gate * module names) because that's all it has. We load by filename and once 2320*7c478bd9Sstevel@tonic-gate * we've loaded a file we can get the module name. 2321*7c478bd9Sstevel@tonic-gate * Unfortunately there isn't a single unified filename/modulename namespace. 2322*7c478bd9Sstevel@tonic-gate * C'est la vie. 2323*7c478bd9Sstevel@tonic-gate * 2324*7c478bd9Sstevel@tonic-gate * We allow the name being looked up to be prepended by an optional 2325*7c478bd9Sstevel@tonic-gate * subdirectory e.g. we can lookup (NULL, "fs/ufs") or ("fs", "ufs") 2326*7c478bd9Sstevel@tonic-gate */ 2327*7c478bd9Sstevel@tonic-gate struct modctl * 2328*7c478bd9Sstevel@tonic-gate mod_find_by_filename(char *subdir, char *filename) 2329*7c478bd9Sstevel@tonic-gate { 2330*7c478bd9Sstevel@tonic-gate struct modctl *mp; 2331*7c478bd9Sstevel@tonic-gate size_t sublen; 2332*7c478bd9Sstevel@tonic-gate 2333*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&mod_lock)); 2334*7c478bd9Sstevel@tonic-gate if (subdir != NULL) 2335*7c478bd9Sstevel@tonic-gate sublen = strlen(subdir); 2336*7c478bd9Sstevel@tonic-gate else 2337*7c478bd9Sstevel@tonic-gate sublen = 0; 2338*7c478bd9Sstevel@tonic-gate 2339*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 2340*7c478bd9Sstevel@tonic-gate mp = &modules; 2341*7c478bd9Sstevel@tonic-gate do { 2342*7c478bd9Sstevel@tonic-gate if (sublen) { 2343*7c478bd9Sstevel@tonic-gate char *mod_filename = mp->mod_filename; 2344*7c478bd9Sstevel@tonic-gate 2345*7c478bd9Sstevel@tonic-gate if (strncmp(subdir, mod_filename, sublen) == 0 && 2346*7c478bd9Sstevel@tonic-gate mod_filename[sublen] == '/' && 2347*7c478bd9Sstevel@tonic-gate strcmp(filename, &mod_filename[sublen + 1]) == 0) { 2348*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2349*7c478bd9Sstevel@tonic-gate return (mp); 2350*7c478bd9Sstevel@tonic-gate } 2351*7c478bd9Sstevel@tonic-gate } else if (strcmp(filename, mp->mod_filename) == 0) { 2352*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2353*7c478bd9Sstevel@tonic-gate return (mp); 2354*7c478bd9Sstevel@tonic-gate } 2355*7c478bd9Sstevel@tonic-gate } while ((mp = mp->mod_next) != &modules); 2356*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2357*7c478bd9Sstevel@tonic-gate return (NULL); 2358*7c478bd9Sstevel@tonic-gate } 2359*7c478bd9Sstevel@tonic-gate 2360*7c478bd9Sstevel@tonic-gate /* 2361*7c478bd9Sstevel@tonic-gate * Check for circular dependencies. This is called from do_dependents() 2362*7c478bd9Sstevel@tonic-gate * in kobj.c. If we are the thread already loading this module, then 2363*7c478bd9Sstevel@tonic-gate * we're trying to load a dependent that we're already loading which 2364*7c478bd9Sstevel@tonic-gate * means the user specified circular dependencies. 2365*7c478bd9Sstevel@tonic-gate */ 2366*7c478bd9Sstevel@tonic-gate static int 2367*7c478bd9Sstevel@tonic-gate mod_circdep(struct modctl *modp) 2368*7c478bd9Sstevel@tonic-gate { 2369*7c478bd9Sstevel@tonic-gate struct modctl *rmod; 2370*7c478bd9Sstevel@tonic-gate 2371*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mod_lock)); 2372*7c478bd9Sstevel@tonic-gate 2373*7c478bd9Sstevel@tonic-gate /* 2374*7c478bd9Sstevel@tonic-gate * Check the mod_inprogress_thread first. 2375*7c478bd9Sstevel@tonic-gate * mod_inprogress_thread is used in mod_hold_stub() 2376*7c478bd9Sstevel@tonic-gate * directly to improve performance. 2377*7c478bd9Sstevel@tonic-gate */ 2378*7c478bd9Sstevel@tonic-gate if (modp->mod_inprogress_thread == curthread) 2379*7c478bd9Sstevel@tonic-gate return (1); 2380*7c478bd9Sstevel@tonic-gate 2381*7c478bd9Sstevel@tonic-gate /* 2382*7c478bd9Sstevel@tonic-gate * Check the module circular dependencies. 2383*7c478bd9Sstevel@tonic-gate */ 2384*7c478bd9Sstevel@tonic-gate for (rmod = modp; rmod != NULL; rmod = rmod->mod_requisite_loading) { 2385*7c478bd9Sstevel@tonic-gate /* 2386*7c478bd9Sstevel@tonic-gate * Check if there is a module circular dependency. 2387*7c478bd9Sstevel@tonic-gate */ 2388*7c478bd9Sstevel@tonic-gate if (rmod->mod_requisite_loading == modp) 2389*7c478bd9Sstevel@tonic-gate return (1); 2390*7c478bd9Sstevel@tonic-gate } 2391*7c478bd9Sstevel@tonic-gate return (0); 2392*7c478bd9Sstevel@tonic-gate } 2393*7c478bd9Sstevel@tonic-gate 2394*7c478bd9Sstevel@tonic-gate static int 2395*7c478bd9Sstevel@tonic-gate mod_getinfo(struct modctl *modp, struct modinfo *modinfop) 2396*7c478bd9Sstevel@tonic-gate { 2397*7c478bd9Sstevel@tonic-gate int (*func)(struct modinfo *); 2398*7c478bd9Sstevel@tonic-gate int retval; 2399*7c478bd9Sstevel@tonic-gate 2400*7c478bd9Sstevel@tonic-gate ASSERT(modp->mod_busy); 2401*7c478bd9Sstevel@tonic-gate 2402*7c478bd9Sstevel@tonic-gate /* primary modules don't do getinfo */ 2403*7c478bd9Sstevel@tonic-gate if (modp->mod_prim) 2404*7c478bd9Sstevel@tonic-gate return (0); 2405*7c478bd9Sstevel@tonic-gate 2406*7c478bd9Sstevel@tonic-gate func = (int (*)(struct modinfo *))kobj_lookup(modp->mod_mp, "_info"); 2407*7c478bd9Sstevel@tonic-gate 2408*7c478bd9Sstevel@tonic-gate if (kobj_addrcheck(modp->mod_mp, (caddr_t)func)) { 2409*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "_info() not defined properly in %s", 2410*7c478bd9Sstevel@tonic-gate modp->mod_filename); 2411*7c478bd9Sstevel@tonic-gate /* 2412*7c478bd9Sstevel@tonic-gate * The semantics of mod_info(9F) are that 0 is failure 2413*7c478bd9Sstevel@tonic-gate * and non-zero is success. 2414*7c478bd9Sstevel@tonic-gate */ 2415*7c478bd9Sstevel@tonic-gate retval = 0; 2416*7c478bd9Sstevel@tonic-gate } else 2417*7c478bd9Sstevel@tonic-gate retval = (*func)(modinfop); /* call _info() function */ 2418*7c478bd9Sstevel@tonic-gate 2419*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_USERDEBUG) 2420*7c478bd9Sstevel@tonic-gate printf("Returned from _info, retval = %x\n", retval); 2421*7c478bd9Sstevel@tonic-gate 2422*7c478bd9Sstevel@tonic-gate return (retval); 2423*7c478bd9Sstevel@tonic-gate } 2424*7c478bd9Sstevel@tonic-gate 2425*7c478bd9Sstevel@tonic-gate static void 2426*7c478bd9Sstevel@tonic-gate modadd(struct modctl *mp) 2427*7c478bd9Sstevel@tonic-gate { 2428*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mod_lock)); 2429*7c478bd9Sstevel@tonic-gate 2430*7c478bd9Sstevel@tonic-gate mp->mod_id = last_module_id++; 2431*7c478bd9Sstevel@tonic-gate mp->mod_next = &modules; 2432*7c478bd9Sstevel@tonic-gate mp->mod_prev = modules.mod_prev; 2433*7c478bd9Sstevel@tonic-gate modules.mod_prev->mod_next = mp; 2434*7c478bd9Sstevel@tonic-gate modules.mod_prev = mp; 2435*7c478bd9Sstevel@tonic-gate } 2436*7c478bd9Sstevel@tonic-gate 2437*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2438*7c478bd9Sstevel@tonic-gate static struct modctl * 2439*7c478bd9Sstevel@tonic-gate allocate_modp(char *filename, char *modname) 2440*7c478bd9Sstevel@tonic-gate { 2441*7c478bd9Sstevel@tonic-gate struct modctl *mp; 2442*7c478bd9Sstevel@tonic-gate 2443*7c478bd9Sstevel@tonic-gate mp = kobj_zalloc(sizeof (*mp), KM_SLEEP); 2444*7c478bd9Sstevel@tonic-gate mp->mod_modname = kobj_zalloc(strlen(modname) + 1, KM_SLEEP); 2445*7c478bd9Sstevel@tonic-gate (void) strcpy(mp->mod_modname, modname); 2446*7c478bd9Sstevel@tonic-gate return (mp); 2447*7c478bd9Sstevel@tonic-gate } 2448*7c478bd9Sstevel@tonic-gate 2449*7c478bd9Sstevel@tonic-gate /* 2450*7c478bd9Sstevel@tonic-gate * Get the value of a symbol. This is a wrapper routine that 2451*7c478bd9Sstevel@tonic-gate * calls kobj_getsymvalue(). kobj_getsymvalue() may go away but this 2452*7c478bd9Sstevel@tonic-gate * wrapper will prevent callers from noticing. 2453*7c478bd9Sstevel@tonic-gate */ 2454*7c478bd9Sstevel@tonic-gate uintptr_t 2455*7c478bd9Sstevel@tonic-gate modgetsymvalue(char *name, int kernelonly) 2456*7c478bd9Sstevel@tonic-gate { 2457*7c478bd9Sstevel@tonic-gate return (kobj_getsymvalue(name, kernelonly)); 2458*7c478bd9Sstevel@tonic-gate } 2459*7c478bd9Sstevel@tonic-gate 2460*7c478bd9Sstevel@tonic-gate /* 2461*7c478bd9Sstevel@tonic-gate * Get the symbol nearest an address. This is a wrapper routine that 2462*7c478bd9Sstevel@tonic-gate * calls kobj_getsymname(). kobj_getsymname() may go away but this 2463*7c478bd9Sstevel@tonic-gate * wrapper will prevent callers from noticing. 2464*7c478bd9Sstevel@tonic-gate */ 2465*7c478bd9Sstevel@tonic-gate char * 2466*7c478bd9Sstevel@tonic-gate modgetsymname(uintptr_t value, ulong_t *offset) 2467*7c478bd9Sstevel@tonic-gate { 2468*7c478bd9Sstevel@tonic-gate return (kobj_getsymname(value, offset)); 2469*7c478bd9Sstevel@tonic-gate } 2470*7c478bd9Sstevel@tonic-gate 2471*7c478bd9Sstevel@tonic-gate /* 2472*7c478bd9Sstevel@tonic-gate * Lookup a symbol in a specified module. This is a wrapper routine that 2473*7c478bd9Sstevel@tonic-gate * calls kobj_lookup(). kobj_lookup() may go away but this 2474*7c478bd9Sstevel@tonic-gate * wrapper will prevent callers from noticing. 2475*7c478bd9Sstevel@tonic-gate */ 2476*7c478bd9Sstevel@tonic-gate uintptr_t 2477*7c478bd9Sstevel@tonic-gate modlookup(char *modname, char *symname) 2478*7c478bd9Sstevel@tonic-gate { 2479*7c478bd9Sstevel@tonic-gate struct modctl *modp; 2480*7c478bd9Sstevel@tonic-gate uintptr_t val; 2481*7c478bd9Sstevel@tonic-gate 2482*7c478bd9Sstevel@tonic-gate if ((modp = mod_hold_by_name(modname)) == NULL) 2483*7c478bd9Sstevel@tonic-gate return (0); 2484*7c478bd9Sstevel@tonic-gate val = kobj_lookup(modp->mod_mp, symname); 2485*7c478bd9Sstevel@tonic-gate mod_release_mod(modp); 2486*7c478bd9Sstevel@tonic-gate return (val); 2487*7c478bd9Sstevel@tonic-gate } 2488*7c478bd9Sstevel@tonic-gate 2489*7c478bd9Sstevel@tonic-gate /* 2490*7c478bd9Sstevel@tonic-gate * Ask the user for the name of the system file and the default path 2491*7c478bd9Sstevel@tonic-gate * for modules. 2492*7c478bd9Sstevel@tonic-gate */ 2493*7c478bd9Sstevel@tonic-gate void 2494*7c478bd9Sstevel@tonic-gate mod_askparams() 2495*7c478bd9Sstevel@tonic-gate { 2496*7c478bd9Sstevel@tonic-gate static char s0[64]; 2497*7c478bd9Sstevel@tonic-gate intptr_t fd; 2498*7c478bd9Sstevel@tonic-gate 2499*7c478bd9Sstevel@tonic-gate if ((fd = kobj_open(systemfile)) != -1L) 2500*7c478bd9Sstevel@tonic-gate kobj_close(fd); 2501*7c478bd9Sstevel@tonic-gate else 2502*7c478bd9Sstevel@tonic-gate systemfile = NULL; 2503*7c478bd9Sstevel@tonic-gate 2504*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/ 2505*7c478bd9Sstevel@tonic-gate while (1) { 2506*7c478bd9Sstevel@tonic-gate printf("Name of system file [%s]: ", 2507*7c478bd9Sstevel@tonic-gate systemfile ? systemfile : "/dev/null"); 2508*7c478bd9Sstevel@tonic-gate 2509*7c478bd9Sstevel@tonic-gate console_gets(s0, sizeof (s0)); 2510*7c478bd9Sstevel@tonic-gate 2511*7c478bd9Sstevel@tonic-gate if (s0[0] == '\0') 2512*7c478bd9Sstevel@tonic-gate break; 2513*7c478bd9Sstevel@tonic-gate else if (strcmp(s0, "/dev/null") == 0) { 2514*7c478bd9Sstevel@tonic-gate systemfile = NULL; 2515*7c478bd9Sstevel@tonic-gate break; 2516*7c478bd9Sstevel@tonic-gate } else { 2517*7c478bd9Sstevel@tonic-gate if ((fd = kobj_open(s0)) != -1L) { 2518*7c478bd9Sstevel@tonic-gate kobj_close(fd); 2519*7c478bd9Sstevel@tonic-gate systemfile = s0; 2520*7c478bd9Sstevel@tonic-gate break; 2521*7c478bd9Sstevel@tonic-gate } 2522*7c478bd9Sstevel@tonic-gate } 2523*7c478bd9Sstevel@tonic-gate printf("can't find file %s\n", s0); 2524*7c478bd9Sstevel@tonic-gate } 2525*7c478bd9Sstevel@tonic-gate } 2526*7c478bd9Sstevel@tonic-gate 2527*7c478bd9Sstevel@tonic-gate static char loading_msg[] = "loading '%s' id %d\n"; 2528*7c478bd9Sstevel@tonic-gate static char load_msg[] = "load '%s' id %d loaded @ 0x%p/0x%p size %d/%d\n"; 2529*7c478bd9Sstevel@tonic-gate 2530*7c478bd9Sstevel@tonic-gate /* 2531*7c478bd9Sstevel@tonic-gate * Common code for loading a module (but not installing it). 2532*7c478bd9Sstevel@tonic-gate * Handoff the task of module loading to a seperate thread 2533*7c478bd9Sstevel@tonic-gate * with a large stack if possible, since this code may recurse a few times. 2534*7c478bd9Sstevel@tonic-gate * Return zero if there are no errors or an errno value. 2535*7c478bd9Sstevel@tonic-gate */ 2536*7c478bd9Sstevel@tonic-gate static int 2537*7c478bd9Sstevel@tonic-gate mod_load(struct modctl *mp, int usepath) 2538*7c478bd9Sstevel@tonic-gate { 2539*7c478bd9Sstevel@tonic-gate int retval; 2540*7c478bd9Sstevel@tonic-gate struct modinfo *modinfop = NULL; 2541*7c478bd9Sstevel@tonic-gate struct loadmt lt; 2542*7c478bd9Sstevel@tonic-gate 2543*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mod_lock)); 2544*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_busy); 2545*7c478bd9Sstevel@tonic-gate 2546*7c478bd9Sstevel@tonic-gate if (mp->mod_loaded) 2547*7c478bd9Sstevel@tonic-gate return (0); 2548*7c478bd9Sstevel@tonic-gate 2549*7c478bd9Sstevel@tonic-gate if (mod_sysctl(SYS_CHECK_EXCLUDE, mp->mod_modname) != 0 || 2550*7c478bd9Sstevel@tonic-gate mod_sysctl(SYS_CHECK_EXCLUDE, mp->mod_filename) != 0) { 2551*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_LOADMSG) { 2552*7c478bd9Sstevel@tonic-gate printf(mod_excl_msg, mp->mod_filename, 2553*7c478bd9Sstevel@tonic-gate mp->mod_modname); 2554*7c478bd9Sstevel@tonic-gate } 2555*7c478bd9Sstevel@tonic-gate return (ENXIO); 2556*7c478bd9Sstevel@tonic-gate } 2557*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_LOADMSG2) 2558*7c478bd9Sstevel@tonic-gate printf(loading_msg, mp->mod_filename, mp->mod_id); 2559*7c478bd9Sstevel@tonic-gate 2560*7c478bd9Sstevel@tonic-gate if (curthread != &t0) { 2561*7c478bd9Sstevel@tonic-gate lt.mp = mp; 2562*7c478bd9Sstevel@tonic-gate lt.usepath = usepath; 2563*7c478bd9Sstevel@tonic-gate lt.owner = curthread; 2564*7c478bd9Sstevel@tonic-gate sema_init(<.sema, 0, NULL, SEMA_DEFAULT, NULL); 2565*7c478bd9Sstevel@tonic-gate 2566*7c478bd9Sstevel@tonic-gate /* create thread to hand of call to */ 2567*7c478bd9Sstevel@tonic-gate (void) thread_create(NULL, DEFAULTSTKSZ * 2, 2568*7c478bd9Sstevel@tonic-gate modload_thread, <, 0, &p0, TS_RUN, maxclsyspri); 2569*7c478bd9Sstevel@tonic-gate 2570*7c478bd9Sstevel@tonic-gate /* wait for thread to complete kobj_load_module */ 2571*7c478bd9Sstevel@tonic-gate sema_p(<.sema); 2572*7c478bd9Sstevel@tonic-gate 2573*7c478bd9Sstevel@tonic-gate sema_destroy(<.sema); 2574*7c478bd9Sstevel@tonic-gate retval = lt.retval; 2575*7c478bd9Sstevel@tonic-gate } else 2576*7c478bd9Sstevel@tonic-gate retval = kobj_load_module(mp, usepath); 2577*7c478bd9Sstevel@tonic-gate 2578*7c478bd9Sstevel@tonic-gate if (mp->mod_mp) { 2579*7c478bd9Sstevel@tonic-gate ASSERT(retval == 0); 2580*7c478bd9Sstevel@tonic-gate mp->mod_loaded = 1; 2581*7c478bd9Sstevel@tonic-gate mp->mod_loadcnt++; 2582*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_LOADMSG) { 2583*7c478bd9Sstevel@tonic-gate printf(load_msg, mp->mod_filename, mp->mod_id, 2584*7c478bd9Sstevel@tonic-gate (void *)((struct module *)mp->mod_mp)->text, 2585*7c478bd9Sstevel@tonic-gate (void *)((struct module *)mp->mod_mp)->data, 2586*7c478bd9Sstevel@tonic-gate ((struct module *)mp->mod_mp)->text_size, 2587*7c478bd9Sstevel@tonic-gate ((struct module *)mp->mod_mp)->data_size); 2588*7c478bd9Sstevel@tonic-gate } 2589*7c478bd9Sstevel@tonic-gate 2590*7c478bd9Sstevel@tonic-gate /* 2591*7c478bd9Sstevel@tonic-gate * XXX - There should be a better way to get this. 2592*7c478bd9Sstevel@tonic-gate */ 2593*7c478bd9Sstevel@tonic-gate modinfop = kmem_zalloc(sizeof (struct modinfo), KM_SLEEP); 2594*7c478bd9Sstevel@tonic-gate modinfop->mi_info = MI_INFO_LINKAGE; 2595*7c478bd9Sstevel@tonic-gate if (mod_getinfo(mp, modinfop) == 0) 2596*7c478bd9Sstevel@tonic-gate mp->mod_linkage = NULL; 2597*7c478bd9Sstevel@tonic-gate else { 2598*7c478bd9Sstevel@tonic-gate mp->mod_linkage = (void *)modinfop->mi_base; 2599*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_linkage->ml_rev == MODREV_1); 2600*7c478bd9Sstevel@tonic-gate } 2601*7c478bd9Sstevel@tonic-gate 2602*7c478bd9Sstevel@tonic-gate /* 2603*7c478bd9Sstevel@tonic-gate * DCS: bootstrapping code. If the driver is loaded 2604*7c478bd9Sstevel@tonic-gate * before root mount, it is assumed that the driver 2605*7c478bd9Sstevel@tonic-gate * may be used before mounting root. In order to 2606*7c478bd9Sstevel@tonic-gate * access mappings of global to local minor no.'s 2607*7c478bd9Sstevel@tonic-gate * during installation/open of the driver, we load 2608*7c478bd9Sstevel@tonic-gate * them into memory here while the BOP_interfaces 2609*7c478bd9Sstevel@tonic-gate * are still up. 2610*7c478bd9Sstevel@tonic-gate */ 2611*7c478bd9Sstevel@tonic-gate if ((cluster_bootflags & CLUSTER_BOOTED) && !modrootloaded) { 2612*7c478bd9Sstevel@tonic-gate retval = clboot_modload(mp); 2613*7c478bd9Sstevel@tonic-gate } 2614*7c478bd9Sstevel@tonic-gate 2615*7c478bd9Sstevel@tonic-gate kmem_free(modinfop, sizeof (struct modinfo)); 2616*7c478bd9Sstevel@tonic-gate (void) mod_sysctl(SYS_SET_MVAR, (void *)mp); 2617*7c478bd9Sstevel@tonic-gate retval = install_stubs_by_name(mp, mp->mod_modname); 2618*7c478bd9Sstevel@tonic-gate 2619*7c478bd9Sstevel@tonic-gate /* 2620*7c478bd9Sstevel@tonic-gate * Now that the module is loaded, we need to give DTrace 2621*7c478bd9Sstevel@tonic-gate * a chance to notify its providers. This is done via 2622*7c478bd9Sstevel@tonic-gate * the dtrace_modload function pointer. 2623*7c478bd9Sstevel@tonic-gate */ 2624*7c478bd9Sstevel@tonic-gate if (strcmp(mp->mod_modname, "dtrace") != 0) { 2625*7c478bd9Sstevel@tonic-gate struct modctl *dmp = mod_hold_by_name("dtrace"); 2626*7c478bd9Sstevel@tonic-gate 2627*7c478bd9Sstevel@tonic-gate if (dmp != NULL && dtrace_modload != NULL) 2628*7c478bd9Sstevel@tonic-gate (*dtrace_modload)(mp); 2629*7c478bd9Sstevel@tonic-gate 2630*7c478bd9Sstevel@tonic-gate mod_release_mod(dmp); 2631*7c478bd9Sstevel@tonic-gate } 2632*7c478bd9Sstevel@tonic-gate 2633*7c478bd9Sstevel@tonic-gate } else { 2634*7c478bd9Sstevel@tonic-gate /* 2635*7c478bd9Sstevel@tonic-gate * If load failed then we need to release any requisites 2636*7c478bd9Sstevel@tonic-gate * that we had established. 2637*7c478bd9Sstevel@tonic-gate */ 2638*7c478bd9Sstevel@tonic-gate ASSERT(retval); 2639*7c478bd9Sstevel@tonic-gate mod_release_requisites(mp); 2640*7c478bd9Sstevel@tonic-gate 2641*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_ERRMSG) 2642*7c478bd9Sstevel@tonic-gate printf("error loading '%s', error %d\n", 2643*7c478bd9Sstevel@tonic-gate mp->mod_filename, retval); 2644*7c478bd9Sstevel@tonic-gate } 2645*7c478bd9Sstevel@tonic-gate return (retval); 2646*7c478bd9Sstevel@tonic-gate } 2647*7c478bd9Sstevel@tonic-gate 2648*7c478bd9Sstevel@tonic-gate static char unload_msg[] = "unloading %s, module id %d, loadcnt %d.\n"; 2649*7c478bd9Sstevel@tonic-gate 2650*7c478bd9Sstevel@tonic-gate static void 2651*7c478bd9Sstevel@tonic-gate mod_unload(struct modctl *mp) 2652*7c478bd9Sstevel@tonic-gate { 2653*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mod_lock)); 2654*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_busy); 2655*7c478bd9Sstevel@tonic-gate ASSERT((mp->mod_loaded && (mp->mod_installed == 0)) && 2656*7c478bd9Sstevel@tonic-gate ((mp->mod_prim == 0) && (mp->mod_ref >= 0))); 2657*7c478bd9Sstevel@tonic-gate 2658*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_LOADMSG) 2659*7c478bd9Sstevel@tonic-gate printf(unload_msg, mp->mod_modname, 2660*7c478bd9Sstevel@tonic-gate mp->mod_id, mp->mod_loadcnt); 2661*7c478bd9Sstevel@tonic-gate 2662*7c478bd9Sstevel@tonic-gate /* 2663*7c478bd9Sstevel@tonic-gate * If mod_ref is not zero, it means some modules might still refer 2664*7c478bd9Sstevel@tonic-gate * to this module. Then you can't unload this module right now. 2665*7c478bd9Sstevel@tonic-gate * Instead, set 1 to mod_delay_unload to notify the system of 2666*7c478bd9Sstevel@tonic-gate * unloading this module later when it's not required any more. 2667*7c478bd9Sstevel@tonic-gate */ 2668*7c478bd9Sstevel@tonic-gate if (mp->mod_ref > 0) { 2669*7c478bd9Sstevel@tonic-gate mp->mod_delay_unload = 1; 2670*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_LOADMSG2) { 2671*7c478bd9Sstevel@tonic-gate printf("module %s not unloaded," 2672*7c478bd9Sstevel@tonic-gate " non-zero reference count (%d)", 2673*7c478bd9Sstevel@tonic-gate mp->mod_modname, mp->mod_ref); 2674*7c478bd9Sstevel@tonic-gate } 2675*7c478bd9Sstevel@tonic-gate return; 2676*7c478bd9Sstevel@tonic-gate } 2677*7c478bd9Sstevel@tonic-gate 2678*7c478bd9Sstevel@tonic-gate if (((mp->mod_loaded == 0) || mp->mod_installed) || 2679*7c478bd9Sstevel@tonic-gate (mp->mod_ref || mp->mod_prim)) { 2680*7c478bd9Sstevel@tonic-gate /* 2681*7c478bd9Sstevel@tonic-gate * A DEBUG kernel would ASSERT panic above, the code is broken 2682*7c478bd9Sstevel@tonic-gate * if we get this warning. 2683*7c478bd9Sstevel@tonic-gate */ 2684*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mod_unload: %s in incorrect state: %d %d %d", 2685*7c478bd9Sstevel@tonic-gate mp->mod_filename, mp->mod_installed, mp->mod_loaded, 2686*7c478bd9Sstevel@tonic-gate mp->mod_ref); 2687*7c478bd9Sstevel@tonic-gate return; 2688*7c478bd9Sstevel@tonic-gate } 2689*7c478bd9Sstevel@tonic-gate 2690*7c478bd9Sstevel@tonic-gate /* reset stub functions to call the binder again */ 2691*7c478bd9Sstevel@tonic-gate reset_stubs(mp); 2692*7c478bd9Sstevel@tonic-gate 2693*7c478bd9Sstevel@tonic-gate /* 2694*7c478bd9Sstevel@tonic-gate * mark module as unloaded before the modctl structure is freed. 2695*7c478bd9Sstevel@tonic-gate * This is required not to reuse the modctl structure before 2696*7c478bd9Sstevel@tonic-gate * the module is marked as unloaded. 2697*7c478bd9Sstevel@tonic-gate */ 2698*7c478bd9Sstevel@tonic-gate mp->mod_loaded = 0; 2699*7c478bd9Sstevel@tonic-gate mp->mod_linkage = NULL; 2700*7c478bd9Sstevel@tonic-gate 2701*7c478bd9Sstevel@tonic-gate /* free the memory */ 2702*7c478bd9Sstevel@tonic-gate kobj_unload_module(mp); 2703*7c478bd9Sstevel@tonic-gate 2704*7c478bd9Sstevel@tonic-gate if (mp->mod_delay_unload) { 2705*7c478bd9Sstevel@tonic-gate mp->mod_delay_unload = 0; 2706*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_LOADMSG2) { 2707*7c478bd9Sstevel@tonic-gate printf("deferred unload of module %s" 2708*7c478bd9Sstevel@tonic-gate " (id %d) successful", 2709*7c478bd9Sstevel@tonic-gate mp->mod_modname, mp->mod_id); 2710*7c478bd9Sstevel@tonic-gate } 2711*7c478bd9Sstevel@tonic-gate } 2712*7c478bd9Sstevel@tonic-gate 2713*7c478bd9Sstevel@tonic-gate /* release hold on requisites */ 2714*7c478bd9Sstevel@tonic-gate mod_release_requisites(mp); 2715*7c478bd9Sstevel@tonic-gate 2716*7c478bd9Sstevel@tonic-gate /* 2717*7c478bd9Sstevel@tonic-gate * Now that the module is gone, we need to give DTrace a chance to 2718*7c478bd9Sstevel@tonic-gate * remove any probes that it may have had in the module. This is 2719*7c478bd9Sstevel@tonic-gate * done via the dtrace_modunload function pointer. 2720*7c478bd9Sstevel@tonic-gate */ 2721*7c478bd9Sstevel@tonic-gate if (strcmp(mp->mod_modname, "dtrace") != 0) { 2722*7c478bd9Sstevel@tonic-gate struct modctl *dmp = mod_hold_by_name("dtrace"); 2723*7c478bd9Sstevel@tonic-gate 2724*7c478bd9Sstevel@tonic-gate if (dmp != NULL && dtrace_modunload != NULL) 2725*7c478bd9Sstevel@tonic-gate (*dtrace_modunload)(mp); 2726*7c478bd9Sstevel@tonic-gate 2727*7c478bd9Sstevel@tonic-gate mod_release_mod(dmp); 2728*7c478bd9Sstevel@tonic-gate } 2729*7c478bd9Sstevel@tonic-gate } 2730*7c478bd9Sstevel@tonic-gate 2731*7c478bd9Sstevel@tonic-gate static int 2732*7c478bd9Sstevel@tonic-gate modinstall(struct modctl *mp) 2733*7c478bd9Sstevel@tonic-gate { 2734*7c478bd9Sstevel@tonic-gate int val; 2735*7c478bd9Sstevel@tonic-gate int (*func)(void); 2736*7c478bd9Sstevel@tonic-gate 2737*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mod_lock)); 2738*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_busy && mp->mod_loaded); 2739*7c478bd9Sstevel@tonic-gate 2740*7c478bd9Sstevel@tonic-gate if (mp->mod_installed) 2741*7c478bd9Sstevel@tonic-gate return (0); 2742*7c478bd9Sstevel@tonic-gate /* 2743*7c478bd9Sstevel@tonic-gate * If mod_delay_unload is on, it means the system chose the deferred 2744*7c478bd9Sstevel@tonic-gate * unload for this module. Then you can't install this module until 2745*7c478bd9Sstevel@tonic-gate * it's unloaded from the system. 2746*7c478bd9Sstevel@tonic-gate */ 2747*7c478bd9Sstevel@tonic-gate if (mp->mod_delay_unload) 2748*7c478bd9Sstevel@tonic-gate return (ENXIO); 2749*7c478bd9Sstevel@tonic-gate 2750*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_LOADMSG) 2751*7c478bd9Sstevel@tonic-gate printf("installing %s, module id %d.\n", 2752*7c478bd9Sstevel@tonic-gate mp->mod_modname, mp->mod_id); 2753*7c478bd9Sstevel@tonic-gate 2754*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_mp != NULL); 2755*7c478bd9Sstevel@tonic-gate if (mod_install_requisites(mp) != 0) { 2756*7c478bd9Sstevel@tonic-gate /* 2757*7c478bd9Sstevel@tonic-gate * Note that we can't call mod_unload(mp) here since 2758*7c478bd9Sstevel@tonic-gate * if modinstall() was called by mod_install_requisites(), 2759*7c478bd9Sstevel@tonic-gate * we won't be able to hold the dependent modules 2760*7c478bd9Sstevel@tonic-gate * (otherwise there would be a deadlock). 2761*7c478bd9Sstevel@tonic-gate */ 2762*7c478bd9Sstevel@tonic-gate return (ENXIO); 2763*7c478bd9Sstevel@tonic-gate } 2764*7c478bd9Sstevel@tonic-gate 2765*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_ERRMSG) { 2766*7c478bd9Sstevel@tonic-gate printf("init '%s' id %d loaded @ 0x%p/0x%p size %lu/%lu\n", 2767*7c478bd9Sstevel@tonic-gate mp->mod_filename, mp->mod_id, 2768*7c478bd9Sstevel@tonic-gate (void *)((struct module *)mp->mod_mp)->text, 2769*7c478bd9Sstevel@tonic-gate (void *)((struct module *)mp->mod_mp)->data, 2770*7c478bd9Sstevel@tonic-gate ((struct module *)mp->mod_mp)->text_size, 2771*7c478bd9Sstevel@tonic-gate ((struct module *)mp->mod_mp)->data_size); 2772*7c478bd9Sstevel@tonic-gate } 2773*7c478bd9Sstevel@tonic-gate 2774*7c478bd9Sstevel@tonic-gate func = (int (*)())kobj_lookup(mp->mod_mp, "_init"); 2775*7c478bd9Sstevel@tonic-gate 2776*7c478bd9Sstevel@tonic-gate if (kobj_addrcheck(mp->mod_mp, (caddr_t)func)) { 2777*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "_init() not defined properly in %s", 2778*7c478bd9Sstevel@tonic-gate mp->mod_filename); 2779*7c478bd9Sstevel@tonic-gate return (EFAULT); 2780*7c478bd9Sstevel@tonic-gate } 2781*7c478bd9Sstevel@tonic-gate 2782*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_USERDEBUG) { 2783*7c478bd9Sstevel@tonic-gate printf("breakpoint before calling %s:_init()\n", 2784*7c478bd9Sstevel@tonic-gate mp->mod_modname); 2785*7c478bd9Sstevel@tonic-gate if (DEBUGGER_PRESENT) 2786*7c478bd9Sstevel@tonic-gate debug_enter("_init"); 2787*7c478bd9Sstevel@tonic-gate } 2788*7c478bd9Sstevel@tonic-gate 2789*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mod_lock)); 2790*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_busy && mp->mod_loaded); 2791*7c478bd9Sstevel@tonic-gate val = (*func)(); /* call _init */ 2792*7c478bd9Sstevel@tonic-gate 2793*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_USERDEBUG) 2794*7c478bd9Sstevel@tonic-gate printf("Returned from _init, val = %x\n", val); 2795*7c478bd9Sstevel@tonic-gate 2796*7c478bd9Sstevel@tonic-gate if (val == 0) { 2797*7c478bd9Sstevel@tonic-gate /* 2798*7c478bd9Sstevel@tonic-gate * Set the MODS_INSTALLED flag to enable this module 2799*7c478bd9Sstevel@tonic-gate * being called now. 2800*7c478bd9Sstevel@tonic-gate */ 2801*7c478bd9Sstevel@tonic-gate install_stubs(mp); 2802*7c478bd9Sstevel@tonic-gate mp->mod_installed = 1; 2803*7c478bd9Sstevel@tonic-gate } else if (moddebug & MODDEBUG_ERRMSG) 2804*7c478bd9Sstevel@tonic-gate printf(mod_init_msg, mp->mod_filename, mp->mod_modname, val); 2805*7c478bd9Sstevel@tonic-gate 2806*7c478bd9Sstevel@tonic-gate return (val); 2807*7c478bd9Sstevel@tonic-gate } 2808*7c478bd9Sstevel@tonic-gate 2809*7c478bd9Sstevel@tonic-gate static int 2810*7c478bd9Sstevel@tonic-gate detach_driver(char *name) 2811*7c478bd9Sstevel@tonic-gate { 2812*7c478bd9Sstevel@tonic-gate major_t major; 2813*7c478bd9Sstevel@tonic-gate int error; 2814*7c478bd9Sstevel@tonic-gate 2815*7c478bd9Sstevel@tonic-gate /* 2816*7c478bd9Sstevel@tonic-gate * If being called from mod_uninstall_all() then the appropriate 2817*7c478bd9Sstevel@tonic-gate * driver detaches (leaf only) have already been done. 2818*7c478bd9Sstevel@tonic-gate */ 2819*7c478bd9Sstevel@tonic-gate if (mod_in_autounload()) 2820*7c478bd9Sstevel@tonic-gate return (0); 2821*7c478bd9Sstevel@tonic-gate 2822*7c478bd9Sstevel@tonic-gate major = ddi_name_to_major(name); 2823*7c478bd9Sstevel@tonic-gate if (major == (major_t)-1) 2824*7c478bd9Sstevel@tonic-gate return (0); 2825*7c478bd9Sstevel@tonic-gate 2826*7c478bd9Sstevel@tonic-gate error = ndi_devi_unconfig_driver(ddi_root_node(), 2827*7c478bd9Sstevel@tonic-gate NDI_DETACH_DRIVER, major); 2828*7c478bd9Sstevel@tonic-gate return (error == NDI_SUCCESS ? 0 : -1); 2829*7c478bd9Sstevel@tonic-gate } 2830*7c478bd9Sstevel@tonic-gate 2831*7c478bd9Sstevel@tonic-gate static char finiret_msg[] = "Returned from _fini for %s, status = %x\n"; 2832*7c478bd9Sstevel@tonic-gate 2833*7c478bd9Sstevel@tonic-gate static int 2834*7c478bd9Sstevel@tonic-gate moduninstall(struct modctl *mp) 2835*7c478bd9Sstevel@tonic-gate { 2836*7c478bd9Sstevel@tonic-gate int status = 0; 2837*7c478bd9Sstevel@tonic-gate int (*func)(void); 2838*7c478bd9Sstevel@tonic-gate 2839*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mod_lock)); 2840*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_busy); 2841*7c478bd9Sstevel@tonic-gate 2842*7c478bd9Sstevel@tonic-gate /* 2843*7c478bd9Sstevel@tonic-gate * Verify that we need to do something and can uninstall the module. 2844*7c478bd9Sstevel@tonic-gate * 2845*7c478bd9Sstevel@tonic-gate * If we should not uninstall the module or if the module is not in 2846*7c478bd9Sstevel@tonic-gate * the correct state to start an uninstall we return EBUSY to prevent 2847*7c478bd9Sstevel@tonic-gate * us from progressing to mod_unload. If the module has already been 2848*7c478bd9Sstevel@tonic-gate * uninstalled and unloaded we return EALREADY. 2849*7c478bd9Sstevel@tonic-gate */ 2850*7c478bd9Sstevel@tonic-gate if (mp->mod_prim || mp->mod_ref || mp->mod_nenabled != 0) 2851*7c478bd9Sstevel@tonic-gate return (EBUSY); 2852*7c478bd9Sstevel@tonic-gate if ((mp->mod_installed == 0) || (mp->mod_loaded == 0)) 2853*7c478bd9Sstevel@tonic-gate return (EALREADY); 2854*7c478bd9Sstevel@tonic-gate 2855*7c478bd9Sstevel@tonic-gate /* 2856*7c478bd9Sstevel@tonic-gate * To avoid devinfo / module deadlock we must release this module 2857*7c478bd9Sstevel@tonic-gate * prior to initiating the detach_driver, otherwise the detach_driver 2858*7c478bd9Sstevel@tonic-gate * might deadlock on a devinfo node held by another thread 2859*7c478bd9Sstevel@tonic-gate * coming top down and involving the module we have locked. 2860*7c478bd9Sstevel@tonic-gate * 2861*7c478bd9Sstevel@tonic-gate * When we regrab the module we must reverify that it is OK 2862*7c478bd9Sstevel@tonic-gate * to proceed with the uninstall operation. 2863*7c478bd9Sstevel@tonic-gate */ 2864*7c478bd9Sstevel@tonic-gate mod_release_mod(mp); 2865*7c478bd9Sstevel@tonic-gate status = detach_driver(mp->mod_modname); 2866*7c478bd9Sstevel@tonic-gate (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_NOT_HELD); 2867*7c478bd9Sstevel@tonic-gate 2868*7c478bd9Sstevel@tonic-gate /* check detach status and reverify state with lock */ 2869*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 2870*7c478bd9Sstevel@tonic-gate if ((status != 0) || mp->mod_prim || mp->mod_ref) { 2871*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2872*7c478bd9Sstevel@tonic-gate return (EBUSY); 2873*7c478bd9Sstevel@tonic-gate } 2874*7c478bd9Sstevel@tonic-gate if ((mp->mod_installed == 0) || (mp->mod_loaded == 0)) { 2875*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2876*7c478bd9Sstevel@tonic-gate return (EALREADY); 2877*7c478bd9Sstevel@tonic-gate } 2878*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 2879*7c478bd9Sstevel@tonic-gate 2880*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_LOADMSG2) 2881*7c478bd9Sstevel@tonic-gate printf("uninstalling %s\n", mp->mod_modname); 2882*7c478bd9Sstevel@tonic-gate 2883*7c478bd9Sstevel@tonic-gate /* 2884*7c478bd9Sstevel@tonic-gate * lookup _fini, return EBUSY if not defined. 2885*7c478bd9Sstevel@tonic-gate * 2886*7c478bd9Sstevel@tonic-gate * The MODDEBUG_FINI_EBUSY is usefull in resolving leaks in 2887*7c478bd9Sstevel@tonic-gate * detach(9E) - it allows bufctl addresses to be resolved. 2888*7c478bd9Sstevel@tonic-gate */ 2889*7c478bd9Sstevel@tonic-gate func = (int (*)())kobj_lookup(mp->mod_mp, "_fini"); 2890*7c478bd9Sstevel@tonic-gate if ((func == NULL) || (mp->mod_loadflags & MOD_NOUNLOAD) || 2891*7c478bd9Sstevel@tonic-gate (moddebug & MODDEBUG_FINI_EBUSY)) 2892*7c478bd9Sstevel@tonic-gate return (EBUSY); 2893*7c478bd9Sstevel@tonic-gate 2894*7c478bd9Sstevel@tonic-gate /* verify that _fini is in this module */ 2895*7c478bd9Sstevel@tonic-gate if (kobj_addrcheck(mp->mod_mp, (caddr_t)func)) { 2896*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "_fini() not defined properly in %s", 2897*7c478bd9Sstevel@tonic-gate mp->mod_filename); 2898*7c478bd9Sstevel@tonic-gate return (EFAULT); 2899*7c478bd9Sstevel@tonic-gate } 2900*7c478bd9Sstevel@tonic-gate 2901*7c478bd9Sstevel@tonic-gate /* call _fini() */ 2902*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mod_lock)); 2903*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_busy && mp->mod_loaded && mp->mod_installed); 2904*7c478bd9Sstevel@tonic-gate 2905*7c478bd9Sstevel@tonic-gate status = (*func)(); 2906*7c478bd9Sstevel@tonic-gate 2907*7c478bd9Sstevel@tonic-gate if (status == 0) { 2908*7c478bd9Sstevel@tonic-gate /* _fini returned success, the module is no longer installed */ 2909*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_LOADMSG) 2910*7c478bd9Sstevel@tonic-gate printf("uninstalled %s\n", mp->mod_modname); 2911*7c478bd9Sstevel@tonic-gate 2912*7c478bd9Sstevel@tonic-gate /* 2913*7c478bd9Sstevel@tonic-gate * Even though we only set mod_installed to zero here, a zero 2914*7c478bd9Sstevel@tonic-gate * return value means we are commited to a code path were 2915*7c478bd9Sstevel@tonic-gate * mod_loaded will also end up as zero - we have no other 2916*7c478bd9Sstevel@tonic-gate * way to get the module data and bss back to the pre _init 2917*7c478bd9Sstevel@tonic-gate * state except a reload. To ensure this, after return, 2918*7c478bd9Sstevel@tonic-gate * mod_busy must stay set until mod_loaded is cleared. 2919*7c478bd9Sstevel@tonic-gate */ 2920*7c478bd9Sstevel@tonic-gate mp->mod_installed = 0; 2921*7c478bd9Sstevel@tonic-gate 2922*7c478bd9Sstevel@tonic-gate /* 2923*7c478bd9Sstevel@tonic-gate * Clear the MODS_INSTALLED flag not to call functions 2924*7c478bd9Sstevel@tonic-gate * in the module directly from now on. 2925*7c478bd9Sstevel@tonic-gate */ 2926*7c478bd9Sstevel@tonic-gate uninstall_stubs(mp); 2927*7c478bd9Sstevel@tonic-gate } else { 2928*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_USERDEBUG) 2929*7c478bd9Sstevel@tonic-gate printf(finiret_msg, mp->mod_filename, status); 2930*7c478bd9Sstevel@tonic-gate /* 2931*7c478bd9Sstevel@tonic-gate * By definition _fini is only allowed to return EBUSY or the 2932*7c478bd9Sstevel@tonic-gate * result of mod_remove (EBUSY or EINVAL). In the off chance 2933*7c478bd9Sstevel@tonic-gate * that a driver returns EALREADY we convert this to EINVAL 2934*7c478bd9Sstevel@tonic-gate * since to our caller EALREADY means module was already 2935*7c478bd9Sstevel@tonic-gate * removed. 2936*7c478bd9Sstevel@tonic-gate */ 2937*7c478bd9Sstevel@tonic-gate if (status == EALREADY) 2938*7c478bd9Sstevel@tonic-gate status = EINVAL; 2939*7c478bd9Sstevel@tonic-gate } 2940*7c478bd9Sstevel@tonic-gate 2941*7c478bd9Sstevel@tonic-gate return (status); 2942*7c478bd9Sstevel@tonic-gate } 2943*7c478bd9Sstevel@tonic-gate 2944*7c478bd9Sstevel@tonic-gate /* 2945*7c478bd9Sstevel@tonic-gate * Uninstall all modules. 2946*7c478bd9Sstevel@tonic-gate */ 2947*7c478bd9Sstevel@tonic-gate static void 2948*7c478bd9Sstevel@tonic-gate mod_uninstall_all(void) 2949*7c478bd9Sstevel@tonic-gate { 2950*7c478bd9Sstevel@tonic-gate struct modctl *mp; 2951*7c478bd9Sstevel@tonic-gate modid_t modid = 0; 2952*7c478bd9Sstevel@tonic-gate 2953*7c478bd9Sstevel@tonic-gate /* mark this thread as doing autounloading */ 2954*7c478bd9Sstevel@tonic-gate (void) tsd_set(mod_autounload_key, (void *)1); 2955*7c478bd9Sstevel@tonic-gate 2956*7c478bd9Sstevel@tonic-gate (void) devfs_clean(ddi_root_node(), NULL, 0); 2957*7c478bd9Sstevel@tonic-gate (void) ndi_devi_unconfig(ddi_root_node(), NDI_AUTODETACH); 2958*7c478bd9Sstevel@tonic-gate 2959*7c478bd9Sstevel@tonic-gate while ((mp = mod_hold_next_by_id(modid)) != NULL) { 2960*7c478bd9Sstevel@tonic-gate modid = mp->mod_id; 2961*7c478bd9Sstevel@tonic-gate /* 2962*7c478bd9Sstevel@tonic-gate * Skip modules with the MOD_NOAUTOUNLOAD flag set 2963*7c478bd9Sstevel@tonic-gate */ 2964*7c478bd9Sstevel@tonic-gate if (mp->mod_loadflags & MOD_NOAUTOUNLOAD) { 2965*7c478bd9Sstevel@tonic-gate mod_release_mod(mp); 2966*7c478bd9Sstevel@tonic-gate continue; 2967*7c478bd9Sstevel@tonic-gate } 2968*7c478bd9Sstevel@tonic-gate 2969*7c478bd9Sstevel@tonic-gate if (moduninstall(mp) == 0) 2970*7c478bd9Sstevel@tonic-gate mod_unload(mp); 2971*7c478bd9Sstevel@tonic-gate mod_release_mod(mp); 2972*7c478bd9Sstevel@tonic-gate } 2973*7c478bd9Sstevel@tonic-gate 2974*7c478bd9Sstevel@tonic-gate (void) tsd_set(mod_autounload_key, NULL); 2975*7c478bd9Sstevel@tonic-gate } 2976*7c478bd9Sstevel@tonic-gate 2977*7c478bd9Sstevel@tonic-gate static int modunload_disable_count; 2978*7c478bd9Sstevel@tonic-gate 2979*7c478bd9Sstevel@tonic-gate void 2980*7c478bd9Sstevel@tonic-gate modunload_disable(void) 2981*7c478bd9Sstevel@tonic-gate { 2982*7c478bd9Sstevel@tonic-gate INCR_COUNT(&modunload_disable_count, &mod_uninstall_lock); 2983*7c478bd9Sstevel@tonic-gate } 2984*7c478bd9Sstevel@tonic-gate 2985*7c478bd9Sstevel@tonic-gate void 2986*7c478bd9Sstevel@tonic-gate modunload_enable(void) 2987*7c478bd9Sstevel@tonic-gate { 2988*7c478bd9Sstevel@tonic-gate DECR_COUNT(&modunload_disable_count, &mod_uninstall_lock); 2989*7c478bd9Sstevel@tonic-gate } 2990*7c478bd9Sstevel@tonic-gate 2991*7c478bd9Sstevel@tonic-gate void 2992*7c478bd9Sstevel@tonic-gate mod_uninstall_daemon(void) 2993*7c478bd9Sstevel@tonic-gate { 2994*7c478bd9Sstevel@tonic-gate callb_cpr_t cprinfo; 2995*7c478bd9Sstevel@tonic-gate clock_t ticks = 0; 2996*7c478bd9Sstevel@tonic-gate 2997*7c478bd9Sstevel@tonic-gate mod_aul_thread = curthread; 2998*7c478bd9Sstevel@tonic-gate 2999*7c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, &mod_uninstall_lock, callb_generic_cpr, "mud"); 3000*7c478bd9Sstevel@tonic-gate for (;;) { 3001*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_uninstall_lock); 3002*7c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 3003*7c478bd9Sstevel@tonic-gate /* 3004*7c478bd9Sstevel@tonic-gate * In DEBUG kernels, unheld drivers are uninstalled periodically 3005*7c478bd9Sstevel@tonic-gate * every mod_uninstall_interval seconds. Periodic uninstall can 3006*7c478bd9Sstevel@tonic-gate * be disabled by setting mod_uninstall_interval to 0 which is 3007*7c478bd9Sstevel@tonic-gate * the default for a non-DEBUG kernel. 3008*7c478bd9Sstevel@tonic-gate */ 3009*7c478bd9Sstevel@tonic-gate if (mod_uninstall_interval) { 3010*7c478bd9Sstevel@tonic-gate ticks = ddi_get_lbolt() + 3011*7c478bd9Sstevel@tonic-gate drv_usectohz(mod_uninstall_interval * 1000000); 3012*7c478bd9Sstevel@tonic-gate (void) cv_timedwait(&mod_uninstall_cv, 3013*7c478bd9Sstevel@tonic-gate &mod_uninstall_lock, ticks); 3014*7c478bd9Sstevel@tonic-gate } else { 3015*7c478bd9Sstevel@tonic-gate cv_wait(&mod_uninstall_cv, &mod_uninstall_lock); 3016*7c478bd9Sstevel@tonic-gate } 3017*7c478bd9Sstevel@tonic-gate /* 3018*7c478bd9Sstevel@tonic-gate * The whole daemon is safe for CPR except we don't want 3019*7c478bd9Sstevel@tonic-gate * the daemon to run if FREEZE is issued and this daemon 3020*7c478bd9Sstevel@tonic-gate * wakes up from the cv_wait above. In this case, it'll be 3021*7c478bd9Sstevel@tonic-gate * blocked in CALLB_CPR_SAFE_END until THAW is issued. 3022*7c478bd9Sstevel@tonic-gate * 3023*7c478bd9Sstevel@tonic-gate * The reason of calling CALLB_CPR_SAFE_BEGIN twice is that 3024*7c478bd9Sstevel@tonic-gate * mod_uninstall_lock is used to protect cprinfo and 3025*7c478bd9Sstevel@tonic-gate * CALLB_CPR_SAFE_BEGIN assumes that this lock is held when 3026*7c478bd9Sstevel@tonic-gate * called. 3027*7c478bd9Sstevel@tonic-gate */ 3028*7c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, &mod_uninstall_lock); 3029*7c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo); 3030*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_uninstall_lock); 3031*7c478bd9Sstevel@tonic-gate if ((modunload_disable_count == 0) && 3032*7c478bd9Sstevel@tonic-gate ((moddebug & MODDEBUG_NOAUTOUNLOAD) == 0)) { 3033*7c478bd9Sstevel@tonic-gate mod_uninstall_all(); 3034*7c478bd9Sstevel@tonic-gate } 3035*7c478bd9Sstevel@tonic-gate } 3036*7c478bd9Sstevel@tonic-gate } 3037*7c478bd9Sstevel@tonic-gate 3038*7c478bd9Sstevel@tonic-gate /* 3039*7c478bd9Sstevel@tonic-gate * Unload all uninstalled modules. 3040*7c478bd9Sstevel@tonic-gate */ 3041*7c478bd9Sstevel@tonic-gate void 3042*7c478bd9Sstevel@tonic-gate modreap(void) 3043*7c478bd9Sstevel@tonic-gate { 3044*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_uninstall_lock); 3045*7c478bd9Sstevel@tonic-gate cv_broadcast(&mod_uninstall_cv); 3046*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_uninstall_lock); 3047*7c478bd9Sstevel@tonic-gate } 3048*7c478bd9Sstevel@tonic-gate 3049*7c478bd9Sstevel@tonic-gate /* 3050*7c478bd9Sstevel@tonic-gate * Hold the specified module. This is the module holding primitive. 3051*7c478bd9Sstevel@tonic-gate * 3052*7c478bd9Sstevel@tonic-gate * If MOD_LOCK_HELD then the caller already holds the mod_lock. 3053*7c478bd9Sstevel@tonic-gate * 3054*7c478bd9Sstevel@tonic-gate * Return values: 3055*7c478bd9Sstevel@tonic-gate * 0 ==> the module is held 3056*7c478bd9Sstevel@tonic-gate * 1 ==> the module is not held and the MOD_WAIT_ONCE caller needs 3057*7c478bd9Sstevel@tonic-gate * to determine how to retry. 3058*7c478bd9Sstevel@tonic-gate */ 3059*7c478bd9Sstevel@tonic-gate int 3060*7c478bd9Sstevel@tonic-gate mod_hold_by_modctl(struct modctl *mp, int f) 3061*7c478bd9Sstevel@tonic-gate { 3062*7c478bd9Sstevel@tonic-gate ASSERT((f & (MOD_WAIT_ONCE | MOD_WAIT_FOREVER)) && 3063*7c478bd9Sstevel@tonic-gate ((f & (MOD_WAIT_ONCE | MOD_WAIT_FOREVER)) != 3064*7c478bd9Sstevel@tonic-gate (MOD_WAIT_ONCE | MOD_WAIT_FOREVER))); 3065*7c478bd9Sstevel@tonic-gate ASSERT((f & (MOD_LOCK_HELD | MOD_LOCK_NOT_HELD)) && 3066*7c478bd9Sstevel@tonic-gate ((f & (MOD_LOCK_HELD | MOD_LOCK_NOT_HELD)) != 3067*7c478bd9Sstevel@tonic-gate (MOD_LOCK_HELD | MOD_LOCK_NOT_HELD))); 3068*7c478bd9Sstevel@tonic-gate ASSERT((f & MOD_LOCK_NOT_HELD) || MUTEX_HELD(&mod_lock)); 3069*7c478bd9Sstevel@tonic-gate 3070*7c478bd9Sstevel@tonic-gate if (f & MOD_LOCK_NOT_HELD) 3071*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 3072*7c478bd9Sstevel@tonic-gate 3073*7c478bd9Sstevel@tonic-gate while (mp->mod_busy) { 3074*7c478bd9Sstevel@tonic-gate mp->mod_want = 1; 3075*7c478bd9Sstevel@tonic-gate cv_wait(&mod_cv, &mod_lock); 3076*7c478bd9Sstevel@tonic-gate /* 3077*7c478bd9Sstevel@tonic-gate * Module may be unloaded by daemon. 3078*7c478bd9Sstevel@tonic-gate * Nevertheless, modctl structure is still in linked list 3079*7c478bd9Sstevel@tonic-gate * (i.e., off &modules), not freed! 3080*7c478bd9Sstevel@tonic-gate * Caller is not supposed to assume "mp" is valid, but there 3081*7c478bd9Sstevel@tonic-gate * is no reasonable way to detect this but using 3082*7c478bd9Sstevel@tonic-gate * mp->mod_modinfo->mp == NULL check (follow the back pointer) 3083*7c478bd9Sstevel@tonic-gate * (or similar check depending on calling context) 3084*7c478bd9Sstevel@tonic-gate * DON'T free modctl structure, it will be very very 3085*7c478bd9Sstevel@tonic-gate * problematic. 3086*7c478bd9Sstevel@tonic-gate */ 3087*7c478bd9Sstevel@tonic-gate if (f & MOD_WAIT_ONCE) { 3088*7c478bd9Sstevel@tonic-gate if (f & MOD_LOCK_NOT_HELD) 3089*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 3090*7c478bd9Sstevel@tonic-gate return (1); /* caller decides how to retry */ 3091*7c478bd9Sstevel@tonic-gate } 3092*7c478bd9Sstevel@tonic-gate } 3093*7c478bd9Sstevel@tonic-gate 3094*7c478bd9Sstevel@tonic-gate mp->mod_busy = 1; 3095*7c478bd9Sstevel@tonic-gate mp->mod_inprogress_thread = 3096*7c478bd9Sstevel@tonic-gate (curthread == NULL ? (kthread_id_t)-1 : curthread); 3097*7c478bd9Sstevel@tonic-gate 3098*7c478bd9Sstevel@tonic-gate if (f & MOD_LOCK_NOT_HELD) 3099*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 3100*7c478bd9Sstevel@tonic-gate return (0); 3101*7c478bd9Sstevel@tonic-gate } 3102*7c478bd9Sstevel@tonic-gate 3103*7c478bd9Sstevel@tonic-gate static struct modctl * 3104*7c478bd9Sstevel@tonic-gate mod_hold_by_name_common(struct modctl *dep, char *filename) 3105*7c478bd9Sstevel@tonic-gate { 3106*7c478bd9Sstevel@tonic-gate char *modname; 3107*7c478bd9Sstevel@tonic-gate struct modctl *mp; 3108*7c478bd9Sstevel@tonic-gate char *curname, *newname; 3109*7c478bd9Sstevel@tonic-gate int found = 0; 3110*7c478bd9Sstevel@tonic-gate 3111*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 3112*7c478bd9Sstevel@tonic-gate 3113*7c478bd9Sstevel@tonic-gate if ((modname = strrchr(filename, '/')) == NULL) 3114*7c478bd9Sstevel@tonic-gate modname = filename; 3115*7c478bd9Sstevel@tonic-gate else 3116*7c478bd9Sstevel@tonic-gate modname++; 3117*7c478bd9Sstevel@tonic-gate 3118*7c478bd9Sstevel@tonic-gate mp = &modules; 3119*7c478bd9Sstevel@tonic-gate do { 3120*7c478bd9Sstevel@tonic-gate if (strcmp(modname, mp->mod_modname) == 0) { 3121*7c478bd9Sstevel@tonic-gate found = 1; 3122*7c478bd9Sstevel@tonic-gate break; 3123*7c478bd9Sstevel@tonic-gate } 3124*7c478bd9Sstevel@tonic-gate } while ((mp = mp->mod_next) != &modules); 3125*7c478bd9Sstevel@tonic-gate 3126*7c478bd9Sstevel@tonic-gate if (found == 0) { 3127*7c478bd9Sstevel@tonic-gate mp = allocate_modp(filename, modname); 3128*7c478bd9Sstevel@tonic-gate modadd(mp); 3129*7c478bd9Sstevel@tonic-gate } 3130*7c478bd9Sstevel@tonic-gate 3131*7c478bd9Sstevel@tonic-gate /* 3132*7c478bd9Sstevel@tonic-gate * if dep is not NULL, set the mp in mod_requisite_loading for 3133*7c478bd9Sstevel@tonic-gate * the module circular dependency check. This field is used in 3134*7c478bd9Sstevel@tonic-gate * mod_circdep(), but it's cleard in mod_hold_loaded_mod(). 3135*7c478bd9Sstevel@tonic-gate */ 3136*7c478bd9Sstevel@tonic-gate if (dep != NULL) { 3137*7c478bd9Sstevel@tonic-gate ASSERT(dep->mod_busy && dep->mod_requisite_loading == NULL); 3138*7c478bd9Sstevel@tonic-gate dep->mod_requisite_loading = mp; 3139*7c478bd9Sstevel@tonic-gate } 3140*7c478bd9Sstevel@tonic-gate 3141*7c478bd9Sstevel@tonic-gate /* 3142*7c478bd9Sstevel@tonic-gate * If the module was held, then it must be us who has it held. 3143*7c478bd9Sstevel@tonic-gate */ 3144*7c478bd9Sstevel@tonic-gate if (mod_circdep(mp)) 3145*7c478bd9Sstevel@tonic-gate mp = NULL; 3146*7c478bd9Sstevel@tonic-gate else { 3147*7c478bd9Sstevel@tonic-gate (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_HELD); 3148*7c478bd9Sstevel@tonic-gate 3149*7c478bd9Sstevel@tonic-gate /* 3150*7c478bd9Sstevel@tonic-gate * If the name hadn't been set or has changed, allocate 3151*7c478bd9Sstevel@tonic-gate * space and set it. Free space used by previous name. 3152*7c478bd9Sstevel@tonic-gate * 3153*7c478bd9Sstevel@tonic-gate * Do not change the name of primary modules, for primary 3154*7c478bd9Sstevel@tonic-gate * modules the mod_filename was allocated in standalone mode: 3155*7c478bd9Sstevel@tonic-gate * it is illegal to kobj_alloc in standalone mode and kobj_free 3156*7c478bd9Sstevel@tonic-gate * in non-standalone mode. 3157*7c478bd9Sstevel@tonic-gate */ 3158*7c478bd9Sstevel@tonic-gate curname = mp->mod_filename; 3159*7c478bd9Sstevel@tonic-gate if (curname == NULL || 3160*7c478bd9Sstevel@tonic-gate ((mp->mod_prim == 0) && 3161*7c478bd9Sstevel@tonic-gate (curname != filename) && 3162*7c478bd9Sstevel@tonic-gate (modname != filename) && 3163*7c478bd9Sstevel@tonic-gate (strcmp(curname, filename) != 0))) { 3164*7c478bd9Sstevel@tonic-gate newname = kobj_zalloc(strlen(filename) + 1, KM_SLEEP); 3165*7c478bd9Sstevel@tonic-gate (void) strcpy(newname, filename); 3166*7c478bd9Sstevel@tonic-gate mp->mod_filename = newname; 3167*7c478bd9Sstevel@tonic-gate if (curname != NULL) 3168*7c478bd9Sstevel@tonic-gate kobj_free(curname, strlen(curname) + 1); 3169*7c478bd9Sstevel@tonic-gate } 3170*7c478bd9Sstevel@tonic-gate } 3171*7c478bd9Sstevel@tonic-gate 3172*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 3173*7c478bd9Sstevel@tonic-gate if (mp && moddebug & MODDEBUG_LOADMSG2) 3174*7c478bd9Sstevel@tonic-gate printf("Holding %s\n", mp->mod_filename); 3175*7c478bd9Sstevel@tonic-gate if (mp == NULL && moddebug & MODDEBUG_LOADMSG2) 3176*7c478bd9Sstevel@tonic-gate printf("circular dependency loading %s\n", filename); 3177*7c478bd9Sstevel@tonic-gate return (mp); 3178*7c478bd9Sstevel@tonic-gate } 3179*7c478bd9Sstevel@tonic-gate 3180*7c478bd9Sstevel@tonic-gate static struct modctl * 3181*7c478bd9Sstevel@tonic-gate mod_hold_by_name_requisite(struct modctl *dep, char *filename) 3182*7c478bd9Sstevel@tonic-gate { 3183*7c478bd9Sstevel@tonic-gate return (mod_hold_by_name_common(dep, filename)); 3184*7c478bd9Sstevel@tonic-gate } 3185*7c478bd9Sstevel@tonic-gate 3186*7c478bd9Sstevel@tonic-gate struct modctl * 3187*7c478bd9Sstevel@tonic-gate mod_hold_by_name(char *filename) 3188*7c478bd9Sstevel@tonic-gate { 3189*7c478bd9Sstevel@tonic-gate return (mod_hold_by_name_common(NULL, filename)); 3190*7c478bd9Sstevel@tonic-gate } 3191*7c478bd9Sstevel@tonic-gate 3192*7c478bd9Sstevel@tonic-gate static struct modctl * 3193*7c478bd9Sstevel@tonic-gate mod_hold_by_id(modid_t modid) 3194*7c478bd9Sstevel@tonic-gate { 3195*7c478bd9Sstevel@tonic-gate struct modctl *mp; 3196*7c478bd9Sstevel@tonic-gate int found = 0; 3197*7c478bd9Sstevel@tonic-gate 3198*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 3199*7c478bd9Sstevel@tonic-gate mp = &modules; 3200*7c478bd9Sstevel@tonic-gate do { 3201*7c478bd9Sstevel@tonic-gate if (mp->mod_id == modid) { 3202*7c478bd9Sstevel@tonic-gate found = 1; 3203*7c478bd9Sstevel@tonic-gate break; 3204*7c478bd9Sstevel@tonic-gate } 3205*7c478bd9Sstevel@tonic-gate } while ((mp = mp->mod_next) != &modules); 3206*7c478bd9Sstevel@tonic-gate 3207*7c478bd9Sstevel@tonic-gate if ((found == 0) || mod_circdep(mp)) 3208*7c478bd9Sstevel@tonic-gate mp = NULL; 3209*7c478bd9Sstevel@tonic-gate else 3210*7c478bd9Sstevel@tonic-gate (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_HELD); 3211*7c478bd9Sstevel@tonic-gate 3212*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 3213*7c478bd9Sstevel@tonic-gate return (mp); 3214*7c478bd9Sstevel@tonic-gate } 3215*7c478bd9Sstevel@tonic-gate 3216*7c478bd9Sstevel@tonic-gate static struct modctl * 3217*7c478bd9Sstevel@tonic-gate mod_hold_next_by_id(modid_t modid) 3218*7c478bd9Sstevel@tonic-gate { 3219*7c478bd9Sstevel@tonic-gate struct modctl *mp; 3220*7c478bd9Sstevel@tonic-gate int found = 0; 3221*7c478bd9Sstevel@tonic-gate 3222*7c478bd9Sstevel@tonic-gate if (modid < -1) 3223*7c478bd9Sstevel@tonic-gate return (NULL); 3224*7c478bd9Sstevel@tonic-gate 3225*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 3226*7c478bd9Sstevel@tonic-gate 3227*7c478bd9Sstevel@tonic-gate mp = &modules; 3228*7c478bd9Sstevel@tonic-gate do { 3229*7c478bd9Sstevel@tonic-gate if (mp->mod_id > modid) { 3230*7c478bd9Sstevel@tonic-gate found = 1; 3231*7c478bd9Sstevel@tonic-gate break; 3232*7c478bd9Sstevel@tonic-gate } 3233*7c478bd9Sstevel@tonic-gate } while ((mp = mp->mod_next) != &modules); 3234*7c478bd9Sstevel@tonic-gate 3235*7c478bd9Sstevel@tonic-gate if ((found == 0) || mod_circdep(mp)) 3236*7c478bd9Sstevel@tonic-gate mp = NULL; 3237*7c478bd9Sstevel@tonic-gate else 3238*7c478bd9Sstevel@tonic-gate (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_HELD); 3239*7c478bd9Sstevel@tonic-gate 3240*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 3241*7c478bd9Sstevel@tonic-gate return (mp); 3242*7c478bd9Sstevel@tonic-gate } 3243*7c478bd9Sstevel@tonic-gate 3244*7c478bd9Sstevel@tonic-gate static void 3245*7c478bd9Sstevel@tonic-gate mod_release(struct modctl *mp) 3246*7c478bd9Sstevel@tonic-gate { 3247*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mod_lock)); 3248*7c478bd9Sstevel@tonic-gate ASSERT(mp->mod_busy); 3249*7c478bd9Sstevel@tonic-gate 3250*7c478bd9Sstevel@tonic-gate mp->mod_busy = 0; 3251*7c478bd9Sstevel@tonic-gate mp->mod_inprogress_thread = NULL; 3252*7c478bd9Sstevel@tonic-gate if (mp->mod_want) { 3253*7c478bd9Sstevel@tonic-gate mp->mod_want = 0; 3254*7c478bd9Sstevel@tonic-gate cv_broadcast(&mod_cv); 3255*7c478bd9Sstevel@tonic-gate } 3256*7c478bd9Sstevel@tonic-gate } 3257*7c478bd9Sstevel@tonic-gate 3258*7c478bd9Sstevel@tonic-gate void 3259*7c478bd9Sstevel@tonic-gate mod_release_mod(struct modctl *mp) 3260*7c478bd9Sstevel@tonic-gate { 3261*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_LOADMSG2) 3262*7c478bd9Sstevel@tonic-gate printf("Releasing %s\n", mp->mod_filename); 3263*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 3264*7c478bd9Sstevel@tonic-gate mod_release(mp); 3265*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 3266*7c478bd9Sstevel@tonic-gate } 3267*7c478bd9Sstevel@tonic-gate 3268*7c478bd9Sstevel@tonic-gate modid_t 3269*7c478bd9Sstevel@tonic-gate mod_name_to_modid(char *filename) 3270*7c478bd9Sstevel@tonic-gate { 3271*7c478bd9Sstevel@tonic-gate char *modname; 3272*7c478bd9Sstevel@tonic-gate struct modctl *mp; 3273*7c478bd9Sstevel@tonic-gate 3274*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 3275*7c478bd9Sstevel@tonic-gate 3276*7c478bd9Sstevel@tonic-gate if ((modname = strrchr(filename, '/')) == NULL) 3277*7c478bd9Sstevel@tonic-gate modname = filename; 3278*7c478bd9Sstevel@tonic-gate else 3279*7c478bd9Sstevel@tonic-gate modname++; 3280*7c478bd9Sstevel@tonic-gate 3281*7c478bd9Sstevel@tonic-gate mp = &modules; 3282*7c478bd9Sstevel@tonic-gate do { 3283*7c478bd9Sstevel@tonic-gate if (strcmp(modname, mp->mod_modname) == 0) { 3284*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 3285*7c478bd9Sstevel@tonic-gate return (mp->mod_id); 3286*7c478bd9Sstevel@tonic-gate } 3287*7c478bd9Sstevel@tonic-gate } while ((mp = mp->mod_next) != &modules); 3288*7c478bd9Sstevel@tonic-gate 3289*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 3290*7c478bd9Sstevel@tonic-gate return (-1); 3291*7c478bd9Sstevel@tonic-gate } 3292*7c478bd9Sstevel@tonic-gate 3293*7c478bd9Sstevel@tonic-gate 3294*7c478bd9Sstevel@tonic-gate int 3295*7c478bd9Sstevel@tonic-gate mod_remove_by_name(char *name) 3296*7c478bd9Sstevel@tonic-gate { 3297*7c478bd9Sstevel@tonic-gate struct modctl *mp; 3298*7c478bd9Sstevel@tonic-gate int retval; 3299*7c478bd9Sstevel@tonic-gate 3300*7c478bd9Sstevel@tonic-gate mp = mod_hold_by_name(name); 3301*7c478bd9Sstevel@tonic-gate 3302*7c478bd9Sstevel@tonic-gate if (mp == NULL) 3303*7c478bd9Sstevel@tonic-gate return (EINVAL); 3304*7c478bd9Sstevel@tonic-gate 3305*7c478bd9Sstevel@tonic-gate if (mp->mod_loadflags & MOD_NOAUTOUNLOAD) { 3306*7c478bd9Sstevel@tonic-gate /* 3307*7c478bd9Sstevel@tonic-gate * Do not unload forceloaded modules 3308*7c478bd9Sstevel@tonic-gate */ 3309*7c478bd9Sstevel@tonic-gate mod_release_mod(mp); 3310*7c478bd9Sstevel@tonic-gate return (0); 3311*7c478bd9Sstevel@tonic-gate } 3312*7c478bd9Sstevel@tonic-gate 3313*7c478bd9Sstevel@tonic-gate if ((retval = moduninstall(mp)) == 0) 3314*7c478bd9Sstevel@tonic-gate mod_unload(mp); 3315*7c478bd9Sstevel@tonic-gate else if (retval == EALREADY) 3316*7c478bd9Sstevel@tonic-gate retval = 0; /* already unloaded, not an error */ 3317*7c478bd9Sstevel@tonic-gate mod_release_mod(mp); 3318*7c478bd9Sstevel@tonic-gate return (retval); 3319*7c478bd9Sstevel@tonic-gate } 3320*7c478bd9Sstevel@tonic-gate 3321*7c478bd9Sstevel@tonic-gate /* 3322*7c478bd9Sstevel@tonic-gate * Record that module "dep" is dependent on module "on_mod." 3323*7c478bd9Sstevel@tonic-gate */ 3324*7c478bd9Sstevel@tonic-gate static void 3325*7c478bd9Sstevel@tonic-gate mod_make_requisite(struct modctl *dependent, struct modctl *on_mod) 3326*7c478bd9Sstevel@tonic-gate { 3327*7c478bd9Sstevel@tonic-gate struct modctl_list **pmlnp; /* previous next pointer */ 3328*7c478bd9Sstevel@tonic-gate struct modctl_list *mlp; 3329*7c478bd9Sstevel@tonic-gate struct modctl_list *new; 3330*7c478bd9Sstevel@tonic-gate 3331*7c478bd9Sstevel@tonic-gate ASSERT(dependent->mod_busy && on_mod->mod_busy); 3332*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); 3333*7c478bd9Sstevel@tonic-gate 3334*7c478bd9Sstevel@tonic-gate /* 3335*7c478bd9Sstevel@tonic-gate * Search dependent's requisite list to see if on_mod is recorded. 3336*7c478bd9Sstevel@tonic-gate * List is ordered by id. 3337*7c478bd9Sstevel@tonic-gate */ 3338*7c478bd9Sstevel@tonic-gate for (pmlnp = &dependent->mod_requisites, mlp = *pmlnp; 3339*7c478bd9Sstevel@tonic-gate mlp; pmlnp = &mlp->modl_next, mlp = *pmlnp) 3340*7c478bd9Sstevel@tonic-gate if (mlp->modl_modp->mod_id >= on_mod->mod_id) 3341*7c478bd9Sstevel@tonic-gate break; 3342*7c478bd9Sstevel@tonic-gate 3343*7c478bd9Sstevel@tonic-gate /* Create and insert if not already recorded */ 3344*7c478bd9Sstevel@tonic-gate if ((mlp == NULL) || (mlp->modl_modp->mod_id != on_mod->mod_id)) { 3345*7c478bd9Sstevel@tonic-gate new = kobj_zalloc(sizeof (*new), KM_SLEEP); 3346*7c478bd9Sstevel@tonic-gate new->modl_modp = on_mod; 3347*7c478bd9Sstevel@tonic-gate new->modl_next = mlp; 3348*7c478bd9Sstevel@tonic-gate *pmlnp = new; 3349*7c478bd9Sstevel@tonic-gate 3350*7c478bd9Sstevel@tonic-gate /* 3351*7c478bd9Sstevel@tonic-gate * Increment the mod_ref count in our new requisite module. 3352*7c478bd9Sstevel@tonic-gate * This is what keeps a module that has other modules 3353*7c478bd9Sstevel@tonic-gate * which are dependent on it from being uninstalled and 3354*7c478bd9Sstevel@tonic-gate * unloaded. "on_mod"'s mod_ref count decremented in 3355*7c478bd9Sstevel@tonic-gate * mod_release_requisites when the "dependent" module 3356*7c478bd9Sstevel@tonic-gate * unload is complete. "on_mod" must be loaded, but may not 3357*7c478bd9Sstevel@tonic-gate * yet be installed. 3358*7c478bd9Sstevel@tonic-gate */ 3359*7c478bd9Sstevel@tonic-gate on_mod->mod_ref++; 3360*7c478bd9Sstevel@tonic-gate ASSERT(on_mod->mod_ref && on_mod->mod_loaded); 3361*7c478bd9Sstevel@tonic-gate } 3362*7c478bd9Sstevel@tonic-gate 3363*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 3364*7c478bd9Sstevel@tonic-gate } 3365*7c478bd9Sstevel@tonic-gate 3366*7c478bd9Sstevel@tonic-gate /* 3367*7c478bd9Sstevel@tonic-gate * release the hold associated with mod_make_requisite mod_ref++ 3368*7c478bd9Sstevel@tonic-gate * as part of unload. 3369*7c478bd9Sstevel@tonic-gate */ 3370*7c478bd9Sstevel@tonic-gate void 3371*7c478bd9Sstevel@tonic-gate mod_release_requisites(struct modctl *modp) 3372*7c478bd9Sstevel@tonic-gate { 3373*7c478bd9Sstevel@tonic-gate struct modctl_list *modl; 3374*7c478bd9Sstevel@tonic-gate struct modctl_list *next; 3375*7c478bd9Sstevel@tonic-gate struct modctl *req; 3376*7c478bd9Sstevel@tonic-gate struct modctl_list *start = NULL, *mod_garbage; 3377*7c478bd9Sstevel@tonic-gate 3378*7c478bd9Sstevel@tonic-gate ASSERT(modp->mod_busy); 3379*7c478bd9Sstevel@tonic-gate ASSERT(!MUTEX_HELD(&mod_lock)); 3380*7c478bd9Sstevel@tonic-gate 3381*7c478bd9Sstevel@tonic-gate mutex_enter(&mod_lock); /* needed for manipulation of req */ 3382*7c478bd9Sstevel@tonic-gate for (modl = modp->mod_requisites; modl; modl = next) { 3383*7c478bd9Sstevel@tonic-gate next = modl->modl_next; 3384*7c478bd9Sstevel@tonic-gate req = modl->modl_modp; 3385*7c478bd9Sstevel@tonic-gate ASSERT(req->mod_ref >= 1 && req->mod_loaded); 3386*7c478bd9Sstevel@tonic-gate req->mod_ref--; 3387*7c478bd9Sstevel@tonic-gate 3388*7c478bd9Sstevel@tonic-gate /* 3389*7c478bd9Sstevel@tonic-gate * Check if the module has to be unloaded or not. 3390*7c478bd9Sstevel@tonic-gate */ 3391*7c478bd9Sstevel@tonic-gate if (req->mod_ref == 0 && req->mod_delay_unload) { 3392*7c478bd9Sstevel@tonic-gate struct modctl_list *new; 3393*7c478bd9Sstevel@tonic-gate /* 3394*7c478bd9Sstevel@tonic-gate * Allocate the modclt_list holding the garbage 3395*7c478bd9Sstevel@tonic-gate * module which should be unloaded later. 3396*7c478bd9Sstevel@tonic-gate */ 3397*7c478bd9Sstevel@tonic-gate new = kobj_zalloc(sizeof (struct modctl_list), 3398*7c478bd9Sstevel@tonic-gate KM_SLEEP); 3399*7c478bd9Sstevel@tonic-gate new->modl_modp = req; 3400*7c478bd9Sstevel@tonic-gate 3401*7c478bd9Sstevel@tonic-gate if (start == NULL) 3402*7c478bd9Sstevel@tonic-gate mod_garbage = start = new; 3403*7c478bd9Sstevel@tonic-gate else { 3404*7c478bd9Sstevel@tonic-gate mod_garbage->modl_next = new; 3405*7c478bd9Sstevel@tonic-gate mod_garbage = new; 3406*7c478bd9Sstevel@tonic-gate } 3407*7c478bd9Sstevel@tonic-gate } 3408*7c478bd9Sstevel@tonic-gate 3409*7c478bd9Sstevel@tonic-gate /* free the list as we go */ 3410*7c478bd9Sstevel@tonic-gate kobj_free(modl, sizeof (*modl)); 3411*7c478bd9Sstevel@tonic-gate } 3412*7c478bd9Sstevel@tonic-gate modp->mod_requisites = NULL; 3413*7c478bd9Sstevel@tonic-gate mutex_exit(&mod_lock); 3414*7c478bd9Sstevel@tonic-gate 3415*7c478bd9Sstevel@tonic-gate /* 3416*7c478bd9Sstevel@tonic-gate * Unload the garbage modules. 3417*7c478bd9Sstevel@tonic-gate */ 3418*7c478bd9Sstevel@tonic-gate for (mod_garbage = start; mod_garbage != NULL; /* nothing */) { 3419*7c478bd9Sstevel@tonic-gate struct modctl_list *old = mod_garbage; 3420*7c478bd9Sstevel@tonic-gate struct modctl *mp = mod_garbage->modl_modp; 3421*7c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 3422*7c478bd9Sstevel@tonic-gate 3423*7c478bd9Sstevel@tonic-gate /* 3424*7c478bd9Sstevel@tonic-gate * Hold this module until it's unloaded completely. 3425*7c478bd9Sstevel@tonic-gate */ 3426*7c478bd9Sstevel@tonic-gate (void) mod_hold_by_modctl(mp, 3427*7c478bd9Sstevel@tonic-gate MOD_WAIT_FOREVER | MOD_LOCK_NOT_HELD); 3428*7c478bd9Sstevel@tonic-gate /* 3429*7c478bd9Sstevel@tonic-gate * Check if the module is not unloaded yet and nobody requires 3430*7c478bd9Sstevel@tonic-gate * the module. If it's unloaded already or somebody still 3431*7c478bd9Sstevel@tonic-gate * requires the module, don't unload it now. 3432*7c478bd9Sstevel@tonic-gate */ 3433*7c478bd9Sstevel@tonic-gate if (mp->mod_loaded && mp->mod_ref == 0) 3434*7c478bd9Sstevel@tonic-gate mod_unload(mp); 3435*7c478bd9Sstevel@tonic-gate ASSERT((mp->mod_loaded == 0 && mp->mod_delay_unload == 0) || 3436*7c478bd9Sstevel@tonic-gate (mp->mod_ref > 0)); 3437*7c478bd9Sstevel@tonic-gate mod_release_mod(mp); 3438*7c478bd9Sstevel@tonic-gate 3439*7c478bd9Sstevel@tonic-gate mod_garbage = mod_garbage->modl_next; 3440*7c478bd9Sstevel@tonic-gate kobj_free(old, sizeof (struct modctl_list)); 3441*7c478bd9Sstevel@tonic-gate } 3442*7c478bd9Sstevel@tonic-gate } 3443*7c478bd9Sstevel@tonic-gate 3444*7c478bd9Sstevel@tonic-gate /* 3445*7c478bd9Sstevel@tonic-gate * Process dependency of the module represented by "dep" on the 3446*7c478bd9Sstevel@tonic-gate * module named by "on." 3447*7c478bd9Sstevel@tonic-gate * 3448*7c478bd9Sstevel@tonic-gate * Called from kobj_do_dependents() to load a module "on" on which 3449*7c478bd9Sstevel@tonic-gate * "dep" depends. 3450*7c478bd9Sstevel@tonic-gate */ 3451*7c478bd9Sstevel@tonic-gate struct modctl * 3452*7c478bd9Sstevel@tonic-gate mod_load_requisite(struct modctl *dep, char *on) 3453*7c478bd9Sstevel@tonic-gate { 3454*7c478bd9Sstevel@tonic-gate struct modctl *on_mod; 3455*7c478bd9Sstevel@tonic-gate int retval; 3456*7c478bd9Sstevel@tonic-gate 3457*7c478bd9Sstevel@tonic-gate if ((on_mod = mod_hold_loaded_mod(dep, on, &retval)) != NULL) { 3458*7c478bd9Sstevel@tonic-gate mod_make_requisite(dep, on_mod); 3459*7c478bd9Sstevel@tonic-gate } else if (moddebug & MODDEBUG_ERRMSG) { 3460*7c478bd9Sstevel@tonic-gate printf("error processing %s on which module %s depends\n", 3461*7c478bd9Sstevel@tonic-gate on, dep->mod_modname); 3462*7c478bd9Sstevel@tonic-gate } 3463*7c478bd9Sstevel@tonic-gate return (on_mod); 3464*7c478bd9Sstevel@tonic-gate } 3465*7c478bd9Sstevel@tonic-gate 3466*7c478bd9Sstevel@tonic-gate static int 3467*7c478bd9Sstevel@tonic-gate mod_install_requisites(struct modctl *modp) 3468*7c478bd9Sstevel@tonic-gate { 3469*7c478bd9Sstevel@tonic-gate struct modctl_list *modl; 3470*7c478bd9Sstevel@tonic-gate struct modctl *req; 3471*7c478bd9Sstevel@tonic-gate int status = 0; 3472*7c478bd9Sstevel@tonic-gate 3473*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mod_lock)); 3474*7c478bd9Sstevel@tonic-gate ASSERT(modp->mod_busy); 3475*7c478bd9Sstevel@tonic-gate 3476*7c478bd9Sstevel@tonic-gate for (modl = modp->mod_requisites; modl; modl = modl->modl_next) { 3477*7c478bd9Sstevel@tonic-gate req = modl->modl_modp; 3478*7c478bd9Sstevel@tonic-gate (void) mod_hold_by_modctl(req, 3479*7c478bd9Sstevel@tonic-gate MOD_WAIT_FOREVER | MOD_LOCK_NOT_HELD); 3480*7c478bd9Sstevel@tonic-gate status = modinstall(req); 3481*7c478bd9Sstevel@tonic-gate mod_release_mod(req); 3482*7c478bd9Sstevel@tonic-gate 3483*7c478bd9Sstevel@tonic-gate if (status != 0) 3484*7c478bd9Sstevel@tonic-gate break; 3485*7c478bd9Sstevel@tonic-gate } 3486*7c478bd9Sstevel@tonic-gate return (status); 3487*7c478bd9Sstevel@tonic-gate } 3488*7c478bd9Sstevel@tonic-gate 3489*7c478bd9Sstevel@tonic-gate /* 3490*7c478bd9Sstevel@tonic-gate * returns 1 if this thread is doing autounload, 0 otherwise. 3491*7c478bd9Sstevel@tonic-gate * see mod_uninstall_all. 3492*7c478bd9Sstevel@tonic-gate */ 3493*7c478bd9Sstevel@tonic-gate int 3494*7c478bd9Sstevel@tonic-gate mod_in_autounload() 3495*7c478bd9Sstevel@tonic-gate { 3496*7c478bd9Sstevel@tonic-gate return ((int)(uintptr_t)tsd_get(mod_autounload_key)); 3497*7c478bd9Sstevel@tonic-gate } 3498*7c478bd9Sstevel@tonic-gate 3499*7c478bd9Sstevel@tonic-gate /* 3500*7c478bd9Sstevel@tonic-gate * gmatch adapted from libc, stripping the wchar stuff 3501*7c478bd9Sstevel@tonic-gate */ 3502*7c478bd9Sstevel@tonic-gate #define popchar(p, c) \ 3503*7c478bd9Sstevel@tonic-gate c = *p++; \ 3504*7c478bd9Sstevel@tonic-gate if (c == 0) \ 3505*7c478bd9Sstevel@tonic-gate return (0); 3506*7c478bd9Sstevel@tonic-gate 3507*7c478bd9Sstevel@tonic-gate static int 3508*7c478bd9Sstevel@tonic-gate gmatch(const char *s, const char *p) 3509*7c478bd9Sstevel@tonic-gate { 3510*7c478bd9Sstevel@tonic-gate int c, sc; 3511*7c478bd9Sstevel@tonic-gate int ok, lc, notflag; 3512*7c478bd9Sstevel@tonic-gate 3513*7c478bd9Sstevel@tonic-gate sc = *s++; 3514*7c478bd9Sstevel@tonic-gate c = *p++; 3515*7c478bd9Sstevel@tonic-gate if (c == 0) 3516*7c478bd9Sstevel@tonic-gate return (sc == c); /* nothing matches nothing */ 3517*7c478bd9Sstevel@tonic-gate 3518*7c478bd9Sstevel@tonic-gate switch (c) { 3519*7c478bd9Sstevel@tonic-gate case '\\': 3520*7c478bd9Sstevel@tonic-gate /* skip to quoted character */ 3521*7c478bd9Sstevel@tonic-gate popchar(p, c) 3522*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 3523*7c478bd9Sstevel@tonic-gate 3524*7c478bd9Sstevel@tonic-gate default: 3525*7c478bd9Sstevel@tonic-gate /* straight comparison */ 3526*7c478bd9Sstevel@tonic-gate if (c != sc) 3527*7c478bd9Sstevel@tonic-gate return (0); 3528*7c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 3529*7c478bd9Sstevel@tonic-gate 3530*7c478bd9Sstevel@tonic-gate case '?': 3531*7c478bd9Sstevel@tonic-gate /* first char matches, move to remainder */ 3532*7c478bd9Sstevel@tonic-gate return (sc != '\0' ? gmatch(s, p) : 0); 3533*7c478bd9Sstevel@tonic-gate 3534*7c478bd9Sstevel@tonic-gate 3535*7c478bd9Sstevel@tonic-gate case '*': 3536*7c478bd9Sstevel@tonic-gate while (*p == '*') 3537*7c478bd9Sstevel@tonic-gate p++; 3538*7c478bd9Sstevel@tonic-gate 3539*7c478bd9Sstevel@tonic-gate /* * matches everything */ 3540*7c478bd9Sstevel@tonic-gate if (*p == 0) 3541*7c478bd9Sstevel@tonic-gate return (1); 3542*7c478bd9Sstevel@tonic-gate 3543*7c478bd9Sstevel@tonic-gate /* undo skip at the beginning & iterate over substrings */ 3544*7c478bd9Sstevel@tonic-gate --s; 3545*7c478bd9Sstevel@tonic-gate while (*s) { 3546*7c478bd9Sstevel@tonic-gate if (gmatch(s, p)) 3547*7c478bd9Sstevel@tonic-gate return (1); 3548*7c478bd9Sstevel@tonic-gate s++; 3549*7c478bd9Sstevel@tonic-gate } 3550*7c478bd9Sstevel@tonic-gate return (0); 3551*7c478bd9Sstevel@tonic-gate 3552*7c478bd9Sstevel@tonic-gate case '[': 3553*7c478bd9Sstevel@tonic-gate /* match any char within [] */ 3554*7c478bd9Sstevel@tonic-gate if (sc == 0) 3555*7c478bd9Sstevel@tonic-gate return (0); 3556*7c478bd9Sstevel@tonic-gate 3557*7c478bd9Sstevel@tonic-gate ok = lc = notflag = 0; 3558*7c478bd9Sstevel@tonic-gate 3559*7c478bd9Sstevel@tonic-gate if (*p == '!') { 3560*7c478bd9Sstevel@tonic-gate notflag = 1; 3561*7c478bd9Sstevel@tonic-gate p++; 3562*7c478bd9Sstevel@tonic-gate } 3563*7c478bd9Sstevel@tonic-gate popchar(p, c) 3564*7c478bd9Sstevel@tonic-gate 3565*7c478bd9Sstevel@tonic-gate do { 3566*7c478bd9Sstevel@tonic-gate if (c == '-' && lc && *p != ']') { 3567*7c478bd9Sstevel@tonic-gate /* test sc against range [c1-c2] */ 3568*7c478bd9Sstevel@tonic-gate popchar(p, c) 3569*7c478bd9Sstevel@tonic-gate if (c == '\\') { 3570*7c478bd9Sstevel@tonic-gate popchar(p, c) 3571*7c478bd9Sstevel@tonic-gate } 3572*7c478bd9Sstevel@tonic-gate 3573*7c478bd9Sstevel@tonic-gate if (notflag) { 3574*7c478bd9Sstevel@tonic-gate /* return 0 on mismatch */ 3575*7c478bd9Sstevel@tonic-gate if (lc <= sc && sc <= c) 3576*7c478bd9Sstevel@tonic-gate return (0); 3577*7c478bd9Sstevel@tonic-gate ok++; 3578*7c478bd9Sstevel@tonic-gate } else if (lc <= sc && sc <= c) { 3579*7c478bd9Sstevel@tonic-gate ok++; 3580*7c478bd9Sstevel@tonic-gate } 3581*7c478bd9Sstevel@tonic-gate /* keep going, may get a match next */ 3582*7c478bd9Sstevel@tonic-gate } else if (c == '\\') { 3583*7c478bd9Sstevel@tonic-gate /* skip to quoted character */ 3584*7c478bd9Sstevel@tonic-gate popchar(p, c) 3585*7c478bd9Sstevel@tonic-gate } 3586*7c478bd9Sstevel@tonic-gate lc = c; 3587*7c478bd9Sstevel@tonic-gate if (notflag) { 3588*7c478bd9Sstevel@tonic-gate if (sc == lc) 3589*7c478bd9Sstevel@tonic-gate return (0); 3590*7c478bd9Sstevel@tonic-gate ok++; 3591*7c478bd9Sstevel@tonic-gate } else if (sc == lc) { 3592*7c478bd9Sstevel@tonic-gate ok++; 3593*7c478bd9Sstevel@tonic-gate } 3594*7c478bd9Sstevel@tonic-gate popchar(p, c) 3595*7c478bd9Sstevel@tonic-gate } while (c != ']'); 3596*7c478bd9Sstevel@tonic-gate 3597*7c478bd9Sstevel@tonic-gate /* recurse on remainder of string */ 3598*7c478bd9Sstevel@tonic-gate return (ok ? gmatch(s, p) : 0); 3599*7c478bd9Sstevel@tonic-gate } 3600*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3601*7c478bd9Sstevel@tonic-gate } 3602*7c478bd9Sstevel@tonic-gate 3603*7c478bd9Sstevel@tonic-gate 3604*7c478bd9Sstevel@tonic-gate /* 3605*7c478bd9Sstevel@tonic-gate * Get default perm for device from /etc/minor_perm. Return 0 if match found. 3606*7c478bd9Sstevel@tonic-gate * 3607*7c478bd9Sstevel@tonic-gate * Pure wild-carded patterns are handled separately so the ordering of 3608*7c478bd9Sstevel@tonic-gate * these patterns doesn't matter. We're still dependent on ordering 3609*7c478bd9Sstevel@tonic-gate * however as the first matching entry is the one returned. 3610*7c478bd9Sstevel@tonic-gate * Not ideal but all existing examples and usage do imply this 3611*7c478bd9Sstevel@tonic-gate * ordering implicitly. 3612*7c478bd9Sstevel@tonic-gate * 3613*7c478bd9Sstevel@tonic-gate * Drivers using the clone driver are always good for some entertainment. 3614*7c478bd9Sstevel@tonic-gate * Clone nodes under pseudo have the form clone@0:<driver>. Some minor 3615*7c478bd9Sstevel@tonic-gate * perm entries have the form clone:<driver>, others use <driver>:* 3616*7c478bd9Sstevel@tonic-gate * Examples are clone:llc1 vs. llc2:*, for example. 3617*7c478bd9Sstevel@tonic-gate * 3618*7c478bd9Sstevel@tonic-gate * Minor perms in the clone:<driver> form are mapped to the drivers's 3619*7c478bd9Sstevel@tonic-gate * mperm list, not the clone driver, as wildcard entries for clone 3620*7c478bd9Sstevel@tonic-gate * reference only. In other words, a clone wildcard will match 3621*7c478bd9Sstevel@tonic-gate * references for clone@0:<driver> but never <driver>@<minor>. 3622*7c478bd9Sstevel@tonic-gate * 3623*7c478bd9Sstevel@tonic-gate * Additional minor perms in the standard form are also supported, 3624*7c478bd9Sstevel@tonic-gate * for mixed usage, ie a node with an entry clone:<driver> could 3625*7c478bd9Sstevel@tonic-gate * provide further entries <driver>:<minor>. 3626*7c478bd9Sstevel@tonic-gate * 3627*7c478bd9Sstevel@tonic-gate * Finally, some uses of clone use an alias as the minor name rather 3628*7c478bd9Sstevel@tonic-gate * than the driver name, with the alias as the minor perm entry. 3629*7c478bd9Sstevel@tonic-gate * This case is handled by attaching the driver to bring its 3630*7c478bd9Sstevel@tonic-gate * minor list into existence, then discover the alias via DDI_ALIAS. 3631*7c478bd9Sstevel@tonic-gate * The clone device's minor perm list can then be searched for 3632*7c478bd9Sstevel@tonic-gate * that alias. 3633*7c478bd9Sstevel@tonic-gate */ 3634*7c478bd9Sstevel@tonic-gate 3635*7c478bd9Sstevel@tonic-gate static int 3636*7c478bd9Sstevel@tonic-gate dev_alias_minorperm(dev_info_t *dip, char *minor_name, mperm_t *rmp) 3637*7c478bd9Sstevel@tonic-gate { 3638*7c478bd9Sstevel@tonic-gate major_t major; 3639*7c478bd9Sstevel@tonic-gate struct devnames *dnp; 3640*7c478bd9Sstevel@tonic-gate mperm_t *mp; 3641*7c478bd9Sstevel@tonic-gate char *alias = NULL; 3642*7c478bd9Sstevel@tonic-gate dev_info_t *cdevi; 3643*7c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmd; 3644*7c478bd9Sstevel@tonic-gate 3645*7c478bd9Sstevel@tonic-gate major = ddi_name_to_major(minor_name); 3646*7c478bd9Sstevel@tonic-gate 3647*7c478bd9Sstevel@tonic-gate ASSERT(dip == clone_dip); 3648*7c478bd9Sstevel@tonic-gate ASSERT(major != (major_t)-1); 3649*7c478bd9Sstevel@tonic-gate 3650*7c478bd9Sstevel@tonic-gate /* 3651*7c478bd9Sstevel@tonic-gate * Attach the driver named by the minor node, then 3652*7c478bd9Sstevel@tonic-gate * search its first instance's minor list for an 3653*7c478bd9Sstevel@tonic-gate * alias node. 3654*7c478bd9Sstevel@tonic-gate */ 3655*7c478bd9Sstevel@tonic-gate if (ddi_hold_installed_driver(major) == NULL) 3656*7c478bd9Sstevel@tonic-gate return (1); 3657*7c478bd9Sstevel@tonic-gate 3658*7c478bd9Sstevel@tonic-gate dnp = &devnamesp[major]; 3659*7c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 3660*7c478bd9Sstevel@tonic-gate 3661*7c478bd9Sstevel@tonic-gate if ((cdevi = dnp->dn_head) != NULL) { 3662*7c478bd9Sstevel@tonic-gate mutex_enter(&DEVI(cdevi)->devi_lock); 3663*7c478bd9Sstevel@tonic-gate for (dmd = DEVI(cdevi)->devi_minor; dmd; dmd = dmd->next) { 3664*7c478bd9Sstevel@tonic-gate if (dmd->type == DDM_ALIAS) { 3665*7c478bd9Sstevel@tonic-gate alias = i_ddi_strdup(dmd->ddm_name, KM_SLEEP); 3666*7c478bd9Sstevel@tonic-gate break; 3667*7c478bd9Sstevel@tonic-gate } 3668*7c478bd9Sstevel@tonic-gate } 3669*7c478bd9Sstevel@tonic-gate mutex_exit(&DEVI(cdevi)->devi_lock); 3670*7c478bd9Sstevel@tonic-gate } 3671*7c478bd9Sstevel@tonic-gate 3672*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 3673*7c478bd9Sstevel@tonic-gate ddi_rele_driver(major); 3674*7c478bd9Sstevel@tonic-gate 3675*7c478bd9Sstevel@tonic-gate if (alias == NULL) { 3676*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MINORPERM) 3677*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "dev_minorperm: " 3678*7c478bd9Sstevel@tonic-gate "no alias for %s\n", minor_name); 3679*7c478bd9Sstevel@tonic-gate return (1); 3680*7c478bd9Sstevel@tonic-gate } 3681*7c478bd9Sstevel@tonic-gate 3682*7c478bd9Sstevel@tonic-gate major = ddi_driver_major(clone_dip); 3683*7c478bd9Sstevel@tonic-gate dnp = &devnamesp[major]; 3684*7c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 3685*7c478bd9Sstevel@tonic-gate 3686*7c478bd9Sstevel@tonic-gate /* 3687*7c478bd9Sstevel@tonic-gate * Go through the clone driver's mperm list looking 3688*7c478bd9Sstevel@tonic-gate * for a match for the specified alias. 3689*7c478bd9Sstevel@tonic-gate */ 3690*7c478bd9Sstevel@tonic-gate for (mp = dnp->dn_mperm; mp; mp = mp->mp_next) { 3691*7c478bd9Sstevel@tonic-gate if (strcmp(alias, mp->mp_minorname) == 0) { 3692*7c478bd9Sstevel@tonic-gate break; 3693*7c478bd9Sstevel@tonic-gate } 3694*7c478bd9Sstevel@tonic-gate } 3695*7c478bd9Sstevel@tonic-gate 3696*7c478bd9Sstevel@tonic-gate if (mp) { 3697*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MP_MATCH) { 3698*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 3699*7c478bd9Sstevel@tonic-gate "minor perm defaults: %s %s 0%o %d %d (aliased)\n", 3700*7c478bd9Sstevel@tonic-gate minor_name, alias, mp->mp_mode, 3701*7c478bd9Sstevel@tonic-gate mp->mp_uid, mp->mp_gid); 3702*7c478bd9Sstevel@tonic-gate } 3703*7c478bd9Sstevel@tonic-gate rmp->mp_uid = mp->mp_uid; 3704*7c478bd9Sstevel@tonic-gate rmp->mp_gid = mp->mp_gid; 3705*7c478bd9Sstevel@tonic-gate rmp->mp_mode = mp->mp_mode; 3706*7c478bd9Sstevel@tonic-gate } 3707*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 3708*7c478bd9Sstevel@tonic-gate 3709*7c478bd9Sstevel@tonic-gate kmem_free(alias, strlen(alias)+1); 3710*7c478bd9Sstevel@tonic-gate 3711*7c478bd9Sstevel@tonic-gate return (mp == NULL); 3712*7c478bd9Sstevel@tonic-gate } 3713*7c478bd9Sstevel@tonic-gate 3714*7c478bd9Sstevel@tonic-gate int 3715*7c478bd9Sstevel@tonic-gate dev_minorperm(dev_info_t *dip, char *name, mperm_t *rmp) 3716*7c478bd9Sstevel@tonic-gate { 3717*7c478bd9Sstevel@tonic-gate major_t major; 3718*7c478bd9Sstevel@tonic-gate char *minor_name; 3719*7c478bd9Sstevel@tonic-gate struct devnames *dnp; 3720*7c478bd9Sstevel@tonic-gate mperm_t *mp; 3721*7c478bd9Sstevel@tonic-gate int is_clone = 0; 3722*7c478bd9Sstevel@tonic-gate 3723*7c478bd9Sstevel@tonic-gate if (!minorperm_loaded) { 3724*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MINORPERM) 3725*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 3726*7c478bd9Sstevel@tonic-gate "%s: minor perm not yet loaded\n", name); 3727*7c478bd9Sstevel@tonic-gate return (1); 3728*7c478bd9Sstevel@tonic-gate } 3729*7c478bd9Sstevel@tonic-gate 3730*7c478bd9Sstevel@tonic-gate minor_name = strchr(name, ':'); 3731*7c478bd9Sstevel@tonic-gate if (minor_name == NULL) 3732*7c478bd9Sstevel@tonic-gate return (1); 3733*7c478bd9Sstevel@tonic-gate minor_name++; 3734*7c478bd9Sstevel@tonic-gate 3735*7c478bd9Sstevel@tonic-gate /* 3736*7c478bd9Sstevel@tonic-gate * If it's the clone driver, search the driver as named 3737*7c478bd9Sstevel@tonic-gate * by the minor. All clone minor perm entries other than 3738*7c478bd9Sstevel@tonic-gate * alias nodes are actually installed on the real driver's list. 3739*7c478bd9Sstevel@tonic-gate */ 3740*7c478bd9Sstevel@tonic-gate if (dip == clone_dip) { 3741*7c478bd9Sstevel@tonic-gate major = ddi_name_to_major(minor_name); 3742*7c478bd9Sstevel@tonic-gate if (major == (major_t)-1) { 3743*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MINORPERM) 3744*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "dev_minorperm: " 3745*7c478bd9Sstevel@tonic-gate "%s: no such driver\n", minor_name); 3746*7c478bd9Sstevel@tonic-gate return (1); 3747*7c478bd9Sstevel@tonic-gate } 3748*7c478bd9Sstevel@tonic-gate is_clone = 1; 3749*7c478bd9Sstevel@tonic-gate } else { 3750*7c478bd9Sstevel@tonic-gate major = ddi_driver_major(dip); 3751*7c478bd9Sstevel@tonic-gate ASSERT(major != (major_t)-1); 3752*7c478bd9Sstevel@tonic-gate } 3753*7c478bd9Sstevel@tonic-gate 3754*7c478bd9Sstevel@tonic-gate dnp = &devnamesp[major]; 3755*7c478bd9Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 3756*7c478bd9Sstevel@tonic-gate 3757*7c478bd9Sstevel@tonic-gate /* 3758*7c478bd9Sstevel@tonic-gate * Go through the driver's mperm list looking for 3759*7c478bd9Sstevel@tonic-gate * a match for the specified minor. If there's 3760*7c478bd9Sstevel@tonic-gate * no matching pattern, use the wild card. 3761*7c478bd9Sstevel@tonic-gate * Defer to the clone wild for clone if specified, 3762*7c478bd9Sstevel@tonic-gate * otherwise fall back to the normal form. 3763*7c478bd9Sstevel@tonic-gate */ 3764*7c478bd9Sstevel@tonic-gate for (mp = dnp->dn_mperm; mp; mp = mp->mp_next) { 3765*7c478bd9Sstevel@tonic-gate if (gmatch(minor_name, mp->mp_minorname) != 0) { 3766*7c478bd9Sstevel@tonic-gate break; 3767*7c478bd9Sstevel@tonic-gate } 3768*7c478bd9Sstevel@tonic-gate } 3769*7c478bd9Sstevel@tonic-gate if (mp == NULL) { 3770*7c478bd9Sstevel@tonic-gate if (is_clone) 3771*7c478bd9Sstevel@tonic-gate mp = dnp->dn_mperm_clone; 3772*7c478bd9Sstevel@tonic-gate if (mp == NULL) 3773*7c478bd9Sstevel@tonic-gate mp = dnp->dn_mperm_wild; 3774*7c478bd9Sstevel@tonic-gate } 3775*7c478bd9Sstevel@tonic-gate 3776*7c478bd9Sstevel@tonic-gate if (mp) { 3777*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_MP_MATCH) { 3778*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 3779*7c478bd9Sstevel@tonic-gate "minor perm defaults: %s %s 0%o %d %d\n", 3780*7c478bd9Sstevel@tonic-gate name, mp->mp_minorname, mp->mp_mode, 3781*7c478bd9Sstevel@tonic-gate mp->mp_uid, mp->mp_gid); 3782*7c478bd9Sstevel@tonic-gate } 3783*7c478bd9Sstevel@tonic-gate rmp->mp_uid = mp->mp_uid; 3784*7c478bd9Sstevel@tonic-gate rmp->mp_gid = mp->mp_gid; 3785*7c478bd9Sstevel@tonic-gate rmp->mp_mode = mp->mp_mode; 3786*7c478bd9Sstevel@tonic-gate } 3787*7c478bd9Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 3788*7c478bd9Sstevel@tonic-gate 3789*7c478bd9Sstevel@tonic-gate /* 3790*7c478bd9Sstevel@tonic-gate * If no match can be found for a clone node, 3791*7c478bd9Sstevel@tonic-gate * search for a possible match for an alias. 3792*7c478bd9Sstevel@tonic-gate * One such example is /dev/ptmx -> /devices/pseudo/clone@0:ptm, 3793*7c478bd9Sstevel@tonic-gate * with minor perm entry clone:ptmx. 3794*7c478bd9Sstevel@tonic-gate */ 3795*7c478bd9Sstevel@tonic-gate if (mp == NULL && is_clone) { 3796*7c478bd9Sstevel@tonic-gate return (dev_alias_minorperm(dip, minor_name, rmp)); 3797*7c478bd9Sstevel@tonic-gate } 3798*7c478bd9Sstevel@tonic-gate 3799*7c478bd9Sstevel@tonic-gate return (mp == NULL); 3800*7c478bd9Sstevel@tonic-gate } 3801*7c478bd9Sstevel@tonic-gate 3802*7c478bd9Sstevel@tonic-gate /* 3803*7c478bd9Sstevel@tonic-gate * dynamicaly reference load a dl module/library, returning handle 3804*7c478bd9Sstevel@tonic-gate */ 3805*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3806*7c478bd9Sstevel@tonic-gate ddi_modhandle_t 3807*7c478bd9Sstevel@tonic-gate ddi_modopen(const char *modname, int mode, int *errnop) 3808*7c478bd9Sstevel@tonic-gate { 3809*7c478bd9Sstevel@tonic-gate char *subdir; 3810*7c478bd9Sstevel@tonic-gate char *mod; 3811*7c478bd9Sstevel@tonic-gate int subdirlen; 3812*7c478bd9Sstevel@tonic-gate struct modctl *hmodp = NULL; 3813*7c478bd9Sstevel@tonic-gate int retval = EINVAL; 3814*7c478bd9Sstevel@tonic-gate 3815*7c478bd9Sstevel@tonic-gate ASSERT(modname && (mode == KRTLD_MODE_FIRST)); 3816*7c478bd9Sstevel@tonic-gate if ((modname == NULL) || (mode != KRTLD_MODE_FIRST)) 3817*7c478bd9Sstevel@tonic-gate goto out; 3818*7c478bd9Sstevel@tonic-gate 3819*7c478bd9Sstevel@tonic-gate /* find optional first '/' in modname */ 3820*7c478bd9Sstevel@tonic-gate mod = strchr(modname, '/'); 3821*7c478bd9Sstevel@tonic-gate if (mod != strrchr(modname, '/')) 3822*7c478bd9Sstevel@tonic-gate goto out; /* only one '/' is legal */ 3823*7c478bd9Sstevel@tonic-gate 3824*7c478bd9Sstevel@tonic-gate if (mod) { 3825*7c478bd9Sstevel@tonic-gate /* for subdir string without modification to argument */ 3826*7c478bd9Sstevel@tonic-gate mod++; 3827*7c478bd9Sstevel@tonic-gate subdirlen = mod - modname; 3828*7c478bd9Sstevel@tonic-gate subdir = kmem_alloc(subdirlen, KM_SLEEP); 3829*7c478bd9Sstevel@tonic-gate (void) strlcpy(subdir, modname, subdirlen); 3830*7c478bd9Sstevel@tonic-gate } else { 3831*7c478bd9Sstevel@tonic-gate subdirlen = 0; 3832*7c478bd9Sstevel@tonic-gate subdir = "misc"; 3833*7c478bd9Sstevel@tonic-gate mod = (char *)modname; 3834*7c478bd9Sstevel@tonic-gate } 3835*7c478bd9Sstevel@tonic-gate 3836*7c478bd9Sstevel@tonic-gate /* reference load with errno return value */ 3837*7c478bd9Sstevel@tonic-gate retval = modrload(subdir, mod, &hmodp); 3838*7c478bd9Sstevel@tonic-gate 3839*7c478bd9Sstevel@tonic-gate if (subdirlen) 3840*7c478bd9Sstevel@tonic-gate kmem_free(subdir, subdirlen); 3841*7c478bd9Sstevel@tonic-gate 3842*7c478bd9Sstevel@tonic-gate out: if (errnop) 3843*7c478bd9Sstevel@tonic-gate *errnop = retval; 3844*7c478bd9Sstevel@tonic-gate 3845*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_DDI_MOD) 3846*7c478bd9Sstevel@tonic-gate printf("ddi_modopen %s mode %x: %s %p %d\n", 3847*7c478bd9Sstevel@tonic-gate modname ? modname : "<unknown>", mode, 3848*7c478bd9Sstevel@tonic-gate hmodp ? hmodp->mod_filename : "<unknown>", 3849*7c478bd9Sstevel@tonic-gate (void *)hmodp, retval); 3850*7c478bd9Sstevel@tonic-gate 3851*7c478bd9Sstevel@tonic-gate return ((ddi_modhandle_t)hmodp); 3852*7c478bd9Sstevel@tonic-gate } 3853*7c478bd9Sstevel@tonic-gate 3854*7c478bd9Sstevel@tonic-gate /* lookup "name" in open dl module/library */ 3855*7c478bd9Sstevel@tonic-gate void * 3856*7c478bd9Sstevel@tonic-gate ddi_modsym(ddi_modhandle_t h, const char *name, int *errnop) 3857*7c478bd9Sstevel@tonic-gate { 3858*7c478bd9Sstevel@tonic-gate struct modctl *hmodp = (struct modctl *)h; 3859*7c478bd9Sstevel@tonic-gate void *f; 3860*7c478bd9Sstevel@tonic-gate int retval; 3861*7c478bd9Sstevel@tonic-gate 3862*7c478bd9Sstevel@tonic-gate ASSERT(hmodp && name && hmodp->mod_installed && (hmodp->mod_ref >= 1)); 3863*7c478bd9Sstevel@tonic-gate if ((hmodp == NULL) || (name == NULL) || 3864*7c478bd9Sstevel@tonic-gate (hmodp->mod_installed == 0) || (hmodp->mod_ref < 1)) { 3865*7c478bd9Sstevel@tonic-gate f = NULL; 3866*7c478bd9Sstevel@tonic-gate retval = EINVAL; 3867*7c478bd9Sstevel@tonic-gate } else { 3868*7c478bd9Sstevel@tonic-gate f = (void *)kobj_lookup(hmodp->mod_mp, (char *)name); 3869*7c478bd9Sstevel@tonic-gate if (f) 3870*7c478bd9Sstevel@tonic-gate retval = 0; 3871*7c478bd9Sstevel@tonic-gate else 3872*7c478bd9Sstevel@tonic-gate retval = ENOTSUP; 3873*7c478bd9Sstevel@tonic-gate } 3874*7c478bd9Sstevel@tonic-gate 3875*7c478bd9Sstevel@tonic-gate if (moddebug & MODDEBUG_DDI_MOD) 3876*7c478bd9Sstevel@tonic-gate printf("ddi_modsym in %s of %s: %d %p\n", 3877*7c478bd9Sstevel@tonic-gate hmodp ? hmodp->mod_modname : "<unknown>", 3878*7c478bd9Sstevel@tonic-gate name ? name : "<unknown>", retval, f); 3879*7c478bd9Sstevel@tonic-gate 3880*7c478bd9Sstevel@tonic-gate if (errnop) 3881*7c478bd9Sstevel@tonic-gate *errnop = retval; 3882*7c478bd9Sstevel@tonic-gate return (f); 3883*7c478bd9Sstevel@tonic-gate } 3884*7c478bd9Sstevel@tonic-gate 3885*7c478bd9Sstevel@tonic-gate /* dynamic (un)reference unload of an open dl module/library */ 3886*7c478bd9Sstevel@tonic-gate int 3887*7c478bd9Sstevel@tonic-gate ddi_modclose(ddi_modhandle_t h) 3888*7c478bd9Sstevel@tonic-gate { 3889*7c478bd9Sstevel@tonic-gate struct modctl *hmodp = (struct modctl *)h; 3890*7c478bd9Sstevel@tonic-gate struct modctl *modp = NULL; 3891*7c478bd9Sstevel@tonic-gate int retval; 3892*7c478bd9Sstevel@tonic-gate 3893*7c478bd9Sstevel@tonic-gate ASSERT(hmodp && hmodp->mod_installed && (hmodp->mod_ref >= 1)); 3894*7c478bd9Sstevel@tonic-gate if ((hmodp == NULL) || 3895*7c478bd9Sstevel@tonic-gate (hmodp->mod_installed == 0) || (hmodp->mod_ref < 1)) { 3896*7c478bd9Sstevel@tonic-gate retval = EINVAL; 3897*7c478bd9Sstevel@tonic-gate goto out; 3898*7c478bd9Sstevel@tonic-gate } 3899*7c478bd9Sstevel@tonic-gate 3900*7c478bd9Sstevel@tonic-gate retval = modunrload(hmodp->mod_id, &modp, ddi_modclose_unload); 3901*7c478bd9Sstevel@tonic-gate if (retval == EBUSY) 3902*7c478bd9Sstevel@tonic-gate retval = 0; /* EBUSY is not an error */ 3903*7c478bd9Sstevel@tonic-gate 3904*7c478bd9Sstevel@tonic-gate if (retval == 0) { 3905*7c478bd9Sstevel@tonic-gate ASSERT(hmodp == modp); 3906*7c478bd9Sstevel@tonic-gate if (hmodp != modp) 3907*7c478bd9Sstevel@tonic-gate retval = EINVAL; 3908*7c478bd9Sstevel@tonic-gate } 3909*7c478bd9Sstevel@tonic-gate 3910*7c478bd9Sstevel@tonic-gate out: if (moddebug & MODDEBUG_DDI_MOD) 3911*7c478bd9Sstevel@tonic-gate printf("ddi_modclose %s: %d\n", 3912*7c478bd9Sstevel@tonic-gate hmodp ? hmodp->mod_modname : "<unknown>", retval); 3913*7c478bd9Sstevel@tonic-gate 3914*7c478bd9Sstevel@tonic-gate return (retval); 3915*7c478bd9Sstevel@tonic-gate } 3916