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