1 /* $NetBSD: kern_subr.c,v 1.167 2007/12/09 20:28:43 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center, and by Luke Mewburn. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Copyright (c) 1982, 1986, 1991, 1993 42 * The Regents of the University of California. All rights reserved. 43 * (c) UNIX System Laboratories, Inc. 44 * All or some portions of this file are derived from material licensed 45 * to the University of California by American Telephone and Telegraph 46 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 47 * the permission of UNIX System Laboratories, Inc. 48 * 49 * Copyright (c) 1992, 1993 50 * The Regents of the University of California. All rights reserved. 51 * 52 * This software was developed by the Computer Systems Engineering group 53 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 54 * contributed to Berkeley. 55 * 56 * All advertising materials mentioning features or use of this software 57 * must display the following acknowledgement: 58 * This product includes software developed by the University of 59 * California, Lawrence Berkeley Laboratory. 60 * 61 * Redistribution and use in source and binary forms, with or without 62 * modification, are permitted provided that the following conditions 63 * are met: 64 * 1. Redistributions of source code must retain the above copyright 65 * notice, this list of conditions and the following disclaimer. 66 * 2. Redistributions in binary form must reproduce the above copyright 67 * notice, this list of conditions and the following disclaimer in the 68 * documentation and/or other materials provided with the distribution. 69 * 3. Neither the name of the University nor the names of its contributors 70 * may be used to endorse or promote products derived from this software 71 * without specific prior written permission. 72 * 73 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 74 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 76 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 77 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 78 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 79 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 80 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 81 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 82 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 83 * SUCH DAMAGE. 84 * 85 * @(#)kern_subr.c 8.4 (Berkeley) 2/14/95 86 */ 87 88 #include <sys/cdefs.h> 89 __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.167 2007/12/09 20:28:43 jmcneill Exp $"); 90 91 #include "opt_ddb.h" 92 #include "opt_md.h" 93 #include "opt_syscall_debug.h" 94 #include "opt_ktrace.h" 95 #include "opt_ptrace.h" 96 #include "opt_systrace.h" 97 #include "opt_powerhook.h" 98 #include "opt_tftproot.h" 99 100 #include <sys/param.h> 101 #include <sys/systm.h> 102 #include <sys/proc.h> 103 #include <sys/malloc.h> 104 #include <sys/mount.h> 105 #include <sys/device.h> 106 #include <sys/reboot.h> 107 #include <sys/conf.h> 108 #include <sys/disk.h> 109 #include <sys/disklabel.h> 110 #include <sys/queue.h> 111 #include <sys/systrace.h> 112 #include <sys/ktrace.h> 113 #include <sys/ptrace.h> 114 #include <sys/fcntl.h> 115 #include <sys/kauth.h> 116 #include <sys/vnode.h> 117 #include <sys/pmf.h> 118 119 #include <uvm/uvm_extern.h> 120 121 #include <dev/cons.h> 122 123 #include <net/if.h> 124 125 /* XXX these should eventually move to subr_autoconf.c */ 126 static struct device *finddevice(const char *); 127 static struct device *getdisk(char *, int, int, dev_t *, int); 128 static struct device *parsedisk(char *, int, int, dev_t *); 129 static const char *getwedgename(const char *, int); 130 131 /* 132 * A generic linear hook. 133 */ 134 struct hook_desc { 135 LIST_ENTRY(hook_desc) hk_list; 136 void (*hk_fn)(void *); 137 void *hk_arg; 138 }; 139 typedef LIST_HEAD(, hook_desc) hook_list_t; 140 141 MALLOC_DEFINE(M_IOV, "iov", "large iov's"); 142 143 #ifdef TFTPROOT 144 int tftproot_dhcpboot(struct device *); 145 #endif 146 147 void 148 uio_setup_sysspace(struct uio *uio) 149 { 150 151 uio->uio_vmspace = vmspace_kernel(); 152 } 153 154 int 155 uiomove(void *buf, size_t n, struct uio *uio) 156 { 157 struct vmspace *vm = uio->uio_vmspace; 158 struct iovec *iov; 159 u_int cnt; 160 int error = 0; 161 size_t on; 162 char *cp = buf; 163 #ifdef MULTIPROCESSOR 164 int hold_count; 165 #endif 166 167 if ((on = n) >= 1024) { 168 KERNEL_UNLOCK_ALL(NULL, &hold_count); 169 } 170 171 ASSERT_SLEEPABLE(NULL, "uiomove"); 172 173 #ifdef DIAGNOSTIC 174 if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE) 175 panic("uiomove: mode"); 176 #endif 177 while (n > 0 && uio->uio_resid) { 178 iov = uio->uio_iov; 179 cnt = iov->iov_len; 180 if (cnt == 0) { 181 KASSERT(uio->uio_iovcnt > 0); 182 uio->uio_iov++; 183 uio->uio_iovcnt--; 184 continue; 185 } 186 if (cnt > n) 187 cnt = n; 188 if (!VMSPACE_IS_KERNEL_P(vm)) { 189 if (curcpu()->ci_schedstate.spc_flags & 190 SPCF_SHOULDYIELD) 191 preempt(); 192 } 193 194 if (uio->uio_rw == UIO_READ) { 195 error = copyout_vmspace(vm, cp, iov->iov_base, 196 cnt); 197 } else { 198 error = copyin_vmspace(vm, iov->iov_base, cp, 199 cnt); 200 } 201 if (error) { 202 break; 203 } 204 iov->iov_base = (char *)iov->iov_base + cnt; 205 iov->iov_len -= cnt; 206 uio->uio_resid -= cnt; 207 uio->uio_offset += cnt; 208 cp += cnt; 209 KDASSERT(cnt <= n); 210 n -= cnt; 211 } 212 213 if (on >= 1024) { 214 KERNEL_LOCK(hold_count, NULL); 215 } 216 return (error); 217 } 218 219 /* 220 * Wrapper for uiomove() that validates the arguments against a known-good 221 * kernel buffer. 222 */ 223 int 224 uiomove_frombuf(void *buf, size_t buflen, struct uio *uio) 225 { 226 size_t offset; 227 228 if (uio->uio_offset < 0 || /* uio->uio_resid < 0 || */ 229 (offset = uio->uio_offset) != uio->uio_offset) 230 return (EINVAL); 231 if (offset >= buflen) 232 return (0); 233 return (uiomove((char *)buf + offset, buflen - offset, uio)); 234 } 235 236 /* 237 * Give next character to user as result of read. 238 */ 239 int 240 ureadc(int c, struct uio *uio) 241 { 242 struct iovec *iov; 243 244 if (uio->uio_resid <= 0) 245 panic("ureadc: non-positive resid"); 246 again: 247 if (uio->uio_iovcnt <= 0) 248 panic("ureadc: non-positive iovcnt"); 249 iov = uio->uio_iov; 250 if (iov->iov_len <= 0) { 251 uio->uio_iovcnt--; 252 uio->uio_iov++; 253 goto again; 254 } 255 if (!VMSPACE_IS_KERNEL_P(uio->uio_vmspace)) { 256 if (subyte(iov->iov_base, c) < 0) 257 return (EFAULT); 258 } else { 259 *(char *)iov->iov_base = c; 260 } 261 iov->iov_base = (char *)iov->iov_base + 1; 262 iov->iov_len--; 263 uio->uio_resid--; 264 uio->uio_offset++; 265 return (0); 266 } 267 268 /* 269 * Like copyin(), but operates on an arbitrary vmspace. 270 */ 271 int 272 copyin_vmspace(struct vmspace *vm, const void *uaddr, void *kaddr, size_t len) 273 { 274 struct iovec iov; 275 struct uio uio; 276 int error; 277 278 if (len == 0) 279 return (0); 280 281 if (VMSPACE_IS_KERNEL_P(vm)) { 282 return kcopy(uaddr, kaddr, len); 283 } 284 if (__predict_true(vm == curproc->p_vmspace)) { 285 return copyin(uaddr, kaddr, len); 286 } 287 288 iov.iov_base = kaddr; 289 iov.iov_len = len; 290 uio.uio_iov = &iov; 291 uio.uio_iovcnt = 1; 292 uio.uio_offset = (off_t)(intptr_t)uaddr; 293 uio.uio_resid = len; 294 uio.uio_rw = UIO_READ; 295 UIO_SETUP_SYSSPACE(&uio); 296 error = uvm_io(&vm->vm_map, &uio); 297 298 return (error); 299 } 300 301 /* 302 * Like copyout(), but operates on an arbitrary vmspace. 303 */ 304 int 305 copyout_vmspace(struct vmspace *vm, const void *kaddr, void *uaddr, size_t len) 306 { 307 struct iovec iov; 308 struct uio uio; 309 int error; 310 311 if (len == 0) 312 return (0); 313 314 if (VMSPACE_IS_KERNEL_P(vm)) { 315 return kcopy(kaddr, uaddr, len); 316 } 317 if (__predict_true(vm == curproc->p_vmspace)) { 318 return copyout(kaddr, uaddr, len); 319 } 320 321 iov.iov_base = __UNCONST(kaddr); /* XXXUNCONST cast away const */ 322 iov.iov_len = len; 323 uio.uio_iov = &iov; 324 uio.uio_iovcnt = 1; 325 uio.uio_offset = (off_t)(intptr_t)uaddr; 326 uio.uio_resid = len; 327 uio.uio_rw = UIO_WRITE; 328 UIO_SETUP_SYSSPACE(&uio); 329 error = uvm_io(&vm->vm_map, &uio); 330 331 return (error); 332 } 333 334 /* 335 * Like copyin(), but operates on an arbitrary process. 336 */ 337 int 338 copyin_proc(struct proc *p, const void *uaddr, void *kaddr, size_t len) 339 { 340 struct vmspace *vm; 341 int error; 342 343 error = proc_vmspace_getref(p, &vm); 344 if (error) { 345 return error; 346 } 347 error = copyin_vmspace(vm, uaddr, kaddr, len); 348 uvmspace_free(vm); 349 350 return error; 351 } 352 353 /* 354 * Like copyout(), but operates on an arbitrary process. 355 */ 356 int 357 copyout_proc(struct proc *p, const void *kaddr, void *uaddr, size_t len) 358 { 359 struct vmspace *vm; 360 int error; 361 362 error = proc_vmspace_getref(p, &vm); 363 if (error) { 364 return error; 365 } 366 error = copyout_vmspace(vm, kaddr, uaddr, len); 367 uvmspace_free(vm); 368 369 return error; 370 } 371 372 /* 373 * Like copyin(), except it operates on kernel addresses when the FKIOCTL 374 * flag is passed in `ioctlflags' from the ioctl call. 375 */ 376 int 377 ioctl_copyin(int ioctlflags, const void *src, void *dst, size_t len) 378 { 379 if (ioctlflags & FKIOCTL) 380 return kcopy(src, dst, len); 381 return copyin(src, dst, len); 382 } 383 384 /* 385 * Like copyout(), except it operates on kernel addresses when the FKIOCTL 386 * flag is passed in `ioctlflags' from the ioctl call. 387 */ 388 int 389 ioctl_copyout(int ioctlflags, const void *src, void *dst, size_t len) 390 { 391 if (ioctlflags & FKIOCTL) 392 return kcopy(src, dst, len); 393 return copyout(src, dst, len); 394 } 395 396 static void * 397 hook_establish(hook_list_t *list, void (*fn)(void *), void *arg) 398 { 399 struct hook_desc *hd; 400 401 hd = malloc(sizeof(*hd), M_DEVBUF, M_NOWAIT); 402 if (hd == NULL) 403 return (NULL); 404 405 hd->hk_fn = fn; 406 hd->hk_arg = arg; 407 LIST_INSERT_HEAD(list, hd, hk_list); 408 409 return (hd); 410 } 411 412 static void 413 hook_disestablish(hook_list_t *list, void *vhook) 414 { 415 #ifdef DIAGNOSTIC 416 struct hook_desc *hd; 417 418 LIST_FOREACH(hd, list, hk_list) { 419 if (hd == vhook) 420 break; 421 } 422 423 if (hd == NULL) 424 panic("hook_disestablish: hook %p not established", vhook); 425 #endif 426 LIST_REMOVE((struct hook_desc *)vhook, hk_list); 427 free(vhook, M_DEVBUF); 428 } 429 430 static void 431 hook_destroy(hook_list_t *list) 432 { 433 struct hook_desc *hd; 434 435 while ((hd = LIST_FIRST(list)) != NULL) { 436 LIST_REMOVE(hd, hk_list); 437 free(hd, M_DEVBUF); 438 } 439 } 440 441 static void 442 hook_proc_run(hook_list_t *list, struct proc *p) 443 { 444 struct hook_desc *hd; 445 446 for (hd = LIST_FIRST(list); hd != NULL; hd = LIST_NEXT(hd, hk_list)) { 447 ((void (*)(struct proc *, void *))*hd->hk_fn)(p, 448 hd->hk_arg); 449 } 450 } 451 452 /* 453 * "Shutdown hook" types, functions, and variables. 454 * 455 * Should be invoked immediately before the 456 * system is halted or rebooted, i.e. after file systems unmounted, 457 * after crash dump done, etc. 458 * 459 * Each shutdown hook is removed from the list before it's run, so that 460 * it won't be run again. 461 */ 462 463 static hook_list_t shutdownhook_list; 464 465 void * 466 shutdownhook_establish(void (*fn)(void *), void *arg) 467 { 468 return hook_establish(&shutdownhook_list, fn, arg); 469 } 470 471 void 472 shutdownhook_disestablish(void *vhook) 473 { 474 hook_disestablish(&shutdownhook_list, vhook); 475 } 476 477 /* 478 * Run shutdown hooks. Should be invoked immediately before the 479 * system is halted or rebooted, i.e. after file systems unmounted, 480 * after crash dump done, etc. 481 * 482 * Each shutdown hook is removed from the list before it's run, so that 483 * it won't be run again. 484 */ 485 void 486 doshutdownhooks(void) 487 { 488 struct hook_desc *dp; 489 490 while ((dp = LIST_FIRST(&shutdownhook_list)) != NULL) { 491 LIST_REMOVE(dp, hk_list); 492 (*dp->hk_fn)(dp->hk_arg); 493 #if 0 494 /* 495 * Don't bother freeing the hook structure,, since we may 496 * be rebooting because of a memory corruption problem, 497 * and this might only make things worse. It doesn't 498 * matter, anyway, since the system is just about to 499 * reboot. 500 */ 501 free(dp, M_DEVBUF); 502 #endif 503 } 504 505 pmf_system_shutdown(); 506 } 507 508 /* 509 * "Mountroot hook" types, functions, and variables. 510 */ 511 512 static hook_list_t mountroothook_list; 513 514 void * 515 mountroothook_establish(void (*fn)(struct device *), struct device *dev) 516 { 517 return hook_establish(&mountroothook_list, (void (*)(void *))fn, dev); 518 } 519 520 void 521 mountroothook_disestablish(void *vhook) 522 { 523 hook_disestablish(&mountroothook_list, vhook); 524 } 525 526 void 527 mountroothook_destroy(void) 528 { 529 hook_destroy(&mountroothook_list); 530 } 531 532 void 533 domountroothook(void) 534 { 535 struct hook_desc *hd; 536 537 LIST_FOREACH(hd, &mountroothook_list, hk_list) { 538 if (hd->hk_arg == (void *)root_device) { 539 (*hd->hk_fn)(hd->hk_arg); 540 return; 541 } 542 } 543 } 544 545 static hook_list_t exechook_list; 546 547 void * 548 exechook_establish(void (*fn)(struct proc *, void *), void *arg) 549 { 550 return hook_establish(&exechook_list, (void (*)(void *))fn, arg); 551 } 552 553 void 554 exechook_disestablish(void *vhook) 555 { 556 hook_disestablish(&exechook_list, vhook); 557 } 558 559 /* 560 * Run exec hooks. 561 */ 562 void 563 doexechooks(struct proc *p) 564 { 565 hook_proc_run(&exechook_list, p); 566 } 567 568 static hook_list_t exithook_list; 569 570 void * 571 exithook_establish(void (*fn)(struct proc *, void *), void *arg) 572 { 573 return hook_establish(&exithook_list, (void (*)(void *))fn, arg); 574 } 575 576 void 577 exithook_disestablish(void *vhook) 578 { 579 hook_disestablish(&exithook_list, vhook); 580 } 581 582 /* 583 * Run exit hooks. 584 */ 585 void 586 doexithooks(struct proc *p) 587 { 588 hook_proc_run(&exithook_list, p); 589 } 590 591 static hook_list_t forkhook_list; 592 593 void * 594 forkhook_establish(void (*fn)(struct proc *, struct proc *)) 595 { 596 return hook_establish(&forkhook_list, (void (*)(void *))fn, NULL); 597 } 598 599 void 600 forkhook_disestablish(void *vhook) 601 { 602 hook_disestablish(&forkhook_list, vhook); 603 } 604 605 /* 606 * Run fork hooks. 607 */ 608 void 609 doforkhooks(struct proc *p2, struct proc *p1) 610 { 611 struct hook_desc *hd; 612 613 LIST_FOREACH(hd, &forkhook_list, hk_list) { 614 ((void (*)(struct proc *, struct proc *))*hd->hk_fn) 615 (p2, p1); 616 } 617 } 618 619 /* 620 * "Power hook" types, functions, and variables. 621 * The list of power hooks is kept ordered with the last registered hook 622 * first. 623 * When running the hooks on power down the hooks are called in reverse 624 * registration order, when powering up in registration order. 625 */ 626 struct powerhook_desc { 627 CIRCLEQ_ENTRY(powerhook_desc) sfd_list; 628 void (*sfd_fn)(int, void *); 629 void *sfd_arg; 630 char sfd_name[16]; 631 }; 632 633 static CIRCLEQ_HEAD(, powerhook_desc) powerhook_list = 634 CIRCLEQ_HEAD_INITIALIZER(powerhook_list); 635 636 void * 637 powerhook_establish(const char *name, void (*fn)(int, void *), void *arg) 638 { 639 struct powerhook_desc *ndp; 640 641 ndp = (struct powerhook_desc *) 642 malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT); 643 if (ndp == NULL) 644 return (NULL); 645 646 ndp->sfd_fn = fn; 647 ndp->sfd_arg = arg; 648 strlcpy(ndp->sfd_name, name, sizeof(ndp->sfd_name)); 649 CIRCLEQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list); 650 651 aprint_error("%s: WARNING: powerhook_establish is deprecated\n", name); 652 return (ndp); 653 } 654 655 void 656 powerhook_disestablish(void *vhook) 657 { 658 #ifdef DIAGNOSTIC 659 struct powerhook_desc *dp; 660 661 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) 662 if (dp == vhook) 663 goto found; 664 panic("powerhook_disestablish: hook %p not established", vhook); 665 found: 666 #endif 667 668 CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook, 669 sfd_list); 670 free(vhook, M_DEVBUF); 671 } 672 673 /* 674 * Run power hooks. 675 */ 676 void 677 dopowerhooks(int why) 678 { 679 struct powerhook_desc *dp; 680 681 #ifdef POWERHOOK_DEBUG 682 const char *why_name; 683 static const char * pwr_names[] = {PWR_NAMES}; 684 why_name = why < __arraycount(pwr_names) ? pwr_names[why] : "???"; 685 #endif 686 687 if (why == PWR_RESUME || why == PWR_SOFTRESUME) { 688 CIRCLEQ_FOREACH_REVERSE(dp, &powerhook_list, sfd_list) { 689 #ifdef POWERHOOK_DEBUG 690 printf("dopowerhooks %s: %s (%p)\n", why_name, dp->sfd_name, dp); 691 #endif 692 (*dp->sfd_fn)(why, dp->sfd_arg); 693 } 694 } else { 695 CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) { 696 #ifdef POWERHOOK_DEBUG 697 printf("dopowerhooks %s: %s (%p)\n", why_name, dp->sfd_name, dp); 698 #endif 699 (*dp->sfd_fn)(why, dp->sfd_arg); 700 } 701 } 702 703 #ifdef POWERHOOK_DEBUG 704 printf("dopowerhooks: %s done\n", why_name); 705 #endif 706 } 707 708 static int 709 isswap(struct device *dv) 710 { 711 struct dkwedge_info wi; 712 struct vnode *vn; 713 int error; 714 715 if (device_class(dv) != DV_DISK || !device_is_a(dv, "dk")) 716 return 0; 717 718 if ((vn = opendisk(dv)) == NULL) 719 return 0; 720 721 error = VOP_IOCTL(vn, DIOCGWEDGEINFO, &wi, FREAD, NOCRED); 722 VOP_CLOSE(vn, FREAD, NOCRED); 723 vput(vn); 724 if (error) { 725 #ifdef DEBUG_WEDGE 726 printf("%s: Get wedge info returned %d\n", dv->dv_xname, error); 727 #endif 728 return 0; 729 } 730 return strcmp(wi.dkw_ptype, DKW_PTYPE_SWAP) == 0; 731 } 732 733 /* 734 * Determine the root device and, if instructed to, the root file system. 735 */ 736 737 #include "md.h" 738 #if NMD == 0 739 #undef MEMORY_DISK_HOOKS 740 #endif 741 742 #ifdef MEMORY_DISK_HOOKS 743 static struct device fakemdrootdev[NMD]; 744 extern struct cfdriver md_cd; 745 #endif 746 747 #ifdef MEMORY_DISK_IS_ROOT 748 #define BOOT_FROM_MEMORY_HOOKS 1 749 #endif 750 751 /* 752 * The device and wedge that we booted from. If booted_wedge is NULL, 753 * the we might consult booted_partition. 754 */ 755 struct device *booted_device; 756 struct device *booted_wedge; 757 int booted_partition; 758 759 /* 760 * Use partition letters if it's a disk class but not a wedge. 761 * XXX Check for wedge is kinda gross. 762 */ 763 #define DEV_USES_PARTITIONS(dv) \ 764 (device_class((dv)) == DV_DISK && \ 765 !device_is_a((dv), "dk")) 766 767 void 768 setroot(struct device *bootdv, int bootpartition) 769 { 770 struct device *dv; 771 int len, majdev; 772 #ifdef MEMORY_DISK_HOOKS 773 int i; 774 #endif 775 dev_t nrootdev; 776 dev_t ndumpdev = NODEV; 777 char buf[128]; 778 const char *rootdevname; 779 const char *dumpdevname; 780 struct device *rootdv = NULL; /* XXX gcc -Wuninitialized */ 781 struct device *dumpdv = NULL; 782 struct ifnet *ifp; 783 const char *deffsname; 784 struct vfsops *vops; 785 786 #ifdef TFTPROOT 787 if (tftproot_dhcpboot(bootdv) != 0) 788 boothowto |= RB_ASKNAME; 789 #endif 790 791 #ifdef MEMORY_DISK_HOOKS 792 for (i = 0; i < NMD; i++) { 793 fakemdrootdev[i].dv_class = DV_DISK; 794 fakemdrootdev[i].dv_cfdata = NULL; 795 fakemdrootdev[i].dv_cfdriver = &md_cd; 796 fakemdrootdev[i].dv_unit = i; 797 fakemdrootdev[i].dv_parent = NULL; 798 snprintf(fakemdrootdev[i].dv_xname, 799 sizeof(fakemdrootdev[i].dv_xname), "md%d", i); 800 } 801 #endif /* MEMORY_DISK_HOOKS */ 802 803 #ifdef MEMORY_DISK_IS_ROOT 804 bootdv = &fakemdrootdev[0]; 805 bootpartition = 0; 806 #endif 807 808 /* 809 * If NFS is specified as the file system, and we found 810 * a DV_DISK boot device (or no boot device at all), then 811 * find a reasonable network interface for "rootspec". 812 */ 813 vops = vfs_getopsbyname("nfs"); 814 if (vops != NULL && vops->vfs_mountroot == mountroot && 815 rootspec == NULL && 816 (bootdv == NULL || device_class(bootdv) != DV_IFNET)) { 817 IFNET_FOREACH(ifp) { 818 if ((ifp->if_flags & 819 (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) 820 break; 821 } 822 if (ifp == NULL) { 823 /* 824 * Can't find a suitable interface; ask the 825 * user. 826 */ 827 boothowto |= RB_ASKNAME; 828 } else { 829 /* 830 * Have a suitable interface; behave as if 831 * the user specified this interface. 832 */ 833 rootspec = (const char *)ifp->if_xname; 834 } 835 } 836 if (vops != NULL) 837 vfs_delref(vops); 838 839 /* 840 * If wildcarded root and we the boot device wasn't determined, 841 * ask the user. 842 */ 843 if (rootspec == NULL && bootdv == NULL) 844 boothowto |= RB_ASKNAME; 845 846 top: 847 if (boothowto & RB_ASKNAME) { 848 struct device *defdumpdv; 849 850 for (;;) { 851 printf("root device"); 852 if (bootdv != NULL) { 853 printf(" (default %s", bootdv->dv_xname); 854 if (DEV_USES_PARTITIONS(bootdv)) 855 printf("%c", bootpartition + 'a'); 856 printf(")"); 857 } 858 printf(": "); 859 len = cngetsn(buf, sizeof(buf)); 860 if (len == 0 && bootdv != NULL) { 861 strlcpy(buf, bootdv->dv_xname, sizeof(buf)); 862 len = strlen(buf); 863 } 864 if (len > 0 && buf[len - 1] == '*') { 865 buf[--len] = '\0'; 866 dv = getdisk(buf, len, 1, &nrootdev, 0); 867 if (dv != NULL) { 868 rootdv = dv; 869 break; 870 } 871 } 872 dv = getdisk(buf, len, bootpartition, &nrootdev, 0); 873 if (dv != NULL) { 874 rootdv = dv; 875 break; 876 } 877 } 878 879 /* 880 * Set up the default dump device. If root is on 881 * a network device, there is no default dump 882 * device, since we don't support dumps to the 883 * network. 884 */ 885 if (DEV_USES_PARTITIONS(rootdv) == 0) 886 defdumpdv = NULL; 887 else 888 defdumpdv = rootdv; 889 890 for (;;) { 891 printf("dump device"); 892 if (defdumpdv != NULL) { 893 /* 894 * Note, we know it's a disk if we get here. 895 */ 896 printf(" (default %sb)", defdumpdv->dv_xname); 897 } 898 printf(": "); 899 len = cngetsn(buf, sizeof(buf)); 900 if (len == 0) { 901 if (defdumpdv != NULL) { 902 ndumpdev = MAKEDISKDEV(major(nrootdev), 903 DISKUNIT(nrootdev), 1); 904 } 905 dumpdv = defdumpdv; 906 break; 907 } 908 if (len == 4 && strcmp(buf, "none") == 0) { 909 dumpdv = NULL; 910 break; 911 } 912 dv = getdisk(buf, len, 1, &ndumpdev, 1); 913 if (dv != NULL) { 914 dumpdv = dv; 915 break; 916 } 917 } 918 919 rootdev = nrootdev; 920 dumpdev = ndumpdev; 921 922 for (vops = LIST_FIRST(&vfs_list); vops != NULL; 923 vops = LIST_NEXT(vops, vfs_list)) { 924 if (vops->vfs_mountroot != NULL && 925 vops->vfs_mountroot == mountroot) 926 break; 927 } 928 929 if (vops == NULL) { 930 mountroot = NULL; 931 deffsname = "generic"; 932 } else 933 deffsname = vops->vfs_name; 934 935 for (;;) { 936 printf("file system (default %s): ", deffsname); 937 len = cngetsn(buf, sizeof(buf)); 938 if (len == 0) 939 break; 940 if (len == 4 && strcmp(buf, "halt") == 0) 941 cpu_reboot(RB_HALT, NULL); 942 else if (len == 6 && strcmp(buf, "reboot") == 0) 943 cpu_reboot(0, NULL); 944 #if defined(DDB) 945 else if (len == 3 && strcmp(buf, "ddb") == 0) { 946 console_debugger(); 947 } 948 #endif 949 else if (len == 7 && strcmp(buf, "generic") == 0) { 950 mountroot = NULL; 951 break; 952 } 953 vops = vfs_getopsbyname(buf); 954 if (vops == NULL || vops->vfs_mountroot == NULL) { 955 printf("use one of: generic"); 956 for (vops = LIST_FIRST(&vfs_list); 957 vops != NULL; 958 vops = LIST_NEXT(vops, vfs_list)) { 959 if (vops->vfs_mountroot != NULL) 960 printf(" %s", vops->vfs_name); 961 } 962 #if defined(DDB) 963 printf(" ddb"); 964 #endif 965 printf(" halt reboot\n"); 966 } else { 967 mountroot = vops->vfs_mountroot; 968 vfs_delref(vops); 969 break; 970 } 971 } 972 973 } else if (rootspec == NULL) { 974 /* 975 * Wildcarded root; use the boot device. 976 */ 977 rootdv = bootdv; 978 979 majdev = devsw_name2blk(bootdv->dv_xname, NULL, 0); 980 if (majdev >= 0) { 981 /* 982 * Root is on a disk. `bootpartition' is root, 983 * unless the device does not use partitions. 984 */ 985 if (DEV_USES_PARTITIONS(bootdv)) 986 rootdev = MAKEDISKDEV(majdev, 987 device_unit(bootdv), 988 bootpartition); 989 else 990 rootdev = makedev(majdev, device_unit(bootdv)); 991 } 992 } else { 993 994 /* 995 * `root on <dev> ...' 996 */ 997 998 /* 999 * If it's a network interface, we can bail out 1000 * early. 1001 */ 1002 dv = finddevice(rootspec); 1003 if (dv != NULL && device_class(dv) == DV_IFNET) { 1004 rootdv = dv; 1005 goto haveroot; 1006 } 1007 1008 if (rootdev == NODEV && 1009 device_class(dv) == DV_DISK && device_is_a(dv, "dk") && 1010 (majdev = devsw_name2blk(dv->dv_xname, NULL, 0)) >= 0) 1011 rootdev = makedev(majdev, device_unit(dv)); 1012 1013 rootdevname = devsw_blk2name(major(rootdev)); 1014 if (rootdevname == NULL) { 1015 printf("unknown device major 0x%x\n", rootdev); 1016 boothowto |= RB_ASKNAME; 1017 goto top; 1018 } 1019 memset(buf, 0, sizeof(buf)); 1020 snprintf(buf, sizeof(buf), "%s%d", rootdevname, 1021 DISKUNIT(rootdev)); 1022 1023 rootdv = finddevice(buf); 1024 if (rootdv == NULL) { 1025 printf("device %s (0x%x) not configured\n", 1026 buf, rootdev); 1027 boothowto |= RB_ASKNAME; 1028 goto top; 1029 } 1030 } 1031 1032 haveroot: 1033 1034 root_device = rootdv; 1035 1036 switch (device_class(rootdv)) { 1037 case DV_IFNET: 1038 case DV_DISK: 1039 aprint_normal("root on %s", rootdv->dv_xname); 1040 if (DEV_USES_PARTITIONS(rootdv)) 1041 aprint_normal("%c", DISKPART(rootdev) + 'a'); 1042 break; 1043 1044 default: 1045 printf("can't determine root device\n"); 1046 boothowto |= RB_ASKNAME; 1047 goto top; 1048 } 1049 1050 /* 1051 * Now configure the dump device. 1052 * 1053 * If we haven't figured out the dump device, do so, with 1054 * the following rules: 1055 * 1056 * (a) We already know dumpdv in the RB_ASKNAME case. 1057 * 1058 * (b) If dumpspec is set, try to use it. If the device 1059 * is not available, punt. 1060 * 1061 * (c) If dumpspec is not set, the dump device is 1062 * wildcarded or unspecified. If the root device 1063 * is DV_IFNET, punt. Otherwise, use partition b 1064 * of the root device. 1065 */ 1066 1067 if (boothowto & RB_ASKNAME) { /* (a) */ 1068 if (dumpdv == NULL) 1069 goto nodumpdev; 1070 } else if (dumpspec != NULL) { /* (b) */ 1071 if (strcmp(dumpspec, "none") == 0 || dumpdev == NODEV) { 1072 /* 1073 * Operator doesn't want a dump device. 1074 * Or looks like they tried to pick a network 1075 * device. Oops. 1076 */ 1077 goto nodumpdev; 1078 } 1079 1080 dumpdevname = devsw_blk2name(major(dumpdev)); 1081 if (dumpdevname == NULL) 1082 goto nodumpdev; 1083 memset(buf, 0, sizeof(buf)); 1084 snprintf(buf, sizeof(buf), "%s%d", dumpdevname, 1085 DISKUNIT(dumpdev)); 1086 1087 dumpdv = finddevice(buf); 1088 if (dumpdv == NULL) { 1089 /* 1090 * Device not configured. 1091 */ 1092 goto nodumpdev; 1093 } 1094 } else { /* (c) */ 1095 if (DEV_USES_PARTITIONS(rootdv) == 0) { 1096 for (dv = TAILQ_FIRST(&alldevs); dv != NULL; 1097 dv = TAILQ_NEXT(dv, dv_list)) 1098 if (isswap(dv)) 1099 break; 1100 if (dv == NULL) 1101 goto nodumpdev; 1102 1103 majdev = devsw_name2blk(dv->dv_xname, NULL, 0); 1104 if (majdev < 0) 1105 goto nodumpdev; 1106 dumpdv = dv; 1107 dumpdev = makedev(majdev, device_unit(dumpdv)); 1108 } else { 1109 dumpdv = rootdv; 1110 dumpdev = MAKEDISKDEV(major(rootdev), 1111 device_unit(dumpdv), 1); 1112 } 1113 } 1114 1115 aprint_normal(" dumps on %s", dumpdv->dv_xname); 1116 if (DEV_USES_PARTITIONS(dumpdv)) 1117 aprint_normal("%c", DISKPART(dumpdev) + 'a'); 1118 aprint_normal("\n"); 1119 return; 1120 1121 nodumpdev: 1122 dumpdev = NODEV; 1123 aprint_normal("\n"); 1124 } 1125 1126 static struct device * 1127 finddevice(const char *name) 1128 { 1129 const char *wname; 1130 struct device *dv; 1131 #if defined(BOOT_FROM_MEMORY_HOOKS) 1132 int j; 1133 #endif /* BOOT_FROM_MEMORY_HOOKS */ 1134 1135 if ((wname = getwedgename(name, strlen(name))) != NULL) 1136 return dkwedge_find_by_wname(wname); 1137 1138 #ifdef BOOT_FROM_MEMORY_HOOKS 1139 for (j = 0; j < NMD; j++) { 1140 if (strcmp(name, fakemdrootdev[j].dv_xname) == 0) 1141 return &fakemdrootdev[j]; 1142 } 1143 #endif /* BOOT_FROM_MEMORY_HOOKS */ 1144 1145 TAILQ_FOREACH(dv, &alldevs, dv_list) { 1146 if (strcmp(dv->dv_xname, name) == 0) 1147 break; 1148 } 1149 return dv; 1150 } 1151 1152 static struct device * 1153 getdisk(char *str, int len, int defpart, dev_t *devp, int isdump) 1154 { 1155 struct device *dv; 1156 #ifdef MEMORY_DISK_HOOKS 1157 int i; 1158 #endif 1159 1160 if ((dv = parsedisk(str, len, defpart, devp)) == NULL) { 1161 printf("use one of:"); 1162 #ifdef MEMORY_DISK_HOOKS 1163 if (isdump == 0) 1164 for (i = 0; i < NMD; i++) 1165 printf(" %s[a-%c]", fakemdrootdev[i].dv_xname, 1166 'a' + MAXPARTITIONS - 1); 1167 #endif 1168 TAILQ_FOREACH(dv, &alldevs, dv_list) { 1169 if (DEV_USES_PARTITIONS(dv)) 1170 printf(" %s[a-%c]", dv->dv_xname, 1171 'a' + MAXPARTITIONS - 1); 1172 else if (device_class(dv) == DV_DISK) 1173 printf(" %s", dv->dv_xname); 1174 if (isdump == 0 && device_class(dv) == DV_IFNET) 1175 printf(" %s", dv->dv_xname); 1176 } 1177 dkwedge_print_wnames(); 1178 if (isdump) 1179 printf(" none"); 1180 #if defined(DDB) 1181 printf(" ddb"); 1182 #endif 1183 printf(" halt reboot\n"); 1184 } 1185 return dv; 1186 } 1187 1188 static const char * 1189 getwedgename(const char *name, int namelen) 1190 { 1191 const char *wpfx = "wedge:"; 1192 const int wpfxlen = strlen(wpfx); 1193 1194 if (namelen < wpfxlen || strncmp(name, wpfx, wpfxlen) != 0) 1195 return NULL; 1196 1197 return name + wpfxlen; 1198 } 1199 1200 static struct device * 1201 parsedisk(char *str, int len, int defpart, dev_t *devp) 1202 { 1203 struct device *dv; 1204 const char *wname; 1205 char *cp, c; 1206 int majdev, part; 1207 #ifdef MEMORY_DISK_HOOKS 1208 int i; 1209 #endif 1210 if (len == 0) 1211 return (NULL); 1212 1213 if (len == 4 && strcmp(str, "halt") == 0) 1214 cpu_reboot(RB_HALT, NULL); 1215 else if (len == 6 && strcmp(str, "reboot") == 0) 1216 cpu_reboot(0, NULL); 1217 #if defined(DDB) 1218 else if (len == 3 && strcmp(str, "ddb") == 0) 1219 console_debugger(); 1220 #endif 1221 1222 cp = str + len - 1; 1223 c = *cp; 1224 1225 if ((wname = getwedgename(str, len)) != NULL) { 1226 if ((dv = dkwedge_find_by_wname(wname)) == NULL) 1227 return NULL; 1228 part = defpart; 1229 goto gotdisk; 1230 } else if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) { 1231 part = c - 'a'; 1232 *cp = '\0'; 1233 } else 1234 part = defpart; 1235 1236 #ifdef MEMORY_DISK_HOOKS 1237 for (i = 0; i < NMD; i++) 1238 if (strcmp(str, fakemdrootdev[i].dv_xname) == 0) { 1239 dv = &fakemdrootdev[i]; 1240 goto gotdisk; 1241 } 1242 #endif 1243 1244 dv = finddevice(str); 1245 if (dv != NULL) { 1246 if (device_class(dv) == DV_DISK) { 1247 gotdisk: 1248 majdev = devsw_name2blk(dv->dv_xname, NULL, 0); 1249 if (majdev < 0) 1250 panic("parsedisk"); 1251 if (DEV_USES_PARTITIONS(dv)) 1252 *devp = MAKEDISKDEV(majdev, device_unit(dv), 1253 part); 1254 else 1255 *devp = makedev(majdev, device_unit(dv)); 1256 } 1257 1258 if (device_class(dv) == DV_IFNET) 1259 *devp = NODEV; 1260 } 1261 1262 *cp = c; 1263 return (dv); 1264 } 1265 1266 /* 1267 * snprintf() `bytes' into `buf', reformatting it so that the number, 1268 * plus a possible `x' + suffix extension) fits into len bytes (including 1269 * the terminating NUL). 1270 * Returns the number of bytes stored in buf, or -1 if there was a problem. 1271 * E.g, given a len of 9 and a suffix of `B': 1272 * bytes result 1273 * ----- ------ 1274 * 99999 `99999 B' 1275 * 100000 `97 kB' 1276 * 66715648 `65152 kB' 1277 * 252215296 `240 MB' 1278 */ 1279 int 1280 humanize_number(char *buf, size_t len, uint64_t bytes, const char *suffix, 1281 int divisor) 1282 { 1283 /* prefixes are: (none), kilo, Mega, Giga, Tera, Peta, Exa */ 1284 const char *prefixes; 1285 int r; 1286 uint64_t umax; 1287 size_t i, suffixlen; 1288 1289 if (buf == NULL || suffix == NULL) 1290 return (-1); 1291 if (len > 0) 1292 buf[0] = '\0'; 1293 suffixlen = strlen(suffix); 1294 /* check if enough room for `x y' + suffix + `\0' */ 1295 if (len < 4 + suffixlen) 1296 return (-1); 1297 1298 if (divisor == 1024) { 1299 /* 1300 * binary multiplies 1301 * XXX IEC 60027-2 recommends Ki, Mi, Gi... 1302 */ 1303 prefixes = " KMGTPE"; 1304 } else 1305 prefixes = " kMGTPE"; /* SI for decimal multiplies */ 1306 1307 umax = 1; 1308 for (i = 0; i < len - suffixlen - 3; i++) 1309 umax *= 10; 1310 for (i = 0; bytes >= umax && prefixes[i + 1]; i++) 1311 bytes /= divisor; 1312 1313 r = snprintf(buf, len, "%qu%s%c%s", (unsigned long long)bytes, 1314 i == 0 ? "" : " ", prefixes[i], suffix); 1315 1316 return (r); 1317 } 1318 1319 int 1320 format_bytes(char *buf, size_t len, uint64_t bytes) 1321 { 1322 int rv; 1323 size_t nlen; 1324 1325 rv = humanize_number(buf, len, bytes, "B", 1024); 1326 if (rv != -1) { 1327 /* nuke the trailing ` B' if it exists */ 1328 nlen = strlen(buf) - 2; 1329 if (strcmp(&buf[nlen], " B") == 0) 1330 buf[nlen] = '\0'; 1331 } 1332 return (rv); 1333 } 1334 1335 /* 1336 * Return true if system call tracing is enabled for the specified process. 1337 */ 1338 bool 1339 trace_is_enabled(struct proc *p) 1340 { 1341 #ifdef SYSCALL_DEBUG 1342 return (true); 1343 #endif 1344 #ifdef KTRACE 1345 if (ISSET(p->p_traceflag, (KTRFAC_SYSCALL | KTRFAC_SYSRET))) 1346 return (true); 1347 #endif 1348 #ifdef SYSTRACE 1349 if (ISSET(p->p_flag, PK_SYSTRACE)) 1350 return (true); 1351 #endif 1352 #ifdef PTRACE 1353 if (ISSET(p->p_slflag, PSL_SYSCALL)) 1354 return (true); 1355 #endif 1356 1357 return (false); 1358 } 1359 1360 /* 1361 * Start trace of particular system call. If process is being traced, 1362 * this routine is called by MD syscall dispatch code just before 1363 * a system call is actually executed. 1364 * MD caller guarantees the passed 'code' is within the supported 1365 * system call number range for emulation the process runs under. 1366 */ 1367 int 1368 trace_enter(struct lwp *l, register_t code, 1369 register_t realcode, const struct sysent *callp, void *args) 1370 { 1371 #if defined(SYSCALL_DEBUG) || defined(KTRACE) || defined(PTRACE) || defined(SYSTRACE) 1372 struct proc *p = l->l_proc; 1373 1374 #ifdef SYSCALL_DEBUG 1375 scdebug_call(l, code, args); 1376 #endif /* SYSCALL_DEBUG */ 1377 1378 ktrsyscall(code, realcode, callp, args); 1379 1380 #ifdef PTRACE 1381 if ((p->p_slflag & (PSL_SYSCALL|PSL_TRACED)) == 1382 (PSL_SYSCALL|PSL_TRACED)) 1383 process_stoptrace(l); 1384 #endif 1385 1386 #ifdef SYSTRACE 1387 if (ISSET(p->p_flag, PK_SYSTRACE)) { 1388 int error; 1389 KERNEL_LOCK(1, l); 1390 error = systrace_enter(l, code, args); 1391 KERNEL_UNLOCK_ONE(l); 1392 return error; 1393 } 1394 #endif 1395 #endif /* SYSCALL_DEBUG || {K,P,SYS}TRACE */ 1396 return 0; 1397 } 1398 1399 /* 1400 * End trace of particular system call. If process is being traced, 1401 * this routine is called by MD syscall dispatch code just after 1402 * a system call finishes. 1403 * MD caller guarantees the passed 'code' is within the supported 1404 * system call number range for emulation the process runs under. 1405 */ 1406 void 1407 trace_exit(struct lwp *l, register_t code, void *args, register_t rval[], 1408 int error) 1409 { 1410 #if defined(SYSCALL_DEBUG) || defined(KTRACE) || defined(PTRACE) || defined(SYSTRACE) 1411 struct proc *p = l->l_proc; 1412 1413 #ifdef SYSCALL_DEBUG 1414 scdebug_ret(l, code, error, rval); 1415 #endif /* SYSCALL_DEBUG */ 1416 1417 ktrsysret(code, error, rval); 1418 1419 #ifdef PTRACE 1420 if ((p->p_slflag & (PSL_SYSCALL|PSL_TRACED)) == 1421 (PSL_SYSCALL|PSL_TRACED)) 1422 process_stoptrace(l); 1423 #endif 1424 1425 #ifdef SYSTRACE 1426 if (ISSET(p->p_flag, PK_SYSTRACE)) { 1427 KERNEL_LOCK(1, l); 1428 systrace_exit(l, code, args, rval, error); 1429 KERNEL_UNLOCK_ONE(l); 1430 } 1431 #endif 1432 #endif /* SYSCALL_DEBUG || {K,P,SYS}TRACE */ 1433 } 1434 1435 /* 1436 * Disable kernel preemption. 1437 */ 1438 void 1439 crit_enter(void) 1440 { 1441 /* nothing */ 1442 } 1443 1444 /* 1445 * Reenable kernel preemption. 1446 */ 1447 void 1448 crit_exit(void) 1449 { 1450 /* nothing */ 1451 } 1452