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