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