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