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