|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 23: /* ! 24: * Copyright (c) 1989, 1993, 1995 ! 25: * The Regents of the University of California. All rights reserved. ! 26: * ! 27: * Redistribution and use in source and binary forms, with or without ! 28: * modification, are permitted provided that the following conditions ! 29: * are met: ! 30: * 1. Redistributions of source code must retain the above copyright ! 31: * notice, this list of conditions and the following disclaimer. ! 32: * 2. Redistributions in binary form must reproduce the above copyright ! 33: * notice, this list of conditions and the following disclaimer in the ! 34: * documentation and/or other materials provided with the distribution. ! 35: * 3. All advertising materials mentioning features or use of this software ! 36: * must display the following acknowledgement: ! 37: * This product includes software developed by the University of ! 38: * California, Berkeley and its contributors. ! 39: * 4. Neither the name of the University nor the names of its contributors ! 40: * may be used to endorse or promote products derived from this software ! 41: * without specific prior written permission. ! 42: * ! 43: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 44: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 45: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 46: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 47: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 48: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 49: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 50: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 51: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 52: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 53: * SUCH DAMAGE. ! 54: * ! 55: * @(#)spec_vnops.c 8.14 (Berkeley) 5/21/95 ! 56: */ ! 57: ! 58: #include <sys/param.h> ! 59: #include <sys/proc.h> ! 60: #include <sys/systm.h> ! 61: #include <sys/kernel.h> ! 62: #include <sys/conf.h> ! 63: #include <sys/buf.h> ! 64: #include <sys/mount.h> ! 65: #include <sys/namei.h> ! 66: #include <sys/vnode.h> ! 67: #include <sys/stat.h> ! 68: #include <sys/errno.h> ! 69: #include <sys/ioctl.h> ! 70: #include <sys/file.h> ! 71: #include <sys/malloc.h> ! 72: #include <bsd/dev/disk.h> ! 73: #include <miscfs/specfs/specdev.h> ! 74: #include <vfs/vfs_support.h> ! 75: ! 76: extern int doclusterread, doclusterwrite; ! 77: ! 78: struct vnode *speclisth[SPECHSZ]; ! 79: ! 80: /* symbolic sleep message strings for devices */ ! 81: char devopn[] = "devopn"; ! 82: char devio[] = "devio"; ! 83: char devwait[] = "devwait"; ! 84: char devin[] = "devin"; ! 85: char devout[] = "devout"; ! 86: char devioc[] = "devioc"; ! 87: char devcls[] = "devcls"; ! 88: ! 89: int (**spec_vnodeop_p)(); ! 90: struct vnodeopv_entry_desc spec_vnodeop_entries[] = { ! 91: { &vop_default_desc, vn_default_error }, ! 92: { &vop_lookup_desc, spec_lookup }, /* lookup */ ! 93: { &vop_create_desc, err_create }, /* create */ ! 94: { &vop_mknod_desc, err_mknod }, /* mknod */ ! 95: { &vop_open_desc, spec_open }, /* open */ ! 96: { &vop_close_desc, spec_close }, /* close */ ! 97: { &vop_access_desc, spec_access }, /* access */ ! 98: { &vop_getattr_desc, spec_getattr }, /* getattr */ ! 99: { &vop_setattr_desc, spec_setattr }, /* setattr */ ! 100: { &vop_read_desc, spec_read }, /* read */ ! 101: { &vop_write_desc, spec_write }, /* write */ ! 102: { &vop_lease_desc, nop_lease }, /* lease */ ! 103: { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ ! 104: { &vop_select_desc, spec_select }, /* select */ ! 105: { &vop_revoke_desc, nop_revoke }, /* revoke */ ! 106: { &vop_mmap_desc, err_mmap }, /* mmap */ ! 107: { &vop_fsync_desc, spec_fsync }, /* fsync */ ! 108: { &vop_seek_desc, err_seek }, /* seek */ ! 109: { &vop_remove_desc, err_remove }, /* remove */ ! 110: { &vop_link_desc, err_link }, /* link */ ! 111: { &vop_rename_desc, err_rename }, /* rename */ ! 112: { &vop_mkdir_desc, err_mkdir }, /* mkdir */ ! 113: { &vop_rmdir_desc, err_rmdir }, /* rmdir */ ! 114: { &vop_symlink_desc, err_symlink }, /* symlink */ ! 115: { &vop_readdir_desc, err_readdir }, /* readdir */ ! 116: { &vop_readlink_desc, err_readlink }, /* readlink */ ! 117: { &vop_abortop_desc, err_abortop }, /* abortop */ ! 118: { &vop_inactive_desc, nop_inactive }, /* inactive */ ! 119: { &vop_reclaim_desc, nop_reclaim }, /* reclaim */ ! 120: { &vop_lock_desc, nop_lock }, /* lock */ ! 121: { &vop_unlock_desc, nop_unlock }, /* unlock */ ! 122: { &vop_bmap_desc, spec_bmap }, /* bmap */ ! 123: { &vop_strategy_desc, spec_strategy }, /* strategy */ ! 124: { &vop_print_desc, spec_print }, /* print */ ! 125: { &vop_islocked_desc, nop_islocked }, /* islocked */ ! 126: { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ ! 127: { &vop_advlock_desc, err_advlock }, /* advlock */ ! 128: { &vop_blkatoff_desc, err_blkatoff }, /* blkatoff */ ! 129: { &vop_valloc_desc, err_valloc }, /* valloc */ ! 130: { &vop_vfree_desc, err_vfree }, /* vfree */ ! 131: { &vop_truncate_desc, nop_truncate }, /* truncate */ ! 132: { &vop_update_desc, nop_update }, /* update */ ! 133: { &vop_bwrite_desc, spec_bwrite }, /* bwrite */ ! 134: { &vop_devblocksize_desc, spec_devblocksize }, /* devblocksize */ ! 135: { &vop_pagein_desc, spec_pagein }, /* Pagein */ ! 136: { &vop_pageout_desc, spec_pageout }, /* Pageout */ ! 137: { &vop_copyfile_desc, err_copyfile }, /* Copyfile */ ! 138: { (struct vnodeop_desc*)NULL, (int(*)())NULL } ! 139: }; ! 140: struct vnodeopv_desc spec_vnodeop_opv_desc = ! 141: { &spec_vnodeop_p, spec_vnodeop_entries }; ! 142: ! 143: /* ! 144: * Trivial lookup routine that always fails. ! 145: */ ! 146: int ! 147: spec_lookup(ap) ! 148: struct vop_lookup_args /* { ! 149: struct vnode *a_dvp; ! 150: struct vnode **a_vpp; ! 151: struct componentname *a_cnp; ! 152: } */ *ap; ! 153: { ! 154: ! 155: *ap->a_vpp = NULL; ! 156: return (ENOTDIR); ! 157: } ! 158: ! 159: void ! 160: set_blocksize(struct vnode *vp, dev_t dev) ! 161: { ! 162: int (*size)(); ! 163: int rsize; ! 164: ! 165: if ((major(dev) < nblkdev) && (size = bdevsw[major(dev)].d_psize)) { ! 166: rsize = (*size)(dev); ! 167: if (rsize <= 0) /* did size fail? */ ! 168: vp->v_specsize = DEV_BSIZE; ! 169: else ! 170: vp->v_specsize = rsize; ! 171: } ! 172: else ! 173: vp->v_specsize = DEV_BSIZE; ! 174: } ! 175: ! 176: void ! 177: set_fsblocksize(struct vnode *vp) ! 178: { ! 179: ! 180: if (vp->v_type == VBLK) { ! 181: dev_t dev = (dev_t)vp->v_rdev; ! 182: int maj = major(dev); ! 183: ! 184: if ((u_int)maj >= nblkdev) ! 185: return; ! 186: ! 187: set_blocksize(vp, dev); ! 188: } ! 189: ! 190: } ! 191: ! 192: ! 193: /* ! 194: * Open a special file. ! 195: */ ! 196: /* ARGSUSED */ ! 197: spec_open(ap) ! 198: struct vop_open_args /* { ! 199: struct vnode *a_vp; ! 200: int a_mode; ! 201: struct ucred *a_cred; ! 202: struct proc *a_p; ! 203: } */ *ap; ! 204: { ! 205: struct proc *p = ap->a_p; ! 206: struct vnode *bvp, *vp = ap->a_vp; ! 207: dev_t bdev, dev = (dev_t)vp->v_rdev; ! 208: int maj = major(dev); ! 209: int error; ! 210: ! 211: /* ! 212: * Don't allow open if fs is mounted -nodev. ! 213: */ ! 214: if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) ! 215: return (ENXIO); ! 216: ! 217: switch (vp->v_type) { ! 218: ! 219: case VCHR: ! 220: if ((u_int)maj >= nchrdev) ! 221: return (ENXIO); ! 222: if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) { ! 223: /* ! 224: * When running in very secure mode, do not allow ! 225: * opens for writing of any disk character devices. ! 226: */ ! 227: if (securelevel >= 2 && isdisk(dev, VCHR)) ! 228: return (EPERM); ! 229: /* ! 230: * When running in secure mode, do not allow opens ! 231: * for writing of /dev/mem, /dev/kmem, or character ! 232: * devices whose corresponding block devices are ! 233: * currently mounted. ! 234: */ ! 235: if (securelevel >= 1) { ! 236: if ((bdev = chrtoblk(dev)) != NODEV && ! 237: vfinddev(bdev, VBLK, &bvp) && ! 238: bvp->v_usecount > 0 && ! 239: (error = vfs_mountedon(bvp))) ! 240: return (error); ! 241: if (iskmemdev(dev)) ! 242: return (EPERM); ! 243: } ! 244: } ! 245: if (cdevsw[maj].d_type == D_TTY) ! 246: vp->v_flag |= VISTTY; ! 247: VOP_UNLOCK(vp, 0, p); ! 248: error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, p); ! 249: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 250: return (error); ! 251: ! 252: case VBLK: ! 253: if ((u_int)maj >= nblkdev) ! 254: return (ENXIO); ! 255: /* ! 256: * When running in very secure mode, do not allow ! 257: * opens for writing of any disk block devices. ! 258: */ ! 259: if (securelevel >= 2 && ap->a_cred != FSCRED && ! 260: (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK) ! 261: return (EPERM); ! 262: /* ! 263: * Do not allow opens of block devices that are ! 264: * currently mounted. ! 265: */ ! 266: if (error = vfs_mountedon(vp)) ! 267: return (error); ! 268: ! 269: error = (*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, p); ! 270: if (!error) { ! 271: set_blocksize(vp, dev); ! 272: } ! 273: return(error); ! 274: } ! 275: return (0); ! 276: } ! 277: ! 278: /* ! 279: * Vnode op for read ! 280: */ ! 281: /* ARGSUSED */ ! 282: spec_read(ap) ! 283: struct vop_read_args /* { ! 284: struct vnode *a_vp; ! 285: struct uio *a_uio; ! 286: int a_ioflag; ! 287: struct ucred *a_cred; ! 288: } */ *ap; ! 289: { ! 290: register struct vnode *vp = ap->a_vp; ! 291: register struct uio *uio = ap->a_uio; ! 292: struct proc *p = uio->uio_procp; ! 293: struct buf *bp; ! 294: daddr_t bn, nextbn; ! 295: long bsize, bscale; ! 296: int devBlockSize=0; ! 297: int firstpass, seq; ! 298: int n, on, majordev, (*ioctl)(); ! 299: int error = 0; ! 300: dev_t dev; ! 301: ! 302: #if DIAGNOSTIC ! 303: if (uio->uio_rw != UIO_READ) ! 304: panic("spec_read mode"); ! 305: if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != current_proc()) ! 306: panic("spec_read proc"); ! 307: #endif ! 308: if (uio->uio_resid == 0) ! 309: return (0); ! 310: ! 311: switch (vp->v_type) { ! 312: ! 313: case VCHR: ! 314: VOP_UNLOCK(vp, 0, p); ! 315: error = (*cdevsw[major(vp->v_rdev)].d_read) ! 316: (vp->v_rdev, uio, ap->a_ioflag); ! 317: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 318: return (error); ! 319: ! 320: case VBLK: ! 321: if (uio->uio_offset < 0) ! 322: return (EINVAL); ! 323: bsize = PAGE_SIZE; ! 324: dev = vp->v_rdev; ! 325: devBlockSize = vp->v_specsize; ! 326: bscale = bsize / devBlockSize; ! 327: firstpass = TRUE; ! 328: ! 329: do { ! 330: on = uio->uio_offset % bsize; ! 331: ! 332: if (doclusterread && doclusterwrite) { ! 333: bn = uio->uio_offset / bsize; ! 334: ! 335: error = cluster_read(vp, (u_quad_t)0x7fffffffffffffff, bn, bsize, NOCRED, ! 336: &bp, devBlockSize, firstpass, uio->uio_resid+on, &seq); ! 337: } else { ! 338: bn = (uio->uio_offset / devBlockSize) &~ (bscale - 1); ! 339: ! 340: if (vp->v_lastr + bscale == bn) { ! 341: nextbn = bn + bscale; ! 342: error = breadn(vp, bn, (int)bsize, &nextbn, ! 343: (int *)&bsize, 1, NOCRED, &bp); ! 344: } else ! 345: error = bread(vp, bn, (int)bsize, NOCRED, &bp); ! 346: } ! 347: firstpass = FALSE; ! 348: ! 349: vp->v_lastr = bn; ! 350: n = bsize - bp->b_resid; ! 351: if ((on > n) || error) { ! 352: if (!error) ! 353: error = EINVAL; ! 354: brelse(bp); ! 355: return (error); ! 356: } ! 357: n = min((unsigned)(n - on), uio->uio_resid); ! 358: ! 359: error = uiomove((char *)bp->b_data + on, n, uio); ! 360: if (n + on == bsize) ! 361: bp->b_flags |= B_AGE; ! 362: brelse(bp); ! 363: } while (error == 0 && uio->uio_resid > 0 && n != 0); ! 364: ! 365: return (error); ! 366: ! 367: default: ! 368: panic("spec_read type"); ! 369: } ! 370: /* NOTREACHED */ ! 371: } ! 372: ! 373: /* ! 374: * Vnode op for write ! 375: */ ! 376: /* ARGSUSED */ ! 377: spec_write(ap) ! 378: struct vop_write_args /* { ! 379: struct vnode *a_vp; ! 380: struct uio *a_uio; ! 381: int a_ioflag; ! 382: struct ucred *a_cred; ! 383: } */ *ap; ! 384: { ! 385: register struct vnode *vp = ap->a_vp; ! 386: register struct uio *uio = ap->a_uio; ! 387: struct proc *p = uio->uio_procp; ! 388: struct buf *bp; ! 389: daddr_t bn; ! 390: int bsize, blkmask; ! 391: register int io_sync; ! 392: register int io_size; ! 393: register int forcewrite; ! 394: int devBlockSize=0; ! 395: register int n, on; ! 396: int error = 0; ! 397: dev_t dev; ! 398: ! 399: #if DIAGNOSTIC ! 400: if (uio->uio_rw != UIO_WRITE) ! 401: panic("spec_write mode"); ! 402: if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != current_proc()) ! 403: panic("spec_write proc"); ! 404: #endif ! 405: ! 406: switch (vp->v_type) { ! 407: ! 408: case VCHR: ! 409: VOP_UNLOCK(vp, 0, p); ! 410: error = (*cdevsw[major(vp->v_rdev)].d_write) ! 411: (vp->v_rdev, uio, ap->a_ioflag); ! 412: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 413: return (error); ! 414: ! 415: case VBLK: ! 416: if (uio->uio_resid == 0) ! 417: return (0); ! 418: if (uio->uio_offset < 0) ! 419: return (EINVAL); ! 420: ! 421: bsize = PAGE_SIZE; ! 422: io_sync = (ap->a_ioflag & IO_SYNC); ! 423: io_size = uio->uio_resid; ! 424: dev = (vp->v_rdev); ! 425: devBlockSize = vp->v_specsize; ! 426: blkmask = (bsize / devBlockSize) - 1; ! 427: ! 428: do { ! 429: forcewrite = 0; ! 430: ! 431: if (doclusterread && doclusterwrite) ! 432: bn = uio->uio_offset / bsize; ! 433: else ! 434: bn = (uio->uio_offset / devBlockSize) &~ blkmask; ! 435: on = uio->uio_offset % bsize; ! 436: ! 437: n = min((unsigned)(bsize - on), uio->uio_resid); ! 438: ! 439: if (doclusterread && doclusterwrite) { ! 440: bp = getblk(vp, bn, bsize, 0, 0); ! 441: ! 442: VOP_BMAP(vp, bn, NULL, &bp->b_blkno, NULL); ! 443: ! 444: if (n != bsize && !(bp->b_flags & (B_DONE|B_DELWRI))) { ! 445: if ((on % devBlockSize) || (n % devBlockSize)) { ! 446: bp->b_flags |= B_READ; ! 447: VOP_STRATEGY(bp); ! 448: error = biowait(bp); ! 449: } else { ! 450: if (on) { ! 451: bp->b_blkno += (on / devBlockSize); ! 452: on = 0; ! 453: } ! 454: forcewrite = 1; ! 455: bp->b_bcount = n; ! 456: bp->b_flags |= B_INVAL; ! 457: } ! 458: } ! 459: } else { ! 460: if (n == bsize) ! 461: bp = getblk(vp, bn, bsize, 0, 0); ! 462: else ! 463: error = bread(vp, bn, bsize, NOCRED, &bp); ! 464: } ! 465: if (error) { ! 466: brelse(bp); ! 467: return (error); ! 468: } ! 469: n = min(n, bsize - bp->b_resid); ! 470: ! 471: error = uiomove((char *)bp->b_data + on, n, uio); ! 472: ! 473: if (forcewrite) { ! 474: if (uio->uio_resid == 0) ! 475: bwrite(bp); ! 476: else ! 477: bawrite(bp); ! 478: } else if (((io_size >= bsize) || ((n + on) == bsize)) && doclusterread && doclusterwrite) { ! 479: if (io_sync) { ! 480: if (uio->uio_resid < bsize) ! 481: bp->b_flags |= (B_CLUST_SYNC | B_CLUST_COMMIT); ! 482: else ! 483: bp->b_flags |= B_CLUST_SYNC; ! 484: ! 485: error = cluster_write(bp, (u_quad_t)0x7fffffffffffffff, devBlockSize); ! 486: } else ! 487: cluster_write(bp, (u_quad_t)0x7fffffffffffffff, devBlockSize); ! 488: } else { ! 489: bp->b_flags |= B_AGE; ! 490: ! 491: if (io_sync) ! 492: bwrite(bp); ! 493: else { ! 494: if ((n + on) == bsize) ! 495: bawrite(bp); ! 496: else ! 497: bdwrite(bp); ! 498: } ! 499: } ! 500: } while (error == 0 && uio->uio_resid > 0 && n != 0); ! 501: ! 502: return (error); ! 503: ! 504: default: ! 505: panic("spec_write type"); ! 506: } ! 507: /* NOTREACHED */ ! 508: } ! 509: ! 510: /* ! 511: * Device ioctl operation. ! 512: */ ! 513: /* ARGSUSED */ ! 514: spec_ioctl(ap) ! 515: struct vop_ioctl_args /* { ! 516: struct vnode *a_vp; ! 517: int a_command; ! 518: caddr_t a_data; ! 519: int a_fflag; ! 520: struct ucred *a_cred; ! 521: struct proc *a_p; ! 522: } */ *ap; ! 523: { ! 524: dev_t dev = ap->a_vp->v_rdev; ! 525: ! 526: switch (ap->a_vp->v_type) { ! 527: ! 528: case VCHR: ! 529: return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, ! 530: ap->a_fflag, ap->a_p)); ! 531: ! 532: case VBLK: ! 533: if (ap->a_command == 0 && (int)ap->a_data == B_TAPE) ! 534: if (bdevsw[major(dev)].d_type == D_TAPE) ! 535: return (0); ! 536: else ! 537: return (1); ! 538: return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data, ! 539: ap->a_fflag, ap->a_p)); ! 540: ! 541: default: ! 542: panic("spec_ioctl"); ! 543: /* NOTREACHED */ ! 544: } ! 545: } ! 546: ! 547: /* ARGSUSED */ ! 548: spec_select(ap) ! 549: struct vop_select_args /* { ! 550: struct vnode *a_vp; ! 551: int a_which; ! 552: int a_fflags; ! 553: struct ucred *a_cred; ! 554: struct proc *a_p; ! 555: } */ *ap; ! 556: { ! 557: register dev_t dev; ! 558: ! 559: switch (ap->a_vp->v_type) { ! 560: ! 561: default: ! 562: return (1); /* XXX */ ! 563: ! 564: case VCHR: ! 565: dev = ap->a_vp->v_rdev; ! 566: return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p); ! 567: } ! 568: } ! 569: /* ! 570: * Synch buffers associated with a block device ! 571: */ ! 572: /* ARGSUSED */ ! 573: int ! 574: spec_fsync(ap) ! 575: struct vop_fsync_args /* { ! 576: struct vnode *a_vp; ! 577: struct ucred *a_cred; ! 578: int a_waitfor; ! 579: struct proc *a_p; ! 580: } */ *ap; ! 581: { ! 582: register struct vnode *vp = ap->a_vp; ! 583: register struct buf *bp; ! 584: struct buf *nbp; ! 585: int s; ! 586: ! 587: if (vp->v_type == VCHR) ! 588: return (0); ! 589: /* ! 590: * Flush all dirty buffers associated with a block device. ! 591: */ ! 592: loop: ! 593: s = splbio(); ! 594: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { ! 595: nbp = bp->b_vnbufs.le_next; ! 596: if ((bp->b_flags & B_BUSY)) ! 597: continue; ! 598: if ((bp->b_flags & B_DELWRI) == 0) ! 599: panic("spec_fsync: not dirty"); ! 600: bremfree(bp); ! 601: bp->b_flags |= B_BUSY; ! 602: splx(s); ! 603: bawrite(bp); ! 604: goto loop; ! 605: } ! 606: if (ap->a_waitfor == MNT_WAIT) { ! 607: while (vp->v_numoutput) { ! 608: vp->v_flag |= VBWAIT; ! 609: tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "spec_fsync", 0); ! 610: } ! 611: #if DIAGNOSTIC ! 612: if (vp->v_dirtyblkhd.lh_first) { ! 613: vprint("spec_fsync: dirty", vp); ! 614: splx(s); ! 615: goto loop; ! 616: } ! 617: #endif ! 618: } ! 619: splx(s); ! 620: return (0); ! 621: } ! 622: ! 623: /* ! 624: * Just call the device strategy routine ! 625: */ ! 626: spec_strategy(ap) ! 627: struct vop_strategy_args /* { ! 628: struct buf *a_bp; ! 629: } */ *ap; ! 630: { ! 631: (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); ! 632: return (0); ! 633: } ! 634: ! 635: /* ! 636: * This is a noop, simply returning what one has been given. ! 637: */ ! 638: spec_bmap(ap) ! 639: struct vop_bmap_args /* { ! 640: struct vnode *a_vp; ! 641: daddr_t a_bn; ! 642: struct vnode **a_vpp; ! 643: daddr_t *a_bnp; ! 644: int *a_runp; ! 645: } */ *ap; ! 646: { ! 647: ! 648: if (ap->a_vpp != NULL) ! 649: *ap->a_vpp = ap->a_vp; ! 650: if (ap->a_bnp != NULL) ! 651: *ap->a_bnp = ap->a_bn * (PAGE_SIZE / ap->a_vp->v_specsize); ! 652: if (ap->a_runp != NULL) ! 653: *ap->a_runp = (MAXPHYSIO / PAGE_SIZE) - 1; ! 654: return (0); ! 655: } ! 656: ! 657: /* ! 658: * Device close routine ! 659: */ ! 660: /* ARGSUSED */ ! 661: spec_close(ap) ! 662: struct vop_close_args /* { ! 663: struct vnode *a_vp; ! 664: int a_fflag; ! 665: struct ucred *a_cred; ! 666: struct proc *a_p; ! 667: } */ *ap; ! 668: { ! 669: register struct vnode *vp = ap->a_vp; ! 670: dev_t dev = vp->v_rdev; ! 671: int (*devclose) __P((dev_t, int, int, struct proc *)); ! 672: int mode, error; ! 673: ! 674: switch (vp->v_type) { ! 675: ! 676: case VCHR: ! 677: /* ! 678: * Hack: a tty device that is a controlling terminal ! 679: * has a reference from the session structure. ! 680: * We cannot easily tell that a character device is ! 681: * a controlling terminal, unless it is the closing ! 682: * process' controlling terminal. In that case, ! 683: * if the reference count is 2 (this last descriptor ! 684: * plus the session), release the reference from the session. ! 685: */ ! 686: if (vcount(vp) == 2 && ap->a_p && ! 687: vp == ap->a_p->p_session->s_ttyvp) { ! 688: vrele(vp); ! 689: ap->a_p->p_session->s_ttyvp = NULL; ! 690: } ! 691: /* ! 692: * If the vnode is locked, then we are in the midst ! 693: * of forcably closing the device, otherwise we only ! 694: * close on last reference. ! 695: */ ! 696: if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) ! 697: return (0); ! 698: devclose = cdevsw[major(dev)].d_close; ! 699: mode = S_IFCHR; ! 700: break; ! 701: ! 702: case VBLK: ! 703: /* ! 704: * On last close of a block device (that isn't mounted) ! 705: * we must invalidate any in core blocks, so that ! 706: * we can, for instance, change floppy disks. ! 707: */ ! 708: if (error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0)) ! 709: return (error); ! 710: /* ! 711: * We do not want to really close the device if it ! 712: * is still in use unless we are trying to close it ! 713: * forcibly. Since every use (buffer, vnode, swap, cmap) ! 714: * holds a reference to the vnode, and because we mark ! 715: * any other vnodes that alias this device, when the ! 716: * sum of the reference counts on all the aliased ! 717: * vnodes descends to one, we are on last close. ! 718: */ ! 719: if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) ! 720: return (0); ! 721: devclose = bdevsw[major(dev)].d_close; ! 722: mode = S_IFBLK; ! 723: break; ! 724: ! 725: default: ! 726: panic("spec_close: not special"); ! 727: } ! 728: ! 729: return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p)); ! 730: } ! 731: ! 732: /* ! 733: * Print out the contents of a special device vnode. ! 734: */ ! 735: spec_print(ap) ! 736: struct vop_print_args /* { ! 737: struct vnode *a_vp; ! 738: } */ *ap; ! 739: { ! 740: ! 741: printf("tag VT_NON, dev %d, %d\n", major(ap->a_vp->v_rdev), ! 742: minor(ap->a_vp->v_rdev)); ! 743: } ! 744: ! 745: /* ! 746: * Return POSIX pathconf information applicable to special devices. ! 747: */ ! 748: spec_pathconf(ap) ! 749: struct vop_pathconf_args /* { ! 750: struct vnode *a_vp; ! 751: int a_name; ! 752: int *a_retval; ! 753: } */ *ap; ! 754: { ! 755: ! 756: switch (ap->a_name) { ! 757: case _PC_LINK_MAX: ! 758: *ap->a_retval = LINK_MAX; ! 759: return (0); ! 760: case _PC_MAX_CANON: ! 761: *ap->a_retval = MAX_CANON; ! 762: return (0); ! 763: case _PC_MAX_INPUT: ! 764: *ap->a_retval = MAX_INPUT; ! 765: return (0); ! 766: case _PC_PIPE_BUF: ! 767: *ap->a_retval = PIPE_BUF; ! 768: return (0); ! 769: case _PC_CHOWN_RESTRICTED: ! 770: *ap->a_retval = 1; ! 771: return (0); ! 772: case _PC_VDISABLE: ! 773: *ap->a_retval = _POSIX_VDISABLE; ! 774: return (0); ! 775: default: ! 776: return (EINVAL); ! 777: } ! 778: /* NOTREACHED */ ! 779: } ! 780: ! 781: int ! 782: spec_devblocksize(ap) ! 783: struct vop_devblocksize_args /* { ! 784: struct vnode *a_vp; ! 785: int *a_retval; ! 786: } */ *ap; ! 787: { ! 788: *ap->a_retval = (ap->a_vp->v_specsize); ! 789: return (0); ! 790: } ! 791: ! 792: /* ! 793: * Special device failed operation ! 794: */ ! 795: spec_ebadf() ! 796: { ! 797: ! 798: return (EBADF); ! 799: } ! 800: ! 801: /* ! 802: * Special device bad operation ! 803: */ ! 804: spec_badop() ! 805: { ! 806: ! 807: panic("spec_badop called"); ! 808: /* NOTREACHED */ ! 809: } ! 810: /* Pagein */ ! 811: spec_pagein(ap) ! 812: struct vop_pagein_args /* { ! 813: struct vnode *a_vp; ! 814: struct uio *a_uio; ! 815: int a_ioflag; ! 816: struct ucred *a_cred; ! 817: } */ *ap; ! 818: { ! 819: /* pass thru to read */ ! 820: return (VOP_READ(ap->a_vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); ! 821: } ! 822: ! 823: /* Pageout */ ! 824: spec_pageout(ap) ! 825: struct vop_pageout_args /* { ! 826: struct vnode *a_vp; ! 827: struct uio *a_uio; ! 828: int a_ioflag; ! 829: struct ucred *a_cred; ! 830: } */ *ap; ! 831: { ! 832: /* pass thru to write */ ! 833: return (VOP_WRITE(ap->a_vp, ap->a_uio, ap->a_ioflag, ap->a_cred)); ! 834: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.