Print this page
10908 Simplify SMAP relocations with krtld
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/os/modctl.c
+++ new/usr/src/uts/common/os/modctl.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
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
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 /*
23 23 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright (c) 2017 Joyent, Inc.
24 25 */
25 26
26 27 /*
27 28 * modctl system call for loadable module support.
28 29 */
29 30
30 31 #include <sys/param.h>
31 32 #include <sys/user.h>
32 33 #include <sys/systm.h>
33 34 #include <sys/exec.h>
34 35 #include <sys/file.h>
35 36 #include <sys/stat.h>
36 37 #include <sys/conf.h>
37 38 #include <sys/time.h>
38 39 #include <sys/reboot.h>
39 40 #include <sys/fs/ufs_fsdir.h>
40 41 #include <sys/kmem.h>
41 42 #include <sys/sysconf.h>
42 43 #include <sys/cmn_err.h>
43 44 #include <sys/ddi.h>
44 45 #include <sys/sunddi.h>
45 46 #include <sys/sunndi.h>
46 47 #include <sys/ndi_impldefs.h>
47 48 #include <sys/ddi_impldefs.h>
48 49 #include <sys/ddi_implfuncs.h>
49 50 #include <sys/bootconf.h>
50 51 #include <sys/dc_ki.h>
51 52 #include <sys/cladm.h>
52 53 #include <sys/dtrace.h>
53 54 #include <sys/kdi.h>
54 55
55 56 #include <sys/devpolicy.h>
56 57 #include <sys/modctl.h>
57 58 #include <sys/kobj.h>
58 59 #include <sys/devops.h>
59 60 #include <sys/autoconf.h>
60 61 #include <sys/hwconf.h>
61 62 #include <sys/callb.h>
62 63 #include <sys/debug.h>
63 64 #include <sys/cpuvar.h>
64 65 #include <sys/sysmacros.h>
65 66 #include <sys/sysevent.h>
66 67 #include <sys/sysevent_impl.h>
67 68 #include <sys/instance.h>
68 69 #include <sys/modhash.h>
69 70 #include <sys/modhash_impl.h>
70 71 #include <sys/dacf_impl.h>
71 72 #include <sys/vfs.h>
72 73 #include <sys/pathname.h>
73 74 #include <sys/console.h>
74 75 #include <sys/policy.h>
75 76 #include <ipp/ipp_impl.h>
76 77 #include <sys/fs/dv_node.h>
77 78 #include <sys/strsubr.h>
78 79 #include <sys/fs/sdev_impl.h>
79 80
80 81 static int mod_circdep(struct modctl *);
81 82 static int modinfo(modid_t, struct modinfo *);
82 83
83 84 static void mod_uninstall_all(void);
84 85 static int mod_getinfo(struct modctl *, struct modinfo *);
85 86 static struct modctl *allocate_modp(const char *, const char *);
86 87
87 88 static int mod_load(struct modctl *, int);
88 89 static void mod_unload(struct modctl *);
89 90 static int modinstall(struct modctl *);
90 91 static int moduninstall(struct modctl *);
91 92
92 93 static struct modctl *mod_hold_by_name_common(struct modctl *, const char *);
93 94 static struct modctl *mod_hold_next_by_id(modid_t);
94 95 static struct modctl *mod_hold_loaded_mod(struct modctl *, char *, int *);
95 96 static struct modctl *mod_hold_installed_mod(char *, int, int, int *);
96 97
97 98 static void mod_release(struct modctl *);
98 99 static void mod_make_requisite(struct modctl *, struct modctl *);
99 100 static int mod_install_requisites(struct modctl *);
100 101 static void check_esc_sequences(char *, char *);
101 102 static struct modctl *mod_hold_by_name_requisite(struct modctl *, char *);
102 103
103 104 /*
104 105 * module loading thread control structure. Calls to kobj_load_module()() are
105 106 * handled off to a separate thead using this structure.
106 107 */
107 108 struct loadmt {
108 109 ksema_t sema;
109 110 struct modctl *mp;
110 111 int usepath;
111 112 kthread_t *owner;
112 113 int retval;
113 114 };
114 115
115 116 static void modload_thread(struct loadmt *);
116 117
117 118 kcondvar_t mod_cv;
118 119 kcondvar_t mod_uninstall_cv; /* Communication between swapper */
119 120 /* and the uninstall daemon. */
120 121 kmutex_t mod_lock; /* protects &modules insert linkage, */
121 122 /* mod_busy, mod_want, and mod_ref. */
122 123 /* blocking operations while holding */
123 124 /* mod_lock should be avoided */
124 125 kmutex_t mod_uninstall_lock; /* protects mod_uninstall_cv */
125 126 kthread_id_t mod_aul_thread;
126 127
127 128 int modunload_wait;
128 129 kmutex_t modunload_wait_mutex;
129 130 kcondvar_t modunload_wait_cv;
130 131 int modunload_active_count;
131 132 int modunload_disable_count;
132 133
133 134 int isminiroot; /* set if running as miniroot */
134 135 int modrootloaded; /* set after root driver and fs are loaded */
135 136 int moddebug = 0x0; /* debug flags for module writers */
136 137 int swaploaded; /* set after swap driver and fs are loaded */
137 138 int bop_io_quiesced = 0; /* set when BOP I/O can no longer be used */
138 139 int last_module_id;
139 140 clock_t mod_uninstall_interval = 0;
140 141 int mod_uninstall_pass_max = 6;
141 142 int mod_uninstall_ref_zero; /* # modules that went mod_ref == 0 */
142 143 int mod_uninstall_pass_exc; /* mod_uninstall_all left new stuff */
143 144
144 145 int ddi_modclose_unload = 1; /* 0 -> just decrement reference */
145 146
146 147 int devcnt_incr = 256; /* allow for additional drivers */
147 148 int devcnt_min = 512; /* and always at least this number */
148 149
149 150 struct devnames *devnamesp;
150 151 struct devnames orphanlist;
151 152
152 153 krwlock_t devinfo_tree_lock; /* obsolete, to be removed */
153 154
154 155 #define MAJBINDFILE "/etc/name_to_major"
155 156 #define SYSBINDFILE "/etc/name_to_sysnum"
156 157
157 158 static char majbind[] = MAJBINDFILE;
158 159 static char sysbind[] = SYSBINDFILE;
159 160 static uint_t mod_autounload_key; /* for module autounload detection */
160 161
161 162 extern int obpdebug;
162 163
163 164 #define DEBUGGER_PRESENT ((boothowto & RB_DEBUG) || (obpdebug != 0))
164 165
165 166 static int minorperm_loaded = 0;
166 167
167 168 void
168 169 mod_setup(void)
169 170 {
170 171 struct sysent *callp;
171 172 int callnum, exectype;
172 173 int num_devs;
173 174 int i;
174 175
175 176 /*
176 177 * Initialize the list of loaded driver dev_ops.
177 178 * XXX - This must be done before reading the system file so that
178 179 * forceloads of drivers will work.
179 180 */
180 181 num_devs = read_binding_file(majbind, mb_hashtab, make_mbind);
181 182 /*
182 183 * Since read_binding_file is common code, it doesn't enforce that all
183 184 * of the binding file entries have major numbers <= MAXMAJ32. Thus,
184 185 * ensure that we don't allocate some massive amount of space due to a
185 186 * bad entry. We can't have major numbers bigger than MAXMAJ32
186 187 * until file system support for larger major numbers exists.
187 188 */
188 189
189 190 /*
190 191 * Leave space for expansion, but not more than L_MAXMAJ32
191 192 */
192 193 devcnt = MIN(num_devs + devcnt_incr, L_MAXMAJ32);
193 194 devcnt = MAX(devcnt, devcnt_min);
194 195 devopsp = kmem_alloc(devcnt * sizeof (struct dev_ops *), KM_SLEEP);
195 196 for (i = 0; i < devcnt; i++)
196 197 devopsp[i] = &mod_nodev_ops;
197 198
198 199 init_devnamesp(devcnt);
199 200
200 201 /*
201 202 * Sync up with the work that the stand-alone linker has already done.
202 203 */
203 204 (void) kobj_sync();
204 205
205 206 if (boothowto & RB_DEBUG)
206 207 kdi_dvec_modavail();
207 208
208 209 make_aliases(mb_hashtab);
209 210
210 211 /*
211 212 * Initialize streams device implementation structures.
212 213 */
213 214 devimpl = kmem_zalloc(devcnt * sizeof (cdevsw_impl_t), KM_SLEEP);
214 215
215 216 /*
216 217 * If the cl_bootstrap module is present,
217 218 * we should be configured as a cluster. Loading this module
218 219 * will set "cluster_bootflags" to non-zero.
219 220 */
220 221 (void) modload("misc", "cl_bootstrap");
221 222
222 223 (void) read_binding_file(sysbind, sb_hashtab, make_mbind);
223 224 init_syscallnames(NSYSCALL);
224 225
225 226 /*
226 227 * Start up dynamic autoconfiguration framework (dacf).
227 228 */
228 229 mod_hash_init();
229 230 dacf_init();
230 231
231 232 /*
232 233 * Start up IP policy framework (ipp).
233 234 */
234 235 ipp_init();
235 236
236 237 /*
237 238 * Allocate loadable native system call locks.
238 239 */
239 240 for (callnum = 0, callp = sysent; callnum < NSYSCALL;
240 241 callnum++, callp++) {
241 242 if (LOADABLE_SYSCALL(callp)) {
242 243 if (mod_getsysname(callnum) != NULL) {
243 244 callp->sy_lock =
244 245 kobj_zalloc(sizeof (krwlock_t), KM_SLEEP);
245 246 rw_init(callp->sy_lock, NULL, RW_DEFAULT, NULL);
246 247 } else {
247 248 callp->sy_flags &= ~SE_LOADABLE;
248 249 callp->sy_callc = nosys;
249 250 }
250 251 #ifdef DEBUG
251 252 } else {
252 253 /*
253 254 * Do some sanity checks on the sysent table
254 255 */
255 256 switch (callp->sy_flags & SE_RVAL_MASK) {
256 257 case SE_32RVAL1:
257 258 /* only r_val1 returned */
258 259 case SE_32RVAL1 | SE_32RVAL2:
259 260 /* r_val1 and r_val2 returned */
260 261 case SE_64RVAL:
261 262 /* 64-bit rval returned */
262 263 break;
263 264 default:
264 265 cmn_err(CE_WARN, "sysent[%d]: bad flags %x",
265 266 callnum, callp->sy_flags);
266 267 }
267 268 #endif
268 269 }
269 270 }
270 271
271 272 #ifdef _SYSCALL32_IMPL
272 273 /*
273 274 * Allocate loadable system call locks for 32-bit compat syscalls
274 275 */
275 276 for (callnum = 0, callp = sysent32; callnum < NSYSCALL;
276 277 callnum++, callp++) {
277 278 if (LOADABLE_SYSCALL(callp)) {
278 279 if (mod_getsysname(callnum) != NULL) {
279 280 callp->sy_lock =
280 281 kobj_zalloc(sizeof (krwlock_t), KM_SLEEP);
281 282 rw_init(callp->sy_lock, NULL, RW_DEFAULT, NULL);
282 283 } else {
283 284 callp->sy_flags &= ~SE_LOADABLE;
284 285 callp->sy_callc = nosys;
285 286 }
286 287 #ifdef DEBUG
287 288 } else {
288 289 /*
289 290 * Do some sanity checks on the sysent table
290 291 */
291 292 switch (callp->sy_flags & SE_RVAL_MASK) {
292 293 case SE_32RVAL1:
293 294 /* only r_val1 returned */
294 295 case SE_32RVAL1 | SE_32RVAL2:
295 296 /* r_val1 and r_val2 returned */
296 297 case SE_64RVAL:
297 298 /* 64-bit rval returned */
298 299 break;
299 300 default:
300 301 cmn_err(CE_WARN, "sysent32[%d]: bad flags %x",
301 302 callnum, callp->sy_flags);
302 303 goto skip;
303 304 }
304 305
305 306 /*
306 307 * Cross-check the native and compatibility tables.
307 308 */
308 309 if (callp->sy_callc == nosys ||
309 310 sysent[callnum].sy_callc == nosys)
310 311 continue;
311 312 /*
312 313 * If only one or the other slot is loadable, then
313 314 * there's an error -- they should match!
314 315 */
315 316 if ((callp->sy_callc == loadable_syscall) ^
316 317 (sysent[callnum].sy_callc == loadable_syscall)) {
317 318 cmn_err(CE_WARN, "sysent[%d] loadable?",
318 319 callnum);
319 320 }
320 321 /*
321 322 * This is more of a heuristic test -- if the
322 323 * system call returns two values in the 32-bit
323 324 * world, it should probably return two 32-bit
324 325 * values in the 64-bit world too.
325 326 */
326 327 if (((callp->sy_flags & SE_32RVAL2) == 0) ^
327 328 ((sysent[callnum].sy_flags & SE_32RVAL2) == 0)) {
328 329 cmn_err(CE_WARN, "sysent[%d] rval2 mismatch!",
329 330 callnum);
330 331 }
331 332 skip:;
332 333 #endif /* DEBUG */
333 334 }
334 335 }
335 336 #endif /* _SYSCALL32_IMPL */
336 337
337 338 /*
338 339 * Allocate loadable exec locks. (Assumes all execs are loadable)
339 340 */
340 341 for (exectype = 0; exectype < nexectype; exectype++) {
341 342 execsw[exectype].exec_lock =
342 343 kobj_zalloc(sizeof (krwlock_t), KM_SLEEP);
343 344 rw_init(execsw[exectype].exec_lock, NULL, RW_DEFAULT, NULL);
344 345 }
345 346
346 347 read_class_file();
347 348
348 349 /* init thread specific structure for mod_uninstall_all */
349 350 tsd_create(&mod_autounload_key, NULL);
350 351 }
351 352
352 353 static int
353 354 modctl_modload(int use_path, char *filename, int *rvp)
354 355 {
355 356 struct modctl *modp;
356 357 int retval = 0;
357 358 char *filenamep;
358 359 int modid;
359 360
360 361 filenamep = kmem_zalloc(MOD_MAXPATH, KM_SLEEP);
361 362
362 363 if (copyinstr(filename, filenamep, MOD_MAXPATH, 0)) {
363 364 retval = EFAULT;
364 365 goto out;
365 366 }
366 367
367 368 filenamep[MOD_MAXPATH - 1] = 0;
368 369 modp = mod_hold_installed_mod(filenamep, use_path, 0, &retval);
369 370
370 371 if (modp == NULL)
371 372 goto out;
372 373
373 374 modp->mod_loadflags |= MOD_NOAUTOUNLOAD;
374 375 modid = modp->mod_id;
375 376 mod_release_mod(modp);
376 377 CPU_STATS_ADDQ(CPU, sys, modload, 1);
377 378 if (rvp != NULL && copyout(&modid, rvp, sizeof (modid)) != 0)
378 379 retval = EFAULT;
379 380 out:
380 381 kmem_free(filenamep, MOD_MAXPATH);
381 382
382 383 return (retval);
383 384 }
384 385
385 386 static int
386 387 modctl_modunload(modid_t id)
387 388 {
388 389 int rval = 0;
389 390
390 391 if (id == 0) {
391 392 #ifdef DEBUG
392 393 /*
393 394 * Turn on mod_uninstall_daemon
394 395 */
395 396 if (mod_uninstall_interval == 0) {
396 397 mod_uninstall_interval = 60;
397 398 modreap();
398 399 return (rval);
399 400 }
400 401 #endif
401 402 mod_uninstall_all();
402 403 } else {
403 404 rval = modunload(id);
404 405 }
405 406 return (rval);
406 407 }
407 408
408 409 static int
409 410 modctl_modinfo(modid_t id, struct modinfo *umodi)
410 411 {
411 412 int retval;
412 413 struct modinfo modi;
413 414 #if defined(_SYSCALL32_IMPL)
414 415 int nobase;
415 416 struct modinfo32 modi32;
416 417 #endif
417 418
418 419 if (get_udatamodel() == DATAMODEL_NATIVE) {
419 420 if (copyin(umodi, &modi, sizeof (struct modinfo)) != 0)
420 421 return (EFAULT);
421 422 }
422 423 #ifdef _SYSCALL32_IMPL
423 424 else {
424 425 bzero(&modi, sizeof (modi));
425 426 if (copyin(umodi, &modi32, sizeof (struct modinfo32)) != 0)
426 427 return (EFAULT);
427 428 modi.mi_info = modi32.mi_info;
428 429 modi.mi_id = modi32.mi_id;
429 430 modi.mi_nextid = modi32.mi_nextid;
430 431 nobase = modi.mi_info & MI_INFO_NOBASE;
431 432 }
432 433 #endif
433 434 /*
434 435 * This flag is -only- for the kernels use.
435 436 */
436 437 modi.mi_info &= ~MI_INFO_LINKAGE;
437 438
438 439 retval = modinfo(id, &modi);
439 440 if (retval)
440 441 return (retval);
441 442
442 443 if (get_udatamodel() == DATAMODEL_NATIVE) {
443 444 if (copyout(&modi, umodi, sizeof (struct modinfo)) != 0)
444 445 retval = EFAULT;
445 446 #ifdef _SYSCALL32_IMPL
446 447 } else {
447 448 int i;
448 449
449 450 if (!nobase && (uintptr_t)modi.mi_base > UINT32_MAX)
450 451 return (EOVERFLOW);
451 452
452 453 modi32.mi_info = modi.mi_info;
453 454 modi32.mi_state = modi.mi_state;
454 455 modi32.mi_id = modi.mi_id;
455 456 modi32.mi_nextid = modi.mi_nextid;
456 457 modi32.mi_base = (caddr32_t)(uintptr_t)modi.mi_base;
457 458 modi32.mi_size = modi.mi_size;
458 459 modi32.mi_rev = modi.mi_rev;
459 460 modi32.mi_loadcnt = modi.mi_loadcnt;
460 461 bcopy(modi.mi_name, modi32.mi_name, sizeof (modi32.mi_name));
461 462 for (i = 0; i < MODMAXLINK32; i++) {
462 463 modi32.mi_msinfo[i].msi_p0 = modi.mi_msinfo[i].msi_p0;
463 464 bcopy(modi.mi_msinfo[i].msi_linkinfo,
464 465 modi32.mi_msinfo[i].msi_linkinfo,
465 466 sizeof (modi32.mi_msinfo[0].msi_linkinfo));
466 467 }
467 468 if (copyout(&modi32, umodi, sizeof (struct modinfo32)) != 0)
468 469 retval = EFAULT;
469 470 #endif
470 471 }
471 472
472 473 return (retval);
473 474 }
474 475
475 476 /*
476 477 * Return the last major number in the range of permissible major numbers.
477 478 */
478 479 /*ARGSUSED*/
479 480 static int
480 481 modctl_modreserve(modid_t id, int *data)
481 482 {
482 483 if (copyout(&devcnt, data, sizeof (devcnt)) != 0)
483 484 return (EFAULT);
484 485 return (0);
485 486 }
486 487
487 488 /* Add/Remove driver and binding aliases */
488 489 static int
489 490 modctl_update_driver_aliases(int add, int *data)
490 491 {
491 492 struct modconfig mc;
492 493 int i, n, rv = 0;
493 494 struct aliases alias;
494 495 struct aliases *ap;
495 496 char name[MAXMODCONFNAME];
496 497 char cname[MAXMODCONFNAME];
497 498 char *drvname;
498 499 int resid;
499 500 struct alias_info {
500 501 char *alias_name;
501 502 int alias_resid;
502 503 } *aliases, *aip;
503 504
504 505 bzero(&mc, sizeof (struct modconfig));
505 506 if (get_udatamodel() == DATAMODEL_NATIVE) {
506 507 if (copyin(data, &mc, sizeof (struct modconfig)) != 0)
507 508 return (EFAULT);
508 509 }
509 510 #ifdef _SYSCALL32_IMPL
510 511 else {
511 512 struct modconfig32 modc32;
512 513 if (copyin(data, &modc32, sizeof (struct modconfig32)) != 0)
513 514 return (EFAULT);
514 515 else {
515 516 bcopy(modc32.drvname, mc.drvname,
516 517 sizeof (modc32.drvname));
517 518 bcopy(modc32.drvclass, mc.drvclass,
518 519 sizeof (modc32.drvclass));
519 520 mc.major = modc32.major;
520 521 mc.flags = modc32.flags;
521 522 mc.num_aliases = modc32.num_aliases;
522 523 mc.ap = (struct aliases *)(uintptr_t)modc32.ap;
523 524 }
524 525 }
525 526 #endif
526 527
527 528 /*
528 529 * If the driver is already in the mb_hashtab, and the name given
529 530 * doesn't match that driver's name, fail. Otherwise, pass, since
530 531 * we may be adding aliases.
531 532 */
532 533 drvname = mod_major_to_name(mc.major);
533 534 if ((drvname != NULL) && strcmp(drvname, mc.drvname) != 0)
534 535 return (EINVAL);
535 536
536 537 /*
537 538 * Precede alias removal by unbinding as many devices as possible.
538 539 */
539 540 if (add == 0) {
540 541 (void) i_ddi_unload_drvconf(mc.major);
541 542 i_ddi_unbind_devs(mc.major);
542 543 }
543 544
544 545 /*
545 546 * Add/remove each supplied driver alias to/from mb_hashtab
546 547 */
547 548 ap = mc.ap;
548 549 if (mc.num_aliases > 0)
549 550 aliases = kmem_zalloc(
550 551 mc.num_aliases * sizeof (struct alias_info), KM_SLEEP);
551 552 aip = aliases;
552 553 for (i = 0; i < mc.num_aliases; i++) {
553 554 bzero(&alias, sizeof (struct aliases));
554 555 if (get_udatamodel() == DATAMODEL_NATIVE) {
555 556 if (copyin(ap, &alias, sizeof (struct aliases)) != 0) {
556 557 rv = EFAULT;
557 558 goto error;
558 559 }
559 560 if (alias.a_len > MAXMODCONFNAME) {
560 561 rv = EINVAL;
561 562 goto error;
562 563 }
563 564 if (copyin(alias.a_name, name, alias.a_len) != 0) {
564 565 rv = EFAULT;
565 566 goto error;
566 567 }
567 568 if (name[alias.a_len - 1] != '\0') {
568 569 rv = EINVAL;
569 570 goto error;
570 571 }
571 572 }
572 573 #ifdef _SYSCALL32_IMPL
573 574 else {
574 575 struct aliases32 al32;
575 576 bzero(&al32, sizeof (struct aliases32));
576 577 if (copyin(ap, &al32, sizeof (struct aliases32)) != 0) {
577 578 rv = EFAULT;
578 579 goto error;
579 580 }
580 581 if (al32.a_len > MAXMODCONFNAME) {
581 582 rv = EINVAL;
582 583 goto error;
583 584 }
584 585 if (copyin((void *)(uintptr_t)al32.a_name,
585 586 name, al32.a_len) != 0) {
586 587 rv = EFAULT;
587 588 goto error;
588 589 }
589 590 if (name[al32.a_len - 1] != '\0') {
590 591 rv = EINVAL;
591 592 goto error;
592 593 }
593 594 alias.a_next = (void *)(uintptr_t)al32.a_next;
594 595 }
595 596 #endif
596 597 check_esc_sequences(name, cname);
597 598 aip->alias_name = strdup(cname);
598 599 ap = alias.a_next;
599 600 aip++;
600 601 }
601 602
602 603 if (add == 0) {
603 604 ap = mc.ap;
604 605 resid = 0;
605 606 aip = aliases;
606 607 /* attempt to unbind all devices bound to each alias */
607 608 for (i = 0; i < mc.num_aliases; i++) {
608 609 n = i_ddi_unbind_devs_by_alias(
609 610 mc.major, aip->alias_name);
610 611 resid += n;
611 612 aip->alias_resid = n;
612 613 }
613 614
614 615 /*
615 616 * If some device bound to an alias remains in use,
616 617 * and override wasn't specified, no change is made to
617 618 * the binding state and we fail the operation.
618 619 */
619 620 if (resid > 0 && ((mc.flags & MOD_UNBIND_OVERRIDE) == 0)) {
620 621 rv = EBUSY;
621 622 goto error;
622 623 }
623 624
624 625 /*
625 626 * No device remains bound of any of the aliases,
626 627 * or force was requested. Mark each alias as
627 628 * inactive via delete_mbind so no future binds
628 629 * to this alias take place and that a new
629 630 * binding can be established.
630 631 */
631 632 aip = aliases;
632 633 for (i = 0; i < mc.num_aliases; i++) {
633 634 if (moddebug & MODDEBUG_BINDING)
634 635 cmn_err(CE_CONT, "Removing binding for %s "
635 636 "(%d active references)\n",
636 637 aip->alias_name, aip->alias_resid);
637 638 delete_mbind(aip->alias_name, mb_hashtab);
638 639 aip++;
639 640 }
640 641 rv = 0;
641 642 } else {
642 643 aip = aliases;
643 644 for (i = 0; i < mc.num_aliases; i++) {
644 645 if (moddebug & MODDEBUG_BINDING)
645 646 cmn_err(CE_NOTE, "Adding binding for '%s'\n",
646 647 aip->alias_name);
647 648 (void) make_mbind(aip->alias_name,
648 649 mc.major, NULL, mb_hashtab);
649 650 aip++;
650 651 }
651 652 /*
652 653 * Try to establish an mbinding for mc.drvname, and add it to
653 654 * devnames. Add class if any after establishing the major
654 655 * number.
655 656 */
656 657 (void) make_mbind(mc.drvname, mc.major, NULL, mb_hashtab);
657 658 if ((rv = make_devname(mc.drvname, mc.major,
658 659 (mc.flags & MOD_ADDMAJBIND_UPDATE) ?
659 660 DN_DRIVER_INACTIVE : 0)) != 0) {
660 661 goto error;
661 662 }
662 663
663 664 if (mc.drvclass[0] != '\0')
664 665 add_class(mc.drvname, mc.drvclass);
665 666 if ((mc.flags & MOD_ADDMAJBIND_UPDATE) == 0) {
666 667 (void) i_ddi_load_drvconf(mc.major);
667 668 }
668 669 }
669 670
670 671 /*
671 672 * Ensure that all nodes are bound to the most appropriate driver
672 673 * possible, attempting demotion and rebind when a more appropriate
673 674 * driver now exists. But not when adding a driver update-only.
674 675 */
675 676 if ((add == 0) || ((mc.flags & MOD_ADDMAJBIND_UPDATE) == 0)) {
676 677 i_ddi_bind_devs();
677 678 i_ddi_di_cache_invalidate();
678 679 }
679 680
680 681 error:
681 682 if (mc.num_aliases > 0) {
682 683 aip = aliases;
683 684 for (i = 0; i < mc.num_aliases; i++) {
684 685 if (aip->alias_name != NULL)
685 686 strfree(aip->alias_name);
686 687 aip++;
687 688 }
688 689 kmem_free(aliases, mc.num_aliases * sizeof (struct alias_info));
689 690 }
690 691 return (rv);
691 692 }
692 693
693 694 static int
694 695 modctl_add_driver_aliases(int *data)
695 696 {
696 697 return (modctl_update_driver_aliases(1, data));
697 698 }
698 699
699 700 static int
700 701 modctl_remove_driver_aliases(int *data)
701 702 {
702 703 return (modctl_update_driver_aliases(0, data));
703 704 }
704 705
705 706 static int
706 707 modctl_rem_major(major_t major)
707 708 {
708 709 struct devnames *dnp;
709 710
710 711 if (major >= devcnt)
711 712 return (EINVAL);
712 713
713 714 /* mark devnames as removed */
714 715 dnp = &devnamesp[major];
715 716 LOCK_DEV_OPS(&dnp->dn_lock);
716 717 if (dnp->dn_name == NULL ||
717 718 (dnp->dn_flags & (DN_DRIVER_REMOVED | DN_TAKEN_GETUDEV))) {
718 719 UNLOCK_DEV_OPS(&dnp->dn_lock);
719 720 return (EINVAL);
720 721 }
721 722 dnp->dn_flags |= DN_DRIVER_REMOVED;
722 723 pm_driver_removed(major);
723 724 UNLOCK_DEV_OPS(&dnp->dn_lock);
724 725
725 726 (void) i_ddi_unload_drvconf(major);
726 727 i_ddi_unbind_devs(major);
727 728 i_ddi_bind_devs();
728 729 i_ddi_di_cache_invalidate();
729 730
730 731 /* purge all the bindings to this driver */
731 732 purge_mbind(major, mb_hashtab);
732 733 return (0);
733 734 }
734 735
735 736 static struct vfs *
736 737 path_to_vfs(char *name)
737 738 {
738 739 vnode_t *vp;
739 740 struct vfs *vfsp;
740 741
741 742 if (lookupname(name, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp))
742 743 return (NULL);
743 744
744 745 vfsp = vp->v_vfsp;
745 746 VN_RELE(vp);
746 747 return (vfsp);
747 748 }
748 749
749 750 static int
750 751 new_vfs_in_modpath()
751 752 {
752 753 static int n_modpath = 0;
753 754 static char *modpath_copy;
754 755 static struct pathvfs {
755 756 char *path;
756 757 struct vfs *vfsp;
757 758 } *pathvfs;
758 759
759 760 int i, new_vfs = 0;
760 761 char *tmp, *tmp1;
761 762 struct vfs *vfsp;
762 763
763 764 if (n_modpath != 0) {
764 765 for (i = 0; i < n_modpath; i++) {
765 766 vfsp = path_to_vfs(pathvfs[i].path);
766 767 if (vfsp != pathvfs[i].vfsp) {
767 768 pathvfs[i].vfsp = vfsp;
768 769 if (vfsp)
769 770 new_vfs = 1;
770 771 }
771 772 }
772 773 return (new_vfs);
773 774 }
774 775
775 776 /*
776 777 * First call, initialize the pathvfs structure
777 778 */
778 779 modpath_copy = i_ddi_strdup(default_path, KM_SLEEP);
779 780 tmp = modpath_copy;
780 781 n_modpath = 1;
781 782 tmp1 = strchr(tmp, ' ');
782 783 while (tmp1) {
783 784 *tmp1 = '\0';
784 785 n_modpath++;
785 786 tmp = tmp1 + 1;
786 787 tmp1 = strchr(tmp, ' ');
787 788 }
788 789
789 790 pathvfs = kmem_zalloc(n_modpath * sizeof (struct pathvfs), KM_SLEEP);
790 791 tmp = modpath_copy;
791 792 for (i = 0; i < n_modpath; i++) {
792 793 pathvfs[i].path = tmp;
793 794 vfsp = path_to_vfs(tmp);
794 795 pathvfs[i].vfsp = vfsp;
795 796 tmp += strlen(tmp) + 1;
796 797 }
797 798 return (1); /* always reread driver.conf the first time */
798 799 }
799 800
800 801 static int
801 802 modctl_load_drvconf(major_t major, int flags)
802 803 {
803 804 int ret;
804 805
805 806 /*
806 807 * devfsadm -u - read all new driver.conf files
807 808 * and bind and configure devices for new drivers.
808 809 */
809 810 if (flags & MOD_LOADDRVCONF_RECONF) {
810 811 (void) i_ddi_load_drvconf(DDI_MAJOR_T_NONE);
811 812 i_ddi_bind_devs();
812 813 i_ddi_di_cache_invalidate();
813 814 return (0);
814 815 }
815 816
816 817 /*
817 818 * update_drv <drv> - reload driver.conf for the specified driver
818 819 */
819 820 if (major != DDI_MAJOR_T_NONE) {
820 821 ret = i_ddi_load_drvconf(major);
821 822 if (ret == 0)
822 823 i_ddi_bind_devs();
823 824 return (ret);
824 825 }
825 826
826 827 /*
827 828 * We are invoked to rescan new driver.conf files. It is
828 829 * only necessary if a new file system was mounted in the
829 830 * module_path. Because rescanning driver.conf files can
830 831 * take some time on older platforms (sun4m), the following
831 832 * code skips unnecessary driver.conf rescans to optimize
832 833 * boot performance.
833 834 */
834 835 if (new_vfs_in_modpath()) {
835 836 (void) i_ddi_load_drvconf(DDI_MAJOR_T_NONE);
836 837 /*
837 838 * If we are still initializing io subsystem,
838 839 * load drivers with ddi-forceattach property
839 840 */
840 841 if (!i_ddi_io_initialized())
841 842 i_ddi_forceattach_drivers();
842 843 }
843 844 return (0);
844 845 }
845 846
846 847 /*
847 848 * Unload driver.conf file and follow up by attempting
848 849 * to rebind devices to more appropriate driver.
849 850 */
850 851 static int
851 852 modctl_unload_drvconf(major_t major)
852 853 {
853 854 int ret;
854 855
855 856 if (major >= devcnt)
856 857 return (EINVAL);
857 858
858 859 ret = i_ddi_unload_drvconf(major);
859 860 if (ret != 0)
860 861 return (ret);
861 862 (void) i_ddi_unbind_devs(major);
862 863 i_ddi_bind_devs();
863 864
864 865 return (0);
865 866 }
866 867
867 868 static void
868 869 check_esc_sequences(char *str, char *cstr)
869 870 {
870 871 int i;
871 872 size_t len;
872 873 char *p;
873 874
874 875 len = strlen(str);
875 876 for (i = 0; i < len; i++, str++, cstr++) {
876 877 if (*str != '\\') {
877 878 *cstr = *str;
878 879 } else {
879 880 p = str + 1;
880 881 /*
881 882 * we only handle octal escape sequences for SPACE
882 883 */
883 884 if (*p++ == '0' && *p++ == '4' && *p == '0') {
884 885 *cstr = ' ';
885 886 str += 3;
886 887 } else {
887 888 *cstr = *str;
888 889 }
889 890 }
890 891 }
891 892 *cstr = 0;
892 893 }
893 894
894 895 static int
895 896 modctl_getmodpathlen(int *data)
896 897 {
897 898 int len;
898 899 len = strlen(default_path);
899 900 if (copyout(&len, data, sizeof (len)) != 0)
900 901 return (EFAULT);
901 902 return (0);
902 903 }
903 904
904 905 static int
905 906 modctl_getmodpath(char *data)
906 907 {
907 908 if (copyout(default_path, data, strlen(default_path) + 1) != 0)
908 909 return (EFAULT);
909 910 return (0);
910 911 }
911 912
912 913 static int
913 914 modctl_read_sysbinding_file(void)
914 915 {
915 916 (void) read_binding_file(sysbind, sb_hashtab, make_mbind);
916 917 return (0);
917 918 }
918 919
919 920 static int
920 921 modctl_getmaj(char *uname, uint_t ulen, int *umajorp)
921 922 {
922 923 char name[256];
923 924 int retval;
924 925 major_t major;
925 926
926 927 if (ulen == 0)
927 928 return (EINVAL);
928 929 if ((retval = copyinstr(uname, name,
929 930 (ulen < 256) ? ulen : 256, 0)) != 0)
930 931 return (retval);
931 932 if ((major = mod_name_to_major(name)) == DDI_MAJOR_T_NONE)
932 933 return (ENODEV);
933 934 if (copyout(&major, umajorp, sizeof (major_t)) != 0)
934 935 return (EFAULT);
935 936 return (0);
936 937 }
937 938
938 939 static char **
939 940 convert_constraint_string(char *constraints, size_t len)
940 941 {
941 942 int i;
942 943 int n;
943 944 char *p;
944 945 char **array;
945 946
946 947 ASSERT(constraints != NULL);
947 948 ASSERT(len > 0);
948 949
949 950 for (i = 0, p = constraints; strlen(p) > 0; i++, p += strlen(p) + 1)
950 951 ;
951 952
952 953 n = i;
953 954
954 955 if (n == 0) {
955 956 kmem_free(constraints, len);
956 957 return (NULL);
957 958 }
958 959
959 960 array = kmem_alloc((n + 1) * sizeof (char *), KM_SLEEP);
960 961
961 962 for (i = 0, p = constraints; i < n; i++, p += strlen(p) + 1) {
962 963 array[i] = i_ddi_strdup(p, KM_SLEEP);
963 964 }
964 965 array[n] = NULL;
965 966
966 967 kmem_free(constraints, len);
967 968
968 969 return (array);
969 970 }
970 971 /*ARGSUSED*/
971 972 static int
972 973 modctl_retire(char *path, char *uconstraints, size_t ulen)
973 974 {
974 975 char *pathbuf;
975 976 char *devpath;
976 977 size_t pathsz;
977 978 int retval;
978 979 char *constraints;
979 980 char **cons_array;
980 981
981 982 if (path == NULL)
982 983 return (EINVAL);
983 984
984 985 if ((uconstraints == NULL) ^ (ulen == 0))
985 986 return (EINVAL);
986 987
987 988 pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
988 989 retval = copyinstr(path, pathbuf, MAXPATHLEN, &pathsz);
989 990 if (retval != 0) {
990 991 kmem_free(pathbuf, MAXPATHLEN);
991 992 return (retval);
992 993 }
993 994 devpath = i_ddi_strdup(pathbuf, KM_SLEEP);
994 995 kmem_free(pathbuf, MAXPATHLEN);
995 996
996 997 /*
997 998 * First check if the device is already retired.
998 999 * If it is, then persist the retire anyway, just in case the retire
999 1000 * store has got out of sync with the boot archive.
1000 1001 */
1001 1002 if (e_ddi_device_retired(devpath)) {
1002 1003 cmn_err(CE_NOTE, "Device: already retired: %s", devpath);
1003 1004 (void) e_ddi_retire_persist(devpath);
1004 1005 kmem_free(devpath, strlen(devpath) + 1);
1005 1006 return (0);
1006 1007 }
1007 1008
1008 1009 cons_array = NULL;
1009 1010 if (uconstraints) {
1010 1011 constraints = kmem_alloc(ulen, KM_SLEEP);
1011 1012 if (copyin(uconstraints, constraints, ulen)) {
1012 1013 kmem_free(constraints, ulen);
1013 1014 kmem_free(devpath, strlen(devpath) + 1);
1014 1015 return (EFAULT);
1015 1016 }
1016 1017 cons_array = convert_constraint_string(constraints, ulen);
1017 1018 }
1018 1019
1019 1020 /*
1020 1021 * Try to retire the device first. The following
1021 1022 * routine will return an error only if the device
1022 1023 * is not retireable i.e. retire constraints forbid
1023 1024 * a retire. A return of success from this routine
1024 1025 * indicates that device is retireable.
1025 1026 */
1026 1027 retval = e_ddi_retire_device(devpath, cons_array);
1027 1028 if (retval != DDI_SUCCESS) {
1028 1029 cmn_err(CE_WARN, "constraints forbid retire: %s", devpath);
1029 1030 kmem_free(devpath, strlen(devpath) + 1);
1030 1031 return (ENOTSUP);
1031 1032 }
1032 1033
1033 1034 /*
1034 1035 * Ok, the retire succeeded. Persist the retire.
1035 1036 * If retiring a nexus, we need to only persist the
1036 1037 * nexus retire. Any children of a retired nexus
1037 1038 * are automatically covered by the retire store
1038 1039 * code.
1039 1040 */
1040 1041 retval = e_ddi_retire_persist(devpath);
1041 1042 if (retval != 0) {
1042 1043 cmn_err(CE_WARN, "Failed to persist device retire: error %d: "
1043 1044 "%s", retval, devpath);
1044 1045 kmem_free(devpath, strlen(devpath) + 1);
1045 1046 return (retval);
1046 1047 }
1047 1048 if (moddebug & MODDEBUG_RETIRE)
1048 1049 cmn_err(CE_NOTE, "Persisted retire of device: %s", devpath);
1049 1050
1050 1051 kmem_free(devpath, strlen(devpath) + 1);
1051 1052 return (0);
1052 1053 }
1053 1054
1054 1055 static int
1055 1056 modctl_is_retired(char *path, int *statep)
1056 1057 {
1057 1058 char *pathbuf;
1058 1059 char *devpath;
1059 1060 size_t pathsz;
1060 1061 int error;
1061 1062 int status;
1062 1063
1063 1064 if (path == NULL || statep == NULL)
1064 1065 return (EINVAL);
1065 1066
1066 1067 pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1067 1068 error = copyinstr(path, pathbuf, MAXPATHLEN, &pathsz);
1068 1069 if (error != 0) {
1069 1070 kmem_free(pathbuf, MAXPATHLEN);
1070 1071 return (error);
1071 1072 }
1072 1073 devpath = i_ddi_strdup(pathbuf, KM_SLEEP);
1073 1074 kmem_free(pathbuf, MAXPATHLEN);
1074 1075
1075 1076 if (e_ddi_device_retired(devpath))
1076 1077 status = 1;
1077 1078 else
1078 1079 status = 0;
1079 1080 kmem_free(devpath, strlen(devpath) + 1);
1080 1081
1081 1082 return (copyout(&status, statep, sizeof (status)) ? EFAULT : 0);
1082 1083 }
1083 1084
1084 1085 static int
1085 1086 modctl_unretire(char *path)
1086 1087 {
1087 1088 char *pathbuf;
1088 1089 char *devpath;
1089 1090 size_t pathsz;
1090 1091 int retired;
1091 1092 int retval;
1092 1093
1093 1094 if (path == NULL)
1094 1095 return (EINVAL);
1095 1096
1096 1097 pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1097 1098 retval = copyinstr(path, pathbuf, MAXPATHLEN, &pathsz);
1098 1099 if (retval != 0) {
1099 1100 kmem_free(pathbuf, MAXPATHLEN);
1100 1101 return (retval);
1101 1102 }
1102 1103 devpath = i_ddi_strdup(pathbuf, KM_SLEEP);
1103 1104 kmem_free(pathbuf, MAXPATHLEN);
1104 1105
1105 1106 /*
1106 1107 * We check if a device is retired (first) before
1107 1108 * unpersisting the retire, because we use the
1108 1109 * retire store to determine if a device is retired.
1109 1110 * If we unpersist first, the device will always appear
1110 1111 * to be unretired. For the rationale behind unpersisting
1111 1112 * a device that is not retired, see the next comment.
1112 1113 */
1113 1114 retired = e_ddi_device_retired(devpath);
1114 1115
1115 1116 /*
1116 1117 * We call unpersist unconditionally because the lookup
1117 1118 * for retired devices (e_ddi_device_retired()), skips "bypassed"
1118 1119 * devices. We still want to be able remove "bypassed" entries
1119 1120 * from the persistent store, so we unpersist unconditionally
1120 1121 * i.e. whether or not the entry is found on a lookup.
1121 1122 *
1122 1123 * e_ddi_retire_unpersist() returns 1 if it found and cleared
1123 1124 * an entry from the retire store or 0 otherwise.
1124 1125 */
1125 1126 if (e_ddi_retire_unpersist(devpath))
1126 1127 if (moddebug & MODDEBUG_RETIRE) {
1127 1128 cmn_err(CE_NOTE, "Unpersisted retire of device: %s",
1128 1129 devpath);
1129 1130 }
1130 1131
1131 1132 /*
1132 1133 * Check if the device is already unretired. If so,
1133 1134 * the unretire becomes a NOP
1134 1135 */
1135 1136 if (!retired) {
1136 1137 cmn_err(CE_NOTE, "Not retired: %s", devpath);
1137 1138 kmem_free(devpath, strlen(devpath) + 1);
1138 1139 return (0);
1139 1140 }
1140 1141
1141 1142 retval = e_ddi_unretire_device(devpath);
1142 1143 if (retval != 0) {
1143 1144 cmn_err(CE_WARN, "cannot unretire device: error %d, path %s\n",
1144 1145 retval, devpath);
1145 1146 }
1146 1147
1147 1148 kmem_free(devpath, strlen(devpath) + 1);
1148 1149
1149 1150 return (retval);
1150 1151 }
1151 1152
1152 1153 static int
1153 1154 modctl_getname(char *uname, uint_t ulen, int *umajorp)
1154 1155 {
1155 1156 char *name;
1156 1157 major_t major;
1157 1158
1158 1159 if (copyin(umajorp, &major, sizeof (major)) != 0)
1159 1160 return (EFAULT);
1160 1161 if ((name = mod_major_to_name(major)) == NULL)
1161 1162 return (ENODEV);
1162 1163 if ((strlen(name) + 1) > ulen)
1163 1164 return (ENOSPC);
1164 1165 return (copyoutstr(name, uname, ulen, NULL));
1165 1166 }
1166 1167
1167 1168 static int
1168 1169 modctl_devt2instance(dev_t dev, int *uinstancep)
1169 1170 {
1170 1171 int instance;
1171 1172
1172 1173 if ((instance = dev_to_instance(dev)) == -1)
1173 1174 return (EINVAL);
1174 1175
1175 1176 return (copyout(&instance, uinstancep, sizeof (int)));
1176 1177 }
1177 1178
1178 1179 /*
1179 1180 * Return the sizeof of the device id.
1180 1181 */
1181 1182 static int
1182 1183 modctl_sizeof_devid(dev_t dev, uint_t *len)
1183 1184 {
1184 1185 uint_t sz;
1185 1186 ddi_devid_t devid;
1186 1187
1187 1188 /* get device id */
1188 1189 if (ddi_lyr_get_devid(dev, &devid) == DDI_FAILURE)
1189 1190 return (EINVAL);
1190 1191
1191 1192 sz = ddi_devid_sizeof(devid);
1192 1193 ddi_devid_free(devid);
1193 1194
1194 1195 /* copyout device id size */
1195 1196 if (copyout(&sz, len, sizeof (sz)) != 0)
1196 1197 return (EFAULT);
1197 1198
1198 1199 return (0);
1199 1200 }
1200 1201
1201 1202 /*
1202 1203 * Return a copy of the device id.
1203 1204 */
1204 1205 static int
1205 1206 modctl_get_devid(dev_t dev, uint_t len, ddi_devid_t udevid)
1206 1207 {
1207 1208 uint_t sz;
1208 1209 ddi_devid_t devid;
1209 1210 int err = 0;
1210 1211
1211 1212 /* get device id */
1212 1213 if (ddi_lyr_get_devid(dev, &devid) == DDI_FAILURE)
1213 1214 return (EINVAL);
1214 1215
1215 1216 sz = ddi_devid_sizeof(devid);
1216 1217
1217 1218 /* Error if device id is larger than space allocated */
1218 1219 if (sz > len) {
1219 1220 ddi_devid_free(devid);
1220 1221 return (ENOSPC);
1221 1222 }
1222 1223
1223 1224 /* copy out device id */
1224 1225 if (copyout(devid, udevid, sz) != 0)
1225 1226 err = EFAULT;
1226 1227 ddi_devid_free(devid);
1227 1228 return (err);
1228 1229 }
1229 1230
1230 1231 /*
1231 1232 * return the /devices paths associated with the specified devid and
1232 1233 * minor name.
1233 1234 */
1234 1235 /*ARGSUSED*/
1235 1236 static int
1236 1237 modctl_devid2paths(ddi_devid_t udevid, char *uminor_name, uint_t flag,
1237 1238 size_t *ulensp, char *upaths)
1238 1239 {
1239 1240 ddi_devid_t devid = NULL;
1240 1241 int devid_len;
1241 1242 char *minor_name = NULL;
1242 1243 dev_info_t *dip = NULL;
1243 1244 int circ;
1244 1245 struct ddi_minor_data *dmdp;
1245 1246 char *path = NULL;
1246 1247 int ulens;
1247 1248 int lens;
1248 1249 int len;
1249 1250 dev_t *devlist = NULL;
1250 1251 int ndevs;
1251 1252 int i;
1252 1253 int ret = 0;
1253 1254
1254 1255 /*
1255 1256 * If upaths is NULL then we are only computing the amount of space
1256 1257 * needed to hold the paths and returning the value in *ulensp. If we
1257 1258 * are copying out paths then we get the amount of space allocated by
1258 1259 * the caller. If the actual space needed for paths is larger, or
1259 1260 * things are changing out from under us, then we return EAGAIN.
1260 1261 */
1261 1262 if (upaths) {
1262 1263 if (ulensp == NULL)
1263 1264 return (EINVAL);
1264 1265 if (copyin(ulensp, &ulens, sizeof (ulens)) != 0)
1265 1266 return (EFAULT);
1266 1267 }
1267 1268
1268 1269 /*
1269 1270 * copyin enough of the devid to determine the length then
1270 1271 * reallocate and copy in the entire devid.
1271 1272 */
1272 1273 devid_len = ddi_devid_sizeof(NULL);
1273 1274 devid = kmem_alloc(devid_len, KM_SLEEP);
1274 1275 if (copyin(udevid, devid, devid_len)) {
1275 1276 ret = EFAULT;
1276 1277 goto out;
1277 1278 }
1278 1279 len = devid_len;
1279 1280 devid_len = ddi_devid_sizeof(devid);
1280 1281 kmem_free(devid, len);
1281 1282 devid = kmem_alloc(devid_len, KM_SLEEP);
1282 1283 if (copyin(udevid, devid, devid_len)) {
1283 1284 ret = EFAULT;
1284 1285 goto out;
1285 1286 }
1286 1287
1287 1288 /* copyin the minor name if specified. */
1288 1289 minor_name = uminor_name;
1289 1290 if ((minor_name != DEVID_MINOR_NAME_ALL) &&
1290 1291 (minor_name != DEVID_MINOR_NAME_ALL_CHR) &&
1291 1292 (minor_name != DEVID_MINOR_NAME_ALL_BLK)) {
1292 1293 minor_name = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1293 1294 if (copyinstr(uminor_name, minor_name, MAXPATHLEN, 0)) {
1294 1295 ret = EFAULT;
1295 1296 goto out;
1296 1297 }
1297 1298 }
1298 1299
1299 1300 /*
1300 1301 * Use existing function to resolve the devid into a devlist.
1301 1302 *
1302 1303 * NOTE: there is a loss of spectype information in the current
1303 1304 * ddi_lyr_devid_to_devlist implementation. We work around this by not
1304 1305 * passing down DEVID_MINOR_NAME_ALL here, but reproducing all minor
1305 1306 * node forms in the loop processing the devlist below. It would be
1306 1307 * best if at some point the use of this interface here was replaced
1307 1308 * with a path oriented call.
1308 1309 */
1309 1310 if (ddi_lyr_devid_to_devlist(devid,
1310 1311 (minor_name == DEVID_MINOR_NAME_ALL) ?
1311 1312 DEVID_MINOR_NAME_ALL_CHR : minor_name,
1312 1313 &ndevs, &devlist) != DDI_SUCCESS) {
1313 1314 ret = EINVAL;
1314 1315 goto out;
1315 1316 }
1316 1317
1317 1318 /*
1318 1319 * loop over the devlist, converting each devt to a path and doing
1319 1320 * a copyout of the path and computation of the amount of space
1320 1321 * needed to hold all the paths
1321 1322 */
1322 1323 path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1323 1324 for (i = 0, lens = 0; i < ndevs; i++) {
1324 1325
1325 1326 /* find the dip associated with the dev_t */
1326 1327 if ((dip = e_ddi_hold_devi_by_dev(devlist[i], 0)) == NULL)
1327 1328 continue;
1328 1329
1329 1330 /* loop over all the minor nodes, skipping ones we don't want */
1330 1331 ndi_devi_enter(dip, &circ);
1331 1332 for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
1332 1333 if ((dmdp->ddm_dev != devlist[i]) ||
1333 1334 (dmdp->type != DDM_MINOR))
1334 1335 continue;
1335 1336
1336 1337 if ((minor_name != DEVID_MINOR_NAME_ALL) &&
1337 1338 (minor_name != DEVID_MINOR_NAME_ALL_CHR) &&
1338 1339 (minor_name != DEVID_MINOR_NAME_ALL_BLK) &&
1339 1340 strcmp(minor_name, dmdp->ddm_name))
1340 1341 continue;
1341 1342 else {
1342 1343 if ((minor_name == DEVID_MINOR_NAME_ALL_CHR) &&
1343 1344 (dmdp->ddm_spec_type != S_IFCHR))
1344 1345 continue;
1345 1346 if ((minor_name == DEVID_MINOR_NAME_ALL_BLK) &&
1346 1347 (dmdp->ddm_spec_type != S_IFBLK))
1347 1348 continue;
1348 1349 }
1349 1350
1350 1351 (void) ddi_pathname_minor(dmdp, path);
1351 1352 len = strlen(path) + 1;
1352 1353 *(path + len) = '\0'; /* set double termination */
1353 1354 lens += len;
1354 1355
1355 1356 /* copyout the path with double terminations */
1356 1357 if (upaths) {
1357 1358 if (lens > ulens) {
1358 1359 ret = EAGAIN;
1359 1360 goto out;
1360 1361 }
1361 1362 if (copyout(path, upaths, len + 1)) {
1362 1363 ret = EFAULT;
1363 1364 goto out;
1364 1365 }
1365 1366 upaths += len;
1366 1367 }
1367 1368 }
1368 1369 ndi_devi_exit(dip, circ);
1369 1370 ddi_release_devi(dip);
1370 1371 dip = NULL;
1371 1372 }
1372 1373 lens++; /* add one for double termination */
1373 1374
1374 1375 /* copy out the amount of space needed to hold the paths */
1375 1376 if (ulensp && copyout(&lens, ulensp, sizeof (lens))) {
1376 1377 ret = EFAULT;
1377 1378 goto out;
1378 1379 }
1379 1380 ret = 0;
1380 1381
1381 1382 out: if (dip) {
1382 1383 ndi_devi_exit(dip, circ);
1383 1384 ddi_release_devi(dip);
1384 1385 }
1385 1386 if (path)
1386 1387 kmem_free(path, MAXPATHLEN);
1387 1388 if (devlist)
1388 1389 ddi_lyr_free_devlist(devlist, ndevs);
1389 1390 if (minor_name &&
1390 1391 (minor_name != DEVID_MINOR_NAME_ALL) &&
1391 1392 (minor_name != DEVID_MINOR_NAME_ALL_CHR) &&
1392 1393 (minor_name != DEVID_MINOR_NAME_ALL_BLK))
1393 1394 kmem_free(minor_name, MAXPATHLEN);
1394 1395 if (devid)
1395 1396 kmem_free(devid, devid_len);
1396 1397 return (ret);
1397 1398 }
1398 1399
1399 1400 /*
1400 1401 * Return the size of the minor name.
1401 1402 */
1402 1403 static int
1403 1404 modctl_sizeof_minorname(dev_t dev, int spectype, uint_t *len)
1404 1405 {
1405 1406 uint_t sz;
1406 1407 char *name;
1407 1408
1408 1409 /* get the minor name */
1409 1410 if (ddi_lyr_get_minor_name(dev, spectype, &name) == DDI_FAILURE)
1410 1411 return (EINVAL);
1411 1412
1412 1413 sz = strlen(name) + 1;
1413 1414 kmem_free(name, sz);
1414 1415
1415 1416 /* copy out the size of the minor name */
1416 1417 if (copyout(&sz, len, sizeof (sz)) != 0)
1417 1418 return (EFAULT);
1418 1419
1419 1420 return (0);
1420 1421 }
1421 1422
1422 1423 /*
1423 1424 * Return the minor name.
1424 1425 */
1425 1426 static int
1426 1427 modctl_get_minorname(dev_t dev, int spectype, uint_t len, char *uname)
1427 1428 {
1428 1429 uint_t sz;
1429 1430 char *name;
1430 1431 int err = 0;
1431 1432
1432 1433 /* get the minor name */
1433 1434 if (ddi_lyr_get_minor_name(dev, spectype, &name) == DDI_FAILURE)
1434 1435 return (EINVAL);
1435 1436
1436 1437 sz = strlen(name) + 1;
1437 1438
1438 1439 /* Error if the minor name is larger than the space allocated */
1439 1440 if (sz > len) {
1440 1441 kmem_free(name, sz);
1441 1442 return (ENOSPC);
1442 1443 }
1443 1444
1444 1445 /* copy out the minor name */
1445 1446 if (copyout(name, uname, sz) != 0)
1446 1447 err = EFAULT;
1447 1448 kmem_free(name, sz);
1448 1449 return (err);
1449 1450 }
1450 1451
1451 1452 /*
1452 1453 * Return the size of the (dev_t,spectype) devfspath name.
1453 1454 */
1454 1455 static int
1455 1456 modctl_devfspath_len(dev_t dev, int spectype, uint_t *len)
1456 1457 {
1457 1458 uint_t sz;
1458 1459 char *name;
1459 1460
1460 1461 /* get the path name */
1461 1462 name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1462 1463 if (ddi_dev_pathname(dev, spectype, name) == DDI_FAILURE) {
1463 1464 kmem_free(name, MAXPATHLEN);
1464 1465 return (EINVAL);
1465 1466 }
1466 1467
1467 1468 sz = strlen(name) + 1;
1468 1469 kmem_free(name, MAXPATHLEN);
1469 1470
1470 1471 /* copy out the size of the path name */
1471 1472 if (copyout(&sz, len, sizeof (sz)) != 0)
1472 1473 return (EFAULT);
1473 1474
1474 1475 return (0);
1475 1476 }
1476 1477
1477 1478 /*
1478 1479 * Return the (dev_t,spectype) devfspath name.
1479 1480 */
1480 1481 static int
1481 1482 modctl_devfspath(dev_t dev, int spectype, uint_t len, char *uname)
1482 1483 {
1483 1484 uint_t sz;
1484 1485 char *name;
1485 1486 int err = 0;
1486 1487
1487 1488 /* get the path name */
1488 1489 name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1489 1490 if (ddi_dev_pathname(dev, spectype, name) == DDI_FAILURE) {
1490 1491 kmem_free(name, MAXPATHLEN);
1491 1492 return (EINVAL);
1492 1493 }
1493 1494
1494 1495 sz = strlen(name) + 1;
1495 1496
1496 1497 /* Error if the path name is larger than the space allocated */
1497 1498 if (sz > len) {
1498 1499 kmem_free(name, MAXPATHLEN);
1499 1500 return (ENOSPC);
1500 1501 }
1501 1502
1502 1503 /* copy out the path name */
1503 1504 if (copyout(name, uname, sz) != 0)
1504 1505 err = EFAULT;
1505 1506 kmem_free(name, MAXPATHLEN);
1506 1507 return (err);
1507 1508 }
1508 1509
1509 1510 /*
1510 1511 * Return the size of the (major,instance) devfspath name.
1511 1512 */
1512 1513 static int
1513 1514 modctl_devfspath_mi_len(major_t major, int instance, uint_t *len)
1514 1515 {
1515 1516 uint_t sz;
1516 1517 char *name;
1517 1518
1518 1519 /* get the path name */
1519 1520 name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1520 1521 if (e_ddi_majorinstance_to_path(major, instance, name) != DDI_SUCCESS) {
1521 1522 kmem_free(name, MAXPATHLEN);
1522 1523 return (EINVAL);
1523 1524 }
1524 1525
1525 1526 sz = strlen(name) + 1;
1526 1527 kmem_free(name, MAXPATHLEN);
1527 1528
1528 1529 /* copy out the size of the path name */
1529 1530 if (copyout(&sz, len, sizeof (sz)) != 0)
1530 1531 return (EFAULT);
1531 1532
1532 1533 return (0);
1533 1534 }
1534 1535
1535 1536 /*
1536 1537 * Return the (major_instance) devfspath name.
1537 1538 * NOTE: e_ddi_majorinstance_to_path does not require the device to attach to
1538 1539 * return a path - it uses the instance tree.
1539 1540 */
1540 1541 static int
1541 1542 modctl_devfspath_mi(major_t major, int instance, uint_t len, char *uname)
1542 1543 {
1543 1544 uint_t sz;
1544 1545 char *name;
1545 1546 int err = 0;
1546 1547
1547 1548 /* get the path name */
1548 1549 name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1549 1550 if (e_ddi_majorinstance_to_path(major, instance, name) != DDI_SUCCESS) {
1550 1551 kmem_free(name, MAXPATHLEN);
1551 1552 return (EINVAL);
1552 1553 }
1553 1554
1554 1555 sz = strlen(name) + 1;
1555 1556
1556 1557 /* Error if the path name is larger than the space allocated */
1557 1558 if (sz > len) {
1558 1559 kmem_free(name, MAXPATHLEN);
1559 1560 return (ENOSPC);
1560 1561 }
1561 1562
1562 1563 /* copy out the path name */
1563 1564 if (copyout(name, uname, sz) != 0)
1564 1565 err = EFAULT;
1565 1566 kmem_free(name, MAXPATHLEN);
1566 1567 return (err);
1567 1568 }
1568 1569
1569 1570 static int
1570 1571 modctl_get_fbname(char *path)
1571 1572 {
1572 1573 extern dev_t fbdev;
1573 1574 char *pathname = NULL;
1574 1575 int rval = 0;
1575 1576
1576 1577 /* make sure fbdev is set before we plunge in */
1577 1578 if (fbdev == NODEV)
1578 1579 return (ENODEV);
1579 1580
1580 1581 pathname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1581 1582 if ((rval = ddi_dev_pathname(fbdev, S_IFCHR,
1582 1583 pathname)) == DDI_SUCCESS) {
1583 1584 if (copyout(pathname, path, strlen(pathname)+1) != 0) {
1584 1585 rval = EFAULT;
1585 1586 }
1586 1587 }
1587 1588 kmem_free(pathname, MAXPATHLEN);
1588 1589 return (rval);
1589 1590 }
1590 1591
1591 1592 /*
1592 1593 * modctl_reread_dacf()
1593 1594 * Reread the dacf rules database from the named binding file.
1594 1595 * If NULL is specified, pass along the NULL, it means 'use the default'.
1595 1596 */
1596 1597 static int
1597 1598 modctl_reread_dacf(char *path)
1598 1599 {
1599 1600 int rval = 0;
1600 1601 char *filename, *filenamep;
1601 1602
1602 1603 filename = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1603 1604
1604 1605 if (path == NULL) {
1605 1606 filenamep = NULL;
1606 1607 } else {
1607 1608 if (copyinstr(path, filename, MAXPATHLEN, 0) != 0) {
1608 1609 rval = EFAULT;
1609 1610 goto out;
1610 1611 }
1611 1612 filenamep = filename;
1612 1613 filenamep[MAXPATHLEN - 1] = '\0';
1613 1614 }
1614 1615
1615 1616 rval = read_dacf_binding_file(filenamep);
1616 1617 out:
1617 1618 kmem_free(filename, MAXPATHLEN);
1618 1619 return (rval);
1619 1620 }
1620 1621
1621 1622 /*ARGSUSED*/
1622 1623 static int
1623 1624 modctl_modevents(int subcmd, uintptr_t a2, uintptr_t a3, uintptr_t a4,
1624 1625 uint_t flag)
1625 1626 {
1626 1627 int error = 0;
1627 1628 char *filenamep;
1628 1629
1629 1630 switch (subcmd) {
1630 1631
1631 1632 case MODEVENTS_FLUSH:
1632 1633 /* flush all currently queued events */
1633 1634 log_sysevent_flushq(subcmd, flag);
1634 1635 break;
1635 1636
1636 1637 case MODEVENTS_SET_DOOR_UPCALL_FILENAME:
1637 1638 /*
1638 1639 * bind door_upcall to filename
1639 1640 * this should only be done once per invocation
1640 1641 * of the event daemon.
1641 1642 */
1642 1643
1643 1644 filenamep = kmem_zalloc(MOD_MAXPATH, KM_SLEEP);
1644 1645
1645 1646 if (copyinstr((char *)a2, filenamep, MOD_MAXPATH, 0)) {
1646 1647 error = EFAULT;
1647 1648 } else {
1648 1649 error = log_sysevent_filename(filenamep);
1649 1650 }
1650 1651 kmem_free(filenamep, MOD_MAXPATH);
1651 1652 break;
1652 1653
1653 1654 case MODEVENTS_GETDATA:
1654 1655 error = log_sysevent_copyout_data((sysevent_id_t *)a2,
1655 1656 (size_t)a3, (caddr_t)a4);
1656 1657 break;
1657 1658
1658 1659 case MODEVENTS_FREEDATA:
1659 1660 error = log_sysevent_free_data((sysevent_id_t *)a2);
1660 1661 break;
1661 1662 case MODEVENTS_POST_EVENT:
1662 1663 error = log_usr_sysevent((sysevent_t *)a2, (uint32_t)a3,
1663 1664 (sysevent_id_t *)a4);
1664 1665 break;
1665 1666 case MODEVENTS_REGISTER_EVENT:
1666 1667 error = log_sysevent_register((char *)a2, (char *)a3,
1667 1668 (se_pubsub_t *)a4);
1668 1669 break;
1669 1670 default:
1670 1671 error = EINVAL;
1671 1672 }
1672 1673
1673 1674 return (error);
1674 1675 }
1675 1676
1676 1677 static void
1677 1678 free_mperm(mperm_t *mp)
1678 1679 {
1679 1680 int len;
1680 1681
1681 1682 if (mp->mp_minorname) {
1682 1683 len = strlen(mp->mp_minorname) + 1;
1683 1684 kmem_free(mp->mp_minorname, len);
1684 1685 }
1685 1686 kmem_free(mp, sizeof (mperm_t));
1686 1687 }
1687 1688
1688 1689 #define MP_NO_DRV_ERR \
1689 1690 "/etc/minor_perm: no driver for %s\n"
1690 1691
1691 1692 #define MP_EMPTY_MINOR \
1692 1693 "/etc/minor_perm: empty minor name for driver %s\n"
1693 1694
1694 1695 #define MP_NO_MINOR \
1695 1696 "/etc/minor_perm: no minor matching %s for driver %s\n"
1696 1697
1697 1698 /*
1698 1699 * Remove mperm entry with matching minorname
1699 1700 */
1700 1701 static void
1701 1702 rem_minorperm(major_t major, char *drvname, mperm_t *mp, int is_clone)
1702 1703 {
1703 1704 mperm_t **mp_head;
1704 1705 mperm_t *freemp = NULL;
1705 1706 struct devnames *dnp = &devnamesp[major];
1706 1707 mperm_t **wildmp;
1707 1708
1708 1709 ASSERT(mp->mp_minorname && strlen(mp->mp_minorname) > 0);
1709 1710
1710 1711 LOCK_DEV_OPS(&dnp->dn_lock);
1711 1712 if (strcmp(mp->mp_minorname, "*") == 0) {
1712 1713 wildmp = ((is_clone == 0) ?
1713 1714 &dnp->dn_mperm_wild : &dnp->dn_mperm_clone);
1714 1715 if (*wildmp)
1715 1716 freemp = *wildmp;
1716 1717 *wildmp = NULL;
1717 1718 } else {
1718 1719 mp_head = &dnp->dn_mperm;
1719 1720 while (*mp_head) {
1720 1721 if (strcmp((*mp_head)->mp_minorname,
1721 1722 mp->mp_minorname) != 0) {
1722 1723 mp_head = &(*mp_head)->mp_next;
1723 1724 continue;
1724 1725 }
1725 1726 /* remove the entry */
1726 1727 freemp = *mp_head;
1727 1728 *mp_head = freemp->mp_next;
1728 1729 break;
1729 1730 }
1730 1731 }
1731 1732 if (freemp) {
1732 1733 if (moddebug & MODDEBUG_MINORPERM) {
1733 1734 cmn_err(CE_CONT, "< %s %s 0%o %d %d\n",
1734 1735 drvname, freemp->mp_minorname,
1735 1736 freemp->mp_mode & 0777,
1736 1737 freemp->mp_uid, freemp->mp_gid);
1737 1738 }
1738 1739 free_mperm(freemp);
1739 1740 } else {
1740 1741 if (moddebug & MODDEBUG_MINORPERM) {
1741 1742 cmn_err(CE_CONT, MP_NO_MINOR,
1742 1743 drvname, mp->mp_minorname);
1743 1744 }
1744 1745 }
1745 1746
1746 1747 UNLOCK_DEV_OPS(&dnp->dn_lock);
1747 1748 }
1748 1749
1749 1750 /*
1750 1751 * Add minor perm entry
1751 1752 */
1752 1753 static void
1753 1754 add_minorperm(major_t major, char *drvname, mperm_t *mp, int is_clone)
1754 1755 {
1755 1756 mperm_t **mp_head;
1756 1757 mperm_t *freemp = NULL;
1757 1758 struct devnames *dnp = &devnamesp[major];
1758 1759 mperm_t **wildmp;
1759 1760
1760 1761 ASSERT(mp->mp_minorname && strlen(mp->mp_minorname) > 0);
1761 1762
1762 1763 /*
1763 1764 * Note that update_drv replace semantics require
1764 1765 * replacing matching entries with the new permissions.
1765 1766 */
1766 1767 LOCK_DEV_OPS(&dnp->dn_lock);
1767 1768 if (strcmp(mp->mp_minorname, "*") == 0) {
1768 1769 wildmp = ((is_clone == 0) ?
1769 1770 &dnp->dn_mperm_wild : &dnp->dn_mperm_clone);
1770 1771 if (*wildmp)
1771 1772 freemp = *wildmp;
1772 1773 *wildmp = mp;
1773 1774 } else {
1774 1775 mperm_t *p, *v = NULL;
1775 1776 for (p = dnp->dn_mperm; p; v = p, p = p->mp_next) {
1776 1777 if (strcmp(p->mp_minorname, mp->mp_minorname) == 0) {
1777 1778 if (v == NULL)
1778 1779 dnp->dn_mperm = mp;
1779 1780 else
1780 1781 v->mp_next = mp;
1781 1782 mp->mp_next = p->mp_next;
1782 1783 freemp = p;
1783 1784 goto replaced;
1784 1785 }
1785 1786 }
1786 1787 if (p == NULL) {
1787 1788 mp_head = &dnp->dn_mperm;
1788 1789 if (*mp_head == NULL) {
1789 1790 *mp_head = mp;
1790 1791 } else {
1791 1792 mp->mp_next = *mp_head;
1792 1793 *mp_head = mp;
1793 1794 }
1794 1795 }
1795 1796 }
1796 1797 replaced:
1797 1798 if (freemp) {
1798 1799 if (moddebug & MODDEBUG_MINORPERM) {
1799 1800 cmn_err(CE_CONT, "< %s %s 0%o %d %d\n",
1800 1801 drvname, freemp->mp_minorname,
1801 1802 freemp->mp_mode & 0777,
1802 1803 freemp->mp_uid, freemp->mp_gid);
1803 1804 }
1804 1805 free_mperm(freemp);
1805 1806 }
1806 1807 if (moddebug & MODDEBUG_MINORPERM) {
1807 1808 cmn_err(CE_CONT, "> %s %s 0%o %d %d\n",
1808 1809 drvname, mp->mp_minorname, mp->mp_mode & 0777,
1809 1810 mp->mp_uid, mp->mp_gid);
1810 1811 }
1811 1812 UNLOCK_DEV_OPS(&dnp->dn_lock);
1812 1813 }
1813 1814
1814 1815
1815 1816 static int
1816 1817 process_minorperm(int cmd, nvlist_t *nvl)
1817 1818 {
1818 1819 char *minor;
1819 1820 major_t major;
1820 1821 mperm_t *mp;
1821 1822 nvpair_t *nvp;
1822 1823 char *name;
1823 1824 int is_clone;
1824 1825 major_t minmaj;
1825 1826
1826 1827 ASSERT(cmd == MODLOADMINORPERM ||
1827 1828 cmd == MODADDMINORPERM || cmd == MODREMMINORPERM);
1828 1829
1829 1830 nvp = NULL;
1830 1831 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1831 1832 name = nvpair_name(nvp);
1832 1833
1833 1834 is_clone = 0;
1834 1835 (void) nvpair_value_string(nvp, &minor);
1835 1836 major = ddi_name_to_major(name);
1836 1837 if (major != DDI_MAJOR_T_NONE) {
1837 1838 mp = kmem_zalloc(sizeof (*mp), KM_SLEEP);
1838 1839 if (minor == NULL || strlen(minor) == 0) {
1839 1840 if (moddebug & MODDEBUG_MINORPERM) {
1840 1841 cmn_err(CE_CONT, MP_EMPTY_MINOR, name);
1841 1842 }
1842 1843 minor = "*";
1843 1844 }
1844 1845
1845 1846 /*
1846 1847 * The minor name of a node using the clone
1847 1848 * driver must be the driver name. To avoid
1848 1849 * multiple searches, we map entries in the form
1849 1850 * clone:<driver> to <driver>:*. This also allows us
1850 1851 * to filter out some of the litter in /etc/minor_perm.
1851 1852 * Minor perm alias entries where the name is not
1852 1853 * the driver kept on the clone list itself.
1853 1854 * This all seems very fragile as a driver could
1854 1855 * be introduced with an existing alias name.
1855 1856 */
1856 1857 if (strcmp(name, "clone") == 0) {
1857 1858 minmaj = ddi_name_to_major(minor);
1858 1859 if (minmaj != DDI_MAJOR_T_NONE) {
1859 1860 if (moddebug & MODDEBUG_MINORPERM) {
1860 1861 cmn_err(CE_CONT,
1861 1862 "mapping %s:%s to %s:*\n",
1862 1863 name, minor, minor);
1863 1864 }
1864 1865 major = minmaj;
1865 1866 name = minor;
1866 1867 minor = "*";
1867 1868 is_clone = 1;
1868 1869 }
1869 1870 }
1870 1871
1871 1872 if (mp) {
1872 1873 mp->mp_minorname =
1873 1874 i_ddi_strdup(minor, KM_SLEEP);
1874 1875 }
1875 1876 } else {
1876 1877 mp = NULL;
1877 1878 if (moddebug & MODDEBUG_MINORPERM) {
1878 1879 cmn_err(CE_CONT, MP_NO_DRV_ERR, name);
1879 1880 }
1880 1881 }
1881 1882
1882 1883 /* mode */
1883 1884 nvp = nvlist_next_nvpair(nvl, nvp);
1884 1885 ASSERT(strcmp(nvpair_name(nvp), "mode") == 0);
1885 1886 if (mp)
1886 1887 (void) nvpair_value_int32(nvp, (int *)&mp->mp_mode);
1887 1888 /* uid */
1888 1889 nvp = nvlist_next_nvpair(nvl, nvp);
1889 1890 ASSERT(strcmp(nvpair_name(nvp), "uid") == 0);
1890 1891 if (mp)
1891 1892 (void) nvpair_value_uint32(nvp, &mp->mp_uid);
1892 1893 /* gid */
1893 1894 nvp = nvlist_next_nvpair(nvl, nvp);
1894 1895 ASSERT(strcmp(nvpair_name(nvp), "gid") == 0);
1895 1896 if (mp) {
1896 1897 (void) nvpair_value_uint32(nvp, &mp->mp_gid);
1897 1898
1898 1899 if (cmd == MODREMMINORPERM) {
1899 1900 rem_minorperm(major, name, mp, is_clone);
1900 1901 free_mperm(mp);
1901 1902 } else {
1902 1903 add_minorperm(major, name, mp, is_clone);
1903 1904 }
1904 1905 }
1905 1906 }
1906 1907
1907 1908 if (cmd == MODLOADMINORPERM)
1908 1909 minorperm_loaded = 1;
1909 1910
1910 1911 /*
1911 1912 * Reset permissions of cached dv_nodes
1912 1913 */
1913 1914 (void) devfs_reset_perm(DV_RESET_PERM);
1914 1915
1915 1916 return (0);
1916 1917 }
1917 1918
1918 1919 static int
1919 1920 modctl_minorperm(int cmd, char *usrbuf, size_t buflen)
1920 1921 {
1921 1922 int error;
1922 1923 nvlist_t *nvl;
1923 1924 char *buf = kmem_alloc(buflen, KM_SLEEP);
1924 1925
1925 1926 if ((error = ddi_copyin(usrbuf, buf, buflen, 0)) != 0) {
1926 1927 kmem_free(buf, buflen);
1927 1928 return (error);
1928 1929 }
1929 1930
1930 1931 error = nvlist_unpack(buf, buflen, &nvl, KM_SLEEP);
1931 1932 kmem_free(buf, buflen);
1932 1933 if (error)
1933 1934 return (error);
1934 1935
1935 1936 error = process_minorperm(cmd, nvl);
1936 1937 nvlist_free(nvl);
1937 1938 return (error);
1938 1939 }
1939 1940
1940 1941 struct walk_args {
1941 1942 char *wa_drvname;
1942 1943 list_t wa_pathlist;
1943 1944 };
1944 1945
1945 1946 struct path_elem {
1946 1947 char *pe_dir;
1947 1948 char *pe_nodename;
1948 1949 list_node_t pe_node;
1949 1950 int pe_dirlen;
1950 1951 };
1951 1952
1952 1953 /*ARGSUSED*/
1953 1954 static int
1954 1955 modctl_inst_walker(const char *path, in_node_t *np, in_drv_t *dp, void *arg)
1955 1956 {
1956 1957 struct walk_args *wargs = (struct walk_args *)arg;
1957 1958 struct path_elem *pe;
1958 1959 char *nodename;
1959 1960
1960 1961 /*
1961 1962 * Search may be restricted to a single driver in the case of rem_drv
1962 1963 */
1963 1964 if (wargs->wa_drvname &&
1964 1965 strcmp(dp->ind_driver_name, wargs->wa_drvname) != 0)
1965 1966 return (INST_WALK_CONTINUE);
1966 1967
1967 1968 pe = kmem_zalloc(sizeof (*pe), KM_SLEEP);
1968 1969 pe->pe_dir = i_ddi_strdup((char *)path, KM_SLEEP);
1969 1970 pe->pe_dirlen = strlen(pe->pe_dir) + 1;
1970 1971 ASSERT(strrchr(pe->pe_dir, '/') != NULL);
1971 1972 nodename = strrchr(pe->pe_dir, '/');
1972 1973 *nodename++ = 0;
1973 1974 pe->pe_nodename = nodename;
1974 1975 list_insert_tail(&wargs->wa_pathlist, pe);
1975 1976
1976 1977 return (INST_WALK_CONTINUE);
1977 1978 }
1978 1979
1979 1980 /*
1980 1981 * /devices attribute nodes clean-up optionally performed
1981 1982 * when removing a driver (rem_drv -C).
1982 1983 *
1983 1984 * Removing attribute nodes allows a machine to be reprovisioned
1984 1985 * without the side-effect of inadvertently picking up stale
1985 1986 * device node ownership or permissions.
1986 1987 *
1987 1988 * Preserving attributes (not performing cleanup) allows devices
1988 1989 * attribute changes to be preserved across upgrades, as
1989 1990 * upgrade rather heavy-handedly does a rem_drv/add_drv cycle.
1990 1991 */
1991 1992 static int
1992 1993 modctl_remdrv_cleanup(const char *u_drvname)
1993 1994 {
1994 1995 struct walk_args *wargs;
1995 1996 struct path_elem *pe;
1996 1997 char *drvname;
1997 1998 int err, rval = 0;
1998 1999
1999 2000 drvname = kmem_alloc(MAXMODCONFNAME, KM_SLEEP);
2000 2001 if ((err = copyinstr(u_drvname, drvname, MAXMODCONFNAME, 0))) {
2001 2002 kmem_free(drvname, MAXMODCONFNAME);
2002 2003 return (err);
2003 2004 }
2004 2005
2005 2006 /*
2006 2007 * First go through the instance database. For each
2007 2008 * instance of a device bound to the driver being
2008 2009 * removed, remove any underlying devfs attribute nodes.
2009 2010 *
2010 2011 * This is a two-step process. First we go through
2011 2012 * the instance data itself, constructing a list of
2012 2013 * the nodes discovered. The second step is then
2013 2014 * to find and remove any devfs attribute nodes
2014 2015 * for the instances discovered in the first step.
2015 2016 * The two-step process avoids any difficulties
2016 2017 * which could arise by holding the instance data
2017 2018 * lock with simultaneous devfs operations.
2018 2019 */
2019 2020 wargs = kmem_zalloc(sizeof (*wargs), KM_SLEEP);
2020 2021
2021 2022 wargs->wa_drvname = drvname;
2022 2023 list_create(&wargs->wa_pathlist,
2023 2024 sizeof (struct path_elem), offsetof(struct path_elem, pe_node));
2024 2025
2025 2026 (void) e_ddi_walk_instances(modctl_inst_walker, (void *)wargs);
2026 2027
2027 2028 for (pe = list_head(&wargs->wa_pathlist); pe != NULL;
2028 2029 pe = list_next(&wargs->wa_pathlist, pe)) {
2029 2030 err = devfs_remdrv_cleanup((const char *)pe->pe_dir,
2030 2031 (const char *)pe->pe_nodename);
2031 2032 if (rval == 0)
2032 2033 rval = err;
2033 2034 }
2034 2035
2035 2036 while ((pe = list_head(&wargs->wa_pathlist)) != NULL) {
2036 2037 list_remove(&wargs->wa_pathlist, pe);
2037 2038 kmem_free(pe->pe_dir, pe->pe_dirlen);
2038 2039 kmem_free(pe, sizeof (*pe));
2039 2040 }
2040 2041 kmem_free(wargs, sizeof (*wargs));
2041 2042
2042 2043 /*
2043 2044 * Pseudo nodes aren't recorded in the instance database
2044 2045 * so any such nodes need to be handled separately.
2045 2046 */
2046 2047 err = devfs_remdrv_cleanup("pseudo", (const char *)drvname);
2047 2048 if (rval == 0)
2048 2049 rval = err;
2049 2050
2050 2051 kmem_free(drvname, MAXMODCONFNAME);
2051 2052 return (rval);
2052 2053 }
2053 2054
2054 2055 /*
2055 2056 * Perform a cleanup of non-existent /devices attribute nodes,
2056 2057 * similar to rem_drv -C, but for all drivers/devices.
2057 2058 * This is also optional, performed as part of devfsadm -C.
2058 2059 */
2059 2060 void
2060 2061 dev_devices_cleanup()
2061 2062 {
2062 2063 struct walk_args *wargs;
2063 2064 struct path_elem *pe;
2064 2065 dev_info_t *devi;
2065 2066 char *path;
2066 2067 int err;
2067 2068
2068 2069 /*
2069 2070 * It's expected that all drivers have been loaded and
2070 2071 * module unloading disabled while performing cleanup.
2071 2072 */
2072 2073 ASSERT(modunload_disable_count > 0);
2073 2074
2074 2075 wargs = kmem_zalloc(sizeof (*wargs), KM_SLEEP);
2075 2076 wargs->wa_drvname = NULL;
2076 2077 list_create(&wargs->wa_pathlist,
2077 2078 sizeof (struct path_elem), offsetof(struct path_elem, pe_node));
2078 2079
2079 2080 (void) e_ddi_walk_instances(modctl_inst_walker, (void *)wargs);
2080 2081
2081 2082 path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2082 2083
2083 2084 for (pe = list_head(&wargs->wa_pathlist); pe != NULL;
2084 2085 pe = list_next(&wargs->wa_pathlist, pe)) {
2085 2086 (void) snprintf(path, MAXPATHLEN, "%s/%s",
2086 2087 pe->pe_dir, pe->pe_nodename);
2087 2088 devi = e_ddi_hold_devi_by_path(path, 0);
2088 2089 if (devi != NULL) {
2089 2090 ddi_release_devi(devi);
2090 2091 } else {
2091 2092 err = devfs_remdrv_cleanup((const char *)pe->pe_dir,
2092 2093 (const char *)pe->pe_nodename);
2093 2094 if (err) {
2094 2095 cmn_err(CE_CONT,
2095 2096 "devfs: %s: clean-up error %d\n",
2096 2097 path, err);
2097 2098 }
2098 2099 }
2099 2100 }
2100 2101
2101 2102 while ((pe = list_head(&wargs->wa_pathlist)) != NULL) {
2102 2103 list_remove(&wargs->wa_pathlist, pe);
2103 2104 kmem_free(pe->pe_dir, pe->pe_dirlen);
2104 2105 kmem_free(pe, sizeof (*pe));
2105 2106 }
2106 2107 kmem_free(wargs, sizeof (*wargs));
2107 2108 kmem_free(path, MAXPATHLEN);
2108 2109 }
2109 2110
2110 2111 static int
2111 2112 modctl_allocpriv(const char *name)
2112 2113 {
2113 2114 char *pstr = kmem_alloc(PRIVNAME_MAX, KM_SLEEP);
2114 2115 int error;
2115 2116
2116 2117 if ((error = copyinstr(name, pstr, PRIVNAME_MAX, 0))) {
2117 2118 kmem_free(pstr, PRIVNAME_MAX);
2118 2119 return (error);
2119 2120 }
2120 2121 error = priv_getbyname(pstr, PRIV_ALLOC);
2121 2122 if (error < 0)
2122 2123 error = -error;
2123 2124 else
2124 2125 error = 0;
2125 2126 kmem_free(pstr, PRIVNAME_MAX);
2126 2127 return (error);
2127 2128 }
2128 2129
2129 2130 static int
2130 2131 modctl_devexists(const char *upath, int pathlen)
2131 2132 {
2132 2133 char *path;
2133 2134 int ret;
2134 2135
2135 2136 /*
2136 2137 * copy in the path, including the terminating null
2137 2138 */
2138 2139 pathlen++;
2139 2140 if (pathlen <= 1 || pathlen > MAXPATHLEN)
2140 2141 return (EINVAL);
2141 2142 path = kmem_zalloc(pathlen + 1, KM_SLEEP);
2142 2143 if ((ret = copyinstr(upath, path, pathlen, NULL)) == 0) {
2143 2144 ret = sdev_modctl_devexists(path);
2144 2145 }
2145 2146
2146 2147 kmem_free(path, pathlen + 1);
2147 2148 return (ret);
2148 2149 }
2149 2150
2150 2151 static int
2151 2152 modctl_devreaddir(const char *udir, int udirlen,
2152 2153 char *upaths, int64_t *ulensp)
2153 2154 {
2154 2155 char *paths = NULL;
2155 2156 char **dirlist = NULL;
2156 2157 char *dir;
2157 2158 int64_t ulens;
2158 2159 int64_t lens;
2159 2160 int i, n;
2160 2161 int ret = 0;
2161 2162 char *p;
2162 2163 int npaths;
2163 2164 int npaths_alloc;
2164 2165
2165 2166 /*
2166 2167 * If upaths is NULL then we are only computing the amount of space
2167 2168 * needed to return the paths, with the value returned in *ulensp. If we
2168 2169 * are copying out paths then we get the amount of space allocated by
2169 2170 * the caller. If the actual space needed for paths is larger, or
2170 2171 * things are changing out from under us, then we return EAGAIN.
2171 2172 */
2172 2173 if (upaths) {
2173 2174 if (ulensp == NULL)
2174 2175 return (EINVAL);
2175 2176 if (copyin(ulensp, &ulens, sizeof (ulens)) != 0)
2176 2177 return (EFAULT);
2177 2178 }
2178 2179
2179 2180 /*
2180 2181 * copyin the /dev path including terminating null
2181 2182 */
2182 2183 udirlen++;
2183 2184 if (udirlen <= 1 || udirlen > MAXPATHLEN)
2184 2185 return (EINVAL);
2185 2186 dir = kmem_zalloc(udirlen + 1, KM_SLEEP);
2186 2187 if ((ret = copyinstr(udir, dir, udirlen, NULL)) != 0)
2187 2188 goto err;
2188 2189
2189 2190 if ((ret = sdev_modctl_readdir(dir, &dirlist,
2190 2191 &npaths, &npaths_alloc, 0)) != 0) {
2191 2192 ASSERT(dirlist == NULL);
2192 2193 goto err;
2193 2194 }
2194 2195
2195 2196 lens = 0;
2196 2197 for (i = 0; i < npaths; i++) {
2197 2198 lens += strlen(dirlist[i]) + 1;
2198 2199 }
2199 2200 lens++; /* add one for double termination */
2200 2201
2201 2202 if (upaths) {
2202 2203 if (lens > ulens) {
2203 2204 ret = EAGAIN;
2204 2205 goto out;
2205 2206 }
2206 2207
2207 2208 paths = kmem_alloc(lens, KM_SLEEP);
2208 2209
2209 2210 p = paths;
2210 2211 for (i = 0; i < npaths; i++) {
2211 2212 n = strlen(dirlist[i]) + 1;
2212 2213 bcopy(dirlist[i], p, n);
2213 2214 p += n;
2214 2215 }
2215 2216 *p = 0;
2216 2217
2217 2218 if (copyout(paths, upaths, lens)) {
2218 2219 ret = EFAULT;
2219 2220 goto err;
2220 2221 }
2221 2222 }
2222 2223
2223 2224 out:
2224 2225 /* copy out the amount of space needed to hold the paths */
2225 2226 if (copyout(&lens, ulensp, sizeof (lens)))
2226 2227 ret = EFAULT;
2227 2228
2228 2229 err:
2229 2230 if (dirlist)
2230 2231 sdev_modctl_readdir_free(dirlist, npaths, npaths_alloc);
2231 2232 if (paths)
2232 2233 kmem_free(paths, lens);
2233 2234 kmem_free(dir, udirlen + 1);
2234 2235 return (ret);
2235 2236 }
2236 2237
2237 2238 static int
2238 2239 modctl_devemptydir(const char *udir, int udirlen, int *uempty)
2239 2240 {
2240 2241 char *dir;
2241 2242 int ret;
2242 2243 char **dirlist = NULL;
2243 2244 int npaths;
2244 2245 int npaths_alloc;
2245 2246 int empty;
2246 2247
2247 2248 /*
2248 2249 * copyin the /dev path including terminating null
2249 2250 */
2250 2251 udirlen++;
2251 2252 if (udirlen <= 1 || udirlen > MAXPATHLEN)
2252 2253 return (EINVAL);
2253 2254 dir = kmem_zalloc(udirlen + 1, KM_SLEEP);
2254 2255 if ((ret = copyinstr(udir, dir, udirlen, NULL)) != 0)
2255 2256 goto err;
2256 2257
2257 2258 if ((ret = sdev_modctl_readdir(dir, &dirlist,
2258 2259 &npaths, &npaths_alloc, 1)) != 0) {
2259 2260 goto err;
2260 2261 }
2261 2262
2262 2263 empty = npaths ? 0 : 1;
2263 2264 if (copyout(&empty, uempty, sizeof (empty)))
2264 2265 ret = EFAULT;
2265 2266
2266 2267 err:
2267 2268 if (dirlist)
2268 2269 sdev_modctl_readdir_free(dirlist, npaths, npaths_alloc);
2269 2270 kmem_free(dir, udirlen + 1);
2270 2271 return (ret);
2271 2272 }
2272 2273
2273 2274 static int
2274 2275 modctl_hp(int subcmd, const char *path, char *cn_name, uintptr_t arg,
2275 2276 uintptr_t rval)
2276 2277 {
2277 2278 int error = 0;
2278 2279 size_t pathsz, namesz;
2279 2280 char *devpath, *cn_name_str;
2280 2281
2281 2282 if (path == NULL)
2282 2283 return (EINVAL);
2283 2284
2284 2285 devpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
2285 2286 error = copyinstr(path, devpath, MAXPATHLEN, &pathsz);
2286 2287 if (error != 0) {
2287 2288 kmem_free(devpath, MAXPATHLEN);
2288 2289 return (EFAULT);
2289 2290 }
2290 2291
2291 2292 cn_name_str = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
2292 2293 error = copyinstr(cn_name, cn_name_str, MAXNAMELEN, &namesz);
2293 2294 if (error != 0) {
2294 2295 kmem_free(devpath, MAXPATHLEN);
2295 2296 kmem_free(cn_name_str, MAXNAMELEN);
2296 2297
2297 2298 return (EFAULT);
2298 2299 }
2299 2300
2300 2301 switch (subcmd) {
2301 2302 case MODHPOPS_CHANGE_STATE:
2302 2303 error = ddihp_modctl(DDI_HPOP_CN_CHANGE_STATE, devpath,
2303 2304 cn_name_str, arg, 0);
2304 2305 break;
2305 2306 case MODHPOPS_CREATE_PORT:
2306 2307 /* Create an empty PORT */
2307 2308 error = ddihp_modctl(DDI_HPOP_CN_CREATE_PORT, devpath,
2308 2309 cn_name_str, 0, 0);
2309 2310 break;
2310 2311 case MODHPOPS_REMOVE_PORT:
2311 2312 /* Remove an empty PORT */
2312 2313 error = ddihp_modctl(DDI_HPOP_CN_REMOVE_PORT, devpath,
2313 2314 cn_name_str, 0, 0);
2314 2315 break;
2315 2316 case MODHPOPS_BUS_GET:
2316 2317 error = ddihp_modctl(DDI_HPOP_CN_GET_PROPERTY, devpath,
2317 2318 cn_name_str, arg, rval);
2318 2319 break;
2319 2320 case MODHPOPS_BUS_SET:
2320 2321 error = ddihp_modctl(DDI_HPOP_CN_SET_PROPERTY, devpath,
2321 2322 cn_name_str, arg, rval);
2322 2323 break;
2323 2324 default:
2324 2325 error = ENOTSUP;
2325 2326 break;
2326 2327 }
2327 2328
2328 2329 kmem_free(devpath, MAXPATHLEN);
2329 2330 kmem_free(cn_name_str, MAXNAMELEN);
2330 2331
2331 2332 return (error);
2332 2333 }
2333 2334
2334 2335 int
2335 2336 modctl_moddevname(int subcmd, uintptr_t a1, uintptr_t a2)
2336 2337 {
2337 2338 int error = 0;
2338 2339
2339 2340 switch (subcmd) {
2340 2341 case MODDEVNAME_LOOKUPDOOR:
2341 2342 error = devname_filename_register((char *)a1);
2342 2343 break;
2343 2344 case MODDEVNAME_PROFILE:
2344 2345 error = devname_profile_update((char *)a1, (size_t)a2);
2345 2346 break;
2346 2347 case MODDEVNAME_RECONFIG:
2347 2348 i_ddi_set_reconfig();
2348 2349 break;
2349 2350 case MODDEVNAME_SYSAVAIL:
2350 2351 i_ddi_set_sysavail();
2351 2352 break;
2352 2353 default:
2353 2354 error = EINVAL;
2354 2355 break;
2355 2356 }
2356 2357
2357 2358 return (error);
2358 2359 }
2359 2360
2360 2361 /*ARGSUSED5*/
2361 2362 int
2362 2363 modctl(int cmd, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
2363 2364 uintptr_t a5)
2364 2365 {
2365 2366 int error = EINVAL;
2366 2367 dev_t dev;
2367 2368
2368 2369 if (secpolicy_modctl(CRED(), cmd) != 0)
2369 2370 return (set_errno(EPERM));
2370 2371
2371 2372 switch (cmd) {
2372 2373 case MODLOAD: /* load a module */
2373 2374 error = modctl_modload((int)a1, (char *)a2, (int *)a3);
2374 2375 break;
2375 2376
2376 2377 case MODUNLOAD: /* unload a module */
2377 2378 error = modctl_modunload((modid_t)a1);
2378 2379 break;
2379 2380
2380 2381 case MODINFO: /* get module status */
2381 2382 error = modctl_modinfo((modid_t)a1, (struct modinfo *)a2);
2382 2383 break;
2383 2384
2384 2385 case MODRESERVED: /* get last major number in range */
2385 2386 error = modctl_modreserve((modid_t)a1, (int *)a2);
2386 2387 break;
2387 2388
2388 2389 case MODSETMINIROOT: /* we are running in miniroot */
2389 2390 isminiroot = 1;
2390 2391 error = 0;
2391 2392 break;
2392 2393
2393 2394 case MODADDMAJBIND: /* add major / driver alias bindings */
2394 2395 error = modctl_add_driver_aliases((int *)a2);
2395 2396 break;
2396 2397
2397 2398 case MODGETPATHLEN: /* get modpath length */
2398 2399 error = modctl_getmodpathlen((int *)a2);
2399 2400 break;
2400 2401
2401 2402 case MODGETPATH: /* get modpath */
2402 2403 error = modctl_getmodpath((char *)a2);
2403 2404 break;
2404 2405
2405 2406 case MODREADSYSBIND: /* read system call binding file */
2406 2407 error = modctl_read_sysbinding_file();
2407 2408 break;
2408 2409
2409 2410 case MODGETMAJBIND: /* get major number for named device */
2410 2411 error = modctl_getmaj((char *)a1, (uint_t)a2, (int *)a3);
2411 2412 break;
2412 2413
2413 2414 case MODGETNAME: /* get name of device given major number */
2414 2415 error = modctl_getname((char *)a1, (uint_t)a2, (int *)a3);
2415 2416 break;
2416 2417
2417 2418 case MODDEVT2INSTANCE:
2418 2419 if (get_udatamodel() == DATAMODEL_NATIVE) {
2419 2420 dev = (dev_t)a1;
2420 2421 }
2421 2422 #ifdef _SYSCALL32_IMPL
2422 2423 else {
2423 2424 dev = expldev(a1);
2424 2425 }
2425 2426 #endif
2426 2427 error = modctl_devt2instance(dev, (int *)a2);
2427 2428 break;
2428 2429
2429 2430 case MODSIZEOF_DEVID: /* sizeof device id of device given dev_t */
2430 2431 if (get_udatamodel() == DATAMODEL_NATIVE) {
2431 2432 dev = (dev_t)a1;
2432 2433 }
2433 2434 #ifdef _SYSCALL32_IMPL
2434 2435 else {
2435 2436 dev = expldev(a1);
2436 2437 }
2437 2438 #endif
2438 2439 error = modctl_sizeof_devid(dev, (uint_t *)a2);
2439 2440 break;
2440 2441
2441 2442 case MODGETDEVID: /* get device id of device given dev_t */
2442 2443 if (get_udatamodel() == DATAMODEL_NATIVE) {
2443 2444 dev = (dev_t)a1;
2444 2445 }
2445 2446 #ifdef _SYSCALL32_IMPL
2446 2447 else {
2447 2448 dev = expldev(a1);
2448 2449 }
2449 2450 #endif
2450 2451 error = modctl_get_devid(dev, (uint_t)a2, (ddi_devid_t)a3);
2451 2452 break;
2452 2453
2453 2454 case MODSIZEOF_MINORNAME: /* sizeof minor nm (dev_t,spectype) */
2454 2455 if (get_udatamodel() == DATAMODEL_NATIVE) {
2455 2456 error = modctl_sizeof_minorname((dev_t)a1, (int)a2,
2456 2457 (uint_t *)a3);
2457 2458 }
2458 2459 #ifdef _SYSCALL32_IMPL
2459 2460 else {
2460 2461 error = modctl_sizeof_minorname(expldev(a1), (int)a2,
2461 2462 (uint_t *)a3);
2462 2463 }
2463 2464
2464 2465 #endif
2465 2466 break;
2466 2467
2467 2468 case MODGETMINORNAME: /* get minor name of (dev_t,spectype) */
2468 2469 if (get_udatamodel() == DATAMODEL_NATIVE) {
2469 2470 error = modctl_get_minorname((dev_t)a1, (int)a2,
2470 2471 (uint_t)a3, (char *)a4);
2471 2472 }
2472 2473 #ifdef _SYSCALL32_IMPL
2473 2474 else {
2474 2475 error = modctl_get_minorname(expldev(a1), (int)a2,
2475 2476 (uint_t)a3, (char *)a4);
2476 2477 }
2477 2478 #endif
2478 2479 break;
2479 2480
2480 2481 case MODGETDEVFSPATH_LEN: /* sizeof path nm of (dev_t,spectype) */
2481 2482 if (get_udatamodel() == DATAMODEL_NATIVE) {
2482 2483 error = modctl_devfspath_len((dev_t)a1, (int)a2,
2483 2484 (uint_t *)a3);
2484 2485 }
2485 2486 #ifdef _SYSCALL32_IMPL
2486 2487 else {
2487 2488 error = modctl_devfspath_len(expldev(a1), (int)a2,
2488 2489 (uint_t *)a3);
2489 2490 }
2490 2491
2491 2492 #endif
2492 2493 break;
2493 2494
2494 2495 case MODGETDEVFSPATH: /* get path name of (dev_t,spec) type */
2495 2496 if (get_udatamodel() == DATAMODEL_NATIVE) {
2496 2497 error = modctl_devfspath((dev_t)a1, (int)a2,
2497 2498 (uint_t)a3, (char *)a4);
2498 2499 }
2499 2500 #ifdef _SYSCALL32_IMPL
2500 2501 else {
2501 2502 error = modctl_devfspath(expldev(a1), (int)a2,
2502 2503 (uint_t)a3, (char *)a4);
2503 2504 }
2504 2505 #endif
2505 2506 break;
2506 2507
2507 2508 case MODGETDEVFSPATH_MI_LEN: /* sizeof path nm of (major,instance) */
2508 2509 error = modctl_devfspath_mi_len((major_t)a1, (int)a2,
2509 2510 (uint_t *)a3);
2510 2511 break;
2511 2512
2512 2513 case MODGETDEVFSPATH_MI: /* get path name of (major,instance) */
2513 2514 error = modctl_devfspath_mi((major_t)a1, (int)a2,
2514 2515 (uint_t)a3, (char *)a4);
2515 2516 break;
2516 2517
2517 2518
2518 2519 case MODEVENTS:
2519 2520 error = modctl_modevents((int)a1, a2, a3, a4, (uint_t)a5);
2520 2521 break;
2521 2522
2522 2523 case MODGETFBNAME: /* get the framebuffer name */
2523 2524 error = modctl_get_fbname((char *)a1);
2524 2525 break;
2525 2526
2526 2527 case MODREREADDACF: /* reread dacf rule database from given file */
2527 2528 error = modctl_reread_dacf((char *)a1);
2528 2529 break;
2529 2530
2530 2531 case MODLOADDRVCONF: /* load driver.conf file for major */
2531 2532 error = modctl_load_drvconf((major_t)a1, (int)a2);
2532 2533 break;
2533 2534
2534 2535 case MODUNLOADDRVCONF: /* unload driver.conf file for major */
2535 2536 error = modctl_unload_drvconf((major_t)a1);
2536 2537 break;
2537 2538
2538 2539 case MODREMMAJBIND: /* remove a major binding */
2539 2540 error = modctl_rem_major((major_t)a1);
2540 2541 break;
2541 2542
2542 2543 case MODREMDRVALIAS: /* remove a major/alias binding */
2543 2544 error = modctl_remove_driver_aliases((int *)a2);
2544 2545 break;
2545 2546
2546 2547 case MODDEVID2PATHS: /* get paths given devid */
2547 2548 error = modctl_devid2paths((ddi_devid_t)a1, (char *)a2,
2548 2549 (uint_t)a3, (size_t *)a4, (char *)a5);
2549 2550 break;
2550 2551
2551 2552 case MODSETDEVPOLICY: /* establish device policy */
2552 2553 error = devpolicy_load((int)a1, (size_t)a2, (devplcysys_t *)a3);
2553 2554 break;
2554 2555
2555 2556 case MODGETDEVPOLICY: /* get device policy */
2556 2557 error = devpolicy_get((int *)a1, (size_t)a2,
2557 2558 (devplcysys_t *)a3);
2558 2559 break;
2559 2560
2560 2561 case MODALLOCPRIV:
2561 2562 error = modctl_allocpriv((const char *)a1);
2562 2563 break;
2563 2564
2564 2565 case MODGETDEVPOLICYBYNAME:
2565 2566 error = devpolicy_getbyname((size_t)a1,
2566 2567 (devplcysys_t *)a2, (char *)a3);
2567 2568 break;
2568 2569
2569 2570 case MODLOADMINORPERM:
2570 2571 case MODADDMINORPERM:
2571 2572 case MODREMMINORPERM:
2572 2573 error = modctl_minorperm(cmd, (char *)a1, (size_t)a2);
2573 2574 break;
2574 2575
2575 2576 case MODREMDRVCLEANUP:
2576 2577 error = modctl_remdrv_cleanup((const char *)a1);
2577 2578 break;
2578 2579
2579 2580 case MODDEVEXISTS: /* non-reconfiguring /dev lookup */
2580 2581 error = modctl_devexists((const char *)a1, (size_t)a2);
2581 2582 break;
2582 2583
2583 2584 case MODDEVREADDIR: /* non-reconfiguring /dev readdir */
2584 2585 error = modctl_devreaddir((const char *)a1, (size_t)a2,
2585 2586 (char *)a3, (int64_t *)a4);
2586 2587 break;
2587 2588
2588 2589 case MODDEVEMPTYDIR: /* non-reconfiguring /dev emptydir */
2589 2590 error = modctl_devemptydir((const char *)a1, (size_t)a2,
2590 2591 (int *)a3);
2591 2592 break;
2592 2593
2593 2594 case MODDEVNAME:
2594 2595 error = modctl_moddevname((int)a1, a2, a3);
2595 2596 break;
2596 2597
2597 2598 case MODRETIRE: /* retire device named by physpath a1 */
2598 2599 error = modctl_retire((char *)a1, (char *)a2, (size_t)a3);
2599 2600 break;
2600 2601
2601 2602 case MODISRETIRED: /* check if a device is retired. */
2602 2603 error = modctl_is_retired((char *)a1, (int *)a2);
2603 2604 break;
2604 2605
2605 2606 case MODUNRETIRE: /* unretire device named by physpath a1 */
2606 2607 error = modctl_unretire((char *)a1);
2607 2608 break;
2608 2609
2609 2610 case MODHPOPS: /* hotplug operations */
2610 2611 /* device named by physpath a2 and Connection name a3 */
2611 2612 error = modctl_hp((int)a1, (char *)a2, (char *)a3, a4, a5);
2612 2613 break;
2613 2614
2614 2615 default:
2615 2616 error = EINVAL;
2616 2617 break;
2617 2618 }
2618 2619
2619 2620 return (error ? set_errno(error) : 0);
2620 2621 }
2621 2622
2622 2623 /*
2623 2624 * Calls to kobj_load_module()() are handled off to this routine in a
2624 2625 * separate thread.
2625 2626 */
2626 2627 static void
2627 2628 modload_thread(struct loadmt *ltp)
2628 2629 {
2629 2630 /* load the module and signal the creator of this thread */
2630 2631 kmutex_t cpr_lk;
2631 2632 callb_cpr_t cpr_i;
2632 2633
2633 2634 mutex_init(&cpr_lk, NULL, MUTEX_DEFAULT, NULL);
2634 2635 CALLB_CPR_INIT(&cpr_i, &cpr_lk, callb_generic_cpr, "modload");
2635 2636 /* borrow the devi lock from thread which invoked us */
2636 2637 pm_borrow_lock(ltp->owner);
2637 2638 ltp->retval = kobj_load_module(ltp->mp, ltp->usepath);
2638 2639 pm_return_lock();
2639 2640 sema_v(<p->sema);
2640 2641 mutex_enter(&cpr_lk);
2641 2642 CALLB_CPR_EXIT(&cpr_i);
2642 2643 mutex_destroy(&cpr_lk);
2643 2644 thread_exit();
2644 2645 }
2645 2646
2646 2647 /*
2647 2648 * load a module, adding a reference if caller specifies rmodp. If rmodp
2648 2649 * is specified then an errno is returned, otherwise a module index is
2649 2650 * returned (-1 on error).
2650 2651 */
2651 2652 static int
2652 2653 modrload(const char *subdir, const char *filename, struct modctl **rmodp)
2653 2654 {
2654 2655 struct modctl *modp;
2655 2656 size_t size;
2656 2657 char *fullname;
2657 2658 int retval = EINVAL;
2658 2659 int id = -1;
2659 2660
2660 2661 if (rmodp)
2661 2662 *rmodp = NULL; /* avoid garbage */
2662 2663
2663 2664 if (subdir != NULL) {
2664 2665 /*
2665 2666 * refuse / in filename to prevent "../" escapes.
2666 2667 */
2667 2668 if (strchr(filename, '/') != NULL)
2668 2669 return (rmodp ? retval : id);
2669 2670
2670 2671 /*
2671 2672 * allocate enough space for <subdir>/<filename><NULL>
2672 2673 */
2673 2674 size = strlen(subdir) + strlen(filename) + 2;
2674 2675 fullname = kmem_zalloc(size, KM_SLEEP);
2675 2676 (void) sprintf(fullname, "%s/%s", subdir, filename);
2676 2677 } else {
2677 2678 fullname = (char *)filename;
2678 2679 }
2679 2680
2680 2681 modp = mod_hold_installed_mod(fullname, 1, 0, &retval);
2681 2682 if (modp != NULL) {
2682 2683 id = modp->mod_id;
2683 2684 if (rmodp) {
2684 2685 /* add mod_ref and return *rmodp */
2685 2686 mutex_enter(&mod_lock);
2686 2687 modp->mod_ref++;
2687 2688 mutex_exit(&mod_lock);
2688 2689 *rmodp = modp;
2689 2690 }
2690 2691 mod_release_mod(modp);
2691 2692 CPU_STATS_ADDQ(CPU, sys, modload, 1);
2692 2693 }
2693 2694
2694 2695 done: if (subdir != NULL)
2695 2696 kmem_free(fullname, size);
2696 2697 return (rmodp ? retval : id);
2697 2698 }
2698 2699
2699 2700 /*
2700 2701 * This is the primary kernel interface to load a module. It loads and
2701 2702 * installs the named module. It does not hold mod_ref of the module, so
2702 2703 * a module unload attempt can occur at any time - it is up to the
2703 2704 * _fini/mod_remove implementation to determine if unload will succeed.
2704 2705 */
2705 2706 int
2706 2707 modload(const char *subdir, const char *filename)
2707 2708 {
2708 2709 return (modrload(subdir, filename, NULL));
2709 2710 }
2710 2711
2711 2712 /*
2712 2713 * Load a module using a series of qualified names from most specific to least
2713 2714 * specific, e.g. for subdir "foo", p1 "bar", p2 "baz", we might try:
2714 2715 * Value returned in *chosen
2715 2716 * foo/bar.baz.1.2.3 3
2716 2717 * foo/bar.baz.1.2 2
2717 2718 * foo/bar.baz.1 1
2718 2719 * foo/bar.baz 0
2719 2720 *
2720 2721 * Return the module ID on success; -1 if no module was loaded. On success
2721 2722 * and if 'chosen' is not NULL we also return the number of suffices that
2722 2723 * were in the module we chose to load.
2723 2724 */
2724 2725 int
2725 2726 modload_qualified(const char *subdir, const char *p1,
2726 2727 const char *p2, const char *delim, uint_t suffv[], int suffc, int *chosen)
2727 2728 {
2728 2729 char path[MOD_MAXPATH];
2729 2730 size_t n, resid = sizeof (path);
2730 2731 char *p = path;
2731 2732
2732 2733 char **dotv;
2733 2734 int i, rc, id;
2734 2735 modctl_t *mp;
2735 2736
2736 2737 if (p2 != NULL)
2737 2738 n = snprintf(p, resid, "%s/%s%s%s", subdir, p1, delim, p2);
2738 2739 else
2739 2740 n = snprintf(p, resid, "%s/%s", subdir, p1);
2740 2741
2741 2742 if (n >= resid)
2742 2743 return (-1);
2743 2744
2744 2745 p += n;
2745 2746 resid -= n;
2746 2747 dotv = kmem_alloc(sizeof (char *) * (suffc + 1), KM_SLEEP);
2747 2748
2748 2749 for (i = 0; i < suffc; i++) {
2749 2750 dotv[i] = p;
2750 2751 n = snprintf(p, resid, "%s%u", delim, suffv[i]);
2751 2752
2752 2753 if (n >= resid) {
2753 2754 kmem_free(dotv, sizeof (char *) * (suffc + 1));
2754 2755 return (-1);
2755 2756 }
2756 2757
2757 2758 p += n;
2758 2759 resid -= n;
2759 2760 }
2760 2761
2761 2762 dotv[suffc] = p;
2762 2763
2763 2764 for (i = suffc; i >= 0; i--) {
2764 2765 dotv[i][0] = '\0';
2765 2766 mp = mod_hold_installed_mod(path, 1, 1, &rc);
2766 2767
2767 2768 if (mp != NULL) {
2768 2769 kmem_free(dotv, sizeof (char *) * (suffc + 1));
2769 2770 id = mp->mod_id;
2770 2771 mod_release_mod(mp);
2771 2772 if (chosen != NULL)
2772 2773 *chosen = i;
2773 2774 return (id);
2774 2775 }
2775 2776 }
2776 2777
2777 2778 kmem_free(dotv, sizeof (char *) * (suffc + 1));
2778 2779 return (-1);
2779 2780 }
2780 2781
2781 2782 /*
2782 2783 * Load a module.
2783 2784 */
2784 2785 int
2785 2786 modloadonly(const char *subdir, const char *filename)
2786 2787 {
2787 2788 struct modctl *modp;
2788 2789 char *fullname;
2789 2790 size_t size;
2790 2791 int id, retval;
2791 2792
2792 2793 if (subdir != NULL) {
2793 2794 /*
2794 2795 * allocate enough space for <subdir>/<filename><NULL>
2795 2796 */
2796 2797 size = strlen(subdir) + strlen(filename) + 2;
2797 2798 fullname = kmem_zalloc(size, KM_SLEEP);
2798 2799 (void) sprintf(fullname, "%s/%s", subdir, filename);
2799 2800 } else {
2800 2801 fullname = (char *)filename;
2801 2802 }
2802 2803
2803 2804 modp = mod_hold_loaded_mod(NULL, fullname, &retval);
2804 2805 if (modp) {
2805 2806 id = modp->mod_id;
2806 2807 mod_release_mod(modp);
2807 2808 }
2808 2809
2809 2810 if (subdir != NULL)
2810 2811 kmem_free(fullname, size);
2811 2812
2812 2813 if (retval == 0)
2813 2814 return (id);
2814 2815 return (-1);
2815 2816 }
2816 2817
2817 2818 /*
2818 2819 * Try to uninstall and unload a module, removing a reference if caller
2819 2820 * specifies rmodp.
2820 2821 */
2821 2822 static int
2822 2823 modunrload(modid_t id, struct modctl **rmodp, int unload)
2823 2824 {
2824 2825 struct modctl *modp;
2825 2826 int retval;
2826 2827
2827 2828 if (rmodp)
2828 2829 *rmodp = NULL; /* avoid garbage */
2829 2830
2830 2831 if ((modp = mod_hold_by_id((modid_t)id)) == NULL)
2831 2832 return (EINVAL);
2832 2833
2833 2834 if (rmodp) {
2834 2835 mutex_enter(&mod_lock);
2835 2836 modp->mod_ref--;
2836 2837 if (modp->mod_ref == 0)
2837 2838 mod_uninstall_ref_zero++;
2838 2839 mutex_exit(&mod_lock);
2839 2840 *rmodp = modp;
2840 2841 }
2841 2842
2842 2843 if (unload) {
2843 2844 retval = moduninstall(modp);
2844 2845 if (retval == 0) {
2845 2846 mod_unload(modp);
2846 2847 CPU_STATS_ADDQ(CPU, sys, modunload, 1);
2847 2848 } else if (retval == EALREADY)
2848 2849 retval = 0; /* already unloaded, not an error */
2849 2850 } else
2850 2851 retval = 0;
2851 2852
2852 2853 mod_release_mod(modp);
2853 2854 return (retval);
2854 2855 }
2855 2856
2856 2857 /*
2857 2858 * Uninstall and unload a module.
2858 2859 */
2859 2860 int
2860 2861 modunload(modid_t id)
2861 2862 {
2862 2863 int retval;
2863 2864
2864 2865 /* synchronize with any active modunload_disable() */
2865 2866 modunload_begin();
2866 2867 if (ddi_root_node())
2867 2868 (void) devfs_clean(ddi_root_node(), NULL, 0);
2868 2869 retval = modunrload(id, NULL, 1);
2869 2870 modunload_end();
2870 2871 return (retval);
2871 2872 }
2872 2873
2873 2874 /*
2874 2875 * Return status of a loaded module.
2875 2876 */
2876 2877 static int
2877 2878 modinfo(modid_t id, struct modinfo *modinfop)
2878 2879 {
2879 2880 struct modctl *modp;
2880 2881 modid_t mid;
2881 2882 int i;
2882 2883
2883 2884 mid = modinfop->mi_id;
2884 2885 if (modinfop->mi_info & MI_INFO_ALL) {
2885 2886 while ((modp = mod_hold_next_by_id(mid++)) != NULL) {
2886 2887 if ((modinfop->mi_info & MI_INFO_CNT) ||
2887 2888 modp->mod_installed)
2888 2889 break;
2889 2890 mod_release_mod(modp);
2890 2891 }
2891 2892 if (modp == NULL)
2892 2893 return (EINVAL);
2893 2894 } else {
2894 2895 modp = mod_hold_by_id(id);
2895 2896 if (modp == NULL)
2896 2897 return (EINVAL);
2897 2898 if (!(modinfop->mi_info & MI_INFO_CNT) &&
2898 2899 (modp->mod_installed == 0)) {
2899 2900 mod_release_mod(modp);
2900 2901 return (EINVAL);
2901 2902 }
2902 2903 }
2903 2904
2904 2905 modinfop->mi_rev = 0;
2905 2906 modinfop->mi_state = 0;
2906 2907 for (i = 0; i < MODMAXLINK; i++) {
2907 2908 modinfop->mi_msinfo[i].msi_p0 = -1;
2908 2909 modinfop->mi_msinfo[i].msi_linkinfo[0] = 0;
2909 2910 }
2910 2911 if (modp->mod_loaded) {
2911 2912 modinfop->mi_state = MI_LOADED;
2912 2913 kobj_getmodinfo(modp->mod_mp, modinfop);
2913 2914 }
2914 2915 if (modp->mod_installed) {
2915 2916 modinfop->mi_state |= MI_INSTALLED;
2916 2917
2917 2918 (void) mod_getinfo(modp, modinfop);
2918 2919 }
2919 2920
2920 2921 modinfop->mi_id = modp->mod_id;
2921 2922 modinfop->mi_loadcnt = modp->mod_loadcnt;
2922 2923 (void) strcpy(modinfop->mi_name, modp->mod_modname);
2923 2924
2924 2925 mod_release_mod(modp);
2925 2926 return (0);
2926 2927 }
2927 2928
2928 2929 static char mod_stub_err[] = "mod_hold_stub: Couldn't load stub module %s";
2929 2930 static char no_err[] = "No error function for weak stub %s";
2930 2931
2931 2932 /*
2932 2933 * used by the stubs themselves to load and hold a module.
2933 2934 * Returns 0 if the module is successfully held;
2934 2935 * the stub needs to call mod_release_stub().
2935 2936 * -1 if the stub should just call the err_fcn.
2936 2937 * Note that this code is stretched out so that we avoid subroutine calls
2937 2938 * and optimize for the most likely case. That is, the case where the
2938 2939 * module is loaded and installed and not held. In that case we just inc
2939 2940 * the mod_ref count and continue.
2940 2941 */
2941 2942 int
2942 2943 mod_hold_stub(struct mod_stub_info *stub)
2943 2944 {
2944 2945 struct modctl *mp;
2945 2946 struct mod_modinfo *mip;
2946 2947
2947 2948 mip = stub->mods_modinfo;
2948 2949
2949 2950 mutex_enter(&mod_lock);
2950 2951
2951 2952 /* we do mod_hold_by_modctl inline for speed */
2952 2953
2953 2954 mod_check_again:
2954 2955 if ((mp = mip->mp) != NULL) {
2955 2956 if (mp->mod_busy == 0) {
2956 2957 if (mp->mod_installed) {
2957 2958 /* increment the reference count */
2958 2959 mp->mod_ref++;
2959 2960 ASSERT(mp->mod_ref && mp->mod_installed);
2960 2961 mutex_exit(&mod_lock);
2961 2962 return (0);
2962 2963 } else {
2963 2964 mp->mod_busy = 1;
2964 2965 mp->mod_inprogress_thread =
2965 2966 (curthread == NULL ?
2966 2967 (kthread_id_t)-1 : curthread);
2967 2968 }
2968 2969 } else {
2969 2970 /*
2970 2971 * wait one time and then go see if someone
2971 2972 * else has resolved the stub (set mip->mp).
2972 2973 */
2973 2974 if (mod_hold_by_modctl(mp,
2974 2975 MOD_WAIT_ONCE | MOD_LOCK_HELD))
2975 2976 goto mod_check_again;
2976 2977
2977 2978 /*
2978 2979 * what we have now may have been unloaded!, in
2979 2980 * that case, mip->mp will be NULL, we'll hit this
2980 2981 * module and load again..
2981 2982 */
2982 2983 cmn_err(CE_PANIC, "mod_hold_stub should have blocked");
2983 2984 }
2984 2985 mutex_exit(&mod_lock);
2985 2986 } else {
2986 2987 /* first time we've hit this module */
2987 2988 mutex_exit(&mod_lock);
2988 2989 mp = mod_hold_by_name(mip->modm_module_name);
2989 2990 mip->mp = mp;
2990 2991 }
2991 2992
2992 2993 /*
2993 2994 * If we are here, it means that the following conditions
2994 2995 * are satisfied.
2995 2996 *
2996 2997 * mip->mp != NULL
2997 2998 * this thread has set the mp->mod_busy = 1
2998 2999 * mp->mod_installed = 0
2999 3000 *
3000 3001 */
3001 3002 ASSERT(mp != NULL);
3002 3003 ASSERT(mp->mod_busy == 1);
3003 3004
3004 3005 if (mp->mod_installed == 0) {
3005 3006 /* Module not loaded, if weak stub don't load it */
3006 3007 if (stub->mods_flag & MODS_WEAK) {
3007 3008 if (stub->mods_errfcn == NULL) {
3008 3009 mod_release_mod(mp);
3009 3010 cmn_err(CE_PANIC, no_err,
3010 3011 mip->modm_module_name);
3011 3012 }
3012 3013 } else {
3013 3014 /* Not a weak stub so load the module */
3014 3015
3015 3016 if (mod_load(mp, 1) != 0 || modinstall(mp) != 0) {
3016 3017 /*
3017 3018 * If mod_load() was successful
3018 3019 * and modinstall() failed, then
3019 3020 * unload the module.
3020 3021 */
3021 3022 if (mp->mod_loaded)
3022 3023 mod_unload(mp);
3023 3024
3024 3025 mod_release_mod(mp);
3025 3026 if (stub->mods_errfcn == NULL) {
3026 3027 cmn_err(CE_PANIC, mod_stub_err,
3027 3028 mip->modm_module_name);
3028 3029 } else {
3029 3030 return (-1);
3030 3031 }
3031 3032 }
3032 3033 }
3033 3034 }
3034 3035
3035 3036 /*
3036 3037 * At this point module is held and loaded. Release
3037 3038 * the mod_busy and mod_inprogress_thread before
3038 3039 * returning. We actually call mod_release() here so
3039 3040 * that if another stub wants to access this module,
3040 3041 * it can do so. mod_ref is incremented before mod_release()
3041 3042 * is called to prevent someone else from snatching the
3042 3043 * module from this thread.
3043 3044 */
3044 3045 mutex_enter(&mod_lock);
3045 3046 mp->mod_ref++;
3046 3047 ASSERT(mp->mod_ref &&
3047 3048 (mp->mod_loaded || (stub->mods_flag & MODS_WEAK)));
3048 3049 mod_release(mp);
3049 3050 mutex_exit(&mod_lock);
3050 3051 return (0);
3051 3052 }
3052 3053
3053 3054 void
3054 3055 mod_release_stub(struct mod_stub_info *stub)
3055 3056 {
3056 3057 struct modctl *mp = stub->mods_modinfo->mp;
3057 3058
3058 3059 /* inline mod_release_mod */
3059 3060 mutex_enter(&mod_lock);
3060 3061 ASSERT(mp->mod_ref &&
3061 3062 (mp->mod_loaded || (stub->mods_flag & MODS_WEAK)));
3062 3063 mp->mod_ref--;
3063 3064 if (mp->mod_ref == 0)
3064 3065 mod_uninstall_ref_zero++;
3065 3066 if (mp->mod_want) {
3066 3067 mp->mod_want = 0;
3067 3068 cv_broadcast(&mod_cv);
3068 3069 }
3069 3070 mutex_exit(&mod_lock);
3070 3071 }
3071 3072
3072 3073 static struct modctl *
3073 3074 mod_hold_loaded_mod(struct modctl *dep, char *filename, int *status)
3074 3075 {
3075 3076 struct modctl *modp;
3076 3077 int retval;
3077 3078
3078 3079 /*
3079 3080 * Hold the module.
3080 3081 */
3081 3082 modp = mod_hold_by_name_requisite(dep, filename);
3082 3083 if (modp) {
3083 3084 retval = mod_load(modp, 1);
3084 3085 if (retval != 0) {
3085 3086 mod_release_mod(modp);
3086 3087 modp = NULL;
3087 3088 }
3088 3089 *status = retval;
3089 3090 } else {
3090 3091 *status = ENOSPC;
3091 3092 }
3092 3093
3093 3094 /*
3094 3095 * if dep is not NULL, clear the module dependency information.
3095 3096 * This information is set in mod_hold_by_name_common().
3096 3097 */
3097 3098 if (dep != NULL && dep->mod_requisite_loading != NULL) {
3098 3099 ASSERT(dep->mod_busy);
3099 3100 dep->mod_requisite_loading = NULL;
3100 3101 }
3101 3102
3102 3103 return (modp);
3103 3104 }
3104 3105
3105 3106 /*
3106 3107 * hold, load, and install the named module
3107 3108 */
3108 3109 static struct modctl *
3109 3110 mod_hold_installed_mod(char *name, int usepath, int forcecheck, int *r)
3110 3111 {
3111 3112 struct modctl *modp;
3112 3113 int retval;
3113 3114
3114 3115 /*
3115 3116 * Verify that that module in question actually exists on disk
3116 3117 * before allocation of module structure by mod_hold_by_name.
3117 3118 */
3118 3119 if (modrootloaded && swaploaded || forcecheck) {
3119 3120 if (!kobj_path_exists(name, usepath)) {
3120 3121 *r = ENOENT;
3121 3122 return (NULL);
3122 3123 }
3123 3124 }
3124 3125
3125 3126 /*
3126 3127 * Hold the module.
3127 3128 */
3128 3129 modp = mod_hold_by_name(name);
3129 3130 if (modp) {
3130 3131 retval = mod_load(modp, usepath);
3131 3132 if (retval != 0) {
3132 3133 mod_release_mod(modp);
3133 3134 modp = NULL;
3134 3135 *r = retval;
3135 3136 } else {
3136 3137 if ((*r = modinstall(modp)) != 0) {
3137 3138 /*
3138 3139 * We loaded it, but failed to _init() it.
3139 3140 * Be kind to developers -- force it
3140 3141 * out of memory now so that the next
3141 3142 * attempt to use the module will cause
3142 3143 * a reload. See 1093793.
3143 3144 */
3144 3145 mod_unload(modp);
3145 3146 mod_release_mod(modp);
3146 3147 modp = NULL;
3147 3148 }
3148 3149 }
3149 3150 } else {
3150 3151 *r = ENOSPC;
3151 3152 }
3152 3153 return (modp);
3153 3154 }
3154 3155
3155 3156 static char mod_excl_msg[] =
3156 3157 "module %s(%s) is EXCLUDED and will not be loaded\n";
3157 3158 static char mod_init_msg[] = "loadmodule:%s(%s): _init() error %d\n";
3158 3159
3159 3160 /*
3160 3161 * This routine is needed for dependencies. Users specify dependencies
3161 3162 * by declaring a character array initialized to filenames of dependents.
3162 3163 * So the code that handles dependents deals with filenames (and not
3163 3164 * module names) because that's all it has. We load by filename and once
3164 3165 * we've loaded a file we can get the module name.
3165 3166 * Unfortunately there isn't a single unified filename/modulename namespace.
3166 3167 * C'est la vie.
3167 3168 *
3168 3169 * We allow the name being looked up to be prepended by an optional
3169 3170 * subdirectory e.g. we can lookup (NULL, "fs/ufs") or ("fs", "ufs")
3170 3171 */
3171 3172 struct modctl *
3172 3173 mod_find_by_filename(char *subdir, char *filename)
3173 3174 {
3174 3175 struct modctl *mp;
3175 3176 size_t sublen;
3176 3177
3177 3178 ASSERT(!MUTEX_HELD(&mod_lock));
3178 3179 if (subdir != NULL)
3179 3180 sublen = strlen(subdir);
3180 3181 else
3181 3182 sublen = 0;
3182 3183
3183 3184 mutex_enter(&mod_lock);
3184 3185 mp = &modules;
3185 3186 do {
3186 3187 if (sublen) {
3187 3188 char *mod_filename = mp->mod_filename;
3188 3189
3189 3190 if (strncmp(subdir, mod_filename, sublen) == 0 &&
3190 3191 mod_filename[sublen] == '/' &&
3191 3192 strcmp(filename, &mod_filename[sublen + 1]) == 0) {
3192 3193 mutex_exit(&mod_lock);
3193 3194 return (mp);
3194 3195 }
3195 3196 } else if (strcmp(filename, mp->mod_filename) == 0) {
3196 3197 mutex_exit(&mod_lock);
3197 3198 return (mp);
3198 3199 }
3199 3200 } while ((mp = mp->mod_next) != &modules);
3200 3201 mutex_exit(&mod_lock);
3201 3202 return (NULL);
3202 3203 }
3203 3204
3204 3205 /*
3205 3206 * Check for circular dependencies. This is called from do_dependents()
3206 3207 * in kobj.c. If we are the thread already loading this module, then
3207 3208 * we're trying to load a dependent that we're already loading which
3208 3209 * means the user specified circular dependencies.
3209 3210 */
3210 3211 static int
3211 3212 mod_circdep(struct modctl *modp)
3212 3213 {
3213 3214 struct modctl *rmod;
3214 3215
3215 3216 ASSERT(MUTEX_HELD(&mod_lock));
3216 3217
3217 3218 /*
3218 3219 * Check the mod_inprogress_thread first.
3219 3220 * mod_inprogress_thread is used in mod_hold_stub()
3220 3221 * directly to improve performance.
3221 3222 */
3222 3223 if (modp->mod_inprogress_thread == curthread)
3223 3224 return (1);
3224 3225
3225 3226 /*
3226 3227 * Check the module circular dependencies.
3227 3228 */
3228 3229 for (rmod = modp; rmod != NULL; rmod = rmod->mod_requisite_loading) {
3229 3230 /*
3230 3231 * Check if there is a module circular dependency.
3231 3232 */
3232 3233 if (rmod->mod_requisite_loading == modp)
3233 3234 return (1);
3234 3235 }
3235 3236 return (0);
3236 3237 }
3237 3238
3238 3239 static int
3239 3240 mod_getinfo(struct modctl *modp, struct modinfo *modinfop)
3240 3241 {
3241 3242 int (*func)(struct modinfo *);
3242 3243 int retval;
3243 3244
3244 3245 ASSERT(modp->mod_busy);
3245 3246
3246 3247 /* primary modules don't do getinfo */
3247 3248 if (modp->mod_prim)
3248 3249 return (0);
3249 3250
3250 3251 func = (int (*)(struct modinfo *))kobj_lookup(modp->mod_mp, "_info");
3251 3252
3252 3253 if (kobj_addrcheck(modp->mod_mp, (caddr_t)func)) {
3253 3254 cmn_err(CE_WARN, "_info() not defined properly in %s",
3254 3255 modp->mod_filename);
3255 3256 /*
3256 3257 * The semantics of mod_info(9F) are that 0 is failure
3257 3258 * and non-zero is success.
3258 3259 */
3259 3260 retval = 0;
3260 3261 } else
3261 3262 retval = (*func)(modinfop); /* call _info() function */
3262 3263
3263 3264 if (moddebug & MODDEBUG_USERDEBUG)
3264 3265 printf("Returned from _info, retval = %x\n", retval);
3265 3266
3266 3267 return (retval);
3267 3268 }
3268 3269
3269 3270 static void
3270 3271 modadd(struct modctl *mp)
3271 3272 {
3272 3273 ASSERT(MUTEX_HELD(&mod_lock));
3273 3274
3274 3275 mp->mod_id = last_module_id++;
3275 3276 mp->mod_next = &modules;
3276 3277 mp->mod_prev = modules.mod_prev;
3277 3278 modules.mod_prev->mod_next = mp;
3278 3279 modules.mod_prev = mp;
3279 3280 }
3280 3281
3281 3282 /*ARGSUSED*/
3282 3283 static struct modctl *
3283 3284 allocate_modp(const char *filename, const char *modname)
3284 3285 {
3285 3286 struct modctl *mp;
3286 3287
3287 3288 mp = kobj_zalloc(sizeof (*mp), KM_SLEEP);
3288 3289 mp->mod_modname = kobj_zalloc(strlen(modname) + 1, KM_SLEEP);
3289 3290 (void) strcpy(mp->mod_modname, modname);
3290 3291 return (mp);
3291 3292 }
3292 3293
3293 3294 /*
3294 3295 * Get the value of a symbol. This is a wrapper routine that
3295 3296 * calls kobj_getsymvalue(). kobj_getsymvalue() may go away but this
3296 3297 * wrapper will prevent callers from noticing.
3297 3298 */
3298 3299 uintptr_t
3299 3300 modgetsymvalue(char *name, int kernelonly)
3300 3301 {
3301 3302 return (kobj_getsymvalue(name, kernelonly));
3302 3303 }
3303 3304
3304 3305 /*
3305 3306 * Get the symbol nearest an address. This is a wrapper routine that
3306 3307 * calls kobj_getsymname(). kobj_getsymname() may go away but this
3307 3308 * wrapper will prevent callers from noticing.
3308 3309 */
3309 3310 char *
3310 3311 modgetsymname(uintptr_t value, ulong_t *offset)
3311 3312 {
3312 3313 return (kobj_getsymname(value, offset));
3313 3314 }
3314 3315
3315 3316 /*
3316 3317 * Lookup a symbol in a specified module. These are wrapper routines that
3317 3318 * call kobj_lookup(). kobj_lookup() may go away but these wrappers will
3318 3319 * prevent callers from noticing.
3319 3320 */
3320 3321 uintptr_t
3321 3322 modlookup(const char *modname, const char *symname)
3322 3323 {
3323 3324 struct modctl *modp;
3324 3325 uintptr_t val;
3325 3326
3326 3327 if ((modp = mod_hold_by_name(modname)) == NULL)
3327 3328 return (0);
3328 3329 val = kobj_lookup(modp->mod_mp, symname);
3329 3330 mod_release_mod(modp);
3330 3331 return (val);
3331 3332 }
3332 3333
3333 3334 uintptr_t
3334 3335 modlookup_by_modctl(modctl_t *modp, const char *symname)
3335 3336 {
3336 3337 ASSERT(modp->mod_ref > 0 || modp->mod_busy);
3337 3338
3338 3339 return (kobj_lookup(modp->mod_mp, symname));
3339 3340 }
3340 3341
3341 3342 /*
3342 3343 * Ask the user for the name of the system file and the default path
3343 3344 * for modules.
3344 3345 */
3345 3346 void
3346 3347 mod_askparams()
3347 3348 {
3348 3349 static char s0[64];
3349 3350 intptr_t fd;
3350 3351
3351 3352 if ((fd = kobj_open(systemfile)) != -1L)
3352 3353 kobj_close(fd);
3353 3354 else
3354 3355 systemfile = self_assembly = NULL;
3355 3356
3356 3357 /*CONSTANTCONDITION*/
3357 3358 while (1) {
3358 3359 printf("Name of system file [%s]: ",
3359 3360 systemfile ? systemfile : "/dev/null");
3360 3361
3361 3362 console_gets(s0, sizeof (s0));
3362 3363
3363 3364 if (s0[0] == '\0')
3364 3365 break;
3365 3366 else if (strcmp(s0, "/dev/null") == 0) {
3366 3367 systemfile = self_assembly = NULL;
3367 3368 break;
3368 3369 } else {
3369 3370 if ((fd = kobj_open(s0)) != -1L) {
3370 3371 kobj_close(fd);
3371 3372 systemfile = s0;
3372 3373 self_assembly = NULL;
3373 3374 break;
3374 3375 }
3375 3376 }
3376 3377 printf("can't find file %s\n", s0);
3377 3378 }
3378 3379 }
3379 3380
3380 3381 static char loading_msg[] = "loading '%s' id %d\n";
3381 3382 static char load_msg[] = "load '%s' id %d loaded @ 0x%p/0x%p size %d/%d\n";
3382 3383
3383 3384 /*
3384 3385 * Common code for loading a module (but not installing it).
3385 3386 * Handoff the task of module loading to a separate thread
3386 3387 * with a large stack if possible, since this code may recurse a few times.
3387 3388 * Return zero if there are no errors or an errno value.
3388 3389 */
3389 3390 static int
3390 3391 mod_load(struct modctl *mp, int usepath)
3391 3392 {
3392 3393 int retval;
3393 3394 struct modinfo *modinfop = NULL;
3394 3395 struct loadmt lt;
3395 3396
3396 3397 ASSERT(MUTEX_NOT_HELD(&mod_lock));
3397 3398 ASSERT(mp->mod_busy);
3398 3399
3399 3400 if (mp->mod_loaded)
3400 3401 return (0);
3401 3402
3402 3403 if (mod_sysctl(SYS_CHECK_EXCLUDE, mp->mod_modname) != 0 ||
3403 3404 mod_sysctl(SYS_CHECK_EXCLUDE, mp->mod_filename) != 0) {
3404 3405 if (moddebug & MODDEBUG_LOADMSG) {
3405 3406 printf(mod_excl_msg, mp->mod_filename,
3406 3407 mp->mod_modname);
3407 3408 }
3408 3409 return (ENXIO);
3409 3410 }
3410 3411 if (moddebug & MODDEBUG_LOADMSG2)
3411 3412 printf(loading_msg, mp->mod_filename, mp->mod_id);
3412 3413
3413 3414 if (curthread != &t0) {
3414 3415 lt.mp = mp;
3415 3416 lt.usepath = usepath;
3416 3417 lt.owner = curthread;
3417 3418 sema_init(<.sema, 0, NULL, SEMA_DEFAULT, NULL);
3418 3419
3419 3420 /* create thread to hand of call to */
3420 3421 (void) thread_create(NULL, DEFAULTSTKSZ * 2,
3421 3422 modload_thread, <, 0, &p0, TS_RUN, maxclsyspri);
3422 3423
3423 3424 /* wait for thread to complete kobj_load_module */
3424 3425 sema_p(<.sema);
3425 3426
3426 3427 sema_destroy(<.sema);
3427 3428 retval = lt.retval;
3428 3429 } else
3429 3430 retval = kobj_load_module(mp, usepath);
3430 3431
3431 3432 if (mp->mod_mp) {
3432 3433 ASSERT(retval == 0);
3433 3434 mp->mod_loaded = 1;
3434 3435 mp->mod_loadcnt++;
3435 3436 if (moddebug & MODDEBUG_LOADMSG) {
3436 3437 printf(load_msg, mp->mod_filename, mp->mod_id,
3437 3438 (void *)((struct module *)mp->mod_mp)->text,
3438 3439 (void *)((struct module *)mp->mod_mp)->data,
3439 3440 ((struct module *)mp->mod_mp)->text_size,
3440 3441 ((struct module *)mp->mod_mp)->data_size);
3441 3442 }
3442 3443
3443 3444 /*
3444 3445 * XXX - There should be a better way to get this.
3445 3446 */
3446 3447 modinfop = kmem_zalloc(sizeof (struct modinfo), KM_SLEEP);
3447 3448 modinfop->mi_info = MI_INFO_LINKAGE;
3448 3449 if (mod_getinfo(mp, modinfop) == 0)
3449 3450 mp->mod_linkage = NULL;
3450 3451 else {
3451 3452 mp->mod_linkage = (void *)modinfop->mi_base;
3452 3453 ASSERT(mp->mod_linkage->ml_rev == MODREV_1);
3453 3454 }
3454 3455
3455 3456 /*
3456 3457 * DCS: bootstrapping code. If the driver is loaded
3457 3458 * before root mount, it is assumed that the driver
3458 3459 * may be used before mounting root. In order to
3459 3460 * access mappings of global to local minor no.'s
3460 3461 * during installation/open of the driver, we load
3461 3462 * them into memory here while the BOP_interfaces
3462 3463 * are still up.
↓ open down ↓ |
3429 lines elided |
↑ open up ↑ |
3463 3464 */
3464 3465 if ((cluster_bootflags & CLUSTER_BOOTED) && !modrootloaded) {
3465 3466 retval = clboot_modload(mp);
3466 3467 }
3467 3468
3468 3469 kmem_free(modinfop, sizeof (struct modinfo));
3469 3470 (void) mod_sysctl(SYS_SET_MVAR, (void *)mp);
3470 3471 retval = install_stubs_by_name(mp, mp->mod_modname);
3471 3472
3472 3473 /*
3474 + * Perform hotinlines before module is started.
3475 + */
3476 + do_hotinlines(mp->mod_mp);
3477 +
3478 + /*
3473 3479 * Now that the module is loaded, we need to give DTrace
3474 3480 * a chance to notify its providers. This is done via
3475 3481 * the dtrace_modload function pointer.
3476 3482 */
3477 3483 if (strcmp(mp->mod_modname, "dtrace") != 0) {
3478 3484 struct modctl *dmp = mod_hold_by_name("dtrace");
3479 3485
3480 3486 if (dmp != NULL && dtrace_modload != NULL)
3481 3487 (*dtrace_modload)(mp);
3482 3488
3483 3489 mod_release_mod(dmp);
3484 3490 }
3485 3491
3486 3492 } else {
3487 3493 /*
3488 3494 * If load failed then we need to release any requisites
3489 3495 * that we had established.
3490 3496 */
3491 3497 ASSERT(retval);
3492 3498 mod_release_requisites(mp);
3493 3499
3494 3500 if (moddebug & MODDEBUG_ERRMSG)
3495 3501 printf("error loading '%s', error %d\n",
3496 3502 mp->mod_filename, retval);
3497 3503 }
3498 3504 return (retval);
3499 3505 }
3500 3506
3501 3507 static char unload_msg[] = "unloading %s, module id %d, loadcnt %d.\n";
3502 3508
3503 3509 static void
3504 3510 mod_unload(struct modctl *mp)
3505 3511 {
3506 3512 ASSERT(MUTEX_NOT_HELD(&mod_lock));
3507 3513 ASSERT(mp->mod_busy);
3508 3514 ASSERT((mp->mod_loaded && (mp->mod_installed == 0)) &&
3509 3515 ((mp->mod_prim == 0) && (mp->mod_ref >= 0)));
3510 3516
3511 3517 if (moddebug & MODDEBUG_LOADMSG)
3512 3518 printf(unload_msg, mp->mod_modname,
3513 3519 mp->mod_id, mp->mod_loadcnt);
3514 3520
3515 3521 /*
3516 3522 * If mod_ref is not zero, it means some modules might still refer
3517 3523 * to this module. Then you can't unload this module right now.
3518 3524 * Instead, set 1 to mod_delay_unload to notify the system of
3519 3525 * unloading this module later when it's not required any more.
3520 3526 */
3521 3527 if (mp->mod_ref > 0) {
3522 3528 mp->mod_delay_unload = 1;
3523 3529 if (moddebug & MODDEBUG_LOADMSG2) {
3524 3530 printf("module %s not unloaded,"
3525 3531 " non-zero reference count (%d)",
3526 3532 mp->mod_modname, mp->mod_ref);
3527 3533 }
3528 3534 return;
3529 3535 }
3530 3536
3531 3537 if (((mp->mod_loaded == 0) || mp->mod_installed) ||
3532 3538 (mp->mod_ref || mp->mod_prim)) {
3533 3539 /*
3534 3540 * A DEBUG kernel would ASSERT panic above, the code is broken
3535 3541 * if we get this warning.
3536 3542 */
3537 3543 cmn_err(CE_WARN, "mod_unload: %s in incorrect state: %d %d %d",
3538 3544 mp->mod_filename, mp->mod_installed, mp->mod_loaded,
3539 3545 mp->mod_ref);
3540 3546 return;
3541 3547 }
3542 3548
3543 3549 /* reset stub functions to call the binder again */
3544 3550 reset_stubs(mp);
3545 3551
3546 3552 /*
3547 3553 * mark module as unloaded before the modctl structure is freed.
3548 3554 * This is required not to reuse the modctl structure before
3549 3555 * the module is marked as unloaded.
3550 3556 */
3551 3557 mp->mod_loaded = 0;
3552 3558 mp->mod_linkage = NULL;
3553 3559
3554 3560 /* free the memory */
3555 3561 kobj_unload_module(mp);
3556 3562
3557 3563 if (mp->mod_delay_unload) {
3558 3564 mp->mod_delay_unload = 0;
3559 3565 if (moddebug & MODDEBUG_LOADMSG2) {
3560 3566 printf("deferred unload of module %s"
3561 3567 " (id %d) successful",
3562 3568 mp->mod_modname, mp->mod_id);
3563 3569 }
3564 3570 }
3565 3571
3566 3572 /* release hold on requisites */
3567 3573 mod_release_requisites(mp);
3568 3574
3569 3575 /*
3570 3576 * Now that the module is gone, we need to give DTrace a chance to
3571 3577 * remove any probes that it may have had in the module. This is
3572 3578 * done via the dtrace_modunload function pointer.
3573 3579 */
3574 3580 if (strcmp(mp->mod_modname, "dtrace") != 0) {
3575 3581 struct modctl *dmp = mod_hold_by_name("dtrace");
3576 3582
3577 3583 if (dmp != NULL && dtrace_modunload != NULL)
3578 3584 (*dtrace_modunload)(mp);
3579 3585
3580 3586 mod_release_mod(dmp);
3581 3587 }
3582 3588 }
3583 3589
3584 3590 static int
3585 3591 modinstall(struct modctl *mp)
3586 3592 {
3587 3593 int val;
3588 3594 int (*func)(void);
3589 3595
3590 3596 ASSERT(MUTEX_NOT_HELD(&mod_lock));
3591 3597 ASSERT(mp->mod_busy && mp->mod_loaded);
3592 3598
3593 3599 if (mp->mod_installed)
3594 3600 return (0);
3595 3601 /*
3596 3602 * If mod_delay_unload is on, it means the system chose the deferred
3597 3603 * unload for this module. Then you can't install this module until
3598 3604 * it's unloaded from the system.
3599 3605 */
3600 3606 if (mp->mod_delay_unload)
3601 3607 return (ENXIO);
3602 3608
3603 3609 if (moddebug & MODDEBUG_LOADMSG)
3604 3610 printf("installing %s, module id %d.\n",
3605 3611 mp->mod_modname, mp->mod_id);
3606 3612
3607 3613 ASSERT(mp->mod_mp != NULL);
3608 3614 if (mod_install_requisites(mp) != 0) {
3609 3615 /*
3610 3616 * Note that we can't call mod_unload(mp) here since
3611 3617 * if modinstall() was called by mod_install_requisites(),
3612 3618 * we won't be able to hold the dependent modules
3613 3619 * (otherwise there would be a deadlock).
3614 3620 */
3615 3621 return (ENXIO);
3616 3622 }
3617 3623
3618 3624 if (moddebug & MODDEBUG_ERRMSG) {
3619 3625 printf("init '%s' id %d loaded @ 0x%p/0x%p size %lu/%lu\n",
3620 3626 mp->mod_filename, mp->mod_id,
3621 3627 (void *)((struct module *)mp->mod_mp)->text,
3622 3628 (void *)((struct module *)mp->mod_mp)->data,
3623 3629 ((struct module *)mp->mod_mp)->text_size,
3624 3630 ((struct module *)mp->mod_mp)->data_size);
3625 3631 }
3626 3632
3627 3633 func = (int (*)())kobj_lookup(mp->mod_mp, "_init");
3628 3634
3629 3635 if (kobj_addrcheck(mp->mod_mp, (caddr_t)func)) {
3630 3636 cmn_err(CE_WARN, "_init() not defined properly in %s",
3631 3637 mp->mod_filename);
3632 3638 return (EFAULT);
3633 3639 }
3634 3640
3635 3641 if (moddebug & MODDEBUG_USERDEBUG) {
3636 3642 printf("breakpoint before calling %s:_init()\n",
3637 3643 mp->mod_modname);
3638 3644 if (DEBUGGER_PRESENT)
3639 3645 debug_enter("_init");
3640 3646 }
3641 3647
3642 3648 ASSERT(MUTEX_NOT_HELD(&mod_lock));
3643 3649 ASSERT(mp->mod_busy && mp->mod_loaded);
3644 3650 val = (*func)(); /* call _init */
3645 3651
3646 3652 if (moddebug & MODDEBUG_USERDEBUG)
3647 3653 printf("Returned from _init, val = %x\n", val);
3648 3654
3649 3655 if (val == 0) {
3650 3656 /*
3651 3657 * Set the MODS_INSTALLED flag to enable this module
3652 3658 * being called now.
3653 3659 */
3654 3660 install_stubs(mp);
3655 3661 mp->mod_installed = 1;
3656 3662 } else if (moddebug & MODDEBUG_ERRMSG)
3657 3663 printf(mod_init_msg, mp->mod_filename, mp->mod_modname, val);
3658 3664
3659 3665 return (val);
3660 3666 }
3661 3667
3662 3668 int detach_driver_unconfig = 0;
3663 3669
3664 3670 static int
3665 3671 detach_driver(char *name)
3666 3672 {
3667 3673 major_t major;
3668 3674 int error;
3669 3675
3670 3676 /*
3671 3677 * If being called from mod_uninstall_all() then the appropriate
3672 3678 * driver detaches (leaf only) have already been done.
3673 3679 */
3674 3680 if (mod_in_autounload())
3675 3681 return (0);
3676 3682
3677 3683 major = ddi_name_to_major(name);
3678 3684 if (major == DDI_MAJOR_T_NONE)
3679 3685 return (0);
3680 3686
3681 3687 error = ndi_devi_unconfig_driver(ddi_root_node(),
3682 3688 NDI_DETACH_DRIVER | detach_driver_unconfig, major);
3683 3689 return (error == NDI_SUCCESS ? 0 : -1);
3684 3690 }
3685 3691
3686 3692 static char finiret_msg[] = "Returned from _fini for %s, status = %x\n";
3687 3693
3688 3694 static int
3689 3695 moduninstall(struct modctl *mp)
3690 3696 {
3691 3697 int status = 0;
3692 3698 int (*func)(void);
3693 3699
3694 3700 ASSERT(MUTEX_NOT_HELD(&mod_lock));
3695 3701 ASSERT(mp->mod_busy);
3696 3702
3697 3703 /*
3698 3704 * Verify that we need to do something and can uninstall the module.
3699 3705 *
3700 3706 * If we should not uninstall the module or if the module is not in
3701 3707 * the correct state to start an uninstall we return EBUSY to prevent
3702 3708 * us from progressing to mod_unload. If the module has already been
3703 3709 * uninstalled and unloaded we return EALREADY.
3704 3710 */
3705 3711 if (mp->mod_prim || mp->mod_ref || mp->mod_nenabled != 0)
3706 3712 return (EBUSY);
3707 3713 if ((mp->mod_installed == 0) || (mp->mod_loaded == 0))
3708 3714 return (EALREADY);
3709 3715
3710 3716 /*
3711 3717 * To avoid devinfo / module deadlock we must release this module
3712 3718 * prior to initiating the detach_driver, otherwise the detach_driver
3713 3719 * might deadlock on a devinfo node held by another thread
3714 3720 * coming top down and involving the module we have locked.
3715 3721 *
3716 3722 * When we regrab the module we must reverify that it is OK
3717 3723 * to proceed with the uninstall operation.
3718 3724 */
3719 3725 mod_release_mod(mp);
3720 3726 status = detach_driver(mp->mod_modname);
3721 3727 (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_NOT_HELD);
3722 3728
3723 3729 /* check detach status and reverify state with lock */
3724 3730 mutex_enter(&mod_lock);
3725 3731 if ((status != 0) || mp->mod_prim || mp->mod_ref) {
3726 3732 mutex_exit(&mod_lock);
3727 3733 return (EBUSY);
3728 3734 }
3729 3735 if ((mp->mod_installed == 0) || (mp->mod_loaded == 0)) {
3730 3736 mutex_exit(&mod_lock);
3731 3737 return (EALREADY);
3732 3738 }
3733 3739 mutex_exit(&mod_lock);
3734 3740
3735 3741 if (moddebug & MODDEBUG_LOADMSG2)
3736 3742 printf("uninstalling %s\n", mp->mod_modname);
3737 3743
3738 3744 /*
3739 3745 * lookup _fini, return EBUSY if not defined.
3740 3746 *
3741 3747 * The MODDEBUG_FINI_EBUSY is usefull in resolving leaks in
3742 3748 * detach(9E) - it allows bufctl addresses to be resolved.
3743 3749 */
3744 3750 func = (int (*)())kobj_lookup(mp->mod_mp, "_fini");
3745 3751 if ((func == NULL) || (mp->mod_loadflags & MOD_NOUNLOAD) ||
3746 3752 (moddebug & MODDEBUG_FINI_EBUSY))
3747 3753 return (EBUSY);
3748 3754
3749 3755 /* verify that _fini is in this module */
3750 3756 if (kobj_addrcheck(mp->mod_mp, (caddr_t)func)) {
3751 3757 cmn_err(CE_WARN, "_fini() not defined properly in %s",
3752 3758 mp->mod_filename);
3753 3759 return (EFAULT);
3754 3760 }
3755 3761
3756 3762 /* call _fini() */
3757 3763 ASSERT(MUTEX_NOT_HELD(&mod_lock));
3758 3764 ASSERT(mp->mod_busy && mp->mod_loaded && mp->mod_installed);
3759 3765
3760 3766 status = (*func)();
3761 3767
3762 3768 if (status == 0) {
3763 3769 /* _fini returned success, the module is no longer installed */
3764 3770 if (moddebug & MODDEBUG_LOADMSG)
3765 3771 printf("uninstalled %s\n", mp->mod_modname);
3766 3772
3767 3773 /*
3768 3774 * Even though we only set mod_installed to zero here, a zero
3769 3775 * return value means we are committed to a code path were
3770 3776 * mod_loaded will also end up as zero - we have no other
3771 3777 * way to get the module data and bss back to the pre _init
3772 3778 * state except a reload. To ensure this, after return,
3773 3779 * mod_busy must stay set until mod_loaded is cleared.
3774 3780 */
3775 3781 mp->mod_installed = 0;
3776 3782
3777 3783 /*
3778 3784 * Clear the MODS_INSTALLED flag not to call functions
3779 3785 * in the module directly from now on.
3780 3786 */
3781 3787 uninstall_stubs(mp);
3782 3788 } else {
3783 3789 if (moddebug & MODDEBUG_USERDEBUG)
3784 3790 printf(finiret_msg, mp->mod_filename, status);
3785 3791 /*
3786 3792 * By definition _fini is only allowed to return EBUSY or the
3787 3793 * result of mod_remove (EBUSY or EINVAL). In the off chance
3788 3794 * that a driver returns EALREADY we convert this to EINVAL
3789 3795 * since to our caller EALREADY means module was already
3790 3796 * removed.
3791 3797 */
3792 3798 if (status == EALREADY)
3793 3799 status = EINVAL;
3794 3800 }
3795 3801
3796 3802 return (status);
3797 3803 }
3798 3804
3799 3805 /*
3800 3806 * Uninstall all modules.
3801 3807 */
3802 3808 static void
3803 3809 mod_uninstall_all(void)
3804 3810 {
3805 3811 struct modctl *mp;
3806 3812 int pass;
3807 3813 modid_t modid;
3808 3814
3809 3815 /* synchronize with any active modunload_disable() */
3810 3816 modunload_begin();
3811 3817
3812 3818 /* mark this thread as doing autounloading */
3813 3819 (void) tsd_set(mod_autounload_key, (void *)1);
3814 3820
3815 3821 (void) devfs_clean(ddi_root_node(), NULL, 0);
3816 3822 (void) ndi_devi_unconfig(ddi_root_node(), NDI_AUTODETACH);
3817 3823
3818 3824 /*
3819 3825 * Loop up to max times if we keep producing unreferenced modules.
3820 3826 * A new unreferenced module is an opportunity to unload.
3821 3827 */
3822 3828 for (pass = 0; pass < mod_uninstall_pass_max; pass++) {
3823 3829
3824 3830 /* zero count of modules that go unreferenced during pass */
3825 3831 mod_uninstall_ref_zero = 0;
3826 3832
3827 3833 modid = 0;
3828 3834 while ((mp = mod_hold_next_by_id(modid)) != NULL) {
3829 3835 modid = mp->mod_id;
3830 3836
3831 3837 /*
3832 3838 * Skip modules with the MOD_NOAUTOUNLOAD flag set
3833 3839 */
3834 3840 if (mp->mod_loadflags & MOD_NOAUTOUNLOAD) {
3835 3841 mod_release_mod(mp);
3836 3842 continue;
3837 3843 }
3838 3844
3839 3845 if (moduninstall(mp) == 0) {
3840 3846 mod_unload(mp);
3841 3847 CPU_STATS_ADDQ(CPU, sys, modunload, 1);
3842 3848 }
3843 3849 mod_release_mod(mp);
3844 3850 }
3845 3851
3846 3852 /* break if no modules went unreferenced during pass */
3847 3853 if (mod_uninstall_ref_zero == 0)
3848 3854 break;
3849 3855 }
3850 3856 if (pass >= mod_uninstall_pass_max)
3851 3857 mod_uninstall_pass_exc++;
3852 3858
3853 3859 (void) tsd_set(mod_autounload_key, NULL);
3854 3860 modunload_end();
3855 3861 }
3856 3862
3857 3863 /* wait for unloads that have begun before registering disable */
3858 3864 void
3859 3865 modunload_disable(void)
3860 3866 {
3861 3867 mutex_enter(&modunload_wait_mutex);
3862 3868 while (modunload_active_count) {
3863 3869 modunload_wait++;
3864 3870 cv_wait(&modunload_wait_cv, &modunload_wait_mutex);
3865 3871 modunload_wait--;
3866 3872 }
3867 3873 modunload_disable_count++;
3868 3874 mutex_exit(&modunload_wait_mutex);
3869 3875 }
3870 3876
3871 3877 /* mark end of disable and signal waiters */
3872 3878 void
3873 3879 modunload_enable(void)
3874 3880 {
3875 3881 mutex_enter(&modunload_wait_mutex);
3876 3882 modunload_disable_count--;
3877 3883 if ((modunload_disable_count == 0) && modunload_wait)
3878 3884 cv_broadcast(&modunload_wait_cv);
3879 3885 mutex_exit(&modunload_wait_mutex);
3880 3886 }
3881 3887
3882 3888 /* wait for disables to complete before begining unload */
3883 3889 void
3884 3890 modunload_begin()
3885 3891 {
3886 3892 mutex_enter(&modunload_wait_mutex);
3887 3893 while (modunload_disable_count) {
3888 3894 modunload_wait++;
3889 3895 cv_wait(&modunload_wait_cv, &modunload_wait_mutex);
3890 3896 modunload_wait--;
3891 3897 }
3892 3898 modunload_active_count++;
3893 3899 mutex_exit(&modunload_wait_mutex);
3894 3900 }
3895 3901
3896 3902 /* mark end of unload and signal waiters */
3897 3903 void
3898 3904 modunload_end()
3899 3905 {
3900 3906 mutex_enter(&modunload_wait_mutex);
3901 3907 modunload_active_count--;
3902 3908 if ((modunload_active_count == 0) && modunload_wait)
3903 3909 cv_broadcast(&modunload_wait_cv);
3904 3910 mutex_exit(&modunload_wait_mutex);
3905 3911 }
3906 3912
3907 3913 void
3908 3914 mod_uninstall_daemon(void)
3909 3915 {
3910 3916 callb_cpr_t cprinfo;
3911 3917 clock_t ticks;
3912 3918
3913 3919 mod_aul_thread = curthread;
3914 3920
3915 3921 CALLB_CPR_INIT(&cprinfo, &mod_uninstall_lock, callb_generic_cpr, "mud");
3916 3922 for (;;) {
3917 3923 mutex_enter(&mod_uninstall_lock);
3918 3924 CALLB_CPR_SAFE_BEGIN(&cprinfo);
3919 3925 /*
3920 3926 * In DEBUG kernels, unheld drivers are uninstalled periodically
3921 3927 * every mod_uninstall_interval seconds. Periodic uninstall can
3922 3928 * be disabled by setting mod_uninstall_interval to 0 which is
3923 3929 * the default for a non-DEBUG kernel.
3924 3930 */
3925 3931 if (mod_uninstall_interval) {
3926 3932 ticks = drv_usectohz(mod_uninstall_interval * 1000000);
3927 3933 (void) cv_reltimedwait(&mod_uninstall_cv,
3928 3934 &mod_uninstall_lock, ticks, TR_CLOCK_TICK);
3929 3935 } else {
3930 3936 cv_wait(&mod_uninstall_cv, &mod_uninstall_lock);
3931 3937 }
3932 3938 /*
3933 3939 * The whole daemon is safe for CPR except we don't want
3934 3940 * the daemon to run if FREEZE is issued and this daemon
3935 3941 * wakes up from the cv_wait above. In this case, it'll be
3936 3942 * blocked in CALLB_CPR_SAFE_END until THAW is issued.
3937 3943 *
3938 3944 * The reason of calling CALLB_CPR_SAFE_BEGIN twice is that
3939 3945 * mod_uninstall_lock is used to protect cprinfo and
3940 3946 * CALLB_CPR_SAFE_BEGIN assumes that this lock is held when
3941 3947 * called.
3942 3948 */
3943 3949 CALLB_CPR_SAFE_END(&cprinfo, &mod_uninstall_lock);
3944 3950 CALLB_CPR_SAFE_BEGIN(&cprinfo);
3945 3951 mutex_exit(&mod_uninstall_lock);
3946 3952 if ((modunload_disable_count == 0) &&
3947 3953 ((moddebug & MODDEBUG_NOAUTOUNLOAD) == 0)) {
3948 3954 mod_uninstall_all();
3949 3955 }
3950 3956 }
3951 3957 }
3952 3958
3953 3959 /*
3954 3960 * Unload all uninstalled modules.
3955 3961 */
3956 3962 void
3957 3963 modreap(void)
3958 3964 {
3959 3965 mutex_enter(&mod_uninstall_lock);
3960 3966 cv_broadcast(&mod_uninstall_cv);
3961 3967 mutex_exit(&mod_uninstall_lock);
3962 3968 }
3963 3969
3964 3970 /*
3965 3971 * Hold the specified module. This is the module holding primitive.
3966 3972 *
3967 3973 * If MOD_LOCK_HELD then the caller already holds the mod_lock.
3968 3974 *
3969 3975 * Return values:
3970 3976 * 0 ==> the module is held
3971 3977 * 1 ==> the module is not held and the MOD_WAIT_ONCE caller needs
3972 3978 * to determine how to retry.
3973 3979 */
3974 3980 int
3975 3981 mod_hold_by_modctl(struct modctl *mp, int f)
3976 3982 {
3977 3983 ASSERT((f & (MOD_WAIT_ONCE | MOD_WAIT_FOREVER)) &&
3978 3984 ((f & (MOD_WAIT_ONCE | MOD_WAIT_FOREVER)) !=
3979 3985 (MOD_WAIT_ONCE | MOD_WAIT_FOREVER)));
3980 3986 ASSERT((f & (MOD_LOCK_HELD | MOD_LOCK_NOT_HELD)) &&
3981 3987 ((f & (MOD_LOCK_HELD | MOD_LOCK_NOT_HELD)) !=
3982 3988 (MOD_LOCK_HELD | MOD_LOCK_NOT_HELD)));
3983 3989 ASSERT((f & MOD_LOCK_NOT_HELD) || MUTEX_HELD(&mod_lock));
3984 3990
3985 3991 if (f & MOD_LOCK_NOT_HELD)
3986 3992 mutex_enter(&mod_lock);
3987 3993
3988 3994 while (mp->mod_busy) {
3989 3995 mp->mod_want = 1;
3990 3996 cv_wait(&mod_cv, &mod_lock);
3991 3997 /*
3992 3998 * Module may be unloaded by daemon.
3993 3999 * Nevertheless, modctl structure is still in linked list
3994 4000 * (i.e., off &modules), not freed!
3995 4001 * Caller is not supposed to assume "mp" is valid, but there
3996 4002 * is no reasonable way to detect this but using
3997 4003 * mp->mod_modinfo->mp == NULL check (follow the back pointer)
3998 4004 * (or similar check depending on calling context)
3999 4005 * DON'T free modctl structure, it will be very very
4000 4006 * problematic.
4001 4007 */
4002 4008 if (f & MOD_WAIT_ONCE) {
4003 4009 if (f & MOD_LOCK_NOT_HELD)
4004 4010 mutex_exit(&mod_lock);
4005 4011 return (1); /* caller decides how to retry */
4006 4012 }
4007 4013 }
4008 4014
4009 4015 mp->mod_busy = 1;
4010 4016 mp->mod_inprogress_thread =
4011 4017 (curthread == NULL ? (kthread_id_t)-1 : curthread);
4012 4018
4013 4019 if (f & MOD_LOCK_NOT_HELD)
4014 4020 mutex_exit(&mod_lock);
4015 4021 return (0);
4016 4022 }
4017 4023
4018 4024 static struct modctl *
4019 4025 mod_hold_by_name_common(struct modctl *dep, const char *filename)
4020 4026 {
4021 4027 const char *modname;
4022 4028 struct modctl *mp;
4023 4029 char *curname, *newname;
4024 4030 int found = 0;
4025 4031
4026 4032 mutex_enter(&mod_lock);
4027 4033
4028 4034 if ((modname = strrchr(filename, '/')) == NULL)
4029 4035 modname = filename;
4030 4036 else
4031 4037 modname++;
4032 4038
4033 4039 mp = &modules;
4034 4040 do {
4035 4041 if (strcmp(modname, mp->mod_modname) == 0) {
4036 4042 found = 1;
4037 4043 break;
4038 4044 }
4039 4045 } while ((mp = mp->mod_next) != &modules);
4040 4046
4041 4047 if (found == 0) {
4042 4048 mp = allocate_modp(filename, modname);
4043 4049 modadd(mp);
4044 4050 }
4045 4051
4046 4052 /*
4047 4053 * if dep is not NULL, set the mp in mod_requisite_loading for
4048 4054 * the module circular dependency check. This field is used in
4049 4055 * mod_circdep(), but it's cleard in mod_hold_loaded_mod().
4050 4056 */
4051 4057 if (dep != NULL) {
4052 4058 ASSERT(dep->mod_busy && dep->mod_requisite_loading == NULL);
4053 4059 dep->mod_requisite_loading = mp;
4054 4060 }
4055 4061
4056 4062 /*
4057 4063 * If the module was held, then it must be us who has it held.
4058 4064 */
4059 4065 if (mod_circdep(mp))
4060 4066 mp = NULL;
4061 4067 else {
4062 4068 (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_HELD);
4063 4069
4064 4070 /*
4065 4071 * If the name hadn't been set or has changed, allocate
4066 4072 * space and set it. Free space used by previous name.
4067 4073 *
4068 4074 * Do not change the name of primary modules, for primary
4069 4075 * modules the mod_filename was allocated in standalone mode:
4070 4076 * it is illegal to kobj_alloc in standalone mode and kobj_free
4071 4077 * in non-standalone mode.
4072 4078 */
4073 4079 curname = mp->mod_filename;
4074 4080 if (curname == NULL ||
4075 4081 ((mp->mod_prim == 0) &&
4076 4082 (curname != filename) &&
4077 4083 (modname != filename) &&
4078 4084 (strcmp(curname, filename) != 0))) {
4079 4085 newname = kobj_zalloc(strlen(filename) + 1, KM_SLEEP);
4080 4086 (void) strcpy(newname, filename);
4081 4087 mp->mod_filename = newname;
4082 4088 if (curname != NULL)
4083 4089 kobj_free(curname, strlen(curname) + 1);
4084 4090 }
4085 4091 }
4086 4092
4087 4093 mutex_exit(&mod_lock);
4088 4094 if (mp && moddebug & MODDEBUG_LOADMSG2)
4089 4095 printf("Holding %s\n", mp->mod_filename);
4090 4096 if (mp == NULL && moddebug & MODDEBUG_LOADMSG2)
4091 4097 printf("circular dependency loading %s\n", filename);
4092 4098 return (mp);
4093 4099 }
4094 4100
4095 4101 static struct modctl *
4096 4102 mod_hold_by_name_requisite(struct modctl *dep, char *filename)
4097 4103 {
4098 4104 return (mod_hold_by_name_common(dep, filename));
4099 4105 }
4100 4106
4101 4107 struct modctl *
4102 4108 mod_hold_by_name(const char *filename)
4103 4109 {
4104 4110 return (mod_hold_by_name_common(NULL, filename));
4105 4111 }
4106 4112
4107 4113 struct modctl *
4108 4114 mod_hold_by_id(modid_t modid)
4109 4115 {
4110 4116 struct modctl *mp;
4111 4117 int found = 0;
4112 4118
4113 4119 mutex_enter(&mod_lock);
4114 4120 mp = &modules;
4115 4121 do {
4116 4122 if (mp->mod_id == modid) {
4117 4123 found = 1;
4118 4124 break;
4119 4125 }
4120 4126 } while ((mp = mp->mod_next) != &modules);
4121 4127
4122 4128 if ((found == 0) || mod_circdep(mp))
4123 4129 mp = NULL;
4124 4130 else
4125 4131 (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_HELD);
4126 4132
4127 4133 mutex_exit(&mod_lock);
4128 4134 return (mp);
4129 4135 }
4130 4136
4131 4137 static struct modctl *
4132 4138 mod_hold_next_by_id(modid_t modid)
4133 4139 {
4134 4140 struct modctl *mp;
4135 4141 int found = 0;
4136 4142
4137 4143 if (modid < -1)
4138 4144 return (NULL);
4139 4145
4140 4146 mutex_enter(&mod_lock);
4141 4147
4142 4148 mp = &modules;
4143 4149 do {
4144 4150 if (mp->mod_id > modid) {
4145 4151 found = 1;
4146 4152 break;
4147 4153 }
4148 4154 } while ((mp = mp->mod_next) != &modules);
4149 4155
4150 4156 if ((found == 0) || mod_circdep(mp))
4151 4157 mp = NULL;
4152 4158 else
4153 4159 (void) mod_hold_by_modctl(mp, MOD_WAIT_FOREVER | MOD_LOCK_HELD);
4154 4160
4155 4161 mutex_exit(&mod_lock);
4156 4162 return (mp);
4157 4163 }
4158 4164
4159 4165 static void
4160 4166 mod_release(struct modctl *mp)
4161 4167 {
4162 4168 ASSERT(MUTEX_HELD(&mod_lock));
4163 4169 ASSERT(mp->mod_busy);
4164 4170
4165 4171 mp->mod_busy = 0;
4166 4172 mp->mod_inprogress_thread = NULL;
4167 4173 if (mp->mod_want) {
4168 4174 mp->mod_want = 0;
4169 4175 cv_broadcast(&mod_cv);
4170 4176 }
4171 4177 }
4172 4178
4173 4179 void
4174 4180 mod_release_mod(struct modctl *mp)
4175 4181 {
4176 4182 if (moddebug & MODDEBUG_LOADMSG2)
4177 4183 printf("Releasing %s\n", mp->mod_filename);
4178 4184 mutex_enter(&mod_lock);
4179 4185 mod_release(mp);
4180 4186 mutex_exit(&mod_lock);
4181 4187 }
4182 4188
4183 4189 modid_t
4184 4190 mod_name_to_modid(char *filename)
4185 4191 {
4186 4192 char *modname;
4187 4193 struct modctl *mp;
4188 4194
4189 4195 mutex_enter(&mod_lock);
4190 4196
4191 4197 if ((modname = strrchr(filename, '/')) == NULL)
4192 4198 modname = filename;
4193 4199 else
4194 4200 modname++;
4195 4201
4196 4202 mp = &modules;
4197 4203 do {
4198 4204 if (strcmp(modname, mp->mod_modname) == 0) {
4199 4205 mutex_exit(&mod_lock);
4200 4206 return (mp->mod_id);
4201 4207 }
4202 4208 } while ((mp = mp->mod_next) != &modules);
4203 4209
4204 4210 mutex_exit(&mod_lock);
4205 4211 return (-1);
4206 4212 }
4207 4213
4208 4214
4209 4215 int
4210 4216 mod_remove_by_name(char *name)
4211 4217 {
4212 4218 struct modctl *mp;
4213 4219 int retval;
4214 4220
4215 4221 mp = mod_hold_by_name(name);
4216 4222
4217 4223 if (mp == NULL)
4218 4224 return (EINVAL);
4219 4225
4220 4226 if (mp->mod_loadflags & MOD_NOAUTOUNLOAD) {
4221 4227 /*
4222 4228 * Do not unload forceloaded modules
4223 4229 */
4224 4230 mod_release_mod(mp);
4225 4231 return (0);
4226 4232 }
4227 4233
4228 4234 if ((retval = moduninstall(mp)) == 0) {
4229 4235 mod_unload(mp);
4230 4236 CPU_STATS_ADDQ(CPU, sys, modunload, 1);
4231 4237 } else if (retval == EALREADY)
4232 4238 retval = 0; /* already unloaded, not an error */
4233 4239 mod_release_mod(mp);
4234 4240 return (retval);
4235 4241 }
4236 4242
4237 4243 /*
4238 4244 * Record that module "dep" is dependent on module "on_mod."
4239 4245 */
4240 4246 static void
4241 4247 mod_make_requisite(struct modctl *dependent, struct modctl *on_mod)
4242 4248 {
4243 4249 struct modctl_list **pmlnp; /* previous next pointer */
4244 4250 struct modctl_list *mlp;
4245 4251 struct modctl_list *new;
4246 4252
4247 4253 ASSERT(dependent->mod_busy && on_mod->mod_busy);
4248 4254 mutex_enter(&mod_lock);
4249 4255
4250 4256 /*
4251 4257 * Search dependent's requisite list to see if on_mod is recorded.
4252 4258 * List is ordered by id.
4253 4259 */
4254 4260 for (pmlnp = &dependent->mod_requisites, mlp = *pmlnp;
4255 4261 mlp; pmlnp = &mlp->modl_next, mlp = *pmlnp)
4256 4262 if (mlp->modl_modp->mod_id >= on_mod->mod_id)
4257 4263 break;
4258 4264
4259 4265 /* Create and insert if not already recorded */
4260 4266 if ((mlp == NULL) || (mlp->modl_modp->mod_id != on_mod->mod_id)) {
4261 4267 new = kobj_zalloc(sizeof (*new), KM_SLEEP);
4262 4268 new->modl_modp = on_mod;
4263 4269 new->modl_next = mlp;
4264 4270 *pmlnp = new;
4265 4271
4266 4272 /*
4267 4273 * Increment the mod_ref count in our new requisite module.
4268 4274 * This is what keeps a module that has other modules
4269 4275 * which are dependent on it from being uninstalled and
4270 4276 * unloaded. "on_mod"'s mod_ref count decremented in
4271 4277 * mod_release_requisites when the "dependent" module
4272 4278 * unload is complete. "on_mod" must be loaded, but may not
4273 4279 * yet be installed.
4274 4280 */
4275 4281 on_mod->mod_ref++;
4276 4282 ASSERT(on_mod->mod_ref && on_mod->mod_loaded);
4277 4283 }
4278 4284
4279 4285 mutex_exit(&mod_lock);
4280 4286 }
4281 4287
4282 4288 /*
4283 4289 * release the hold associated with mod_make_requisite mod_ref++
4284 4290 * as part of unload.
4285 4291 */
4286 4292 void
4287 4293 mod_release_requisites(struct modctl *modp)
4288 4294 {
4289 4295 struct modctl_list *modl;
4290 4296 struct modctl_list *next;
4291 4297 struct modctl *req;
4292 4298 struct modctl_list *start = NULL, *mod_garbage;
4293 4299
4294 4300 ASSERT(!quiesce_active);
4295 4301 ASSERT(modp->mod_busy);
4296 4302 ASSERT(MUTEX_NOT_HELD(&mod_lock));
4297 4303
4298 4304 mutex_enter(&mod_lock); /* needed for manipulation of req */
4299 4305 for (modl = modp->mod_requisites; modl; modl = next) {
4300 4306 next = modl->modl_next;
4301 4307 req = modl->modl_modp;
4302 4308 ASSERT(req->mod_ref >= 1 && req->mod_loaded);
4303 4309 req->mod_ref--;
4304 4310 if (req->mod_ref == 0)
4305 4311 mod_uninstall_ref_zero++;
4306 4312
4307 4313 /*
4308 4314 * Check if the module has to be unloaded or not.
4309 4315 */
4310 4316 if (req->mod_ref == 0 && req->mod_delay_unload) {
4311 4317 struct modctl_list *new;
4312 4318 /*
4313 4319 * Allocate the modclt_list holding the garbage
4314 4320 * module which should be unloaded later.
4315 4321 */
4316 4322 new = kobj_zalloc(sizeof (struct modctl_list),
4317 4323 KM_SLEEP);
4318 4324 new->modl_modp = req;
4319 4325
4320 4326 if (start == NULL)
4321 4327 mod_garbage = start = new;
4322 4328 else {
4323 4329 mod_garbage->modl_next = new;
4324 4330 mod_garbage = new;
4325 4331 }
4326 4332 }
4327 4333
4328 4334 /* free the list as we go */
4329 4335 kobj_free(modl, sizeof (*modl));
4330 4336 }
4331 4337 modp->mod_requisites = NULL;
4332 4338 mutex_exit(&mod_lock);
4333 4339
4334 4340 /*
4335 4341 * Unload the garbage modules.
4336 4342 */
4337 4343 for (mod_garbage = start; mod_garbage != NULL; /* nothing */) {
4338 4344 struct modctl_list *old = mod_garbage;
4339 4345 struct modctl *mp = mod_garbage->modl_modp;
4340 4346 ASSERT(mp != NULL);
4341 4347
4342 4348 /*
4343 4349 * Hold this module until it's unloaded completely.
4344 4350 */
4345 4351 (void) mod_hold_by_modctl(mp,
4346 4352 MOD_WAIT_FOREVER | MOD_LOCK_NOT_HELD);
4347 4353 /*
4348 4354 * Check if the module is not unloaded yet and nobody requires
4349 4355 * the module. If it's unloaded already or somebody still
4350 4356 * requires the module, don't unload it now.
4351 4357 */
4352 4358 if (mp->mod_loaded && mp->mod_ref == 0)
4353 4359 mod_unload(mp);
4354 4360 ASSERT((mp->mod_loaded == 0 && mp->mod_delay_unload == 0) ||
4355 4361 (mp->mod_ref > 0));
4356 4362 mod_release_mod(mp);
4357 4363
4358 4364 mod_garbage = mod_garbage->modl_next;
4359 4365 kobj_free(old, sizeof (struct modctl_list));
4360 4366 }
4361 4367 }
4362 4368
4363 4369 /*
4364 4370 * Process dependency of the module represented by "dep" on the
4365 4371 * module named by "on."
4366 4372 *
4367 4373 * Called from kobj_do_dependents() to load a module "on" on which
4368 4374 * "dep" depends.
4369 4375 */
4370 4376 struct modctl *
4371 4377 mod_load_requisite(struct modctl *dep, char *on)
4372 4378 {
4373 4379 struct modctl *on_mod;
4374 4380 int retval;
4375 4381
4376 4382 if ((on_mod = mod_hold_loaded_mod(dep, on, &retval)) != NULL) {
4377 4383 mod_make_requisite(dep, on_mod);
4378 4384 } else if (moddebug & MODDEBUG_ERRMSG) {
4379 4385 printf("error processing %s on which module %s depends\n",
4380 4386 on, dep->mod_modname);
4381 4387 }
4382 4388 return (on_mod);
4383 4389 }
4384 4390
4385 4391 static int
4386 4392 mod_install_requisites(struct modctl *modp)
4387 4393 {
4388 4394 struct modctl_list *modl;
4389 4395 struct modctl *req;
4390 4396 int status = 0;
4391 4397
4392 4398 ASSERT(MUTEX_NOT_HELD(&mod_lock));
4393 4399 ASSERT(modp->mod_busy);
4394 4400
4395 4401 for (modl = modp->mod_requisites; modl; modl = modl->modl_next) {
4396 4402 req = modl->modl_modp;
4397 4403 (void) mod_hold_by_modctl(req,
4398 4404 MOD_WAIT_FOREVER | MOD_LOCK_NOT_HELD);
4399 4405 status = modinstall(req);
4400 4406 mod_release_mod(req);
4401 4407
4402 4408 if (status != 0)
4403 4409 break;
4404 4410 }
4405 4411 return (status);
4406 4412 }
4407 4413
4408 4414 /*
4409 4415 * returns 1 if this thread is doing autounload, 0 otherwise.
4410 4416 * see mod_uninstall_all.
4411 4417 */
4412 4418 int
4413 4419 mod_in_autounload()
4414 4420 {
4415 4421 return ((int)(uintptr_t)tsd_get(mod_autounload_key));
4416 4422 }
4417 4423
4418 4424 /*
4419 4425 * gmatch adapted from libc, stripping the wchar stuff
4420 4426 */
4421 4427 #define popchar(p, c) { \
4422 4428 c = *p++; \
4423 4429 if (c == 0) { \
4424 4430 return (0); \
4425 4431 } \
4426 4432 }
4427 4433
4428 4434 int
4429 4435 gmatch(const char *s, const char *p)
4430 4436 {
4431 4437 int c, sc;
4432 4438 int ok, lc, notflag;
4433 4439
4434 4440 sc = *s++;
4435 4441 c = *p++;
4436 4442 if (c == 0)
4437 4443 return (sc == c); /* nothing matches nothing */
4438 4444
4439 4445 switch (c) {
4440 4446 case '\\':
4441 4447 /* skip to quoted character */
4442 4448 popchar(p, c);
4443 4449 /*FALLTHRU*/
4444 4450
4445 4451 default:
4446 4452 /* straight comparison */
4447 4453 if (c != sc)
4448 4454 return (0);
4449 4455 /*FALLTHRU*/
4450 4456
4451 4457 case '?':
4452 4458 /* first char matches, move to remainder */
4453 4459 return (sc != '\0' ? gmatch(s, p) : 0);
4454 4460
4455 4461
4456 4462 case '*':
4457 4463 while (*p == '*')
4458 4464 p++;
4459 4465
4460 4466 /* * matches everything */
4461 4467 if (*p == 0)
4462 4468 return (1);
4463 4469
4464 4470 /* undo skip at the beginning & iterate over substrings */
4465 4471 --s;
4466 4472 while (*s) {
4467 4473 if (gmatch(s, p))
4468 4474 return (1);
4469 4475 s++;
4470 4476 }
4471 4477 return (0);
4472 4478
4473 4479 case '[':
4474 4480 /* match any char within [] */
4475 4481 if (sc == 0)
4476 4482 return (0);
4477 4483
4478 4484 ok = lc = notflag = 0;
4479 4485
4480 4486 if (*p == '!') {
4481 4487 notflag = 1;
4482 4488 p++;
4483 4489 }
4484 4490 popchar(p, c);
4485 4491
4486 4492 do {
4487 4493 if (c == '-' && lc && *p != ']') {
4488 4494 /* test sc against range [c1-c2] */
4489 4495 popchar(p, c);
4490 4496 if (c == '\\') {
4491 4497 popchar(p, c);
4492 4498 }
4493 4499
4494 4500 if (notflag) {
4495 4501 /* return 0 on mismatch */
4496 4502 if (lc <= sc && sc <= c)
4497 4503 return (0);
4498 4504 ok++;
4499 4505 } else if (lc <= sc && sc <= c) {
4500 4506 ok++;
4501 4507 }
4502 4508 /* keep going, may get a match next */
4503 4509 } else if (c == '\\') {
4504 4510 /* skip to quoted character */
4505 4511 popchar(p, c);
4506 4512 }
4507 4513 lc = c;
4508 4514 if (notflag) {
4509 4515 if (sc == lc)
4510 4516 return (0);
4511 4517 ok++;
4512 4518 } else if (sc == lc) {
4513 4519 ok++;
4514 4520 }
4515 4521 popchar(p, c);
4516 4522 } while (c != ']');
4517 4523
4518 4524 /* recurse on remainder of string */
4519 4525 return (ok ? gmatch(s, p) : 0);
4520 4526 }
4521 4527 /*NOTREACHED*/
4522 4528 }
4523 4529
4524 4530
4525 4531 /*
4526 4532 * Get default perm for device from /etc/minor_perm. Return 0 if match found.
4527 4533 *
4528 4534 * Pure wild-carded patterns are handled separately so the ordering of
4529 4535 * these patterns doesn't matter. We're still dependent on ordering
4530 4536 * however as the first matching entry is the one returned.
4531 4537 * Not ideal but all existing examples and usage do imply this
4532 4538 * ordering implicitly.
4533 4539 *
4534 4540 * Drivers using the clone driver are always good for some entertainment.
4535 4541 * Clone nodes under pseudo have the form clone@0:<driver>. Some minor
4536 4542 * perm entries have the form clone:<driver>, others use <driver>:*
4537 4543 * Examples are clone:llc1 vs. llc2:*, for example.
4538 4544 *
4539 4545 * Minor perms in the clone:<driver> form are mapped to the drivers's
4540 4546 * mperm list, not the clone driver, as wildcard entries for clone
4541 4547 * reference only. In other words, a clone wildcard will match
4542 4548 * references for clone@0:<driver> but never <driver>@<minor>.
4543 4549 *
4544 4550 * Additional minor perms in the standard form are also supported,
4545 4551 * for mixed usage, ie a node with an entry clone:<driver> could
4546 4552 * provide further entries <driver>:<minor>.
4547 4553 *
4548 4554 * Finally, some uses of clone use an alias as the minor name rather
4549 4555 * than the driver name, with the alias as the minor perm entry.
4550 4556 * This case is handled by attaching the driver to bring its
4551 4557 * minor list into existence, then discover the alias via DDI_ALIAS.
4552 4558 * The clone device's minor perm list can then be searched for
4553 4559 * that alias.
4554 4560 */
4555 4561
4556 4562 static int
4557 4563 dev_alias_minorperm(dev_info_t *dip, char *minor_name, mperm_t *rmp)
4558 4564 {
4559 4565 major_t major;
4560 4566 struct devnames *dnp;
4561 4567 mperm_t *mp;
4562 4568 char *alias = NULL;
4563 4569 dev_info_t *cdevi;
4564 4570 int circ;
4565 4571 struct ddi_minor_data *dmd;
4566 4572
4567 4573 major = ddi_name_to_major(minor_name);
4568 4574
4569 4575 ASSERT(dip == clone_dip);
4570 4576 ASSERT(major != DDI_MAJOR_T_NONE);
4571 4577
4572 4578 /*
4573 4579 * Attach the driver named by the minor node, then
4574 4580 * search its first instance's minor list for an
4575 4581 * alias node.
4576 4582 */
4577 4583 if (ddi_hold_installed_driver(major) == NULL)
4578 4584 return (1);
4579 4585
4580 4586 dnp = &devnamesp[major];
4581 4587 LOCK_DEV_OPS(&dnp->dn_lock);
4582 4588
4583 4589 if ((cdevi = dnp->dn_head) != NULL) {
4584 4590 ndi_devi_enter(cdevi, &circ);
4585 4591 for (dmd = DEVI(cdevi)->devi_minor; dmd; dmd = dmd->next) {
4586 4592 if (dmd->type == DDM_ALIAS) {
4587 4593 alias = i_ddi_strdup(dmd->ddm_name, KM_SLEEP);
4588 4594 break;
4589 4595 }
4590 4596 }
4591 4597 ndi_devi_exit(cdevi, circ);
4592 4598 }
4593 4599
4594 4600 UNLOCK_DEV_OPS(&dnp->dn_lock);
4595 4601 ddi_rele_driver(major);
4596 4602
4597 4603 if (alias == NULL) {
4598 4604 if (moddebug & MODDEBUG_MINORPERM)
4599 4605 cmn_err(CE_CONT, "dev_minorperm: "
4600 4606 "no alias for %s\n", minor_name);
4601 4607 return (1);
4602 4608 }
4603 4609
4604 4610 major = ddi_driver_major(clone_dip);
4605 4611 dnp = &devnamesp[major];
4606 4612 LOCK_DEV_OPS(&dnp->dn_lock);
4607 4613
4608 4614 /*
4609 4615 * Go through the clone driver's mperm list looking
4610 4616 * for a match for the specified alias.
4611 4617 */
4612 4618 for (mp = dnp->dn_mperm; mp; mp = mp->mp_next) {
4613 4619 if (strcmp(alias, mp->mp_minorname) == 0) {
4614 4620 break;
4615 4621 }
4616 4622 }
4617 4623
4618 4624 if (mp) {
4619 4625 if (moddebug & MODDEBUG_MP_MATCH) {
4620 4626 cmn_err(CE_CONT,
4621 4627 "minor perm defaults: %s %s 0%o %d %d (aliased)\n",
4622 4628 minor_name, alias, mp->mp_mode,
4623 4629 mp->mp_uid, mp->mp_gid);
4624 4630 }
4625 4631 rmp->mp_uid = mp->mp_uid;
4626 4632 rmp->mp_gid = mp->mp_gid;
4627 4633 rmp->mp_mode = mp->mp_mode;
4628 4634 }
4629 4635 UNLOCK_DEV_OPS(&dnp->dn_lock);
4630 4636
4631 4637 kmem_free(alias, strlen(alias)+1);
4632 4638
4633 4639 return (mp == NULL);
4634 4640 }
4635 4641
4636 4642 int
4637 4643 dev_minorperm(dev_info_t *dip, char *name, mperm_t *rmp)
4638 4644 {
4639 4645 major_t major;
4640 4646 char *minor_name;
4641 4647 struct devnames *dnp;
4642 4648 mperm_t *mp;
4643 4649 int is_clone = 0;
4644 4650
4645 4651 if (!minorperm_loaded) {
4646 4652 if (moddebug & MODDEBUG_MINORPERM)
4647 4653 cmn_err(CE_CONT,
4648 4654 "%s: minor perm not yet loaded\n", name);
4649 4655 return (1);
4650 4656 }
4651 4657
4652 4658 minor_name = strchr(name, ':');
4653 4659 if (minor_name == NULL)
4654 4660 return (1);
4655 4661 minor_name++;
4656 4662
4657 4663 /*
4658 4664 * If it's the clone driver, search the driver as named
4659 4665 * by the minor. All clone minor perm entries other than
4660 4666 * alias nodes are actually installed on the real driver's list.
4661 4667 */
4662 4668 if (dip == clone_dip) {
4663 4669 major = ddi_name_to_major(minor_name);
4664 4670 if (major == DDI_MAJOR_T_NONE) {
4665 4671 if (moddebug & MODDEBUG_MINORPERM)
4666 4672 cmn_err(CE_CONT, "dev_minorperm: "
4667 4673 "%s: no such driver\n", minor_name);
4668 4674 return (1);
4669 4675 }
4670 4676 is_clone = 1;
4671 4677 } else {
4672 4678 major = ddi_driver_major(dip);
4673 4679 ASSERT(major != DDI_MAJOR_T_NONE);
4674 4680 }
4675 4681
4676 4682 dnp = &devnamesp[major];
4677 4683 LOCK_DEV_OPS(&dnp->dn_lock);
4678 4684
4679 4685 /*
4680 4686 * Go through the driver's mperm list looking for
4681 4687 * a match for the specified minor. If there's
4682 4688 * no matching pattern, use the wild card.
4683 4689 * Defer to the clone wild for clone if specified,
4684 4690 * otherwise fall back to the normal form.
4685 4691 */
4686 4692 for (mp = dnp->dn_mperm; mp; mp = mp->mp_next) {
4687 4693 if (gmatch(minor_name, mp->mp_minorname) != 0) {
4688 4694 break;
4689 4695 }
4690 4696 }
4691 4697 if (mp == NULL) {
4692 4698 if (is_clone)
4693 4699 mp = dnp->dn_mperm_clone;
4694 4700 if (mp == NULL)
4695 4701 mp = dnp->dn_mperm_wild;
4696 4702 }
4697 4703
4698 4704 if (mp) {
4699 4705 if (moddebug & MODDEBUG_MP_MATCH) {
4700 4706 cmn_err(CE_CONT,
4701 4707 "minor perm defaults: %s %s 0%o %d %d\n",
4702 4708 name, mp->mp_minorname, mp->mp_mode,
4703 4709 mp->mp_uid, mp->mp_gid);
4704 4710 }
4705 4711 rmp->mp_uid = mp->mp_uid;
4706 4712 rmp->mp_gid = mp->mp_gid;
4707 4713 rmp->mp_mode = mp->mp_mode;
4708 4714 }
4709 4715 UNLOCK_DEV_OPS(&dnp->dn_lock);
4710 4716
4711 4717 /*
4712 4718 * If no match can be found for a clone node,
4713 4719 * search for a possible match for an alias.
4714 4720 * One such example is /dev/ptmx -> /devices/pseudo/clone@0:ptm,
4715 4721 * with minor perm entry clone:ptmx.
4716 4722 */
4717 4723 if (mp == NULL && is_clone) {
4718 4724 return (dev_alias_minorperm(dip, minor_name, rmp));
4719 4725 }
4720 4726
4721 4727 return (mp == NULL);
4722 4728 }
4723 4729
4724 4730 /*
4725 4731 * dynamicaly reference load a dl module/library, returning handle
4726 4732 */
4727 4733 /*ARGSUSED*/
4728 4734 ddi_modhandle_t
4729 4735 ddi_modopen(const char *modname, int mode, int *errnop)
4730 4736 {
4731 4737 char *subdir;
4732 4738 char *mod;
4733 4739 int subdirlen;
4734 4740 struct modctl *hmodp = NULL;
4735 4741 int retval = EINVAL;
4736 4742
4737 4743 ASSERT(modname && (mode == KRTLD_MODE_FIRST));
4738 4744 if ((modname == NULL) || (mode != KRTLD_MODE_FIRST))
4739 4745 goto out;
4740 4746
4741 4747 /* find last '/' in modname */
4742 4748 mod = strrchr(modname, '/');
4743 4749
4744 4750 if (mod) {
4745 4751 /* for subdir string without modification to argument */
4746 4752 mod++;
4747 4753 subdirlen = mod - modname;
4748 4754 subdir = kmem_alloc(subdirlen, KM_SLEEP);
4749 4755 (void) strlcpy(subdir, modname, subdirlen);
4750 4756 } else {
4751 4757 subdirlen = 0;
4752 4758 subdir = "misc";
4753 4759 mod = (char *)modname;
4754 4760 }
4755 4761
4756 4762 /* reference load with errno return value */
4757 4763 retval = modrload(subdir, mod, &hmodp);
4758 4764
4759 4765 if (subdirlen)
4760 4766 kmem_free(subdir, subdirlen);
4761 4767
4762 4768 out: if (errnop)
4763 4769 *errnop = retval;
4764 4770
4765 4771 if (moddebug & MODDEBUG_DDI_MOD)
4766 4772 printf("ddi_modopen %s mode %x: %s %p %d\n",
4767 4773 modname ? modname : "<unknown>", mode,
4768 4774 hmodp ? hmodp->mod_filename : "<unknown>",
4769 4775 (void *)hmodp, retval);
4770 4776
4771 4777 return ((ddi_modhandle_t)hmodp);
4772 4778 }
4773 4779
4774 4780 /* lookup "name" in open dl module/library */
4775 4781 void *
4776 4782 ddi_modsym(ddi_modhandle_t h, const char *name, int *errnop)
4777 4783 {
4778 4784 struct modctl *hmodp = (struct modctl *)h;
4779 4785 void *f;
4780 4786 int retval;
4781 4787
4782 4788 ASSERT(hmodp && name && hmodp->mod_installed && (hmodp->mod_ref >= 1));
4783 4789 if ((hmodp == NULL) || (name == NULL) ||
4784 4790 (hmodp->mod_installed == 0) || (hmodp->mod_ref < 1)) {
4785 4791 f = NULL;
4786 4792 retval = EINVAL;
4787 4793 } else {
4788 4794 f = (void *)kobj_lookup(hmodp->mod_mp, (char *)name);
4789 4795 if (f)
4790 4796 retval = 0;
4791 4797 else
4792 4798 retval = ENOTSUP;
4793 4799 }
4794 4800
4795 4801 if (moddebug & MODDEBUG_DDI_MOD)
4796 4802 printf("ddi_modsym in %s of %s: %d %p\n",
4797 4803 hmodp ? hmodp->mod_modname : "<unknown>",
4798 4804 name ? name : "<unknown>", retval, f);
4799 4805
4800 4806 if (errnop)
4801 4807 *errnop = retval;
4802 4808 return (f);
4803 4809 }
4804 4810
4805 4811 /* dynamic (un)reference unload of an open dl module/library */
4806 4812 int
4807 4813 ddi_modclose(ddi_modhandle_t h)
4808 4814 {
4809 4815 struct modctl *hmodp = (struct modctl *)h;
4810 4816 struct modctl *modp = NULL;
4811 4817 int retval;
4812 4818
4813 4819 ASSERT(hmodp && hmodp->mod_installed && (hmodp->mod_ref >= 1));
4814 4820 if ((hmodp == NULL) ||
4815 4821 (hmodp->mod_installed == 0) || (hmodp->mod_ref < 1)) {
4816 4822 retval = EINVAL;
4817 4823 goto out;
4818 4824 }
4819 4825
4820 4826 retval = modunrload(hmodp->mod_id, &modp, ddi_modclose_unload);
4821 4827 if (retval == EBUSY)
4822 4828 retval = 0; /* EBUSY is not an error */
4823 4829
4824 4830 if (retval == 0) {
4825 4831 ASSERT(hmodp == modp);
4826 4832 if (hmodp != modp)
4827 4833 retval = EINVAL;
4828 4834 }
4829 4835
4830 4836 out: if (moddebug & MODDEBUG_DDI_MOD)
4831 4837 printf("ddi_modclose %s: %d\n",
4832 4838 hmodp ? hmodp->mod_modname : "<unknown>", retval);
4833 4839
4834 4840 return (retval);
4835 4841 }
↓ open down ↓ |
1353 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX