1 /* $NetBSD: vfs_subr.c,v 1.432 2012/02/01 05:34:41 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 1997, 1998, 2004, 2005, 2007, 2008 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, by Charles M. Hannum, and by Andrew Doran. 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 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1989, 1993 35 * The Regents of the University of California. All rights reserved. 36 * (c) UNIX System Laboratories, Inc. 37 * All or some portions of this file are derived from material licensed 38 * to the University of California by American Telephone and Telegraph 39 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 40 * the permission of UNIX System Laboratories, Inc. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 * 66 * @(#)vfs_subr.c 8.13 (Berkeley) 4/18/94 67 */ 68 69 #include <sys/cdefs.h> 70 __KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.432 2012/02/01 05:34:41 dholland Exp $"); 71 72 #include "opt_ddb.h" 73 #include "opt_compat_netbsd.h" 74 #include "opt_compat_43.h" 75 76 #include <sys/param.h> 77 #include <sys/systm.h> 78 #include <sys/conf.h> 79 #include <sys/dirent.h> 80 #include <sys/filedesc.h> 81 #include <sys/kernel.h> 82 #include <sys/mount.h> 83 #include <sys/vnode.h> 84 #include <sys/stat.h> 85 #include <sys/sysctl.h> 86 #include <sys/namei.h> 87 #include <sys/buf.h> 88 #include <sys/errno.h> 89 #include <sys/kmem.h> 90 #include <sys/syscallargs.h> 91 #include <sys/kauth.h> 92 #include <sys/module.h> 93 94 #include <miscfs/genfs/genfs.h> 95 #include <miscfs/syncfs/syncfs.h> 96 #include <miscfs/specfs/specdev.h> 97 #include <uvm/uvm_ddb.h> 98 99 const enum vtype iftovt_tab[16] = { 100 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, 101 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, 102 }; 103 const int vttoif_tab[9] = { 104 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 105 S_IFSOCK, S_IFIFO, S_IFMT, 106 }; 107 108 /* 109 * Insq/Remq for the vnode usage lists. 110 */ 111 #define bufinsvn(bp, dp) LIST_INSERT_HEAD(dp, bp, b_vnbufs) 112 #define bufremvn(bp) { \ 113 LIST_REMOVE(bp, b_vnbufs); \ 114 (bp)->b_vnbufs.le_next = NOLIST; \ 115 } 116 117 int doforce = 1; /* 1 => permit forcible unmounting */ 118 int prtactive = 0; /* 1 => print out reclaim of active vnodes */ 119 120 /* 121 * Local declarations. 122 */ 123 124 static int getdevvp(dev_t, vnode_t **, enum vtype); 125 126 /* 127 * Initialize the vnode management data structures. 128 */ 129 void 130 vntblinit(void) 131 { 132 133 vn_initialize_syncerd(); 134 vfs_vnode_sysinit(); 135 vfs_mount_sysinit(); 136 } 137 138 /* 139 * Flush out and invalidate all buffers associated with a vnode. 140 * Called with the underlying vnode locked, which should prevent new dirty 141 * buffers from being queued. 142 */ 143 int 144 vinvalbuf(struct vnode *vp, int flags, kauth_cred_t cred, struct lwp *l, 145 bool catch, int slptimeo) 146 { 147 struct buf *bp, *nbp; 148 int error; 149 int flushflags = PGO_ALLPAGES | PGO_FREE | PGO_SYNCIO | 150 (flags & V_SAVE ? PGO_CLEANIT | PGO_RECLAIM : 0); 151 152 /* XXXUBC this doesn't look at flags or slp* */ 153 mutex_enter(vp->v_interlock); 154 error = VOP_PUTPAGES(vp, 0, 0, flushflags); 155 if (error) { 156 return error; 157 } 158 159 if (flags & V_SAVE) { 160 error = VOP_FSYNC(vp, cred, FSYNC_WAIT|FSYNC_RECLAIM, 0, 0); 161 if (error) 162 return (error); 163 KASSERT(LIST_EMPTY(&vp->v_dirtyblkhd)); 164 } 165 166 mutex_enter(&bufcache_lock); 167 restart: 168 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 169 KASSERT(bp->b_vp == vp); 170 nbp = LIST_NEXT(bp, b_vnbufs); 171 error = bbusy(bp, catch, slptimeo, NULL); 172 if (error != 0) { 173 if (error == EPASSTHROUGH) 174 goto restart; 175 mutex_exit(&bufcache_lock); 176 return (error); 177 } 178 brelsel(bp, BC_INVAL | BC_VFLUSH); 179 } 180 181 for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) { 182 KASSERT(bp->b_vp == vp); 183 nbp = LIST_NEXT(bp, b_vnbufs); 184 error = bbusy(bp, catch, slptimeo, NULL); 185 if (error != 0) { 186 if (error == EPASSTHROUGH) 187 goto restart; 188 mutex_exit(&bufcache_lock); 189 return (error); 190 } 191 /* 192 * XXX Since there are no node locks for NFS, I believe 193 * there is a slight chance that a delayed write will 194 * occur while sleeping just above, so check for it. 195 */ 196 if ((bp->b_oflags & BO_DELWRI) && (flags & V_SAVE)) { 197 #ifdef DEBUG 198 printf("buffer still DELWRI\n"); 199 #endif 200 bp->b_cflags |= BC_BUSY | BC_VFLUSH; 201 mutex_exit(&bufcache_lock); 202 VOP_BWRITE(bp->b_vp, bp); 203 mutex_enter(&bufcache_lock); 204 goto restart; 205 } 206 brelsel(bp, BC_INVAL | BC_VFLUSH); 207 } 208 209 #ifdef DIAGNOSTIC 210 if (!LIST_EMPTY(&vp->v_cleanblkhd) || !LIST_EMPTY(&vp->v_dirtyblkhd)) 211 panic("vinvalbuf: flush failed, vp %p", vp); 212 #endif 213 214 mutex_exit(&bufcache_lock); 215 216 return (0); 217 } 218 219 /* 220 * Destroy any in core blocks past the truncation length. 221 * Called with the underlying vnode locked, which should prevent new dirty 222 * buffers from being queued. 223 */ 224 int 225 vtruncbuf(struct vnode *vp, daddr_t lbn, bool catch, int slptimeo) 226 { 227 struct buf *bp, *nbp; 228 int error; 229 voff_t off; 230 231 off = round_page((voff_t)lbn << vp->v_mount->mnt_fs_bshift); 232 mutex_enter(vp->v_interlock); 233 error = VOP_PUTPAGES(vp, off, 0, PGO_FREE | PGO_SYNCIO); 234 if (error) { 235 return error; 236 } 237 238 mutex_enter(&bufcache_lock); 239 restart: 240 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 241 KASSERT(bp->b_vp == vp); 242 nbp = LIST_NEXT(bp, b_vnbufs); 243 if (bp->b_lblkno < lbn) 244 continue; 245 error = bbusy(bp, catch, slptimeo, NULL); 246 if (error != 0) { 247 if (error == EPASSTHROUGH) 248 goto restart; 249 mutex_exit(&bufcache_lock); 250 return (error); 251 } 252 brelsel(bp, BC_INVAL | BC_VFLUSH); 253 } 254 255 for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) { 256 KASSERT(bp->b_vp == vp); 257 nbp = LIST_NEXT(bp, b_vnbufs); 258 if (bp->b_lblkno < lbn) 259 continue; 260 error = bbusy(bp, catch, slptimeo, NULL); 261 if (error != 0) { 262 if (error == EPASSTHROUGH) 263 goto restart; 264 mutex_exit(&bufcache_lock); 265 return (error); 266 } 267 brelsel(bp, BC_INVAL | BC_VFLUSH); 268 } 269 mutex_exit(&bufcache_lock); 270 271 return (0); 272 } 273 274 /* 275 * Flush all dirty buffers from a vnode. 276 * Called with the underlying vnode locked, which should prevent new dirty 277 * buffers from being queued. 278 */ 279 int 280 vflushbuf(struct vnode *vp, int sync) 281 { 282 struct buf *bp, *nbp; 283 int error, flags = PGO_CLEANIT | PGO_ALLPAGES | (sync ? PGO_SYNCIO : 0); 284 bool dirty; 285 286 mutex_enter(vp->v_interlock); 287 (void) VOP_PUTPAGES(vp, 0, 0, flags); 288 289 loop: 290 mutex_enter(&bufcache_lock); 291 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 292 KASSERT(bp->b_vp == vp); 293 nbp = LIST_NEXT(bp, b_vnbufs); 294 if ((bp->b_cflags & BC_BUSY)) 295 continue; 296 if ((bp->b_oflags & BO_DELWRI) == 0) 297 panic("vflushbuf: not dirty, bp %p", bp); 298 bp->b_cflags |= BC_BUSY | BC_VFLUSH; 299 mutex_exit(&bufcache_lock); 300 /* 301 * Wait for I/O associated with indirect blocks to complete, 302 * since there is no way to quickly wait for them below. 303 */ 304 if (bp->b_vp == vp || sync == 0) 305 (void) bawrite(bp); 306 else { 307 error = bwrite(bp); 308 if (error) 309 return error; 310 } 311 goto loop; 312 } 313 mutex_exit(&bufcache_lock); 314 315 if (sync == 0) 316 return 0; 317 318 mutex_enter(vp->v_interlock); 319 while (vp->v_numoutput != 0) 320 cv_wait(&vp->v_cv, vp->v_interlock); 321 dirty = !LIST_EMPTY(&vp->v_dirtyblkhd); 322 mutex_exit(vp->v_interlock); 323 324 if (dirty) { 325 vprint("vflushbuf: dirty", vp); 326 goto loop; 327 } 328 329 return 0; 330 } 331 332 /* 333 * Create a vnode for a block device. 334 * Used for root filesystem and swap areas. 335 * Also used for memory file system special devices. 336 */ 337 int 338 bdevvp(dev_t dev, vnode_t **vpp) 339 { 340 341 return (getdevvp(dev, vpp, VBLK)); 342 } 343 344 /* 345 * Create a vnode for a character device. 346 * Used for kernfs and some console handling. 347 */ 348 int 349 cdevvp(dev_t dev, vnode_t **vpp) 350 { 351 352 return (getdevvp(dev, vpp, VCHR)); 353 } 354 355 /* 356 * Associate a buffer with a vnode. There must already be a hold on 357 * the vnode. 358 */ 359 void 360 bgetvp(struct vnode *vp, struct buf *bp) 361 { 362 363 KASSERT(bp->b_vp == NULL); 364 KASSERT(bp->b_objlock == &buffer_lock); 365 KASSERT(mutex_owned(vp->v_interlock)); 366 KASSERT(mutex_owned(&bufcache_lock)); 367 KASSERT((bp->b_cflags & BC_BUSY) != 0); 368 KASSERT(!cv_has_waiters(&bp->b_done)); 369 370 vholdl(vp); 371 bp->b_vp = vp; 372 if (vp->v_type == VBLK || vp->v_type == VCHR) 373 bp->b_dev = vp->v_rdev; 374 else 375 bp->b_dev = NODEV; 376 377 /* 378 * Insert onto list for new vnode. 379 */ 380 bufinsvn(bp, &vp->v_cleanblkhd); 381 bp->b_objlock = vp->v_interlock; 382 } 383 384 /* 385 * Disassociate a buffer from a vnode. 386 */ 387 void 388 brelvp(struct buf *bp) 389 { 390 struct vnode *vp = bp->b_vp; 391 392 KASSERT(vp != NULL); 393 KASSERT(bp->b_objlock == vp->v_interlock); 394 KASSERT(mutex_owned(vp->v_interlock)); 395 KASSERT(mutex_owned(&bufcache_lock)); 396 KASSERT((bp->b_cflags & BC_BUSY) != 0); 397 KASSERT(!cv_has_waiters(&bp->b_done)); 398 399 /* 400 * Delete from old vnode list, if on one. 401 */ 402 if (LIST_NEXT(bp, b_vnbufs) != NOLIST) 403 bufremvn(bp); 404 405 if (vp->v_uobj.uo_npages == 0 && (vp->v_iflag & VI_ONWORKLST) && 406 LIST_FIRST(&vp->v_dirtyblkhd) == NULL) { 407 vp->v_iflag &= ~VI_WRMAPDIRTY; 408 vn_syncer_remove_from_worklist(vp); 409 } 410 411 bp->b_objlock = &buffer_lock; 412 bp->b_vp = NULL; 413 holdrelel(vp); 414 } 415 416 /* 417 * Reassign a buffer from one vnode list to another. 418 * The list reassignment must be within the same vnode. 419 * Used to assign file specific control information 420 * (indirect blocks) to the list to which they belong. 421 */ 422 void 423 reassignbuf(struct buf *bp, struct vnode *vp) 424 { 425 struct buflists *listheadp; 426 int delayx; 427 428 KASSERT(mutex_owned(&bufcache_lock)); 429 KASSERT(bp->b_objlock == vp->v_interlock); 430 KASSERT(mutex_owned(vp->v_interlock)); 431 KASSERT((bp->b_cflags & BC_BUSY) != 0); 432 433 /* 434 * Delete from old vnode list, if on one. 435 */ 436 if (LIST_NEXT(bp, b_vnbufs) != NOLIST) 437 bufremvn(bp); 438 439 /* 440 * If dirty, put on list of dirty buffers; 441 * otherwise insert onto list of clean buffers. 442 */ 443 if ((bp->b_oflags & BO_DELWRI) == 0) { 444 listheadp = &vp->v_cleanblkhd; 445 if (vp->v_uobj.uo_npages == 0 && 446 (vp->v_iflag & VI_ONWORKLST) && 447 LIST_FIRST(&vp->v_dirtyblkhd) == NULL) { 448 vp->v_iflag &= ~VI_WRMAPDIRTY; 449 vn_syncer_remove_from_worklist(vp); 450 } 451 } else { 452 listheadp = &vp->v_dirtyblkhd; 453 if ((vp->v_iflag & VI_ONWORKLST) == 0) { 454 switch (vp->v_type) { 455 case VDIR: 456 delayx = dirdelay; 457 break; 458 case VBLK: 459 if (vp->v_specmountpoint != NULL) { 460 delayx = metadelay; 461 break; 462 } 463 /* fall through */ 464 default: 465 delayx = filedelay; 466 break; 467 } 468 if (!vp->v_mount || 469 (vp->v_mount->mnt_flag & MNT_ASYNC) == 0) 470 vn_syncer_add_to_worklist(vp, delayx); 471 } 472 } 473 bufinsvn(bp, listheadp); 474 } 475 476 /* 477 * Create a vnode for a device. 478 * Used by bdevvp (block device) for root file system etc., 479 * and by cdevvp (character device) for console and kernfs. 480 */ 481 static int 482 getdevvp(dev_t dev, vnode_t **vpp, enum vtype type) 483 { 484 vnode_t *vp; 485 vnode_t *nvp; 486 int error; 487 488 if (dev == NODEV) { 489 *vpp = NULL; 490 return (0); 491 } 492 error = getnewvnode(VT_NON, NULL, spec_vnodeop_p, NULL, &nvp); 493 if (error) { 494 *vpp = NULL; 495 return (error); 496 } 497 vp = nvp; 498 vp->v_type = type; 499 vp->v_vflag |= VV_MPSAFE; 500 uvm_vnp_setsize(vp, 0); 501 spec_node_init(vp, dev); 502 *vpp = vp; 503 return (0); 504 } 505 506 /* 507 * Lookup a vnode by device number and return it referenced. 508 */ 509 int 510 vfinddev(dev_t dev, enum vtype type, vnode_t **vpp) 511 { 512 vnode_t *vp; 513 514 mutex_enter(&device_lock); 515 for (vp = specfs_hash[SPECHASH(dev)]; vp; vp = vp->v_specnext) { 516 if (type == vp->v_type && dev == vp->v_rdev) 517 break; 518 } 519 if (vp == NULL) { 520 mutex_exit(&device_lock); 521 return 0; 522 } 523 mutex_enter(vp->v_interlock); 524 mutex_exit(&device_lock); 525 if (vget(vp, 0) != 0) 526 return 0; 527 *vpp = vp; 528 return 1; 529 } 530 531 /* 532 * Revoke all the vnodes corresponding to the specified minor number 533 * range (endpoints inclusive) of the specified major. 534 */ 535 void 536 vdevgone(int maj, int minl, int minh, enum vtype type) 537 { 538 vnode_t *vp, **vpp; 539 dev_t dev; 540 int mn; 541 542 vp = NULL; /* XXX gcc */ 543 544 mutex_enter(&device_lock); 545 for (mn = minl; mn <= minh; mn++) { 546 dev = makedev(maj, mn); 547 vpp = &specfs_hash[SPECHASH(dev)]; 548 for (vp = *vpp; vp != NULL;) { 549 mutex_enter(vp->v_interlock); 550 if ((vp->v_iflag & VI_CLEAN) != 0 || 551 type != vp->v_type || dev != vp->v_rdev) { 552 mutex_exit(vp->v_interlock); 553 vp = vp->v_specnext; 554 continue; 555 } 556 mutex_exit(&device_lock); 557 if (vget(vp, 0) == 0) { 558 VOP_REVOKE(vp, REVOKEALL); 559 vrele(vp); 560 } 561 mutex_enter(&device_lock); 562 vp = *vpp; 563 } 564 } 565 mutex_exit(&device_lock); 566 } 567 568 /* 569 * sysctl helper routine to return list of supported fstypes 570 */ 571 int 572 sysctl_vfs_generic_fstypes(SYSCTLFN_ARGS) 573 { 574 char bf[sizeof(((struct statvfs *)NULL)->f_fstypename)]; 575 char *where = oldp; 576 struct vfsops *v; 577 size_t needed, left, slen; 578 int error, first; 579 580 if (newp != NULL) 581 return (EPERM); 582 if (namelen != 0) 583 return (EINVAL); 584 585 first = 1; 586 error = 0; 587 needed = 0; 588 left = *oldlenp; 589 590 sysctl_unlock(); 591 mutex_enter(&vfs_list_lock); 592 LIST_FOREACH(v, &vfs_list, vfs_list) { 593 if (where == NULL) 594 needed += strlen(v->vfs_name) + 1; 595 else { 596 memset(bf, 0, sizeof(bf)); 597 if (first) { 598 strncpy(bf, v->vfs_name, sizeof(bf)); 599 first = 0; 600 } else { 601 bf[0] = ' '; 602 strncpy(bf + 1, v->vfs_name, sizeof(bf) - 1); 603 } 604 bf[sizeof(bf)-1] = '\0'; 605 slen = strlen(bf); 606 if (left < slen + 1) 607 break; 608 v->vfs_refcount++; 609 mutex_exit(&vfs_list_lock); 610 /* +1 to copy out the trailing NUL byte */ 611 error = copyout(bf, where, slen + 1); 612 mutex_enter(&vfs_list_lock); 613 v->vfs_refcount--; 614 if (error) 615 break; 616 where += slen; 617 needed += slen; 618 left -= slen; 619 } 620 } 621 mutex_exit(&vfs_list_lock); 622 sysctl_relock(); 623 *oldlenp = needed; 624 return (error); 625 } 626 627 int kinfo_vdebug = 1; 628 int kinfo_vgetfailed; 629 630 #define KINFO_VNODESLOP 10 631 632 /* 633 * Dump vnode list (via sysctl). 634 * Copyout address of vnode followed by vnode. 635 */ 636 int 637 sysctl_kern_vnode(SYSCTLFN_ARGS) 638 { 639 char *where = oldp; 640 size_t *sizep = oldlenp; 641 struct mount *mp, *nmp; 642 vnode_t *vp, *mvp, vbuf; 643 char *bp = where; 644 char *ewhere; 645 int error; 646 647 if (namelen != 0) 648 return (EOPNOTSUPP); 649 if (newp != NULL) 650 return (EPERM); 651 652 #define VPTRSZ sizeof(vnode_t *) 653 #define VNODESZ sizeof(vnode_t) 654 if (where == NULL) { 655 *sizep = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ); 656 return (0); 657 } 658 ewhere = where + *sizep; 659 660 sysctl_unlock(); 661 mutex_enter(&mountlist_lock); 662 for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist; 663 mp = nmp) { 664 if (vfs_busy(mp, &nmp)) { 665 continue; 666 } 667 /* Allocate a marker vnode. */ 668 mvp = vnalloc(mp); 669 /* Should never fail for mp != NULL */ 670 KASSERT(mvp != NULL); 671 mutex_enter(&mntvnode_lock); 672 for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; 673 vp = vunmark(mvp)) { 674 vmark(mvp, vp); 675 /* 676 * Check that the vp is still associated with 677 * this filesystem. RACE: could have been 678 * recycled onto the same filesystem. 679 */ 680 if (vp->v_mount != mp || vismarker(vp)) 681 continue; 682 if (bp + VPTRSZ + VNODESZ > ewhere) { 683 (void)vunmark(mvp); 684 mutex_exit(&mntvnode_lock); 685 vnfree(mvp); 686 vfs_unbusy(mp, false, NULL); 687 sysctl_relock(); 688 *sizep = bp - where; 689 return (ENOMEM); 690 } 691 memcpy(&vbuf, vp, VNODESZ); 692 mutex_exit(&mntvnode_lock); 693 if ((error = copyout(&vp, bp, VPTRSZ)) || 694 (error = copyout(&vbuf, bp + VPTRSZ, VNODESZ))) { 695 mutex_enter(&mntvnode_lock); 696 (void)vunmark(mvp); 697 mutex_exit(&mntvnode_lock); 698 vnfree(mvp); 699 vfs_unbusy(mp, false, NULL); 700 sysctl_relock(); 701 return (error); 702 } 703 bp += VPTRSZ + VNODESZ; 704 mutex_enter(&mntvnode_lock); 705 } 706 mutex_exit(&mntvnode_lock); 707 vnfree(mvp); 708 vfs_unbusy(mp, false, &nmp); 709 } 710 mutex_exit(&mountlist_lock); 711 sysctl_relock(); 712 713 *sizep = bp - where; 714 return (0); 715 } 716 717 /* 718 * Set vnode attributes to VNOVAL 719 */ 720 void 721 vattr_null(struct vattr *vap) 722 { 723 724 memset(vap, 0, sizeof(*vap)); 725 726 vap->va_type = VNON; 727 728 /* 729 * Assign individually so that it is safe even if size and 730 * sign of each member are varied. 731 */ 732 vap->va_mode = VNOVAL; 733 vap->va_nlink = VNOVAL; 734 vap->va_uid = VNOVAL; 735 vap->va_gid = VNOVAL; 736 vap->va_fsid = VNOVAL; 737 vap->va_fileid = VNOVAL; 738 vap->va_size = VNOVAL; 739 vap->va_blocksize = VNOVAL; 740 vap->va_atime.tv_sec = 741 vap->va_mtime.tv_sec = 742 vap->va_ctime.tv_sec = 743 vap->va_birthtime.tv_sec = VNOVAL; 744 vap->va_atime.tv_nsec = 745 vap->va_mtime.tv_nsec = 746 vap->va_ctime.tv_nsec = 747 vap->va_birthtime.tv_nsec = VNOVAL; 748 vap->va_gen = VNOVAL; 749 vap->va_flags = VNOVAL; 750 vap->va_rdev = VNOVAL; 751 vap->va_bytes = VNOVAL; 752 } 753 754 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) 755 #define ARRAY_PRINT(idx, arr) \ 756 ((unsigned int)(idx) < ARRAY_SIZE(arr) ? (arr)[(idx)] : "UNKNOWN") 757 758 const char * const vnode_tags[] = { VNODE_TAGS }; 759 const char * const vnode_types[] = { VNODE_TYPES }; 760 const char vnode_flagbits[] = VNODE_FLAGBITS; 761 762 /* 763 * Print out a description of a vnode. 764 */ 765 void 766 vprint(const char *label, struct vnode *vp) 767 { 768 char bf[96]; 769 int flag; 770 771 flag = vp->v_iflag | vp->v_vflag | vp->v_uflag; 772 snprintb(bf, sizeof(bf), vnode_flagbits, flag); 773 774 if (label != NULL) 775 printf("%s: ", label); 776 printf("vnode @ %p, flags (%s)\n\ttag %s(%d), type %s(%d), " 777 "usecount %d, writecount %d, holdcount %d\n" 778 "\tfreelisthd %p, mount %p, data %p lock %p\n", 779 vp, bf, ARRAY_PRINT(vp->v_tag, vnode_tags), vp->v_tag, 780 ARRAY_PRINT(vp->v_type, vnode_types), vp->v_type, 781 vp->v_usecount, vp->v_writecount, vp->v_holdcnt, 782 vp->v_freelisthd, vp->v_mount, vp->v_data, &vp->v_lock); 783 if (vp->v_data != NULL) { 784 printf("\t"); 785 VOP_PRINT(vp); 786 } 787 } 788 789 /* Deprecated. Kept for KPI compatibility. */ 790 int 791 vaccess(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid, 792 mode_t acc_mode, kauth_cred_t cred) 793 { 794 795 #ifdef DIAGNOSTIC 796 printf("vaccess: deprecated interface used.\n"); 797 #endif /* DIAGNOSTIC */ 798 799 return genfs_can_access(type, file_mode, uid, gid, acc_mode, cred); 800 } 801 802 /* 803 * Given a file system name, look up the vfsops for that 804 * file system, or return NULL if file system isn't present 805 * in the kernel. 806 */ 807 struct vfsops * 808 vfs_getopsbyname(const char *name) 809 { 810 struct vfsops *v; 811 812 mutex_enter(&vfs_list_lock); 813 LIST_FOREACH(v, &vfs_list, vfs_list) { 814 if (strcmp(v->vfs_name, name) == 0) 815 break; 816 } 817 if (v != NULL) 818 v->vfs_refcount++; 819 mutex_exit(&vfs_list_lock); 820 821 return (v); 822 } 823 824 void 825 copy_statvfs_info(struct statvfs *sbp, const struct mount *mp) 826 { 827 const struct statvfs *mbp; 828 829 if (sbp == (mbp = &mp->mnt_stat)) 830 return; 831 832 (void)memcpy(&sbp->f_fsidx, &mbp->f_fsidx, sizeof(sbp->f_fsidx)); 833 sbp->f_fsid = mbp->f_fsid; 834 sbp->f_owner = mbp->f_owner; 835 sbp->f_flag = mbp->f_flag; 836 sbp->f_syncwrites = mbp->f_syncwrites; 837 sbp->f_asyncwrites = mbp->f_asyncwrites; 838 sbp->f_syncreads = mbp->f_syncreads; 839 sbp->f_asyncreads = mbp->f_asyncreads; 840 (void)memcpy(sbp->f_spare, mbp->f_spare, sizeof(mbp->f_spare)); 841 (void)memcpy(sbp->f_fstypename, mbp->f_fstypename, 842 sizeof(sbp->f_fstypename)); 843 (void)memcpy(sbp->f_mntonname, mbp->f_mntonname, 844 sizeof(sbp->f_mntonname)); 845 (void)memcpy(sbp->f_mntfromname, mp->mnt_stat.f_mntfromname, 846 sizeof(sbp->f_mntfromname)); 847 sbp->f_namemax = mbp->f_namemax; 848 } 849 850 int 851 set_statvfs_info(const char *onp, int ukon, const char *fromp, int ukfrom, 852 const char *vfsname, struct mount *mp, struct lwp *l) 853 { 854 int error; 855 size_t size; 856 struct statvfs *sfs = &mp->mnt_stat; 857 int (*fun)(const void *, void *, size_t, size_t *); 858 859 (void)strlcpy(mp->mnt_stat.f_fstypename, vfsname, 860 sizeof(mp->mnt_stat.f_fstypename)); 861 862 if (onp) { 863 struct cwdinfo *cwdi = l->l_proc->p_cwdi; 864 fun = (ukon == UIO_SYSSPACE) ? copystr : copyinstr; 865 if (cwdi->cwdi_rdir != NULL) { 866 size_t len; 867 char *bp; 868 char *path = PNBUF_GET(); 869 870 bp = path + MAXPATHLEN; 871 *--bp = '\0'; 872 rw_enter(&cwdi->cwdi_lock, RW_READER); 873 error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, 874 path, MAXPATHLEN / 2, 0, l); 875 rw_exit(&cwdi->cwdi_lock); 876 if (error) { 877 PNBUF_PUT(path); 878 return error; 879 } 880 881 len = strlen(bp); 882 if (len > sizeof(sfs->f_mntonname) - 1) 883 len = sizeof(sfs->f_mntonname) - 1; 884 (void)strncpy(sfs->f_mntonname, bp, len); 885 PNBUF_PUT(path); 886 887 if (len < sizeof(sfs->f_mntonname) - 1) { 888 error = (*fun)(onp, &sfs->f_mntonname[len], 889 sizeof(sfs->f_mntonname) - len - 1, &size); 890 if (error) 891 return error; 892 size += len; 893 } else { 894 size = len; 895 } 896 } else { 897 error = (*fun)(onp, &sfs->f_mntonname, 898 sizeof(sfs->f_mntonname) - 1, &size); 899 if (error) 900 return error; 901 } 902 (void)memset(sfs->f_mntonname + size, 0, 903 sizeof(sfs->f_mntonname) - size); 904 } 905 906 if (fromp) { 907 fun = (ukfrom == UIO_SYSSPACE) ? copystr : copyinstr; 908 error = (*fun)(fromp, sfs->f_mntfromname, 909 sizeof(sfs->f_mntfromname) - 1, &size); 910 if (error) 911 return error; 912 (void)memset(sfs->f_mntfromname + size, 0, 913 sizeof(sfs->f_mntfromname) - size); 914 } 915 return 0; 916 } 917 918 void 919 vfs_timestamp(struct timespec *ts) 920 { 921 922 nanotime(ts); 923 } 924 925 time_t rootfstime; /* recorded root fs time, if known */ 926 void 927 setrootfstime(time_t t) 928 { 929 rootfstime = t; 930 } 931 932 static const uint8_t vttodt_tab[9] = { 933 DT_UNKNOWN, /* VNON */ 934 DT_REG, /* VREG */ 935 DT_DIR, /* VDIR */ 936 DT_BLK, /* VBLK */ 937 DT_CHR, /* VCHR */ 938 DT_LNK, /* VLNK */ 939 DT_SOCK, /* VSUCK */ 940 DT_FIFO, /* VFIFO */ 941 DT_UNKNOWN /* VBAD */ 942 }; 943 944 uint8_t 945 vtype2dt(enum vtype vt) 946 { 947 948 CTASSERT(VBAD == __arraycount(vttodt_tab) - 1); 949 return vttodt_tab[vt]; 950 } 951 952 int 953 VFS_MOUNT(struct mount *mp, const char *a, void *b, size_t *c) 954 { 955 int error; 956 957 KERNEL_LOCK(1, NULL); 958 error = (*(mp->mnt_op->vfs_mount))(mp, a, b, c); 959 KERNEL_UNLOCK_ONE(NULL); 960 961 return error; 962 } 963 964 int 965 VFS_START(struct mount *mp, int a) 966 { 967 int error; 968 969 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 970 KERNEL_LOCK(1, NULL); 971 } 972 error = (*(mp->mnt_op->vfs_start))(mp, a); 973 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 974 KERNEL_UNLOCK_ONE(NULL); 975 } 976 977 return error; 978 } 979 980 int 981 VFS_UNMOUNT(struct mount *mp, int a) 982 { 983 int error; 984 985 KERNEL_LOCK(1, NULL); 986 error = (*(mp->mnt_op->vfs_unmount))(mp, a); 987 KERNEL_UNLOCK_ONE(NULL); 988 989 return error; 990 } 991 992 int 993 VFS_ROOT(struct mount *mp, struct vnode **a) 994 { 995 int error; 996 997 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 998 KERNEL_LOCK(1, NULL); 999 } 1000 error = (*(mp->mnt_op->vfs_root))(mp, a); 1001 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1002 KERNEL_UNLOCK_ONE(NULL); 1003 } 1004 1005 return error; 1006 } 1007 1008 int 1009 VFS_QUOTACTL(struct mount *mp, struct quotactl_args *args) 1010 { 1011 int error; 1012 1013 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1014 KERNEL_LOCK(1, NULL); 1015 } 1016 error = (*(mp->mnt_op->vfs_quotactl))(mp, args); 1017 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1018 KERNEL_UNLOCK_ONE(NULL); 1019 } 1020 1021 return error; 1022 } 1023 1024 int 1025 VFS_STATVFS(struct mount *mp, struct statvfs *a) 1026 { 1027 int error; 1028 1029 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1030 KERNEL_LOCK(1, NULL); 1031 } 1032 error = (*(mp->mnt_op->vfs_statvfs))(mp, a); 1033 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1034 KERNEL_UNLOCK_ONE(NULL); 1035 } 1036 1037 return error; 1038 } 1039 1040 int 1041 VFS_SYNC(struct mount *mp, int a, struct kauth_cred *b) 1042 { 1043 int error; 1044 1045 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1046 KERNEL_LOCK(1, NULL); 1047 } 1048 error = (*(mp->mnt_op->vfs_sync))(mp, a, b); 1049 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1050 KERNEL_UNLOCK_ONE(NULL); 1051 } 1052 1053 return error; 1054 } 1055 1056 int 1057 VFS_FHTOVP(struct mount *mp, struct fid *a, struct vnode **b) 1058 { 1059 int error; 1060 1061 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1062 KERNEL_LOCK(1, NULL); 1063 } 1064 error = (*(mp->mnt_op->vfs_fhtovp))(mp, a, b); 1065 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1066 KERNEL_UNLOCK_ONE(NULL); 1067 } 1068 1069 return error; 1070 } 1071 1072 int 1073 VFS_VPTOFH(struct vnode *vp, struct fid *a, size_t *b) 1074 { 1075 int error; 1076 1077 if ((vp->v_vflag & VV_MPSAFE) == 0) { 1078 KERNEL_LOCK(1, NULL); 1079 } 1080 error = (*(vp->v_mount->mnt_op->vfs_vptofh))(vp, a, b); 1081 if ((vp->v_vflag & VV_MPSAFE) == 0) { 1082 KERNEL_UNLOCK_ONE(NULL); 1083 } 1084 1085 return error; 1086 } 1087 1088 int 1089 VFS_SNAPSHOT(struct mount *mp, struct vnode *a, struct timespec *b) 1090 { 1091 int error; 1092 1093 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1094 KERNEL_LOCK(1, NULL); 1095 } 1096 error = (*(mp->mnt_op->vfs_snapshot))(mp, a, b); 1097 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1098 KERNEL_UNLOCK_ONE(NULL); 1099 } 1100 1101 return error; 1102 } 1103 1104 int 1105 VFS_EXTATTRCTL(struct mount *mp, int a, struct vnode *b, int c, const char *d) 1106 { 1107 int error; 1108 1109 KERNEL_LOCK(1, NULL); /* XXXSMP check ffs */ 1110 error = (*(mp->mnt_op->vfs_extattrctl))(mp, a, b, c, d); 1111 KERNEL_UNLOCK_ONE(NULL); /* XXX */ 1112 1113 return error; 1114 } 1115 1116 int 1117 VFS_SUSPENDCTL(struct mount *mp, int a) 1118 { 1119 int error; 1120 1121 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1122 KERNEL_LOCK(1, NULL); 1123 } 1124 error = (*(mp->mnt_op->vfs_suspendctl))(mp, a); 1125 if ((mp->mnt_iflag & IMNT_MPSAFE) == 0) { 1126 KERNEL_UNLOCK_ONE(NULL); 1127 } 1128 1129 return error; 1130 } 1131 1132 #if defined(DDB) || defined(DEBUGPRINT) 1133 static const char buf_flagbits[] = BUF_FLAGBITS; 1134 1135 void 1136 vfs_buf_print(struct buf *bp, int full, void (*pr)(const char *, ...)) 1137 { 1138 char bf[1024]; 1139 1140 (*pr)(" vp %p lblkno 0x%"PRIx64" blkno 0x%"PRIx64" rawblkno 0x%" 1141 PRIx64 " dev 0x%x\n", 1142 bp->b_vp, bp->b_lblkno, bp->b_blkno, bp->b_rawblkno, bp->b_dev); 1143 1144 snprintb(bf, sizeof(bf), 1145 buf_flagbits, bp->b_flags | bp->b_oflags | bp->b_cflags); 1146 (*pr)(" error %d flags 0x%s\n", bp->b_error, bf); 1147 1148 (*pr)(" bufsize 0x%lx bcount 0x%lx resid 0x%lx\n", 1149 bp->b_bufsize, bp->b_bcount, bp->b_resid); 1150 (*pr)(" data %p saveaddr %p\n", 1151 bp->b_data, bp->b_saveaddr); 1152 (*pr)(" iodone %p objlock %p\n", bp->b_iodone, bp->b_objlock); 1153 } 1154 1155 void 1156 vfs_vnode_print(struct vnode *vp, int full, void (*pr)(const char *, ...)) 1157 { 1158 char bf[256]; 1159 1160 uvm_object_printit(&vp->v_uobj, full, pr); 1161 snprintb(bf, sizeof(bf), 1162 vnode_flagbits, vp->v_iflag | vp->v_vflag | vp->v_uflag); 1163 (*pr)("\nVNODE flags %s\n", bf); 1164 (*pr)("mp %p numoutput %d size 0x%llx writesize 0x%llx\n", 1165 vp->v_mount, vp->v_numoutput, vp->v_size, vp->v_writesize); 1166 1167 (*pr)("data %p writecount %ld holdcnt %ld\n", 1168 vp->v_data, vp->v_writecount, vp->v_holdcnt); 1169 1170 (*pr)("tag %s(%d) type %s(%d) mount %p typedata %p\n", 1171 ARRAY_PRINT(vp->v_tag, vnode_tags), vp->v_tag, 1172 ARRAY_PRINT(vp->v_type, vnode_types), vp->v_type, 1173 vp->v_mount, vp->v_mountedhere); 1174 1175 (*pr)("v_lock %p\n", &vp->v_lock); 1176 1177 if (full) { 1178 struct buf *bp; 1179 1180 (*pr)("clean bufs:\n"); 1181 LIST_FOREACH(bp, &vp->v_cleanblkhd, b_vnbufs) { 1182 (*pr)(" bp %p\n", bp); 1183 vfs_buf_print(bp, full, pr); 1184 } 1185 1186 (*pr)("dirty bufs:\n"); 1187 LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) { 1188 (*pr)(" bp %p\n", bp); 1189 vfs_buf_print(bp, full, pr); 1190 } 1191 } 1192 } 1193 1194 void 1195 vfs_mount_print(struct mount *mp, int full, void (*pr)(const char *, ...)) 1196 { 1197 char sbuf[256]; 1198 1199 (*pr)("vnodecovered = %p syncer = %p data = %p\n", 1200 mp->mnt_vnodecovered,mp->mnt_syncer,mp->mnt_data); 1201 1202 (*pr)("fs_bshift %d dev_bshift = %d\n", 1203 mp->mnt_fs_bshift,mp->mnt_dev_bshift); 1204 1205 snprintb(sbuf, sizeof(sbuf), __MNT_FLAG_BITS, mp->mnt_flag); 1206 (*pr)("flag = %s\n", sbuf); 1207 1208 snprintb(sbuf, sizeof(sbuf), __IMNT_FLAG_BITS, mp->mnt_iflag); 1209 (*pr)("iflag = %s\n", sbuf); 1210 1211 (*pr)("refcnt = %d unmounting @ %p updating @ %p\n", mp->mnt_refcnt, 1212 &mp->mnt_unmounting, &mp->mnt_updating); 1213 1214 (*pr)("statvfs cache:\n"); 1215 (*pr)("\tbsize = %lu\n",mp->mnt_stat.f_bsize); 1216 (*pr)("\tfrsize = %lu\n",mp->mnt_stat.f_frsize); 1217 (*pr)("\tiosize = %lu\n",mp->mnt_stat.f_iosize); 1218 1219 (*pr)("\tblocks = %"PRIu64"\n",mp->mnt_stat.f_blocks); 1220 (*pr)("\tbfree = %"PRIu64"\n",mp->mnt_stat.f_bfree); 1221 (*pr)("\tbavail = %"PRIu64"\n",mp->mnt_stat.f_bavail); 1222 (*pr)("\tbresvd = %"PRIu64"\n",mp->mnt_stat.f_bresvd); 1223 1224 (*pr)("\tfiles = %"PRIu64"\n",mp->mnt_stat.f_files); 1225 (*pr)("\tffree = %"PRIu64"\n",mp->mnt_stat.f_ffree); 1226 (*pr)("\tfavail = %"PRIu64"\n",mp->mnt_stat.f_favail); 1227 (*pr)("\tfresvd = %"PRIu64"\n",mp->mnt_stat.f_fresvd); 1228 1229 (*pr)("\tf_fsidx = { 0x%"PRIx32", 0x%"PRIx32" }\n", 1230 mp->mnt_stat.f_fsidx.__fsid_val[0], 1231 mp->mnt_stat.f_fsidx.__fsid_val[1]); 1232 1233 (*pr)("\towner = %"PRIu32"\n",mp->mnt_stat.f_owner); 1234 (*pr)("\tnamemax = %lu\n",mp->mnt_stat.f_namemax); 1235 1236 snprintb(sbuf, sizeof(sbuf), __MNT_FLAG_BITS, mp->mnt_stat.f_flag); 1237 1238 (*pr)("\tflag = %s\n",sbuf); 1239 (*pr)("\tsyncwrites = %" PRIu64 "\n",mp->mnt_stat.f_syncwrites); 1240 (*pr)("\tasyncwrites = %" PRIu64 "\n",mp->mnt_stat.f_asyncwrites); 1241 (*pr)("\tsyncreads = %" PRIu64 "\n",mp->mnt_stat.f_syncreads); 1242 (*pr)("\tasyncreads = %" PRIu64 "\n",mp->mnt_stat.f_asyncreads); 1243 (*pr)("\tfstypename = %s\n",mp->mnt_stat.f_fstypename); 1244 (*pr)("\tmntonname = %s\n",mp->mnt_stat.f_mntonname); 1245 (*pr)("\tmntfromname = %s\n",mp->mnt_stat.f_mntfromname); 1246 1247 { 1248 int cnt = 0; 1249 struct vnode *vp; 1250 (*pr)("locked vnodes ="); 1251 TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { 1252 if (VOP_ISLOCKED(vp)) { 1253 if ((++cnt % 6) == 0) { 1254 (*pr)(" %p,\n\t", vp); 1255 } else { 1256 (*pr)(" %p,", vp); 1257 } 1258 } 1259 } 1260 (*pr)("\n"); 1261 } 1262 1263 if (full) { 1264 int cnt = 0; 1265 struct vnode *vp; 1266 (*pr)("all vnodes ="); 1267 TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { 1268 if (!TAILQ_NEXT(vp, v_mntvnodes)) { 1269 (*pr)(" %p", vp); 1270 } else if ((++cnt % 6) == 0) { 1271 (*pr)(" %p,\n\t", vp); 1272 } else { 1273 (*pr)(" %p,", vp); 1274 } 1275 } 1276 (*pr)("\n", vp); 1277 } 1278 } 1279 1280 /* 1281 * List all of the locked vnodes in the system. 1282 */ 1283 void printlockedvnodes(void); 1284 1285 void 1286 printlockedvnodes(void) 1287 { 1288 struct mount *mp, *nmp; 1289 struct vnode *vp; 1290 1291 printf("Locked vnodes\n"); 1292 mutex_enter(&mountlist_lock); 1293 for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist; 1294 mp = nmp) { 1295 if (vfs_busy(mp, &nmp)) { 1296 continue; 1297 } 1298 TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { 1299 if (VOP_ISLOCKED(vp)) 1300 vprint(NULL, vp); 1301 } 1302 mutex_enter(&mountlist_lock); 1303 vfs_unbusy(mp, false, &nmp); 1304 } 1305 mutex_exit(&mountlist_lock); 1306 } 1307 1308 #endif /* DDB || DEBUGPRINT */ 1309