xref: /illumos-gate/usr/src/uts/common/os/modconf.c (revision d8109ce4330e1b8ad6c29f9fccacec969066bb9d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright (c) 2018, Joyent, Inc.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/systm.h>
32 #include <sys/param.h>
33 #include <sys/user.h>
34 #include <sys/vm.h>
35 #include <sys/conf.h>
36 #include <sys/class.h>
37 #include <sys/vfs.h>
38 #include <sys/vnode.h>
39 #include <sys/mount.h>
40 #include <sys/systm.h>
41 #include <sys/modctl.h>
42 #include <sys/exec.h>
43 #include <sys/exechdr.h>
44 #include <sys/devops.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/cmn_err.h>
48 #include <sys/hwconf.h>
49 #include <sys/ddi_impldefs.h>
50 #include <sys/autoconf.h>
51 #include <sys/disp.h>
52 #include <sys/kmem.h>
53 #include <sys/instance.h>
54 #include <sys/modhash.h>
55 #include <sys/dacf.h>
56 #include <sys/debug.h>
57 #include <ipp/ipp.h>
58 #include <sys/strsubr.h>
59 #include <sys/kcpc.h>
60 #include <sys/brand.h>
61 #include <sys/cpc_pcbe.h>
62 #include <sys/kstat.h>
63 #include <sys/socketvar.h>
64 #include <sys/kiconv.h>
65 
66 extern int moddebug;
67 
68 extern struct cb_ops no_cb_ops;
69 extern struct dev_ops nodev_ops;
70 extern struct dev_ops mod_nodev_ops;
71 
72 extern struct modctl *mod_getctl(struct modlinkage *);
73 extern int errsys(), nodev(), nulldev();
74 
75 extern int findmodbyname(char *);
76 extern int mod_getsysnum(char *);
77 
78 extern struct execsw execsw[];
79 
80 /*
81  * Define dev_ops for unused devopsp entry.
82  */
83 struct dev_ops mod_nodev_ops = {
84 	DEVO_REV,		/* devo_rev	*/
85 	0,			/* refcnt	*/
86 	ddi_no_info,		/* info */
87 	nulldev,		/* identify	*/
88 	nulldev,		/* probe	*/
89 	ddifail,		/* attach	*/
90 	nodev,			/* detach	*/
91 	nulldev,		/* reset	*/
92 	&no_cb_ops,		/* character/block driver operations */
93 	(struct bus_ops *)0	/* bus operations for nexus drivers */
94 };
95 
96 /*
97  * Define mod_ops for each supported module type
98  */
99 
100 /*
101  * Null operations; used for uninitialized and "misc" modules.
102  */
103 static int mod_null(struct modldrv *, struct modlinkage *);
104 static int mod_infonull(void *, struct modlinkage *, int *);
105 
106 struct mod_ops mod_miscops = {
107 	mod_null, mod_null, mod_infonull
108 };
109 
110 /* CPU Modules */
111 struct mod_ops mod_cpuops = {
112 	mod_null, mod_null, mod_infonull
113 };
114 
115 /*
116  * Cryptographic Modules
117  */
118 struct mod_ops mod_cryptoops = {
119 	mod_null, mod_null, mod_infonull
120 };
121 
122 /*
123  * IP Policy Modules
124  */
125 static int mod_installipp(struct modlipp *, struct modlinkage *);
126 static int mod_removeipp(struct modlipp *, struct modlinkage *);
127 static int mod_infoipp(struct modlipp *, struct modlinkage *, int *);
128 
129 struct mod_ops mod_ippops = {
130 	mod_installipp, mod_removeipp, mod_infoipp
131 };
132 
133 /*
134  * Device drivers
135  */
136 static int mod_infodrv(struct modldrv *, struct modlinkage *, int *);
137 static int mod_installdrv(struct modldrv *, struct modlinkage *);
138 static int mod_removedrv(struct modldrv *, struct modlinkage *);
139 
140 struct mod_ops mod_driverops = {
141 	mod_installdrv, mod_removedrv, mod_infodrv
142 };
143 
144 /*
145  * System calls (new interface)
146  */
147 static int mod_infosys(struct modlsys *, struct modlinkage *, int *);
148 static int mod_installsys(struct modlsys *, struct modlinkage *);
149 static int mod_removesys(struct modlsys *, struct modlinkage *);
150 
151 struct mod_ops mod_syscallops = {
152 	mod_installsys, mod_removesys, mod_infosys
153 };
154 
155 #ifdef _SYSCALL32_IMPL
156 /*
157  * 32-bit system calls in 64-bit kernel
158  */
159 static int mod_infosys32(struct modlsys *, struct modlinkage *, int *);
160 static int mod_installsys32(struct modlsys *, struct modlinkage *);
161 static int mod_removesys32(struct modlsys *, struct modlinkage *);
162 
163 struct mod_ops mod_syscallops32 = {
164 	mod_installsys32, mod_removesys32, mod_infosys32
165 };
166 #endif	/* _SYSCALL32_IMPL */
167 
168 /*
169  * Filesystems
170  */
171 static int mod_infofs(struct modlfs *, struct modlinkage *, int *);
172 static int mod_installfs(struct modlfs *, struct modlinkage *);
173 static int mod_removefs(struct modlfs *, struct modlinkage *);
174 
175 struct mod_ops mod_fsops = {
176 	mod_installfs, mod_removefs, mod_infofs
177 };
178 
179 /*
180  * Streams modules.
181  */
182 static int mod_infostrmod(struct modlstrmod *, struct modlinkage *, int *);
183 static int mod_installstrmod(struct modlstrmod *, struct modlinkage *);
184 static int mod_removestrmod(struct modlstrmod *, struct modlinkage *);
185 
186 struct mod_ops mod_strmodops = {
187 	mod_installstrmod, mod_removestrmod, mod_infostrmod
188 };
189 
190 /*
191  * Socket modules.
192  */
193 static int mod_infosockmod(struct modlsockmod *, struct modlinkage *, int *);
194 static int mod_installsockmod(struct modlsockmod *, struct modlinkage *);
195 static int mod_removesockmod(struct modlsockmod *, struct modlinkage *);
196 
197 struct mod_ops mod_sockmodops = {
198 	mod_installsockmod, mod_removesockmod, mod_infosockmod
199 };
200 
201 /*
202  * Scheduling classes.
203  */
204 static int mod_infosched(struct modlsched *, struct modlinkage *, int *);
205 static int mod_installsched(struct modlsched *, struct modlinkage *);
206 static int mod_removesched(struct modlsched *, struct modlinkage *);
207 
208 struct mod_ops mod_schedops = {
209 	mod_installsched, mod_removesched, mod_infosched
210 };
211 
212 /*
213  * Exec file type (like ELF, ...).
214  */
215 static int mod_infoexec(struct modlexec *, struct modlinkage *, int *);
216 static int mod_installexec(struct modlexec *, struct modlinkage *);
217 static int mod_removeexec(struct modlexec *, struct modlinkage *);
218 
219 struct mod_ops mod_execops = {
220 	mod_installexec, mod_removeexec, mod_infoexec
221 };
222 
223 /*
224  * Dacf (Dynamic Autoconfiguration) modules.
225  */
226 static int mod_infodacf(struct modldacf *, struct modlinkage *, int *);
227 static int mod_installdacf(struct modldacf *, struct modlinkage *);
228 static int mod_removedacf(struct modldacf *, struct modlinkage *);
229 
230 struct mod_ops mod_dacfops = {
231 	mod_installdacf, mod_removedacf, mod_infodacf
232 };
233 
234 /*
235  * PCBE (Performance Counter BackEnd) modules.
236  */
237 static int mod_installpcbe(struct modlpcbe *, struct modlinkage *);
238 static int mod_removepcbe(struct modlpcbe *, struct modlinkage *);
239 
240 struct mod_ops mod_pcbeops = {
241 	mod_installpcbe, mod_removepcbe, mod_infonull
242 };
243 
244 /*
245  * Brand modules.
246  */
247 static int mod_installbrand(struct modlbrand *, struct modlinkage *);
248 static int mod_removebrand(struct modlbrand *, struct modlinkage *);
249 
250 struct mod_ops mod_brandops = {
251 	mod_installbrand, mod_removebrand, mod_infonull
252 };
253 
254 /*
255  * kiconv modules.
256  */
257 static int mod_installkiconv(struct modlkiconv *, struct modlinkage *);
258 static int mod_removekiconv(struct modlkiconv *, struct modlinkage *);
259 
260 struct mod_ops mod_kiconvops = {
261 	mod_installkiconv, mod_removekiconv, mod_infonull
262 };
263 
264 static struct sysent *mod_getsysent(struct modlinkage *, struct sysent *);
265 
266 static char uninstall_err[] = "Cannot uninstall %s; not installed";
267 
268 /*
269  * Debugging support
270  */
271 #define	DRV_DBG		MODDEBUG_LOADMSG2
272 
273 /*PRINTFLIKE2*/
274 static void mod_dprintf(int flag, const char *format, ...) __KPRINTFLIKE(2);
275 
276 static void
277 mod_dprintf(int flag, const char *format, ...)
278 {
279 	va_list alist;
280 
281 	if ((moddebug & flag) != 0) {
282 		va_start(alist, format);
283 		(void) vprintf(format, alist);
284 		va_end(alist);
285 	}
286 }
287 
288 /*
289  * Install a module.
290  * (This routine is in the Solaris SPARC DDI/DKI)
291  */
292 int
293 mod_install(struct modlinkage *modlp)
294 {
295 	int retval = -1;	/* No linkage structures */
296 	struct modlmisc **linkpp;
297 	struct modlmisc **linkpp1;
298 
299 	if (modlp->ml_rev != MODREV_1) {
300 		printf("mod_install:  modlinkage structure is not MODREV_1\n");
301 		return (EINVAL);
302 	}
303 	linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
304 
305 	while (*linkpp != NULL) {
306 		if ((retval = MODL_INSTALL(*linkpp, modlp)) != 0) {
307 			linkpp1 = (struct modlmisc **)&modlp->ml_linkage[0];
308 
309 			while (linkpp1 != linkpp) {
310 				MODL_REMOVE(*linkpp1, modlp); /* clean up */
311 				linkpp1++;
312 			}
313 			break;
314 		}
315 		linkpp++;
316 	}
317 	return (retval);
318 }
319 
320 static char *reins_err =
321 	"Could not reinstall %s\nReboot to correct the problem";
322 
323 /*
324  * Remove a module.  This is called by the module wrapper routine.
325  * (This routine is in the Solaris SPARC DDI/DKI)
326  */
327 int
328 mod_remove(struct modlinkage *modlp)
329 {
330 	int retval = 0;
331 	struct modlmisc **linkpp, *last_linkp;
332 
333 	linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
334 
335 	while (*linkpp != NULL) {
336 		if ((retval = MODL_REMOVE(*linkpp, modlp)) != 0) {
337 			last_linkp = *linkpp;
338 			linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
339 			while (*linkpp != last_linkp) {
340 				if (MODL_INSTALL(*linkpp, modlp) != 0) {
341 					cmn_err(CE_WARN, reins_err,
342 					    (*linkpp)->misc_linkinfo);
343 					break;
344 				}
345 				linkpp++;
346 			}
347 			break;
348 		}
349 		linkpp++;
350 	}
351 	return (retval);
352 }
353 
354 /*
355  * Get module status.
356  * (This routine is in the Solaris SPARC DDI/DKI)
357  */
358 int
359 mod_info(struct modlinkage *modlp, struct modinfo *modinfop)
360 {
361 	int i;
362 	int retval = 0;
363 	struct modspecific_info *msip;
364 	struct modlmisc **linkpp;
365 
366 	modinfop->mi_rev = modlp->ml_rev;
367 
368 	linkpp = (struct modlmisc **)modlp->ml_linkage;
369 	msip = &modinfop->mi_msinfo[0];
370 
371 	for (i = 0; i < MODMAXLINK; i++) {
372 		if (*linkpp == NULL) {
373 			msip->msi_linkinfo[0] = '\0';
374 		} else {
375 			(void) strncpy(msip->msi_linkinfo,
376 			    (*linkpp)->misc_linkinfo, MODMAXLINKINFOLEN);
377 			retval = MODL_INFO(*linkpp, modlp, &msip->msi_p0);
378 			if (retval != 0)
379 				break;
380 			linkpp++;
381 		}
382 		msip++;
383 	}
384 
385 	if (modinfop->mi_info == MI_INFO_LINKAGE) {
386 		/*
387 		 * Slight kludge used to extract the address of the
388 		 * modlinkage structure from the module (just after
389 		 * loading a module for the very first time)
390 		 */
391 		modinfop->mi_base = (void *)modlp;
392 	}
393 
394 	if (retval == 0)
395 		return (1);
396 	return (0);
397 }
398 
399 /*
400  * Get module name.
401  */
402 const char *
403 mod_modname(struct modlinkage *modlp)
404 {
405 	struct modctl	*mcp;
406 
407 	if ((mcp = mod_getctl(modlp)) == NULL)
408 		return (NULL);
409 
410 	return (mcp->mod_modname);
411 }
412 
413 /*
414  * Null operation; return 0.
415  */
416 /*ARGSUSED*/
417 static int
418 mod_null(struct modldrv *modl, struct modlinkage *modlp)
419 {
420 	return (0);
421 }
422 
423 /*
424  * Status for User modules.
425  */
426 /*ARGSUSED*/
427 static int
428 mod_infonull(void *modl, struct modlinkage *modlp, int *p0)
429 {
430 	*p0 = -1;		/* for modinfo display */
431 	return (0);
432 }
433 
434 /*
435  * Driver status info
436  */
437 /*ARGSUSED*/
438 static int
439 mod_infodrv(struct modldrv *modl, struct modlinkage *modlp, int *p0)
440 {
441 	struct modctl *mcp;
442 	char *mod_name;
443 
444 	if ((mcp = mod_getctl(modlp)) == NULL) {
445 		*p0 = -1;
446 		return (0);	/* driver is not yet installed */
447 	}
448 
449 	mod_name = mcp->mod_modname;
450 
451 	*p0 = ddi_name_to_major(mod_name);
452 	return (0);
453 }
454 
455 /*
456  * Manage dacf (device autoconfiguration) modules
457  */
458 
459 /*ARGSUSED*/
460 static int
461 mod_infodacf(struct modldacf *modl, struct modlinkage *modlp, int *p0)
462 {
463 	if (mod_getctl(modlp) == NULL) {
464 		*p0 = -1;
465 		return (0);	/* module is not yet installed */
466 	}
467 
468 	*p0 = 0;
469 	return (0);
470 }
471 
472 static int
473 mod_installdacf(struct modldacf *modl, struct modlinkage *modlp)
474 {
475 	struct modctl	*mcp;
476 
477 	if ((mcp = mod_getctl(modlp)) == NULL)
478 		return (EINVAL);
479 	return (dacf_module_register(mcp->mod_modname, modl->dacf_dacfsw));
480 }
481 
482 /*ARGSUSED*/
483 static int
484 mod_removedacf(struct modldacf *modl, struct modlinkage *modlp)
485 {
486 	struct modctl	*mcp;
487 
488 	if ((mcp = mod_getctl(modlp)) == NULL)
489 		return (EINVAL);
490 	return (dacf_module_unregister(mcp->mod_modname));
491 }
492 
493 /*
494  * Manage PCBE (Performance Counter BackEnd) modules.
495  */
496 /*ARGSUSED*/
497 static int
498 mod_installpcbe(struct modlpcbe *modl, struct modlinkage *modlp)
499 {
500 	if (modl->pcbe_ops->pcbe_ver != PCBE_VER_1) {
501 		cmn_err(CE_WARN, "pcbe '%s' version mismatch",
502 		    modl->pcbe_linkinfo);
503 		return (EINVAL);
504 	}
505 
506 	kcpc_register_pcbe(modl->pcbe_ops);
507 	return (0);
508 }
509 
510 /*
511  * PCBEs may not be unloaded. It would make CPC locking too complex, and since
512  * PCBEs are loaded once and used for life, there is no harm done in leaving
513  * them in the system.
514  */
515 /*ARGSUSED*/
516 static int
517 mod_removepcbe(struct modlpcbe *modl, struct modlinkage *modlp)
518 {
519 	return (EBUSY);
520 }
521 
522 /*
523  * Manage BrandZ modules.
524  */
525 /*ARGSUSED*/
526 static int
527 mod_installbrand(struct modlbrand *modl, struct modlinkage *modlp)
528 {
529 	return (brand_register(modl->brand_branddef));
530 }
531 
532 /*ARGSUSED*/
533 static int
534 mod_removebrand(struct modlbrand *modl, struct modlinkage *modlp)
535 {
536 	return (brand_unregister(modl->brand_branddef));
537 }
538 
539 /*
540  * Install a new driver
541  */
542 static int
543 mod_installdrv(struct modldrv *modl, struct modlinkage *modlp)
544 {
545 	struct modctl *mcp;
546 	struct dev_ops *ops;
547 	char *modname;
548 	major_t major;
549 	struct dev_ops *dp;
550 	struct devnames *dnp;
551 	struct streamtab *str;
552 	cdevsw_impl_t *cdp;
553 	uint_t sqtype;
554 	uint_t qflag;
555 	uint_t flag;
556 	int err = 0;
557 
558 	/* sanity check module */
559 	if ((mcp = mod_getctl(modlp)) == NULL) {
560 		cmn_err(CE_WARN, "mod_install: bad module linkage data");
561 		err = ENXIO;
562 		goto done;
563 	}
564 	modname = mcp->mod_modname;
565 
566 	/* Sanity check modname */
567 	if ((major = ddi_name_to_major(modname)) == DDI_MAJOR_T_NONE) {
568 #ifdef DEBUG
569 		cmn_err(CE_WARN,
570 		    "mod_installdrv: no major number for %s", modname);
571 #endif
572 		err = ENXIO;
573 		goto done;
574 	}
575 
576 	/* Verify MP safety flag */
577 	ops = modl->drv_dev_ops;
578 	if (ops->devo_bus_ops == NULL && ops->devo_cb_ops != NULL &&
579 	    !(ops->devo_cb_ops->cb_flag & D_MP)) {
580 		cmn_err(CE_WARN,
581 		    "mod_installdrv: MT-unsafe driver '%s' rejected", modname);
582 		err = ENXIO;
583 		goto done;
584 	}
585 
586 
587 	/* Is bus_map_fault signature correct (version 8 and higher)? */
588 	if (ops->devo_bus_ops != NULL &&
589 	    ops->devo_bus_ops->bus_map_fault != NULL &&
590 	    ops->devo_bus_ops->bus_map_fault != i_ddi_map_fault &&
591 	    ops->devo_bus_ops->busops_rev < BUSO_REV_8) {
592 
593 		cmn_err(CE_WARN,
594 		    "mod_installdrv: busops' revision of '%s' is too low"
595 		    " (must be at least 8)", modname);
596 		err = ENXIO;
597 		goto done;
598 	}
599 
600 
601 	/* Make sure the driver is uninstalled */
602 	dnp = &devnamesp[major];
603 	LOCK_DEV_OPS(&dnp->dn_lock);
604 	dp = devopsp[major];
605 
606 	if (dnp->dn_flags & (DN_DRIVER_REMOVED|DN_DRIVER_INACTIVE)) {
607 #ifdef DEBUG
608 		cmn_err(CE_CONT,
609 		    "mod_installdrv: driver %s not installed", modname);
610 #endif
611 		err = ENXIO;
612 		goto unlock;
613 	}
614 
615 	if (dp != &nodev_ops && dp != &mod_nodev_ops) {
616 		cmn_err(CE_WARN,
617 		    "mod_installdrv: driver already installed %s", modname);
618 		err = EALREADY;
619 		goto unlock;
620 	}
621 
622 	devopsp[major] = ops; /* setup devopsp */
623 
624 	if ((str = STREAMSTAB(major)) != NULL) {	/* streams driver */
625 		flag = CBFLAG(major);
626 		if ((err = devflg_to_qflag(str, flag, &qflag, &sqtype)) != 0)
627 			goto unlock;
628 		cdp = &devimpl[major];
629 		ASSERT(cdp->d_str == NULL);
630 		cdp->d_str = str;
631 		cdp->d_qflag = qflag | QISDRV;
632 		cdp->d_sqtype = sqtype;
633 	}
634 
635 	if (ops->devo_bus_ops == NULL)
636 		dnp->dn_flags |= DN_LEAF_DRIVER;
637 
638 unlock:
639 	UNLOCK_DEV_OPS(&dnp->dn_lock);
640 done:
641 	return (err);
642 }
643 
644 static int
645 mod_removedrv(struct modldrv *modl, struct modlinkage *modlp)
646 {
647 	struct modctl *mcp;
648 	struct dev_ops *ops;
649 	struct devnames *dnp;
650 	struct dev_ops *dp;
651 	major_t major;
652 	char *modname;
653 	extern kthread_id_t mod_aul_thread;
654 	struct streamtab *str;
655 	cdevsw_impl_t *cdp;
656 	int err = 0;
657 
658 	/* Don't auto unload modules on if moddebug flag is set */
659 	if ((moddebug & MODDEBUG_NOAUL_DRV) && (mod_aul_thread == curthread)) {
660 		err = EBUSY;
661 		goto done;
662 	}
663 
664 	/* Verify modname has a driver major */
665 	mcp = mod_getctl(modlp);
666 	ASSERT(mcp != NULL);
667 	modname = mcp->mod_modname;
668 
669 	if ((major = ddi_name_to_major(modname)) == -1) {
670 		cmn_err(CE_WARN, uninstall_err, modname);
671 		err = EINVAL;
672 		goto done;
673 	}
674 
675 	ops = modl->drv_dev_ops;
676 	dnp = &(devnamesp[major]);
677 	LOCK_DEV_OPS(&(dnp->dn_lock));
678 
679 	dp = devopsp[major];
680 
681 	if (dp != ops)  {
682 		cmn_err(CE_NOTE, "mod_removedrv: mismatched driver for %s",
683 		    modname);
684 		err = EBUSY;
685 		goto unlock;
686 	}
687 
688 	/*
689 	 * A driver is not unloadable if its dev_ops are held
690 	 */
691 	if (!DRV_UNLOADABLE(dp)) {
692 		mod_dprintf(DRV_DBG, "Cannot unload device driver <%s>,"
693 		    " refcnt %d\n", modname, dp->devo_refcnt);
694 		err = EBUSY;
695 		goto unlock;
696 	}
697 
698 	/*
699 	 * OK to unload.
700 	 */
701 	if ((str = STREAMSTAB(major)) != NULL) {	/* streams driver */
702 		cdp = &devimpl[major];
703 		ASSERT(cdp->d_str == str);
704 		cdp->d_str = NULL;
705 
706 		/* check for reference to per-dev syncq */
707 		if (cdp->d_dmp != NULL) {
708 			rele_dm(cdp->d_dmp);
709 			cdp->d_dmp = NULL;
710 		}
711 	}
712 
713 	devopsp[major] = &mod_nodev_ops;
714 	dnp->dn_flags &= ~(DN_DRIVER_HELD|DN_NO_AUTODETACH);
715 
716 unlock:
717 	UNLOCK_DEV_OPS(&(dnp->dn_lock));
718 done:
719 	return (err);
720 }
721 
722 /*
723  * System call subroutines
724  */
725 
726 /*
727  * Compute system call number for given sysent and sysent table
728  */
729 static int
730 mod_infosysnum(struct modlinkage *modlp, struct sysent table[])
731 {
732 	struct sysent *sysp;
733 
734 	if ((sysp = mod_getsysent(modlp, table)) == NULL)
735 		return (-1);
736 	return ((int)(sysp - table));
737 }
738 
739 /*
740  * Put a loadable system call entry into a sysent table.
741  */
742 static int
743 mod_installsys_sysent(
744 	struct modlsys		*modl,
745 	struct modlinkage	*modlp,
746 	struct sysent		table[])
747 {
748 	struct sysent *sysp;
749 	struct sysent *mp;
750 
751 #ifdef DEBUG
752 	/*
753 	 * Before we even play with the sysent table, sanity check the
754 	 * incoming flags to make sure the entry is valid
755 	 */
756 	switch (modl->sys_sysent->sy_flags & SE_RVAL_MASK) {
757 	case SE_32RVAL1:
758 		/* only r_val1 returned */
759 	case SE_32RVAL1 | SE_32RVAL2:
760 		/* r_val1 and r_val2 returned */
761 	case SE_64RVAL:
762 		/* 64-bit rval returned */
763 		break;
764 	default:
765 		cmn_err(CE_WARN, "loadable syscall: %p: bad rval flags %x",
766 		    (void *)modl, modl->sys_sysent->sy_flags);
767 		return (ENOSYS);
768 	}
769 #endif
770 	if ((sysp = mod_getsysent(modlp, table)) == NULL)
771 		return (ENOSPC);
772 
773 	/*
774 	 * We should only block here until the reader in syscall gives
775 	 * up the lock.  Multiple writers are prevented in the mod layer.
776 	 */
777 	rw_enter(sysp->sy_lock, RW_WRITER);
778 	mp = modl->sys_sysent;
779 	sysp->sy_narg = mp->sy_narg;
780 	sysp->sy_call = mp->sy_call;
781 
782 	/*
783 	 * clear the old call method flag, and get the new one from the module.
784 	 */
785 	sysp->sy_flags &= ~SE_ARGC;
786 	sysp->sy_flags |= SE_LOADED |
787 	    (mp->sy_flags & (SE_ARGC | SE_NOUNLOAD | SE_RVAL_MASK));
788 
789 	/*
790 	 * If the syscall doesn't need or want unloading, it can avoid
791 	 * the locking overhead on each entry.  Convert the sysent to a
792 	 * normal non-loadable entry in that case.
793 	 */
794 	if (mp->sy_flags & SE_NOUNLOAD) {
795 		if (mp->sy_flags & SE_ARGC) {
796 			sysp->sy_callc = (int64_t (*)())(uintptr_t)mp->sy_call;
797 		} else {
798 			sysp->sy_callc = syscall_ap;
799 		}
800 		sysp->sy_flags &= ~SE_LOADABLE;
801 	}
802 	rw_exit(sysp->sy_lock);
803 	return (0);
804 }
805 
806 /*
807  * Remove a loadable system call entry from a sysent table.
808  */
809 static int
810 mod_removesys_sysent(
811 	struct modlsys		*modl,
812 	struct modlinkage	*modlp,
813 	struct sysent		table[])
814 {
815 	struct sysent	*sysp;
816 
817 	if ((sysp = mod_getsysent(modlp, table)) == NULL ||
818 	    (sysp->sy_flags & (SE_LOADABLE | SE_NOUNLOAD)) == 0 ||
819 	    sysp->sy_call != modl->sys_sysent->sy_call) {
820 
821 		struct modctl *mcp = mod_getctl(modlp);
822 		char *modname = mcp->mod_modname;
823 
824 		cmn_err(CE_WARN, uninstall_err, modname);
825 		return (EINVAL);
826 	}
827 
828 	/* If we can't get the write lock, we can't unlink from the system */
829 
830 	if (!(moddebug & MODDEBUG_NOAUL_SYS) &&
831 	    rw_tryenter(sysp->sy_lock, RW_WRITER)) {
832 		/*
833 		 * Check the flags to be sure the syscall is still
834 		 * (un)loadable.
835 		 * If SE_NOUNLOAD is set, SE_LOADABLE will not be.
836 		 */
837 		if ((sysp->sy_flags & (SE_LOADED | SE_LOADABLE)) ==
838 		    (SE_LOADED | SE_LOADABLE)) {
839 			sysp->sy_flags &= ~SE_LOADED;
840 			sysp->sy_callc = loadable_syscall;
841 			sysp->sy_call = nosys32;
842 			rw_exit(sysp->sy_lock);
843 			return (0);
844 		}
845 		rw_exit(sysp->sy_lock);
846 	}
847 	return (EBUSY);
848 }
849 
850 /*
851  * System call status info
852  */
853 /*ARGSUSED*/
854 static int
855 mod_infosys(struct modlsys *modl, struct modlinkage *modlp, int *p0)
856 {
857 	*p0 = mod_infosysnum(modlp, sysent);
858 	return (0);
859 }
860 
861 /*
862  * Link a system call into the system by setting the proper sysent entry.
863  * Called from the module's _init routine.
864  */
865 static int
866 mod_installsys(struct modlsys *modl, struct modlinkage *modlp)
867 {
868 	return (mod_installsys_sysent(modl, modlp, sysent));
869 }
870 
871 /*
872  * Unlink a system call from the system.
873  * Called from a modules _fini routine.
874  */
875 static int
876 mod_removesys(struct modlsys *modl, struct modlinkage *modlp)
877 {
878 	return (mod_removesys_sysent(modl, modlp, sysent));
879 }
880 
881 #ifdef _SYSCALL32_IMPL
882 
883 /*
884  * 32-bit system call status info
885  */
886 /*ARGSUSED*/
887 static int
888 mod_infosys32(struct modlsys *modl, struct modlinkage *modlp, int *p0)
889 {
890 	*p0 = mod_infosysnum(modlp, sysent32);
891 	return (0);
892 }
893 
894 /*
895  * Link the 32-bit syscall into the system by setting the proper sysent entry.
896  * Also called from the module's _init routine.
897  */
898 static int
899 mod_installsys32(struct modlsys *modl, struct modlinkage *modlp)
900 {
901 	return (mod_installsys_sysent(modl, modlp, sysent32));
902 }
903 
904 /*
905  * Unlink the 32-bit flavor of a system call from the system.
906  * Also called from a module's _fini routine.
907  */
908 static int
909 mod_removesys32(struct modlsys *modl, struct modlinkage *modlp)
910 {
911 	return (mod_removesys_sysent(modl, modlp, sysent32));
912 }
913 
914 #endif	/* _SYSCALL32_IMPL */
915 
916 /*
917  * Filesystem status info
918  */
919 /*ARGSUSED*/
920 static int
921 mod_infofs(struct modlfs *modl, struct modlinkage *modlp, int *p0)
922 {
923 	struct vfssw *vswp;
924 
925 	RLOCK_VFSSW();
926 	if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL)
927 		*p0 = -1;
928 	else {
929 		*p0 = vswp - vfssw;
930 		vfs_unrefvfssw(vswp);
931 	}
932 	RUNLOCK_VFSSW();
933 	return (0);
934 }
935 
936 /*
937  * Install a filesystem.
938  */
939 /*ARGSUSED1*/
940 static int
941 mod_installfs(struct modlfs *modl, struct modlinkage *modlp)
942 {
943 	struct vfssw *vswp;
944 	struct modctl *mcp;
945 	char *fsname;
946 	char ksname[KSTAT_STRLEN + 1];
947 	int fstype;	/* index into vfssw[] and vsanchor_fstype[] */
948 	int allocated;
949 	int err;
950 	int vsw_stats_enabled;
951 	/* Not for public consumption so these aren't in a header file */
952 	extern int	vopstats_enabled;
953 	extern vopstats_t **vopstats_fstype;
954 	extern kstat_t *new_vskstat(char *, vopstats_t *);
955 	extern void initialize_vopstats(vopstats_t *);
956 
957 	if (modl->fs_vfsdef->def_version == VFSDEF_VERSION) {
958 		/* Version matched */
959 		fsname = modl->fs_vfsdef->name;
960 	} else {
961 		if ((modl->fs_vfsdef->def_version > 0) &&
962 		    (modl->fs_vfsdef->def_version < VFSDEF_VERSION)) {
963 			/* Older VFSDEF_VERSION */
964 			fsname = modl->fs_vfsdef->name;
965 		} else if ((mcp = mod_getctl(modlp)) != NULL) {
966 			/* Pre-VFSDEF_VERSION */
967 			fsname = mcp->mod_modname;
968 		} else {
969 			/* If all else fails... */
970 			fsname = "<unknown file system type>";
971 		}
972 
973 		cmn_err(CE_WARN, "file system '%s' version mismatch", fsname);
974 		return (ENXIO);
975 	}
976 
977 	allocated = 0;
978 
979 	WLOCK_VFSSW();
980 	if ((vswp = vfs_getvfsswbyname(fsname)) == NULL) {
981 		if ((vswp = allocate_vfssw(fsname)) == NULL) {
982 			WUNLOCK_VFSSW();
983 			/*
984 			 * See 1095689.  If this message appears, then
985 			 * we either need to make the vfssw table bigger
986 			 * statically, or make it grow dynamically.
987 			 */
988 			cmn_err(CE_WARN, "no room for '%s' in vfssw!", fsname);
989 			return (ENXIO);
990 		}
991 		allocated = 1;
992 	}
993 	ASSERT(vswp != NULL);
994 
995 	fstype = vswp - vfssw;	/* Pointer arithmetic to get the fstype */
996 
997 	/* Turn on everything by default *except* VSW_STATS */
998 	vswp->vsw_flag = modl->fs_vfsdef->flags & ~(VSW_STATS);
999 
1000 	if (modl->fs_vfsdef->flags & VSW_HASPROTO) {
1001 		vfs_mergeopttbl(&vfs_mntopts, modl->fs_vfsdef->optproto,
1002 		    &vswp->vsw_optproto);
1003 	} else {
1004 		vfs_copyopttbl(&vfs_mntopts, &vswp->vsw_optproto);
1005 	}
1006 
1007 	if (modl->fs_vfsdef->flags & VSW_CANRWRO) {
1008 		/*
1009 		 * This obviously implies VSW_CANREMOUNT.
1010 		 */
1011 		vswp->vsw_flag |= VSW_CANREMOUNT;
1012 	}
1013 
1014 	/*
1015 	 * If stats are enabled system wide and for this fstype, then
1016 	 * set the VSW_STATS flag in the proper vfssw[] table entry.
1017 	 */
1018 	if (vopstats_enabled && modl->fs_vfsdef->flags & VSW_STATS) {
1019 		vswp->vsw_flag |= VSW_STATS;
1020 	}
1021 
1022 	if (modl->fs_vfsdef->init == NULL)
1023 		err = EFAULT;
1024 	else
1025 		err = (*(modl->fs_vfsdef->init))(fstype, fsname);
1026 
1027 	if (err != 0) {
1028 		if (allocated) {
1029 			kmem_free(vswp->vsw_name, strlen(vswp->vsw_name)+1);
1030 			vswp->vsw_name = "";
1031 		}
1032 		vswp->vsw_flag = 0;
1033 		vswp->vsw_init = NULL;
1034 	}
1035 
1036 	/* We don't want to hold the vfssw[] write lock over a kmem_alloc() */
1037 	vsw_stats_enabled = vswp->vsw_flag & VSW_STATS;
1038 
1039 	vfs_unrefvfssw(vswp);
1040 	WUNLOCK_VFSSW();
1041 
1042 	/* If everything is on, set up the per-fstype vopstats */
1043 	if (vsw_stats_enabled && vopstats_enabled &&
1044 	    vopstats_fstype && vopstats_fstype[fstype] == NULL) {
1045 		(void) strlcpy(ksname, VOPSTATS_STR, sizeof (ksname));
1046 		(void) strlcat(ksname, vfssw[fstype].vsw_name, sizeof (ksname));
1047 		vopstats_fstype[fstype] =
1048 		    kmem_alloc(sizeof (vopstats_t), KM_SLEEP);
1049 		initialize_vopstats(vopstats_fstype[fstype]);
1050 		(void) new_vskstat(ksname, vopstats_fstype[fstype]);
1051 	}
1052 	return (err);
1053 }
1054 
1055 /*
1056  * Remove a filesystem
1057  */
1058 static int
1059 mod_removefs(struct modlfs *modl, struct modlinkage *modlp)
1060 {
1061 	struct vfssw *vswp;
1062 	struct modctl *mcp;
1063 	char *modname;
1064 
1065 	if (moddebug & MODDEBUG_NOAUL_FS)
1066 		return (EBUSY);
1067 
1068 	WLOCK_VFSSW();
1069 	if ((vswp = vfs_getvfsswbyname(modl->fs_vfsdef->name)) == NULL) {
1070 		mcp = mod_getctl(modlp);
1071 		ASSERT(mcp != NULL);
1072 		modname = mcp->mod_modname;
1073 		WUNLOCK_VFSSW();
1074 		cmn_err(CE_WARN, uninstall_err, modname);
1075 		return (EINVAL);
1076 	}
1077 	if (vswp->vsw_count != 1) {
1078 		vfs_unrefvfssw(vswp);
1079 		WUNLOCK_VFSSW();
1080 		return (EBUSY);
1081 	}
1082 
1083 	/*
1084 	 * A mounted filesystem could still have vsw_count = 0
1085 	 * so we must check whether anyone is actually using our ops
1086 	 */
1087 	if (vfs_opsinuse(&vswp->vsw_vfsops)) {
1088 		vfs_unrefvfssw(vswp);
1089 		WUNLOCK_VFSSW();
1090 		return (EBUSY);
1091 	}
1092 
1093 	vfs_freeopttbl(&vswp->vsw_optproto);
1094 	vswp->vsw_optproto.mo_count = 0;
1095 
1096 	vswp->vsw_flag = 0;
1097 	vswp->vsw_init = NULL;
1098 	vfs_unrefvfssw(vswp);
1099 	WUNLOCK_VFSSW();
1100 	return (0);
1101 }
1102 
1103 /*
1104  * Get status of a streams module.
1105  */
1106 /*ARGSUSED*/
1107 static int
1108 mod_infostrmod(struct modlstrmod *modl, struct modlinkage *modlp, int *p0)
1109 {
1110 	*p0 = -1;	/* no useful info */
1111 	return (0);
1112 }
1113 
1114 
1115 /*
1116  * Install a streams module.
1117  */
1118 /*ARGSUSED*/
1119 static int
1120 mod_installstrmod(struct modlstrmod *modl, struct modlinkage *modlp)
1121 {
1122 	struct fmodsw *fp = modl->strmod_fmodsw;
1123 
1124 	if (!(fp->f_flag & D_MP)) {
1125 		cmn_err(CE_WARN, "mod_install: MT-unsafe strmod '%s' rejected",
1126 		    fp->f_name);
1127 		return (ENXIO);
1128 	}
1129 
1130 	return (fmodsw_register(fp->f_name, fp->f_str, fp->f_flag));
1131 }
1132 
1133 /*
1134  * Remove a streams module.
1135  */
1136 /*ARGSUSED*/
1137 static int
1138 mod_removestrmod(struct modlstrmod *modl, struct modlinkage *modlp)
1139 {
1140 	if (moddebug & MODDEBUG_NOAUL_STR)
1141 		return (EBUSY);
1142 
1143 	return (fmodsw_unregister(modl->strmod_fmodsw->f_name));
1144 }
1145 
1146 /*
1147  * Get status of a socket module.
1148  */
1149 /*ARGSUSED*/
1150 static int
1151 mod_infosockmod(struct modlsockmod *modl, struct modlinkage *modlp, int *p0)
1152 {
1153 	*p0 = -1;	/* no useful info */
1154 	return (0);
1155 }
1156 
1157 /*
1158  * Install a socket module.
1159  */
1160 /*ARGSUSED*/
1161 static int
1162 mod_installsockmod(struct modlsockmod *modl, struct modlinkage *modlp)
1163 {
1164 	struct modctl *mcp;
1165 	char *mod_name;
1166 
1167 	mcp = mod_getctl(modlp);
1168 	ASSERT(mcp != NULL);
1169 	mod_name = mcp->mod_modname;
1170 	if (strcmp(mod_name, modl->sockmod_reg_info->smod_name) != 0) {
1171 #ifdef DEBUG
1172 		cmn_err(CE_CONT, "mod_installsockmod: different names"
1173 		    " %s != %s \n", mod_name,
1174 		    modl->sockmod_reg_info->smod_name);
1175 #endif
1176 		return (EINVAL);
1177 	}
1178 
1179 	/*
1180 	 * Register module.
1181 	 */
1182 	return (smod_register(modl->sockmod_reg_info));
1183 }
1184 
1185 /*
1186  * Remove a socket module.
1187  */
1188 /*ARGSUSED*/
1189 static int
1190 mod_removesockmod(struct modlsockmod *modl, struct modlinkage *modlp)
1191 {
1192 	/*
1193 	 * unregister from the global socket creation table
1194 	 * check the refcnt in the lookup table
1195 	 */
1196 	return (smod_unregister(modl->sockmod_reg_info->smod_name));
1197 }
1198 
1199 /*
1200  * Get status of a scheduling class module.
1201  */
1202 /*ARGSUSED1*/
1203 static int
1204 mod_infosched(struct modlsched *modl, struct modlinkage *modlp, int *p0)
1205 {
1206 	int	status;
1207 	auto id_t	cid;
1208 
1209 	status = getcidbyname(modl->sched_class->cl_name, &cid);
1210 
1211 	if (status != 0)
1212 		*p0 = -1;
1213 	else
1214 		*p0 = cid;
1215 
1216 	return (0);
1217 }
1218 
1219 /*
1220  * Install a scheduling class module.
1221  */
1222 /*ARGSUSED1*/
1223 static int
1224 mod_installsched(struct modlsched *modl, struct modlinkage *modlp)
1225 {
1226 	sclass_t *clp;
1227 	int status;
1228 	id_t cid;
1229 
1230 	/*
1231 	 * See if module is already installed.
1232 	 */
1233 	mutex_enter(&class_lock);
1234 	status = alloc_cid(modl->sched_class->cl_name, &cid);
1235 	mutex_exit(&class_lock);
1236 	ASSERT(status == 0);
1237 	clp = &sclass[cid];
1238 	rw_enter(clp->cl_lock, RW_WRITER);
1239 	if (SCHED_INSTALLED(clp)) {
1240 		printf("scheduling class %s is already installed\n",
1241 		    modl->sched_class->cl_name);
1242 		rw_exit(clp->cl_lock);
1243 		return (EBUSY);		/* it's already there */
1244 	}
1245 
1246 	clp->cl_init = modl->sched_class->cl_init;
1247 	clp->cl_funcs = modl->sched_class->cl_funcs;
1248 	modl->sched_class = clp;
1249 	disp_add(clp);
1250 	loaded_classes++;		/* for priocntl system call */
1251 	rw_exit(clp->cl_lock);
1252 	return (0);
1253 }
1254 
1255 /*
1256  * Remove a scheduling class module.
1257  *
1258  * we only null out the init func and the class functions because
1259  * once a class has been loaded it has that slot in the class
1260  * array until the next reboot. We don't decrement loaded_classes
1261  * because this keeps count of the number of classes that have
1262  * been loaded for this session. It will have to be this way until
1263  * we implement the class array as a linked list and do true
1264  * dynamic allocation.
1265  */
1266 static int
1267 mod_removesched(struct modlsched *modl, struct modlinkage *modlp)
1268 {
1269 	int status;
1270 	sclass_t *clp;
1271 	struct modctl *mcp;
1272 	char *modname;
1273 	id_t cid;
1274 
1275 	status = getcidbyname(modl->sched_class->cl_name, &cid);
1276 	if (status != 0) {
1277 		mcp = mod_getctl(modlp);
1278 		ASSERT(mcp != NULL);
1279 		modname = mcp->mod_modname;
1280 		cmn_err(CE_WARN, uninstall_err, modname);
1281 		return (EINVAL);
1282 	}
1283 	clp = &sclass[cid];
1284 	if (moddebug & MODDEBUG_NOAUL_SCHED ||
1285 	    !rw_tryenter(clp->cl_lock, RW_WRITER))
1286 		return (EBUSY);
1287 
1288 	clp->cl_init = NULL;
1289 	clp->cl_funcs = NULL;
1290 	rw_exit(clp->cl_lock);
1291 	return (0);
1292 }
1293 
1294 /*
1295  * Get status of an exec module.
1296  */
1297 /*ARGSUSED1*/
1298 static int
1299 mod_infoexec(struct modlexec *modl, struct modlinkage *modlp, int *p0)
1300 {
1301 	struct execsw *eswp;
1302 
1303 	if ((eswp = findexecsw(modl->exec_execsw->exec_magic)) == NULL)
1304 		*p0 = -1;
1305 	else
1306 		*p0 = eswp - execsw;
1307 
1308 	return (0);
1309 }
1310 
1311 /*
1312  * Install an exec module.
1313  */
1314 static int
1315 mod_installexec(struct modlexec *modl, struct modlinkage *modlp)
1316 {
1317 	struct execsw *eswp;
1318 	struct modctl *mcp;
1319 	char *modname;
1320 	char *magic;
1321 	size_t magic_size;
1322 
1323 	/*
1324 	 * See if execsw entry is already allocated.  Can't use findexectype()
1325 	 * because we may get a recursive call to here.
1326 	 */
1327 
1328 	if ((eswp = findexecsw(modl->exec_execsw->exec_magic)) == NULL) {
1329 		mcp = mod_getctl(modlp);
1330 		ASSERT(mcp != NULL);
1331 		modname = mcp->mod_modname;
1332 		magic = modl->exec_execsw->exec_magic;
1333 		magic_size = modl->exec_execsw->exec_maglen;
1334 		if ((eswp = allocate_execsw(modname, magic, magic_size)) ==
1335 		    NULL) {
1336 			printf("no unused entries in 'execsw'\n");
1337 			return (ENOSPC);
1338 		}
1339 	}
1340 	if (eswp->exec_func != NULL) {
1341 		printf("exec type %x is already installed\n",
1342 		    *eswp->exec_magic);
1343 		return (EBUSY);		 /* it's already there! */
1344 	}
1345 
1346 	rw_enter(eswp->exec_lock, RW_WRITER);
1347 	eswp->exec_func = modl->exec_execsw->exec_func;
1348 	eswp->exec_core = modl->exec_execsw->exec_core;
1349 	rw_exit(eswp->exec_lock);
1350 
1351 	return (0);
1352 }
1353 
1354 /*
1355  * Remove an exec module.
1356  */
1357 static int
1358 mod_removeexec(struct modlexec *modl, struct modlinkage *modlp)
1359 {
1360 	struct execsw *eswp;
1361 	struct modctl *mcp;
1362 	char *modname;
1363 
1364 	eswp = findexecsw(modl->exec_execsw->exec_magic);
1365 	if (eswp == NULL) {
1366 		mcp = mod_getctl(modlp);
1367 		ASSERT(mcp != NULL);
1368 		modname = mcp->mod_modname;
1369 		cmn_err(CE_WARN, uninstall_err, modname);
1370 		return (EINVAL);
1371 	}
1372 	if (moddebug & MODDEBUG_NOAUL_EXEC ||
1373 	    !rw_tryenter(eswp->exec_lock, RW_WRITER))
1374 		return (EBUSY);
1375 	eswp->exec_func = NULL;
1376 	eswp->exec_core = NULL;
1377 	rw_exit(eswp->exec_lock);
1378 	return (0);
1379 }
1380 
1381 /*
1382  * Find a free sysent entry or check if the specified one is free.
1383  */
1384 static struct sysent *
1385 mod_getsysent(struct modlinkage *modlp, struct sysent *se)
1386 {
1387 	int sysnum;
1388 	struct modctl *mcp;
1389 	char *mod_name;
1390 
1391 	if ((mcp = mod_getctl(modlp)) == NULL) {
1392 		/*
1393 		 * This happens when we're looking up the module
1394 		 * pointer as part of a stub installation.  So
1395 		 * there's no need to whine at this point.
1396 		 */
1397 		return (NULL);
1398 	}
1399 
1400 	mod_name = mcp->mod_modname;
1401 
1402 	if ((sysnum = mod_getsysnum(mod_name)) == -1) {
1403 		cmn_err(CE_WARN, "system call missing from bind file");
1404 		return (NULL);
1405 	}
1406 
1407 	if (sysnum > 0 && sysnum < NSYSCALL &&
1408 	    (se[sysnum].sy_flags & (SE_LOADABLE | SE_NOUNLOAD)))
1409 		return (se + sysnum);
1410 
1411 	cmn_err(CE_WARN, "system call entry %d is already in use", sysnum);
1412 	return (NULL);
1413 }
1414 
1415 /*
1416  * IP Policy Modules.
1417  */
1418 /*ARGSUSED*/
1419 static int
1420 mod_infoipp(struct modlipp *modl, struct modlinkage *modlp, int *p0)
1421 {
1422 	struct modctl *mcp = mod_getctl(modlp);
1423 	ipp_mod_id_t mid;
1424 
1425 	if (mcp == NULL) {
1426 		*p0 = -1;
1427 		return (0);	/* module is not yet installed */
1428 	}
1429 
1430 	mid = ipp_mod_lookup(mcp->mod_modname);
1431 
1432 	*p0 = mid;
1433 	return (0);
1434 }
1435 
1436 static int
1437 mod_installipp(struct modlipp *modl, struct modlinkage *modlp)
1438 {
1439 	struct modctl *mcp = mod_getctl(modlp);
1440 
1441 	ASSERT(mcp != NULL);
1442 	return (ipp_mod_register(mcp->mod_modname, modl->ipp_ops));
1443 }
1444 
1445 /*ARGSUSED*/
1446 static int
1447 mod_removeipp(struct modlipp *modl, struct modlinkage *modlp)
1448 {
1449 	struct modctl *mcp = mod_getctl(modlp);
1450 	extern kthread_id_t mod_aul_thread;
1451 	ipp_mod_id_t mid;
1452 
1453 	ASSERT(mcp != NULL);
1454 
1455 	if ((moddebug & MODDEBUG_NOAUL_IPP) && (mod_aul_thread == curthread))
1456 		return (EBUSY);
1457 
1458 	mid = ipp_mod_lookup(mcp->mod_modname);
1459 	ASSERT(mid != IPP_MOD_INVAL);
1460 
1461 	return (ipp_mod_unregister(mid));
1462 }
1463 
1464 /*
1465  * Manage kiconv modules.
1466  */
1467 /*ARGSUSED*/
1468 static int
1469 mod_installkiconv(struct modlkiconv *modl, struct modlinkage *modlp)
1470 {
1471 	return (kiconv_register_module(modl->kiconv_moddef));
1472 }
1473 
1474 /*ARGSUSED*/
1475 static int
1476 mod_removekiconv(struct modlkiconv *modl, struct modlinkage *modlp)
1477 {
1478 	return (kiconv_unregister_module(modl->kiconv_moddef));
1479 }
1480