10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51488Srsb * Common Development and Distribution License (the "License"). 61488Srsb * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 227009Scth * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/types.h> 270Sstevel@tonic-gate #include <sys/systm.h> 280Sstevel@tonic-gate #include <sys/param.h> 290Sstevel@tonic-gate #include <sys/user.h> 300Sstevel@tonic-gate #include <sys/vm.h> 310Sstevel@tonic-gate #include <sys/conf.h> 320Sstevel@tonic-gate #include <sys/class.h> 330Sstevel@tonic-gate #include <sys/vfs.h> 341488Srsb #include <sys/vnode.h> 350Sstevel@tonic-gate #include <sys/mount.h> 360Sstevel@tonic-gate #include <sys/systm.h> 370Sstevel@tonic-gate #include <sys/modctl.h> 380Sstevel@tonic-gate #include <sys/exec.h> 390Sstevel@tonic-gate #include <sys/exechdr.h> 400Sstevel@tonic-gate #include <sys/devops.h> 410Sstevel@tonic-gate #include <sys/ddi.h> 420Sstevel@tonic-gate #include <sys/sunddi.h> 430Sstevel@tonic-gate #include <sys/cmn_err.h> 440Sstevel@tonic-gate #include <sys/hwconf.h> 450Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 460Sstevel@tonic-gate #include <sys/autoconf.h> 470Sstevel@tonic-gate #include <sys/disp.h> 480Sstevel@tonic-gate #include <sys/kmem.h> 490Sstevel@tonic-gate #include <sys/instance.h> 500Sstevel@tonic-gate #include <sys/modhash.h> 510Sstevel@tonic-gate #include <sys/dacf.h> 520Sstevel@tonic-gate #include <sys/debug.h> 530Sstevel@tonic-gate #include <ipp/ipp.h> 540Sstevel@tonic-gate #include <sys/strsubr.h> 550Sstevel@tonic-gate #include <sys/kcpc.h> 562712Snn35248 #include <sys/brand.h> 570Sstevel@tonic-gate #include <sys/cpc_pcbe.h> 581488Srsb #include <sys/kstat.h> 592621Sllai1 #include <sys/fs/sdev_node.h> 60*8348SEric.Yu@Sun.COM #include <sys/socketvar.h> 615206Sis #include <sys/kiconv.h> 620Sstevel@tonic-gate 630Sstevel@tonic-gate extern int moddebug; 640Sstevel@tonic-gate 650Sstevel@tonic-gate extern struct cb_ops no_cb_ops; 660Sstevel@tonic-gate extern struct dev_ops nodev_ops; 670Sstevel@tonic-gate extern struct dev_ops mod_nodev_ops; 680Sstevel@tonic-gate 690Sstevel@tonic-gate extern struct modctl *mod_getctl(struct modlinkage *); 700Sstevel@tonic-gate extern int errsys(), nodev(), nulldev(); 710Sstevel@tonic-gate 720Sstevel@tonic-gate extern int findmodbyname(char *); 730Sstevel@tonic-gate extern int mod_getsysnum(char *); 740Sstevel@tonic-gate 750Sstevel@tonic-gate extern struct execsw execsw[]; 760Sstevel@tonic-gate 770Sstevel@tonic-gate /* 780Sstevel@tonic-gate * Define dev_ops for unused devopsp entry. 790Sstevel@tonic-gate */ 800Sstevel@tonic-gate struct dev_ops mod_nodev_ops = { 810Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 820Sstevel@tonic-gate 0, /* refcnt */ 830Sstevel@tonic-gate ddi_no_info, /* info */ 840Sstevel@tonic-gate nulldev, /* identify */ 850Sstevel@tonic-gate nulldev, /* probe */ 860Sstevel@tonic-gate ddifail, /* attach */ 870Sstevel@tonic-gate nodev, /* detach */ 880Sstevel@tonic-gate nulldev, /* reset */ 890Sstevel@tonic-gate &no_cb_ops, /* character/block driver operations */ 900Sstevel@tonic-gate (struct bus_ops *)0 /* bus operations for nexus drivers */ 910Sstevel@tonic-gate }; 920Sstevel@tonic-gate 930Sstevel@tonic-gate /* 940Sstevel@tonic-gate * Define mod_ops for each supported module type 950Sstevel@tonic-gate */ 960Sstevel@tonic-gate 970Sstevel@tonic-gate /* 980Sstevel@tonic-gate * Null operations; used for uninitialized and "misc" modules. 990Sstevel@tonic-gate */ 1000Sstevel@tonic-gate static int mod_null(struct modldrv *, struct modlinkage *); 1010Sstevel@tonic-gate static int mod_infonull(void *, struct modlinkage *, int *); 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate struct mod_ops mod_miscops = { 1040Sstevel@tonic-gate mod_null, mod_null, mod_infonull 1050Sstevel@tonic-gate }; 1060Sstevel@tonic-gate 1071414Scindi /* CPU Modules */ 1081414Scindi struct mod_ops mod_cpuops = { 1091414Scindi mod_null, mod_null, mod_infonull 1101414Scindi }; 1111414Scindi 1120Sstevel@tonic-gate /* 1130Sstevel@tonic-gate * Cryptographic Modules 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate struct mod_ops mod_cryptoops = { 1160Sstevel@tonic-gate mod_null, mod_null, mod_infonull 1170Sstevel@tonic-gate }; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* 1200Sstevel@tonic-gate * IP Policy Modules 1210Sstevel@tonic-gate */ 1220Sstevel@tonic-gate static int mod_installipp(struct modlipp *, struct modlinkage *); 1230Sstevel@tonic-gate static int mod_removeipp(struct modlipp *, struct modlinkage *); 1240Sstevel@tonic-gate static int mod_infoipp(struct modlipp *, struct modlinkage *, int *); 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate struct mod_ops mod_ippops = { 1270Sstevel@tonic-gate mod_installipp, mod_removeipp, mod_infoipp 1280Sstevel@tonic-gate }; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * Device drivers 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate static int mod_infodrv(struct modldrv *, struct modlinkage *, int *); 1340Sstevel@tonic-gate static int mod_installdrv(struct modldrv *, struct modlinkage *); 1350Sstevel@tonic-gate static int mod_removedrv(struct modldrv *, struct modlinkage *); 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate struct mod_ops mod_driverops = { 1380Sstevel@tonic-gate mod_installdrv, mod_removedrv, mod_infodrv 1390Sstevel@tonic-gate }; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate /* 1420Sstevel@tonic-gate * System calls (new interface) 1430Sstevel@tonic-gate */ 1440Sstevel@tonic-gate static int mod_infosys(struct modlsys *, struct modlinkage *, int *); 1450Sstevel@tonic-gate static int mod_installsys(struct modlsys *, struct modlinkage *); 1460Sstevel@tonic-gate static int mod_removesys(struct modlsys *, struct modlinkage *); 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate struct mod_ops mod_syscallops = { 1490Sstevel@tonic-gate mod_installsys, mod_removesys, mod_infosys 1500Sstevel@tonic-gate }; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1530Sstevel@tonic-gate /* 1540Sstevel@tonic-gate * 32-bit system calls in 64-bit kernel 1550Sstevel@tonic-gate */ 1560Sstevel@tonic-gate static int mod_infosys32(struct modlsys *, struct modlinkage *, int *); 1570Sstevel@tonic-gate static int mod_installsys32(struct modlsys *, struct modlinkage *); 1580Sstevel@tonic-gate static int mod_removesys32(struct modlsys *, struct modlinkage *); 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate struct mod_ops mod_syscallops32 = { 1610Sstevel@tonic-gate mod_installsys32, mod_removesys32, mod_infosys32 1620Sstevel@tonic-gate }; 1630Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate /* 1660Sstevel@tonic-gate * Filesystems 1670Sstevel@tonic-gate */ 1680Sstevel@tonic-gate static int mod_infofs(struct modlfs *, struct modlinkage *, int *); 1690Sstevel@tonic-gate static int mod_installfs(struct modlfs *, struct modlinkage *); 1700Sstevel@tonic-gate static int mod_removefs(struct modlfs *, struct modlinkage *); 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate struct mod_ops mod_fsops = { 1730Sstevel@tonic-gate mod_installfs, mod_removefs, mod_infofs 1740Sstevel@tonic-gate }; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate /* 1770Sstevel@tonic-gate * Streams modules. 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate static int mod_infostrmod(struct modlstrmod *, struct modlinkage *, int *); 1800Sstevel@tonic-gate static int mod_installstrmod(struct modlstrmod *, struct modlinkage *); 1810Sstevel@tonic-gate static int mod_removestrmod(struct modlstrmod *, struct modlinkage *); 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate struct mod_ops mod_strmodops = { 1840Sstevel@tonic-gate mod_installstrmod, mod_removestrmod, mod_infostrmod 1850Sstevel@tonic-gate }; 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate /* 188*8348SEric.Yu@Sun.COM * Socket modules. 189*8348SEric.Yu@Sun.COM */ 190*8348SEric.Yu@Sun.COM static int mod_infosockmod(struct modlsockmod *, struct modlinkage *, int *); 191*8348SEric.Yu@Sun.COM static int mod_installsockmod(struct modlsockmod *, struct modlinkage *); 192*8348SEric.Yu@Sun.COM static int mod_removesockmod(struct modlsockmod *, struct modlinkage *); 193*8348SEric.Yu@Sun.COM 194*8348SEric.Yu@Sun.COM struct mod_ops mod_sockmodops = { 195*8348SEric.Yu@Sun.COM mod_installsockmod, mod_removesockmod, mod_infosockmod 196*8348SEric.Yu@Sun.COM }; 197*8348SEric.Yu@Sun.COM 198*8348SEric.Yu@Sun.COM /* 1990Sstevel@tonic-gate * Scheduling classes. 2000Sstevel@tonic-gate */ 2010Sstevel@tonic-gate static int mod_infosched(struct modlsched *, struct modlinkage *, int *); 2020Sstevel@tonic-gate static int mod_installsched(struct modlsched *, struct modlinkage *); 2030Sstevel@tonic-gate static int mod_removesched(struct modlsched *, struct modlinkage *); 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate struct mod_ops mod_schedops = { 2060Sstevel@tonic-gate mod_installsched, mod_removesched, mod_infosched 2070Sstevel@tonic-gate }; 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate /* 2100Sstevel@tonic-gate * Exec file type (like ELF, ...). 2110Sstevel@tonic-gate */ 2120Sstevel@tonic-gate static int mod_infoexec(struct modlexec *, struct modlinkage *, int *); 2130Sstevel@tonic-gate static int mod_installexec(struct modlexec *, struct modlinkage *); 2140Sstevel@tonic-gate static int mod_removeexec(struct modlexec *, struct modlinkage *); 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate struct mod_ops mod_execops = { 2170Sstevel@tonic-gate mod_installexec, mod_removeexec, mod_infoexec 2180Sstevel@tonic-gate }; 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate /* 2210Sstevel@tonic-gate * Dacf (Dynamic Autoconfiguration) modules. 2220Sstevel@tonic-gate */ 2230Sstevel@tonic-gate static int mod_infodacf(struct modldacf *, struct modlinkage *, int *); 2240Sstevel@tonic-gate static int mod_installdacf(struct modldacf *, struct modlinkage *); 2250Sstevel@tonic-gate static int mod_removedacf(struct modldacf *, struct modlinkage *); 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate struct mod_ops mod_dacfops = { 2280Sstevel@tonic-gate mod_installdacf, mod_removedacf, mod_infodacf 2290Sstevel@tonic-gate }; 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate /* 2322621Sllai1 * /dev fs modules 2332621Sllai1 */ 2342621Sllai1 static int mod_infodev(struct modldev *, struct modlinkage *, int *); 2352621Sllai1 static int mod_installdev(struct modldev *, struct modlinkage *); 2362621Sllai1 static int mod_removedev(struct modldev *, struct modlinkage *); 2372621Sllai1 2382621Sllai1 struct mod_ops mod_devfsops = { 2392621Sllai1 mod_installdev, mod_removedev, mod_infodev 2402621Sllai1 }; 2412621Sllai1 2422621Sllai1 /* 2430Sstevel@tonic-gate * PCBE (Performance Counter BackEnd) modules. 2440Sstevel@tonic-gate */ 2450Sstevel@tonic-gate static int mod_installpcbe(struct modlpcbe *, struct modlinkage *); 2460Sstevel@tonic-gate static int mod_removepcbe(struct modlpcbe *, struct modlinkage *); 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate struct mod_ops mod_pcbeops = { 2490Sstevel@tonic-gate mod_installpcbe, mod_removepcbe, mod_infonull 2500Sstevel@tonic-gate }; 2510Sstevel@tonic-gate 2522712Snn35248 /* 2532712Snn35248 * Brand modules. 2542712Snn35248 */ 2552712Snn35248 static int mod_installbrand(struct modlbrand *, struct modlinkage *); 2562712Snn35248 static int mod_removebrand(struct modlbrand *, struct modlinkage *); 2572712Snn35248 2582712Snn35248 struct mod_ops mod_brandops = { 2592712Snn35248 mod_installbrand, mod_removebrand, mod_infonull 2602712Snn35248 }; 2612712Snn35248 2625206Sis /* 2635206Sis * kiconv modules. 2645206Sis */ 2655206Sis static int mod_installkiconv(struct modlkiconv *, struct modlinkage *); 2665206Sis static int mod_removekiconv(struct modlkiconv *, struct modlinkage *); 2675206Sis 2685206Sis struct mod_ops mod_kiconvops = { 2695206Sis mod_installkiconv, mod_removekiconv, mod_infonull 2705206Sis }; 2715206Sis 2720Sstevel@tonic-gate static struct sysent *mod_getsysent(struct modlinkage *, struct sysent *); 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate static char uninstall_err[] = "Cannot uninstall %s; not installed"; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate /* 2770Sstevel@tonic-gate * Debugging support 2780Sstevel@tonic-gate */ 2790Sstevel@tonic-gate #define DRV_DBG MODDEBUG_LOADMSG2 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate /*PRINTFLIKE2*/ 2820Sstevel@tonic-gate static void mod_dprintf(int flag, const char *format, ...) __KPRINTFLIKE(2); 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate static void 2850Sstevel@tonic-gate mod_dprintf(int flag, const char *format, ...) 2860Sstevel@tonic-gate { 2870Sstevel@tonic-gate va_list alist; 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate if ((moddebug & flag) != 0) { 2900Sstevel@tonic-gate va_start(alist, format); 2910Sstevel@tonic-gate (void) vprintf(format, alist); 2920Sstevel@tonic-gate va_end(alist); 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate /* 2970Sstevel@tonic-gate * Install a module. 2980Sstevel@tonic-gate * (This routine is in the Solaris SPARC DDI/DKI) 2990Sstevel@tonic-gate */ 3000Sstevel@tonic-gate int 3010Sstevel@tonic-gate mod_install(struct modlinkage *modlp) 3020Sstevel@tonic-gate { 3030Sstevel@tonic-gate int retval = -1; /* No linkage structures */ 3040Sstevel@tonic-gate struct modlmisc **linkpp; 3050Sstevel@tonic-gate struct modlmisc **linkpp1; 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate if (modlp->ml_rev != MODREV_1) { 3080Sstevel@tonic-gate printf("mod_install: modlinkage structure is not MODREV_1\n"); 3090Sstevel@tonic-gate return (EINVAL); 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate linkpp = (struct modlmisc **)&modlp->ml_linkage[0]; 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate while (*linkpp != NULL) { 3140Sstevel@tonic-gate if ((retval = MODL_INSTALL(*linkpp, modlp)) != 0) { 3150Sstevel@tonic-gate linkpp1 = (struct modlmisc **)&modlp->ml_linkage[0]; 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate while (linkpp1 != linkpp) { 3180Sstevel@tonic-gate MODL_REMOVE(*linkpp1, modlp); /* clean up */ 3190Sstevel@tonic-gate linkpp1++; 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate break; 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate linkpp++; 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate return (retval); 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate static char *reins_err = 3290Sstevel@tonic-gate "Could not reinstall %s\nReboot to correct the problem"; 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate /* 3320Sstevel@tonic-gate * Remove a module. This is called by the module wrapper routine. 3330Sstevel@tonic-gate * (This routine is in the Solaris SPARC DDI/DKI) 3340Sstevel@tonic-gate */ 3350Sstevel@tonic-gate int 3360Sstevel@tonic-gate mod_remove(struct modlinkage *modlp) 3370Sstevel@tonic-gate { 3380Sstevel@tonic-gate int retval = 0; 3390Sstevel@tonic-gate struct modlmisc **linkpp, *last_linkp; 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate linkpp = (struct modlmisc **)&modlp->ml_linkage[0]; 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate while (*linkpp != NULL) { 3440Sstevel@tonic-gate if ((retval = MODL_REMOVE(*linkpp, modlp)) != 0) { 3450Sstevel@tonic-gate last_linkp = *linkpp; 3460Sstevel@tonic-gate linkpp = (struct modlmisc **)&modlp->ml_linkage[0]; 3470Sstevel@tonic-gate while (*linkpp != last_linkp) { 3480Sstevel@tonic-gate if (MODL_INSTALL(*linkpp, modlp) != 0) { 3490Sstevel@tonic-gate cmn_err(CE_WARN, reins_err, 3505206Sis (*linkpp)->misc_linkinfo); 3510Sstevel@tonic-gate break; 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate linkpp++; 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate break; 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate linkpp++; 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate return (retval); 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate /* 3630Sstevel@tonic-gate * Get module status. 3640Sstevel@tonic-gate * (This routine is in the Solaris SPARC DDI/DKI) 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate int 3670Sstevel@tonic-gate mod_info(struct modlinkage *modlp, struct modinfo *modinfop) 3680Sstevel@tonic-gate { 3690Sstevel@tonic-gate int i; 3700Sstevel@tonic-gate int retval = 0; 3710Sstevel@tonic-gate struct modspecific_info *msip; 3720Sstevel@tonic-gate struct modlmisc **linkpp; 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate modinfop->mi_rev = modlp->ml_rev; 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate linkpp = (struct modlmisc **)modlp->ml_linkage; 3770Sstevel@tonic-gate msip = &modinfop->mi_msinfo[0]; 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate for (i = 0; i < MODMAXLINK; i++) { 3800Sstevel@tonic-gate if (*linkpp == NULL) { 3810Sstevel@tonic-gate msip->msi_linkinfo[0] = '\0'; 3820Sstevel@tonic-gate } else { 3830Sstevel@tonic-gate (void) strncpy(msip->msi_linkinfo, 3840Sstevel@tonic-gate (*linkpp)->misc_linkinfo, MODMAXLINKINFOLEN); 3850Sstevel@tonic-gate retval = MODL_INFO(*linkpp, modlp, &msip->msi_p0); 3860Sstevel@tonic-gate if (retval != 0) 3870Sstevel@tonic-gate break; 3880Sstevel@tonic-gate linkpp++; 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate msip++; 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate if (modinfop->mi_info == MI_INFO_LINKAGE) { 3940Sstevel@tonic-gate /* 3950Sstevel@tonic-gate * Slight kludge used to extract the address of the 3960Sstevel@tonic-gate * modlinkage structure from the module (just after 3970Sstevel@tonic-gate * loading a module for the very first time) 3980Sstevel@tonic-gate */ 3990Sstevel@tonic-gate modinfop->mi_base = (void *)modlp; 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate if (retval == 0) 4030Sstevel@tonic-gate return (1); 4040Sstevel@tonic-gate return (0); 4050Sstevel@tonic-gate } 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate /* 4080Sstevel@tonic-gate * Get module name. 4090Sstevel@tonic-gate */ 4107009Scth const char * 4110Sstevel@tonic-gate mod_modname(struct modlinkage *modlp) 4120Sstevel@tonic-gate { 4130Sstevel@tonic-gate struct modctl *mcp; 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) 4160Sstevel@tonic-gate return (NULL); 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate return (mcp->mod_modname); 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /* 4220Sstevel@tonic-gate * Null operation; return 0. 4230Sstevel@tonic-gate */ 4240Sstevel@tonic-gate /*ARGSUSED*/ 4250Sstevel@tonic-gate static int 4260Sstevel@tonic-gate mod_null(struct modldrv *modl, struct modlinkage *modlp) 4270Sstevel@tonic-gate { 4280Sstevel@tonic-gate return (0); 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate /* 4320Sstevel@tonic-gate * Status for User modules. 4330Sstevel@tonic-gate */ 4340Sstevel@tonic-gate /*ARGSUSED*/ 4350Sstevel@tonic-gate static int 4360Sstevel@tonic-gate mod_infonull(void *modl, struct modlinkage *modlp, int *p0) 4370Sstevel@tonic-gate { 4380Sstevel@tonic-gate *p0 = -1; /* for modinfo display */ 4390Sstevel@tonic-gate return (0); 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate /* 4430Sstevel@tonic-gate * Driver status info 4440Sstevel@tonic-gate */ 4450Sstevel@tonic-gate /*ARGSUSED*/ 4460Sstevel@tonic-gate static int 4470Sstevel@tonic-gate mod_infodrv(struct modldrv *modl, struct modlinkage *modlp, int *p0) 4480Sstevel@tonic-gate { 4490Sstevel@tonic-gate struct modctl *mcp; 4500Sstevel@tonic-gate char *mod_name; 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) { 4530Sstevel@tonic-gate *p0 = -1; 4540Sstevel@tonic-gate return (0); /* driver is not yet installed */ 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate mod_name = mcp->mod_modname; 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate *p0 = ddi_name_to_major(mod_name); 4600Sstevel@tonic-gate return (0); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate /* 4640Sstevel@tonic-gate * Manage dacf (device autoconfiguration) modules 4650Sstevel@tonic-gate */ 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate /*ARGSUSED*/ 4680Sstevel@tonic-gate static int 4690Sstevel@tonic-gate mod_infodacf(struct modldacf *modl, struct modlinkage *modlp, int *p0) 4700Sstevel@tonic-gate { 4710Sstevel@tonic-gate if (mod_getctl(modlp) == NULL) { 4720Sstevel@tonic-gate *p0 = -1; 4730Sstevel@tonic-gate return (0); /* module is not yet installed */ 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate *p0 = 0; 4770Sstevel@tonic-gate return (0); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate static int 4810Sstevel@tonic-gate mod_installdacf(struct modldacf *modl, struct modlinkage *modlp) 4820Sstevel@tonic-gate { 4830Sstevel@tonic-gate struct modctl *mcp; 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) 4860Sstevel@tonic-gate return (EINVAL); 4870Sstevel@tonic-gate return (dacf_module_register(mcp->mod_modname, modl->dacf_dacfsw)); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate /*ARGSUSED*/ 4910Sstevel@tonic-gate static int 4920Sstevel@tonic-gate mod_removedacf(struct modldacf *modl, struct modlinkage *modlp) 4930Sstevel@tonic-gate { 4940Sstevel@tonic-gate struct modctl *mcp; 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) 4970Sstevel@tonic-gate return (EINVAL); 4980Sstevel@tonic-gate return (dacf_module_unregister(mcp->mod_modname)); 4990Sstevel@tonic-gate } 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate /* 5020Sstevel@tonic-gate * Manage PCBE (Performance Counter BackEnd) modules. 5030Sstevel@tonic-gate */ 5040Sstevel@tonic-gate /*ARGSUSED*/ 5050Sstevel@tonic-gate static int 5060Sstevel@tonic-gate mod_installpcbe(struct modlpcbe *modl, struct modlinkage *modlp) 5070Sstevel@tonic-gate { 5080Sstevel@tonic-gate if (modl->pcbe_ops->pcbe_ver != PCBE_VER_1) { 5090Sstevel@tonic-gate cmn_err(CE_WARN, "pcbe '%s' version mismatch", 5100Sstevel@tonic-gate modl->pcbe_linkinfo); 5110Sstevel@tonic-gate return (EINVAL); 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate kcpc_register_pcbe(modl->pcbe_ops); 5150Sstevel@tonic-gate return (0); 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate /* 5190Sstevel@tonic-gate * PCBEs may not be unloaded. It would make CPC locking too complex, and since 5200Sstevel@tonic-gate * PCBEs are loaded once and used for life, there is no harm done in leaving 5210Sstevel@tonic-gate * them in the system. 5220Sstevel@tonic-gate */ 5230Sstevel@tonic-gate /*ARGSUSED*/ 5240Sstevel@tonic-gate static int 5250Sstevel@tonic-gate mod_removepcbe(struct modlpcbe *modl, struct modlinkage *modlp) 5260Sstevel@tonic-gate { 5270Sstevel@tonic-gate return (EBUSY); 5280Sstevel@tonic-gate } 5290Sstevel@tonic-gate 5302621Sllai1 /* 5312712Snn35248 * Manage BrandZ modules. 5322712Snn35248 */ 5332712Snn35248 /*ARGSUSED*/ 5342712Snn35248 static int 5352712Snn35248 mod_installbrand(struct modlbrand *modl, struct modlinkage *modlp) 5362712Snn35248 { 5372712Snn35248 return (brand_register(modl->brand_branddef)); 5382712Snn35248 } 5392712Snn35248 5402712Snn35248 /*ARGSUSED*/ 5412712Snn35248 static int 5422712Snn35248 mod_removebrand(struct modlbrand *modl, struct modlinkage *modlp) 5432712Snn35248 { 5442712Snn35248 return (brand_unregister(modl->brand_branddef)); 5452712Snn35248 } 5462712Snn35248 5472712Snn35248 /* 5482621Sllai1 * manage /dev fs modules 5492621Sllai1 */ 5502621Sllai1 /*ARGSUSED*/ 5512621Sllai1 static int 5522621Sllai1 mod_infodev(struct modldev *modl, struct modlinkage *modlp, int *p0) 5532621Sllai1 { 5542621Sllai1 if (mod_getctl(modlp) == NULL) { 5552621Sllai1 *p0 = -1; 5562621Sllai1 return (0); /* module is not yet installed */ 5572621Sllai1 } 5582621Sllai1 5592621Sllai1 *p0 = 0; 5602621Sllai1 return (0); 5612621Sllai1 } 5622621Sllai1 5632621Sllai1 static int 5642621Sllai1 mod_installdev(struct modldev *modl, struct modlinkage *modlp) 5652621Sllai1 { 5662621Sllai1 struct modctl *mcp; 5672621Sllai1 5682621Sllai1 if ((mcp = mod_getctl(modlp)) == NULL) 5692621Sllai1 return (EINVAL); 5702621Sllai1 return (sdev_module_register(mcp->mod_modname, modl->dev_ops)); 5712621Sllai1 } 5722621Sllai1 5732621Sllai1 /* 5742621Sllai1 * /dev modules are not unloadable. 5752621Sllai1 */ 5762621Sllai1 /*ARGSUSED*/ 5772621Sllai1 static int 5782621Sllai1 mod_removedev(struct modldev *modl, struct modlinkage *modlp) 5792621Sllai1 { 5802621Sllai1 return (EBUSY); 5812621Sllai1 } 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate /* 5840Sstevel@tonic-gate * Install a new driver 5850Sstevel@tonic-gate */ 5860Sstevel@tonic-gate static int 5870Sstevel@tonic-gate mod_installdrv(struct modldrv *modl, struct modlinkage *modlp) 5880Sstevel@tonic-gate { 5890Sstevel@tonic-gate struct modctl *mcp; 5900Sstevel@tonic-gate struct dev_ops *ops; 5910Sstevel@tonic-gate char *modname; 5920Sstevel@tonic-gate major_t major; 5930Sstevel@tonic-gate struct dev_ops *dp; 5940Sstevel@tonic-gate struct devnames *dnp; 5950Sstevel@tonic-gate struct streamtab *str; 5960Sstevel@tonic-gate cdevsw_impl_t *cdp; 5970Sstevel@tonic-gate uint_t sqtype; 5980Sstevel@tonic-gate uint_t qflag; 5990Sstevel@tonic-gate uint_t flag; 6000Sstevel@tonic-gate int err = 0; 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate /* sanity check module */ 6030Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) { 6040Sstevel@tonic-gate cmn_err(CE_WARN, "mod_install: bad module linkage data"); 6050Sstevel@tonic-gate err = ENXIO; 6060Sstevel@tonic-gate goto done; 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate modname = mcp->mod_modname; 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate /* Sanity check modname */ 6117009Scth if ((major = ddi_name_to_major(modname)) == DDI_MAJOR_T_NONE) { 6120Sstevel@tonic-gate #ifdef DEBUG 6130Sstevel@tonic-gate cmn_err(CE_WARN, 6140Sstevel@tonic-gate "mod_installdrv: no major number for %s", modname); 6150Sstevel@tonic-gate #endif 6160Sstevel@tonic-gate err = ENXIO; 6170Sstevel@tonic-gate goto done; 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate /* Verify MP safety flag */ 6210Sstevel@tonic-gate ops = modl->drv_dev_ops; 6220Sstevel@tonic-gate if (ops->devo_bus_ops == NULL && ops->devo_cb_ops != NULL && 6230Sstevel@tonic-gate !(ops->devo_cb_ops->cb_flag & D_MP)) { 6240Sstevel@tonic-gate cmn_err(CE_WARN, 6250Sstevel@tonic-gate "mod_installdrv: MT-unsafe driver '%s' rejected", modname); 6260Sstevel@tonic-gate err = ENXIO; 6270Sstevel@tonic-gate goto done; 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate /* Is bus_map_fault signature correct (version 8 and higher)? */ 6320Sstevel@tonic-gate if (ops->devo_bus_ops != NULL && 6330Sstevel@tonic-gate ops->devo_bus_ops->bus_map_fault != NULL && 6340Sstevel@tonic-gate ops->devo_bus_ops->bus_map_fault != i_ddi_map_fault && 6350Sstevel@tonic-gate ops->devo_bus_ops->busops_rev < BUSO_REV_8) { 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate cmn_err(CE_WARN, 6380Sstevel@tonic-gate "mod_installdrv: busops' revision of '%s' is too low" 6390Sstevel@tonic-gate " (must be at least 8)", modname); 6400Sstevel@tonic-gate err = ENXIO; 6410Sstevel@tonic-gate goto done; 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate /* Make sure the driver is uninstalled */ 6460Sstevel@tonic-gate dnp = &devnamesp[major]; 6470Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 6480Sstevel@tonic-gate dp = devopsp[major]; 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate if (dnp->dn_flags & DN_DRIVER_REMOVED) { 6510Sstevel@tonic-gate #ifdef DEBUG 6520Sstevel@tonic-gate cmn_err(CE_NOTE, 6530Sstevel@tonic-gate "mod_installdrv: driver has been removed %s", modname); 6540Sstevel@tonic-gate #endif 6550Sstevel@tonic-gate err = ENXIO; 6560Sstevel@tonic-gate goto unlock; 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate if (dp != &nodev_ops && dp != &mod_nodev_ops) { 6600Sstevel@tonic-gate cmn_err(CE_WARN, 6610Sstevel@tonic-gate "mod_installdrv: driver already installed %s", modname); 6620Sstevel@tonic-gate err = EALREADY; 6630Sstevel@tonic-gate goto unlock; 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate devopsp[major] = ops; /* setup devopsp */ 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate if ((str = STREAMSTAB(major)) != NULL) { /* streams driver */ 6690Sstevel@tonic-gate flag = CBFLAG(major); 6700Sstevel@tonic-gate if ((err = devflg_to_qflag(str, flag, &qflag, &sqtype)) != 0) 6710Sstevel@tonic-gate goto unlock; 6720Sstevel@tonic-gate cdp = &devimpl[major]; 6730Sstevel@tonic-gate ASSERT(cdp->d_str == NULL); 6740Sstevel@tonic-gate cdp->d_str = str; 6750Sstevel@tonic-gate cdp->d_qflag = qflag | QISDRV; 6760Sstevel@tonic-gate cdp->d_sqtype = sqtype; 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate if (ops->devo_bus_ops == NULL) 6800Sstevel@tonic-gate dnp->dn_flags |= DN_LEAF_DRIVER; 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate unlock: 6830Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 6840Sstevel@tonic-gate done: 6850Sstevel@tonic-gate return (err); 6860Sstevel@tonic-gate } 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate static int 6890Sstevel@tonic-gate mod_removedrv(struct modldrv *modl, struct modlinkage *modlp) 6900Sstevel@tonic-gate { 6910Sstevel@tonic-gate struct modctl *mcp; 6920Sstevel@tonic-gate struct dev_ops *ops; 6930Sstevel@tonic-gate struct devnames *dnp; 6940Sstevel@tonic-gate struct dev_ops *dp; 6950Sstevel@tonic-gate major_t major; 6960Sstevel@tonic-gate char *modname; 6970Sstevel@tonic-gate extern kthread_id_t mod_aul_thread; 6980Sstevel@tonic-gate struct streamtab *str; 6990Sstevel@tonic-gate cdevsw_impl_t *cdp; 7000Sstevel@tonic-gate int err = 0; 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate /* Don't auto unload modules on if moddebug flag is set */ 7030Sstevel@tonic-gate if ((moddebug & MODDEBUG_NOAUL_DRV) && (mod_aul_thread == curthread)) { 7040Sstevel@tonic-gate err = EBUSY; 7050Sstevel@tonic-gate goto done; 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate /* Verify modname has a driver major */ 7090Sstevel@tonic-gate mcp = mod_getctl(modlp); 7100Sstevel@tonic-gate ASSERT(mcp != NULL); 7110Sstevel@tonic-gate modname = mcp->mod_modname; 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate if ((major = ddi_name_to_major(modname)) == -1) { 7140Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 7150Sstevel@tonic-gate err = EINVAL; 7160Sstevel@tonic-gate goto done; 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate ops = modl->drv_dev_ops; 7200Sstevel@tonic-gate dnp = &(devnamesp[major]); 7210Sstevel@tonic-gate LOCK_DEV_OPS(&(dnp->dn_lock)); 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate dp = devopsp[major]; 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate if (dp != ops) { 7260Sstevel@tonic-gate cmn_err(CE_NOTE, "mod_removedrv: mismatched driver for %s", 7270Sstevel@tonic-gate modname); 7280Sstevel@tonic-gate err = EBUSY; 7290Sstevel@tonic-gate goto unlock; 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * A driver is not unloadable if its dev_ops are held 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate if (!DRV_UNLOADABLE(dp)) { 7360Sstevel@tonic-gate mod_dprintf(DRV_DBG, "Cannot unload device driver <%s>," 7370Sstevel@tonic-gate " refcnt %d\n", modname, dp->devo_refcnt); 7380Sstevel@tonic-gate err = EBUSY; 7390Sstevel@tonic-gate goto unlock; 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate /* 7430Sstevel@tonic-gate * OK to unload. 7440Sstevel@tonic-gate */ 7450Sstevel@tonic-gate if ((str = STREAMSTAB(major)) != NULL) { /* streams driver */ 7460Sstevel@tonic-gate cdp = &devimpl[major]; 7470Sstevel@tonic-gate ASSERT(cdp->d_str == str); 7480Sstevel@tonic-gate cdp->d_str = NULL; 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate /* check for reference to per-dev syncq */ 7510Sstevel@tonic-gate if (cdp->d_dmp != NULL) { 7520Sstevel@tonic-gate rele_dm(cdp->d_dmp); 7530Sstevel@tonic-gate cdp->d_dmp = NULL; 7540Sstevel@tonic-gate } 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate devopsp[major] = &mod_nodev_ops; 7580Sstevel@tonic-gate dnp->dn_flags &= ~(DN_DRIVER_HELD|DN_NO_AUTODETACH); 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate unlock: 7610Sstevel@tonic-gate UNLOCK_DEV_OPS(&(dnp->dn_lock)); 7620Sstevel@tonic-gate done: 7630Sstevel@tonic-gate return (err); 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate /* 7670Sstevel@tonic-gate * System call subroutines 7680Sstevel@tonic-gate */ 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate /* 7710Sstevel@tonic-gate * Compute system call number for given sysent and sysent table 7720Sstevel@tonic-gate */ 7730Sstevel@tonic-gate static int 7740Sstevel@tonic-gate mod_infosysnum(struct modlinkage *modlp, struct sysent table[]) 7750Sstevel@tonic-gate { 7760Sstevel@tonic-gate struct sysent *sysp; 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate if ((sysp = mod_getsysent(modlp, table)) == NULL) 7790Sstevel@tonic-gate return (-1); 7800Sstevel@tonic-gate return ((int)(sysp - table)); 7810Sstevel@tonic-gate } 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate /* 7840Sstevel@tonic-gate * Put a loadable system call entry into a sysent table. 7850Sstevel@tonic-gate */ 7860Sstevel@tonic-gate static int 7870Sstevel@tonic-gate mod_installsys_sysent( 7880Sstevel@tonic-gate struct modlsys *modl, 7890Sstevel@tonic-gate struct modlinkage *modlp, 7900Sstevel@tonic-gate struct sysent table[]) 7910Sstevel@tonic-gate { 7920Sstevel@tonic-gate struct sysent *sysp; 7930Sstevel@tonic-gate struct sysent *mp; 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate #ifdef DEBUG 7960Sstevel@tonic-gate /* 7970Sstevel@tonic-gate * Before we even play with the sysent table, sanity check the 7980Sstevel@tonic-gate * incoming flags to make sure the entry is valid 7990Sstevel@tonic-gate */ 8000Sstevel@tonic-gate switch (modl->sys_sysent->sy_flags & SE_RVAL_MASK) { 8010Sstevel@tonic-gate case SE_32RVAL1: 8020Sstevel@tonic-gate /* only r_val1 returned */ 8030Sstevel@tonic-gate case SE_32RVAL1 | SE_32RVAL2: 8040Sstevel@tonic-gate /* r_val1 and r_val2 returned */ 8050Sstevel@tonic-gate case SE_64RVAL: 8060Sstevel@tonic-gate /* 64-bit rval returned */ 8070Sstevel@tonic-gate break; 8080Sstevel@tonic-gate default: 8090Sstevel@tonic-gate cmn_err(CE_WARN, "loadable syscall: %p: bad rval flags %x", 8100Sstevel@tonic-gate (void *)modl, modl->sys_sysent->sy_flags); 8110Sstevel@tonic-gate return (ENOSYS); 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate #endif 8140Sstevel@tonic-gate if ((sysp = mod_getsysent(modlp, table)) == NULL) 8150Sstevel@tonic-gate return (ENOSPC); 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate /* 8180Sstevel@tonic-gate * We should only block here until the reader in syscall gives 8190Sstevel@tonic-gate * up the lock. Multiple writers are prevented in the mod layer. 8200Sstevel@tonic-gate */ 8210Sstevel@tonic-gate rw_enter(sysp->sy_lock, RW_WRITER); 8220Sstevel@tonic-gate mp = modl->sys_sysent; 8230Sstevel@tonic-gate sysp->sy_narg = mp->sy_narg; 8240Sstevel@tonic-gate sysp->sy_call = mp->sy_call; 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate /* 8270Sstevel@tonic-gate * clear the old call method flag, and get the new one from the module. 8280Sstevel@tonic-gate */ 8290Sstevel@tonic-gate sysp->sy_flags &= ~SE_ARGC; 8300Sstevel@tonic-gate sysp->sy_flags |= SE_LOADED | 8310Sstevel@tonic-gate (mp->sy_flags & (SE_ARGC | SE_NOUNLOAD | SE_RVAL_MASK)); 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate /* 8340Sstevel@tonic-gate * If the syscall doesn't need or want unloading, it can avoid 8350Sstevel@tonic-gate * the locking overhead on each entry. Convert the sysent to a 8360Sstevel@tonic-gate * normal non-loadable entry in that case. 8370Sstevel@tonic-gate */ 8380Sstevel@tonic-gate if (mp->sy_flags & SE_NOUNLOAD) { 8390Sstevel@tonic-gate if (mp->sy_flags & SE_ARGC) { 8400Sstevel@tonic-gate sysp->sy_callc = (int64_t (*)())mp->sy_call; 8410Sstevel@tonic-gate } else { 8420Sstevel@tonic-gate sysp->sy_callc = syscall_ap; 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate sysp->sy_flags &= ~SE_LOADABLE; 8450Sstevel@tonic-gate } 8460Sstevel@tonic-gate rw_exit(sysp->sy_lock); 8470Sstevel@tonic-gate return (0); 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate /* 8510Sstevel@tonic-gate * Remove a loadable system call entry from a sysent table. 8520Sstevel@tonic-gate */ 8530Sstevel@tonic-gate static int 8540Sstevel@tonic-gate mod_removesys_sysent( 8550Sstevel@tonic-gate struct modlsys *modl, 8560Sstevel@tonic-gate struct modlinkage *modlp, 8570Sstevel@tonic-gate struct sysent table[]) 8580Sstevel@tonic-gate { 8590Sstevel@tonic-gate struct sysent *sysp; 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate if ((sysp = mod_getsysent(modlp, table)) == NULL || 8620Sstevel@tonic-gate (sysp->sy_flags & (SE_LOADABLE | SE_NOUNLOAD)) == 0 || 8630Sstevel@tonic-gate sysp->sy_call != modl->sys_sysent->sy_call) { 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 8660Sstevel@tonic-gate char *modname = mcp->mod_modname; 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 8690Sstevel@tonic-gate return (EINVAL); 8700Sstevel@tonic-gate } 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate /* If we can't get the write lock, we can't unlink from the system */ 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate if (!(moddebug & MODDEBUG_NOAUL_SYS) && 8750Sstevel@tonic-gate rw_tryenter(sysp->sy_lock, RW_WRITER)) { 8760Sstevel@tonic-gate /* 8770Sstevel@tonic-gate * Check the flags to be sure the syscall is still 8780Sstevel@tonic-gate * (un)loadable. 8790Sstevel@tonic-gate * If SE_NOUNLOAD is set, SE_LOADABLE will not be. 8800Sstevel@tonic-gate */ 8810Sstevel@tonic-gate if ((sysp->sy_flags & (SE_LOADED | SE_LOADABLE)) == 8820Sstevel@tonic-gate (SE_LOADED | SE_LOADABLE)) { 8830Sstevel@tonic-gate sysp->sy_flags &= ~SE_LOADED; 8840Sstevel@tonic-gate sysp->sy_callc = loadable_syscall; 8850Sstevel@tonic-gate sysp->sy_call = (int (*)())nosys; 8860Sstevel@tonic-gate rw_exit(sysp->sy_lock); 8870Sstevel@tonic-gate return (0); 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate rw_exit(sysp->sy_lock); 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate return (EBUSY); 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate /* 8950Sstevel@tonic-gate * System call status info 8960Sstevel@tonic-gate */ 8970Sstevel@tonic-gate /*ARGSUSED*/ 8980Sstevel@tonic-gate static int 8990Sstevel@tonic-gate mod_infosys(struct modlsys *modl, struct modlinkage *modlp, int *p0) 9000Sstevel@tonic-gate { 9010Sstevel@tonic-gate *p0 = mod_infosysnum(modlp, sysent); 9020Sstevel@tonic-gate return (0); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate /* 9060Sstevel@tonic-gate * Link a system call into the system by setting the proper sysent entry. 9070Sstevel@tonic-gate * Called from the module's _init routine. 9080Sstevel@tonic-gate */ 9090Sstevel@tonic-gate static int 9100Sstevel@tonic-gate mod_installsys(struct modlsys *modl, struct modlinkage *modlp) 9110Sstevel@tonic-gate { 9120Sstevel@tonic-gate return (mod_installsys_sysent(modl, modlp, sysent)); 9130Sstevel@tonic-gate } 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate /* 9160Sstevel@tonic-gate * Unlink a system call from the system. 9170Sstevel@tonic-gate * Called from a modules _fini routine. 9180Sstevel@tonic-gate */ 9190Sstevel@tonic-gate static int 9200Sstevel@tonic-gate mod_removesys(struct modlsys *modl, struct modlinkage *modlp) 9210Sstevel@tonic-gate { 9220Sstevel@tonic-gate return (mod_removesys_sysent(modl, modlp, sysent)); 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate /* 9280Sstevel@tonic-gate * 32-bit system call status info 9290Sstevel@tonic-gate */ 9300Sstevel@tonic-gate /*ARGSUSED*/ 9310Sstevel@tonic-gate static int 9320Sstevel@tonic-gate mod_infosys32(struct modlsys *modl, struct modlinkage *modlp, int *p0) 9330Sstevel@tonic-gate { 9340Sstevel@tonic-gate *p0 = mod_infosysnum(modlp, sysent32); 9350Sstevel@tonic-gate return (0); 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate /* 9390Sstevel@tonic-gate * Link the 32-bit syscall into the system by setting the proper sysent entry. 9400Sstevel@tonic-gate * Also called from the module's _init routine. 9410Sstevel@tonic-gate */ 9420Sstevel@tonic-gate static int 9430Sstevel@tonic-gate mod_installsys32(struct modlsys *modl, struct modlinkage *modlp) 9440Sstevel@tonic-gate { 9450Sstevel@tonic-gate return (mod_installsys_sysent(modl, modlp, sysent32)); 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate /* 9490Sstevel@tonic-gate * Unlink the 32-bit flavor of a system call from the system. 9500Sstevel@tonic-gate * Also called from a module's _fini routine. 9510Sstevel@tonic-gate */ 9520Sstevel@tonic-gate static int 9530Sstevel@tonic-gate mod_removesys32(struct modlsys *modl, struct modlinkage *modlp) 9540Sstevel@tonic-gate { 9550Sstevel@tonic-gate return (mod_removesys_sysent(modl, modlp, sysent32)); 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate /* 9610Sstevel@tonic-gate * Filesystem status info 9620Sstevel@tonic-gate */ 9630Sstevel@tonic-gate /*ARGSUSED*/ 9640Sstevel@tonic-gate static int 9650Sstevel@tonic-gate mod_infofs(struct modlfs *modl, struct modlinkage *modlp, int *p0) 9660Sstevel@tonic-gate { 9670Sstevel@tonic-gate struct vfssw *vswp; 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate RLOCK_VFSSW(); 9700Sstevel@tonic-gate if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL) 9710Sstevel@tonic-gate *p0 = -1; 9720Sstevel@tonic-gate else { 9730Sstevel@tonic-gate *p0 = vswp - vfssw; 9740Sstevel@tonic-gate vfs_unrefvfssw(vswp); 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate RUNLOCK_VFSSW(); 9770Sstevel@tonic-gate return (0); 9780Sstevel@tonic-gate } 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate /* 9810Sstevel@tonic-gate * Install a filesystem. 9820Sstevel@tonic-gate */ 9830Sstevel@tonic-gate /*ARGSUSED1*/ 9840Sstevel@tonic-gate static int 9850Sstevel@tonic-gate mod_installfs(struct modlfs *modl, struct modlinkage *modlp) 9860Sstevel@tonic-gate { 9870Sstevel@tonic-gate struct vfssw *vswp; 9880Sstevel@tonic-gate struct modctl *mcp; 9890Sstevel@tonic-gate char *fsname; 9901488Srsb char ksname[KSTAT_STRLEN + 1]; 9911488Srsb int fstype; /* index into vfssw[] and vsanchor_fstype[] */ 9920Sstevel@tonic-gate int allocated; 9930Sstevel@tonic-gate int err; 9941488Srsb int vsw_stats_enabled; 9951488Srsb /* Not for public consumption so these aren't in a header file */ 9961488Srsb extern int vopstats_enabled; 9971488Srsb extern vopstats_t **vopstats_fstype; 9981488Srsb extern kstat_t *new_vskstat(char *, vopstats_t *); 9991488Srsb extern void initialize_vopstats(vopstats_t *); 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate if (modl->fs_vfsdef->def_version == VFSDEF_VERSION) { 10020Sstevel@tonic-gate /* Version matched */ 10030Sstevel@tonic-gate fsname = modl->fs_vfsdef->name; 10040Sstevel@tonic-gate } else { 10050Sstevel@tonic-gate if ((modl->fs_vfsdef->def_version > 0) && 10060Sstevel@tonic-gate (modl->fs_vfsdef->def_version < VFSDEF_VERSION)) { 10070Sstevel@tonic-gate /* Older VFSDEF_VERSION */ 10080Sstevel@tonic-gate fsname = modl->fs_vfsdef->name; 10090Sstevel@tonic-gate } else if ((mcp = mod_getctl(modlp)) != NULL) { 10100Sstevel@tonic-gate /* Pre-VFSDEF_VERSION */ 10110Sstevel@tonic-gate fsname = mcp->mod_modname; 10120Sstevel@tonic-gate } else { 10130Sstevel@tonic-gate /* If all else fails... */ 10140Sstevel@tonic-gate fsname = "<unknown file system type>"; 10150Sstevel@tonic-gate } 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate cmn_err(CE_WARN, "file system '%s' version mismatch", fsname); 10180Sstevel@tonic-gate return (ENXIO); 10190Sstevel@tonic-gate } 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate allocated = 0; 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate WLOCK_VFSSW(); 10240Sstevel@tonic-gate if ((vswp = vfs_getvfsswbyname(fsname)) == NULL) { 10250Sstevel@tonic-gate if ((vswp = allocate_vfssw(fsname)) == NULL) { 10260Sstevel@tonic-gate WUNLOCK_VFSSW(); 10270Sstevel@tonic-gate /* 10280Sstevel@tonic-gate * See 1095689. If this message appears, then 10290Sstevel@tonic-gate * we either need to make the vfssw table bigger 10300Sstevel@tonic-gate * statically, or make it grow dynamically. 10310Sstevel@tonic-gate */ 10320Sstevel@tonic-gate cmn_err(CE_WARN, "no room for '%s' in vfssw!", fsname); 10330Sstevel@tonic-gate return (ENXIO); 10340Sstevel@tonic-gate } 10350Sstevel@tonic-gate allocated = 1; 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate ASSERT(vswp != NULL); 10380Sstevel@tonic-gate 10391488Srsb fstype = vswp - vfssw; /* Pointer arithmetic to get the fstype */ 10401488Srsb 10411488Srsb /* Turn on everything by default *except* VSW_STATS */ 10421488Srsb vswp->vsw_flag = modl->fs_vfsdef->flags & ~(VSW_STATS); 10431488Srsb 10440Sstevel@tonic-gate if (modl->fs_vfsdef->flags & VSW_HASPROTO) { 10450Sstevel@tonic-gate vfs_mergeopttbl(&vfs_mntopts, modl->fs_vfsdef->optproto, 10460Sstevel@tonic-gate &vswp->vsw_optproto); 10470Sstevel@tonic-gate } else { 10480Sstevel@tonic-gate vfs_copyopttbl(&vfs_mntopts, &vswp->vsw_optproto); 10490Sstevel@tonic-gate } 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate if (modl->fs_vfsdef->flags & VSW_CANRWRO) { 10520Sstevel@tonic-gate /* 10530Sstevel@tonic-gate * This obviously implies VSW_CANREMOUNT. 10540Sstevel@tonic-gate */ 10550Sstevel@tonic-gate vswp->vsw_flag |= VSW_CANREMOUNT; 10560Sstevel@tonic-gate } 10571488Srsb 10581488Srsb /* 10591488Srsb * If stats are enabled system wide and for this fstype, then 10601488Srsb * set the VSW_STATS flag in the proper vfssw[] table entry. 10611488Srsb */ 10621488Srsb if (vopstats_enabled && modl->fs_vfsdef->flags & VSW_STATS) { 10631488Srsb vswp->vsw_flag |= VSW_STATS; 10641488Srsb } 10651488Srsb 10660Sstevel@tonic-gate if (modl->fs_vfsdef->init == NULL) 10670Sstevel@tonic-gate err = EFAULT; 10680Sstevel@tonic-gate else 10691488Srsb err = (*(modl->fs_vfsdef->init))(fstype, fsname); 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate if (err != 0) { 10720Sstevel@tonic-gate if (allocated) { 10730Sstevel@tonic-gate kmem_free(vswp->vsw_name, strlen(vswp->vsw_name)+1); 10740Sstevel@tonic-gate vswp->vsw_name = ""; 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate vswp->vsw_flag = 0; 10770Sstevel@tonic-gate vswp->vsw_init = NULL; 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate 10801488Srsb /* We don't want to hold the vfssw[] write lock over a kmem_alloc() */ 10811488Srsb vsw_stats_enabled = vswp->vsw_flag & VSW_STATS; 10821488Srsb 10830Sstevel@tonic-gate vfs_unrefvfssw(vswp); 10840Sstevel@tonic-gate WUNLOCK_VFSSW(); 10850Sstevel@tonic-gate 10861488Srsb /* If everything is on, set up the per-fstype vopstats */ 10871488Srsb if (vsw_stats_enabled && vopstats_enabled && 10881488Srsb vopstats_fstype && vopstats_fstype[fstype] == NULL) { 10891488Srsb (void) strlcpy(ksname, VOPSTATS_STR, sizeof (ksname)); 10901488Srsb (void) strlcat(ksname, vfssw[fstype].vsw_name, sizeof (ksname)); 10911488Srsb vopstats_fstype[fstype] = 10921488Srsb kmem_alloc(sizeof (vopstats_t), KM_SLEEP); 10931488Srsb initialize_vopstats(vopstats_fstype[fstype]); 10941488Srsb (void) new_vskstat(ksname, vopstats_fstype[fstype]); 10951488Srsb } 10960Sstevel@tonic-gate return (err); 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate /* 11000Sstevel@tonic-gate * Remove a filesystem 11010Sstevel@tonic-gate */ 11020Sstevel@tonic-gate static int 11030Sstevel@tonic-gate mod_removefs(struct modlfs *modl, struct modlinkage *modlp) 11040Sstevel@tonic-gate { 11050Sstevel@tonic-gate struct vfssw *vswp; 11060Sstevel@tonic-gate struct modctl *mcp; 11070Sstevel@tonic-gate char *modname; 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_FS) 11100Sstevel@tonic-gate return (EBUSY); 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate WLOCK_VFSSW(); 11130Sstevel@tonic-gate if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL) { 11140Sstevel@tonic-gate mcp = mod_getctl(modlp); 11150Sstevel@tonic-gate ASSERT(mcp != NULL); 11160Sstevel@tonic-gate modname = mcp->mod_modname; 11170Sstevel@tonic-gate WUNLOCK_VFSSW(); 11180Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 11190Sstevel@tonic-gate return (EINVAL); 11200Sstevel@tonic-gate } 11210Sstevel@tonic-gate if (vswp->vsw_count != 1) { 11220Sstevel@tonic-gate vfs_unrefvfssw(vswp); 11230Sstevel@tonic-gate WUNLOCK_VFSSW(); 11240Sstevel@tonic-gate return (EBUSY); 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate 11272712Snn35248 /* 11282712Snn35248 * A mounted filesystem could still have vsw_count = 0 11292712Snn35248 * so we must check whether anyone is actually using our ops 11302712Snn35248 */ 11310Sstevel@tonic-gate if (vfs_opsinuse(&vswp->vsw_vfsops)) { 11321403Ssp92102 vfs_unrefvfssw(vswp); 11330Sstevel@tonic-gate WUNLOCK_VFSSW(); 11340Sstevel@tonic-gate return (EBUSY); 11350Sstevel@tonic-gate } 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate vfs_freeopttbl(&vswp->vsw_optproto); 11380Sstevel@tonic-gate vswp->vsw_optproto.mo_count = 0; 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate vswp->vsw_flag = 0; 11410Sstevel@tonic-gate vswp->vsw_init = NULL; 11420Sstevel@tonic-gate vfs_unrefvfssw(vswp); 11430Sstevel@tonic-gate WUNLOCK_VFSSW(); 11440Sstevel@tonic-gate return (0); 11450Sstevel@tonic-gate } 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate /* 11480Sstevel@tonic-gate * Get status of a streams module. 11490Sstevel@tonic-gate */ 11500Sstevel@tonic-gate /*ARGSUSED*/ 11510Sstevel@tonic-gate static int 11520Sstevel@tonic-gate mod_infostrmod(struct modlstrmod *modl, struct modlinkage *modlp, int *p0) 11530Sstevel@tonic-gate { 11540Sstevel@tonic-gate *p0 = -1; /* no useful info */ 11550Sstevel@tonic-gate return (0); 11560Sstevel@tonic-gate } 11570Sstevel@tonic-gate 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate /* 11600Sstevel@tonic-gate * Install a streams module. 11610Sstevel@tonic-gate */ 11620Sstevel@tonic-gate /*ARGSUSED*/ 11630Sstevel@tonic-gate static int 11640Sstevel@tonic-gate mod_installstrmod(struct modlstrmod *modl, struct modlinkage *modlp) 11650Sstevel@tonic-gate { 11660Sstevel@tonic-gate struct fmodsw *fp = modl->strmod_fmodsw; 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate if (!(fp->f_flag & D_MP)) { 11690Sstevel@tonic-gate cmn_err(CE_WARN, "mod_install: MT-unsafe strmod '%s' rejected", 11700Sstevel@tonic-gate fp->f_name); 11710Sstevel@tonic-gate return (ENXIO); 11720Sstevel@tonic-gate } 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate return (fmodsw_register(fp->f_name, fp->f_str, fp->f_flag)); 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate /* 11780Sstevel@tonic-gate * Remove a streams module. 11790Sstevel@tonic-gate */ 11800Sstevel@tonic-gate /*ARGSUSED*/ 11810Sstevel@tonic-gate static int 11820Sstevel@tonic-gate mod_removestrmod(struct modlstrmod *modl, struct modlinkage *modlp) 11830Sstevel@tonic-gate { 11840Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_STR) 11850Sstevel@tonic-gate return (EBUSY); 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate return (fmodsw_unregister(modl->strmod_fmodsw->f_name)); 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate /* 1191*8348SEric.Yu@Sun.COM * Get status of a socket module. 1192*8348SEric.Yu@Sun.COM */ 1193*8348SEric.Yu@Sun.COM /*ARGSUSED*/ 1194*8348SEric.Yu@Sun.COM static int 1195*8348SEric.Yu@Sun.COM mod_infosockmod(struct modlsockmod *modl, struct modlinkage *modlp, int *p0) 1196*8348SEric.Yu@Sun.COM { 1197*8348SEric.Yu@Sun.COM *p0 = -1; /* no useful info */ 1198*8348SEric.Yu@Sun.COM return (0); 1199*8348SEric.Yu@Sun.COM } 1200*8348SEric.Yu@Sun.COM 1201*8348SEric.Yu@Sun.COM /* 1202*8348SEric.Yu@Sun.COM * Install a socket module. 1203*8348SEric.Yu@Sun.COM */ 1204*8348SEric.Yu@Sun.COM /*ARGSUSED*/ 1205*8348SEric.Yu@Sun.COM static int 1206*8348SEric.Yu@Sun.COM mod_installsockmod(struct modlsockmod *modl, struct modlinkage *modlp) 1207*8348SEric.Yu@Sun.COM { 1208*8348SEric.Yu@Sun.COM struct modctl *mcp; 1209*8348SEric.Yu@Sun.COM char *mod_name; 1210*8348SEric.Yu@Sun.COM 1211*8348SEric.Yu@Sun.COM mcp = mod_getctl(modlp); 1212*8348SEric.Yu@Sun.COM ASSERT(mcp != NULL); 1213*8348SEric.Yu@Sun.COM mod_name = mcp->mod_modname; 1214*8348SEric.Yu@Sun.COM if (strcmp(mod_name, modl->sockmod_reg_info->smod_name) != 0) { 1215*8348SEric.Yu@Sun.COM #ifdef DEBUG 1216*8348SEric.Yu@Sun.COM cmn_err(CE_CONT, "mod_installsockmod: different names" 1217*8348SEric.Yu@Sun.COM " %s != %s \n", mod_name, 1218*8348SEric.Yu@Sun.COM modl->sockmod_reg_info->smod_name); 1219*8348SEric.Yu@Sun.COM #endif 1220*8348SEric.Yu@Sun.COM return (EINVAL); 1221*8348SEric.Yu@Sun.COM } 1222*8348SEric.Yu@Sun.COM 1223*8348SEric.Yu@Sun.COM /* 1224*8348SEric.Yu@Sun.COM * Register module. 1225*8348SEric.Yu@Sun.COM */ 1226*8348SEric.Yu@Sun.COM return (smod_register(modl->sockmod_reg_info)); 1227*8348SEric.Yu@Sun.COM } 1228*8348SEric.Yu@Sun.COM 1229*8348SEric.Yu@Sun.COM /* 1230*8348SEric.Yu@Sun.COM * Remove a socket module. 1231*8348SEric.Yu@Sun.COM */ 1232*8348SEric.Yu@Sun.COM /*ARGSUSED*/ 1233*8348SEric.Yu@Sun.COM static int 1234*8348SEric.Yu@Sun.COM mod_removesockmod(struct modlsockmod *modl, struct modlinkage *modlp) 1235*8348SEric.Yu@Sun.COM { 1236*8348SEric.Yu@Sun.COM /* 1237*8348SEric.Yu@Sun.COM * unregister from the global socket creation table 1238*8348SEric.Yu@Sun.COM * check the refcnt in the lookup table 1239*8348SEric.Yu@Sun.COM */ 1240*8348SEric.Yu@Sun.COM return (smod_unregister(modl->sockmod_reg_info->smod_name)); 1241*8348SEric.Yu@Sun.COM } 1242*8348SEric.Yu@Sun.COM 1243*8348SEric.Yu@Sun.COM /* 12440Sstevel@tonic-gate * Get status of a scheduling class module. 12450Sstevel@tonic-gate */ 12460Sstevel@tonic-gate /*ARGSUSED1*/ 12470Sstevel@tonic-gate static int 12480Sstevel@tonic-gate mod_infosched(struct modlsched *modl, struct modlinkage *modlp, int *p0) 12490Sstevel@tonic-gate { 12500Sstevel@tonic-gate int status; 12510Sstevel@tonic-gate auto id_t cid; 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate status = getcidbyname(modl->sched_class->cl_name, &cid); 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate if (status != 0) 12560Sstevel@tonic-gate *p0 = -1; 12570Sstevel@tonic-gate else 12580Sstevel@tonic-gate *p0 = cid; 12590Sstevel@tonic-gate 12600Sstevel@tonic-gate return (0); 12610Sstevel@tonic-gate } 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate /* 12640Sstevel@tonic-gate * Install a scheduling class module. 12650Sstevel@tonic-gate */ 12660Sstevel@tonic-gate /*ARGSUSED1*/ 12670Sstevel@tonic-gate static int 12680Sstevel@tonic-gate mod_installsched(struct modlsched *modl, struct modlinkage *modlp) 12690Sstevel@tonic-gate { 12700Sstevel@tonic-gate sclass_t *clp; 12710Sstevel@tonic-gate int status; 12720Sstevel@tonic-gate id_t cid; 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate /* 12750Sstevel@tonic-gate * See if module is already installed. 12760Sstevel@tonic-gate */ 12770Sstevel@tonic-gate mutex_enter(&class_lock); 12780Sstevel@tonic-gate status = alloc_cid(modl->sched_class->cl_name, &cid); 12790Sstevel@tonic-gate mutex_exit(&class_lock); 12800Sstevel@tonic-gate ASSERT(status == 0); 12810Sstevel@tonic-gate clp = &sclass[cid]; 12820Sstevel@tonic-gate rw_enter(clp->cl_lock, RW_WRITER); 12830Sstevel@tonic-gate if (SCHED_INSTALLED(clp)) { 12840Sstevel@tonic-gate printf("scheduling class %s is already installed\n", 12855206Sis modl->sched_class->cl_name); 12860Sstevel@tonic-gate rw_exit(clp->cl_lock); 12870Sstevel@tonic-gate return (EBUSY); /* it's already there */ 12880Sstevel@tonic-gate } 12890Sstevel@tonic-gate 12900Sstevel@tonic-gate clp->cl_init = modl->sched_class->cl_init; 12910Sstevel@tonic-gate clp->cl_funcs = modl->sched_class->cl_funcs; 12920Sstevel@tonic-gate modl->sched_class = clp; 12930Sstevel@tonic-gate disp_add(clp); 12940Sstevel@tonic-gate loaded_classes++; /* for priocntl system call */ 12950Sstevel@tonic-gate rw_exit(clp->cl_lock); 12960Sstevel@tonic-gate return (0); 12970Sstevel@tonic-gate } 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate /* 13000Sstevel@tonic-gate * Remove a scheduling class module. 13010Sstevel@tonic-gate * 13020Sstevel@tonic-gate * we only null out the init func and the class functions because 13030Sstevel@tonic-gate * once a class has been loaded it has that slot in the class 13040Sstevel@tonic-gate * array until the next reboot. We don't decrement loaded_classes 13050Sstevel@tonic-gate * because this keeps count of the number of classes that have 13060Sstevel@tonic-gate * been loaded for this session. It will have to be this way until 13070Sstevel@tonic-gate * we implement the class array as a linked list and do true 13080Sstevel@tonic-gate * dynamic allocation. 13090Sstevel@tonic-gate */ 13100Sstevel@tonic-gate static int 13110Sstevel@tonic-gate mod_removesched(struct modlsched *modl, struct modlinkage *modlp) 13120Sstevel@tonic-gate { 13130Sstevel@tonic-gate int status; 13140Sstevel@tonic-gate sclass_t *clp; 13150Sstevel@tonic-gate struct modctl *mcp; 13160Sstevel@tonic-gate char *modname; 13170Sstevel@tonic-gate id_t cid; 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate status = getcidbyname(modl->sched_class->cl_name, &cid); 13200Sstevel@tonic-gate if (status != 0) { 13210Sstevel@tonic-gate mcp = mod_getctl(modlp); 13220Sstevel@tonic-gate ASSERT(mcp != NULL); 13230Sstevel@tonic-gate modname = mcp->mod_modname; 13240Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 13250Sstevel@tonic-gate return (EINVAL); 13260Sstevel@tonic-gate } 13270Sstevel@tonic-gate clp = &sclass[cid]; 13280Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_SCHED || 13290Sstevel@tonic-gate !rw_tryenter(clp->cl_lock, RW_WRITER)) 13300Sstevel@tonic-gate return (EBUSY); 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate clp->cl_init = NULL; 13330Sstevel@tonic-gate clp->cl_funcs = NULL; 13340Sstevel@tonic-gate rw_exit(clp->cl_lock); 13350Sstevel@tonic-gate return (0); 13360Sstevel@tonic-gate } 13370Sstevel@tonic-gate 13380Sstevel@tonic-gate /* 13390Sstevel@tonic-gate * Get status of an exec module. 13400Sstevel@tonic-gate */ 13410Sstevel@tonic-gate /*ARGSUSED1*/ 13420Sstevel@tonic-gate static int 13430Sstevel@tonic-gate mod_infoexec(struct modlexec *modl, struct modlinkage *modlp, int *p0) 13440Sstevel@tonic-gate { 13450Sstevel@tonic-gate struct execsw *eswp; 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate if ((eswp = findexecsw(modl->exec_execsw->exec_magic)) == NULL) 13480Sstevel@tonic-gate *p0 = -1; 13490Sstevel@tonic-gate else 13500Sstevel@tonic-gate *p0 = eswp - execsw; 13510Sstevel@tonic-gate 13520Sstevel@tonic-gate return (0); 13530Sstevel@tonic-gate } 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate /* 13560Sstevel@tonic-gate * Install an exec module. 13570Sstevel@tonic-gate */ 13580Sstevel@tonic-gate static int 13590Sstevel@tonic-gate mod_installexec(struct modlexec *modl, struct modlinkage *modlp) 13600Sstevel@tonic-gate { 13610Sstevel@tonic-gate struct execsw *eswp; 13620Sstevel@tonic-gate struct modctl *mcp; 13630Sstevel@tonic-gate char *modname; 13640Sstevel@tonic-gate char *magic; 13650Sstevel@tonic-gate size_t magic_size; 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate /* 13680Sstevel@tonic-gate * See if execsw entry is already allocated. Can't use findexectype() 13690Sstevel@tonic-gate * because we may get a recursive call to here. 13700Sstevel@tonic-gate */ 13710Sstevel@tonic-gate 13720Sstevel@tonic-gate if ((eswp = findexecsw(modl->exec_execsw->exec_magic)) == NULL) { 13730Sstevel@tonic-gate mcp = mod_getctl(modlp); 13740Sstevel@tonic-gate ASSERT(mcp != NULL); 13750Sstevel@tonic-gate modname = mcp->mod_modname; 13760Sstevel@tonic-gate magic = modl->exec_execsw->exec_magic; 13770Sstevel@tonic-gate magic_size = modl->exec_execsw->exec_maglen; 13780Sstevel@tonic-gate if ((eswp = allocate_execsw(modname, magic, magic_size)) == 13790Sstevel@tonic-gate NULL) { 13800Sstevel@tonic-gate printf("no unused entries in 'execsw'\n"); 13810Sstevel@tonic-gate return (ENOSPC); 13820Sstevel@tonic-gate } 13830Sstevel@tonic-gate } 13840Sstevel@tonic-gate if (eswp->exec_func != NULL) { 13850Sstevel@tonic-gate printf("exec type %x is already installed\n", 13865206Sis *eswp->exec_magic); 13870Sstevel@tonic-gate return (EBUSY); /* it's already there! */ 13880Sstevel@tonic-gate } 13890Sstevel@tonic-gate 13900Sstevel@tonic-gate rw_enter(eswp->exec_lock, RW_WRITER); 13910Sstevel@tonic-gate eswp->exec_func = modl->exec_execsw->exec_func; 13920Sstevel@tonic-gate eswp->exec_core = modl->exec_execsw->exec_core; 13930Sstevel@tonic-gate rw_exit(eswp->exec_lock); 13940Sstevel@tonic-gate 13950Sstevel@tonic-gate return (0); 13960Sstevel@tonic-gate } 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate /* 13990Sstevel@tonic-gate * Remove an exec module. 14000Sstevel@tonic-gate */ 14010Sstevel@tonic-gate static int 14020Sstevel@tonic-gate mod_removeexec(struct modlexec *modl, struct modlinkage *modlp) 14030Sstevel@tonic-gate { 14040Sstevel@tonic-gate struct execsw *eswp; 14050Sstevel@tonic-gate struct modctl *mcp; 14060Sstevel@tonic-gate char *modname; 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate eswp = findexecsw(modl->exec_execsw->exec_magic); 14090Sstevel@tonic-gate if (eswp == NULL) { 14100Sstevel@tonic-gate mcp = mod_getctl(modlp); 14110Sstevel@tonic-gate ASSERT(mcp != NULL); 14120Sstevel@tonic-gate modname = mcp->mod_modname; 14130Sstevel@tonic-gate cmn_err(CE_WARN, uninstall_err, modname); 14140Sstevel@tonic-gate return (EINVAL); 14150Sstevel@tonic-gate } 14160Sstevel@tonic-gate if (moddebug & MODDEBUG_NOAUL_EXEC || 14170Sstevel@tonic-gate !rw_tryenter(eswp->exec_lock, RW_WRITER)) 14180Sstevel@tonic-gate return (EBUSY); 14190Sstevel@tonic-gate eswp->exec_func = NULL; 14200Sstevel@tonic-gate eswp->exec_core = NULL; 14210Sstevel@tonic-gate rw_exit(eswp->exec_lock); 14220Sstevel@tonic-gate return (0); 14230Sstevel@tonic-gate } 14240Sstevel@tonic-gate 14250Sstevel@tonic-gate /* 14260Sstevel@tonic-gate * Find a free sysent entry or check if the specified one is free. 14270Sstevel@tonic-gate */ 14280Sstevel@tonic-gate static struct sysent * 14290Sstevel@tonic-gate mod_getsysent(struct modlinkage *modlp, struct sysent *se) 14300Sstevel@tonic-gate { 14310Sstevel@tonic-gate int sysnum; 14320Sstevel@tonic-gate struct modctl *mcp; 14330Sstevel@tonic-gate char *mod_name; 14340Sstevel@tonic-gate 14350Sstevel@tonic-gate if ((mcp = mod_getctl(modlp)) == NULL) { 14360Sstevel@tonic-gate /* 14370Sstevel@tonic-gate * This happens when we're looking up the module 14380Sstevel@tonic-gate * pointer as part of a stub installation. So 14390Sstevel@tonic-gate * there's no need to whine at this point. 14400Sstevel@tonic-gate */ 14410Sstevel@tonic-gate return (NULL); 14420Sstevel@tonic-gate } 14430Sstevel@tonic-gate 14440Sstevel@tonic-gate mod_name = mcp->mod_modname; 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate if ((sysnum = mod_getsysnum(mod_name)) == -1) { 14470Sstevel@tonic-gate cmn_err(CE_WARN, "system call missing from bind file"); 14480Sstevel@tonic-gate return (NULL); 14490Sstevel@tonic-gate } 14500Sstevel@tonic-gate 14510Sstevel@tonic-gate if (sysnum > 0 && sysnum < NSYSCALL && 14520Sstevel@tonic-gate (se[sysnum].sy_flags & (SE_LOADABLE | SE_NOUNLOAD))) 14530Sstevel@tonic-gate return (se + sysnum); 14540Sstevel@tonic-gate 14550Sstevel@tonic-gate cmn_err(CE_WARN, "system call entry %d is already in use", sysnum); 14560Sstevel@tonic-gate return (NULL); 14570Sstevel@tonic-gate } 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate /* 14600Sstevel@tonic-gate * IP Policy Modules. 14610Sstevel@tonic-gate */ 14620Sstevel@tonic-gate /*ARGSUSED*/ 14630Sstevel@tonic-gate static int 14640Sstevel@tonic-gate mod_infoipp(struct modlipp *modl, struct modlinkage *modlp, int *p0) 14650Sstevel@tonic-gate { 14660Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 14670Sstevel@tonic-gate ipp_mod_id_t mid; 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate if (mcp == NULL) { 14700Sstevel@tonic-gate *p0 = -1; 14710Sstevel@tonic-gate return (0); /* module is not yet installed */ 14720Sstevel@tonic-gate } 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate mid = ipp_mod_lookup(mcp->mod_modname); 14750Sstevel@tonic-gate 14760Sstevel@tonic-gate *p0 = mid; 14770Sstevel@tonic-gate return (0); 14780Sstevel@tonic-gate } 14790Sstevel@tonic-gate 14800Sstevel@tonic-gate static int 14810Sstevel@tonic-gate mod_installipp(struct modlipp *modl, struct modlinkage *modlp) 14820Sstevel@tonic-gate { 14830Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 14840Sstevel@tonic-gate 14850Sstevel@tonic-gate ASSERT(mcp != NULL); 14860Sstevel@tonic-gate return (ipp_mod_register(mcp->mod_modname, modl->ipp_ops)); 14870Sstevel@tonic-gate } 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate /*ARGSUSED*/ 14900Sstevel@tonic-gate static int 14910Sstevel@tonic-gate mod_removeipp(struct modlipp *modl, struct modlinkage *modlp) 14920Sstevel@tonic-gate { 14930Sstevel@tonic-gate struct modctl *mcp = mod_getctl(modlp); 14940Sstevel@tonic-gate extern kthread_id_t mod_aul_thread; 14950Sstevel@tonic-gate ipp_mod_id_t mid; 14960Sstevel@tonic-gate 14970Sstevel@tonic-gate ASSERT(mcp != NULL); 14980Sstevel@tonic-gate 14990Sstevel@tonic-gate if ((moddebug & MODDEBUG_NOAUL_IPP) && (mod_aul_thread == curthread)) 15000Sstevel@tonic-gate return (EBUSY); 15010Sstevel@tonic-gate 15020Sstevel@tonic-gate mid = ipp_mod_lookup(mcp->mod_modname); 15030Sstevel@tonic-gate ASSERT(mid != IPP_MOD_INVAL); 15040Sstevel@tonic-gate 15050Sstevel@tonic-gate return (ipp_mod_unregister(mid)); 15060Sstevel@tonic-gate } 15075206Sis 15085206Sis /* 15095206Sis * Manage kiconv modules. 15105206Sis */ 15115206Sis /*ARGSUSED*/ 15125206Sis static int 15135206Sis mod_installkiconv(struct modlkiconv *modl, struct modlinkage *modlp) 15145206Sis { 15155206Sis return (kiconv_register_module(modl->kiconv_moddef)); 15165206Sis } 15175206Sis 15185206Sis /*ARGSUSED*/ 15195206Sis static int 15205206Sis mod_removekiconv(struct modlkiconv *modl, struct modlinkage *modlp) 15215206Sis { 15225206Sis return (kiconv_unregister_module(modl->kiconv_moddef)); 15235206Sis } 1524