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