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