X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fa4905b191e0d16b0fffd53bd565eca71d01fae0..ccc36f2f2d89f9115c479db4439aa5c88de5b44a:/bsd/miscfs/specfs/spec_vnops.c diff --git a/bsd/miscfs/specfs/spec_vnops.c b/bsd/miscfs/specfs/spec_vnops.c index 81b836085..314464b19 100644 --- a/bsd/miscfs/specfs/spec_vnops.c +++ b/bsd/miscfs/specfs/spec_vnops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -69,10 +69,12 @@ #include #include #include -#include +#include #include +#include #include +#include struct vnode *speclisth[SPECHSZ]; @@ -125,7 +127,7 @@ struct vnodeopv_entry_desc spec_vnodeop_entries[] = { { &vop_print_desc, (VOPFUNC)spec_print }, /* print */ { &vop_islocked_desc, (VOPFUNC)nop_islocked }, /* islocked */ { &vop_pathconf_desc, (VOPFUNC)spec_pathconf }, /* pathconf */ - { &vop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */ + { &vop_advlock_desc, (VOPFUNC)spec_advlock }, /* advlock */ { &vop_blkatoff_desc, (VOPFUNC)err_blkatoff }, /* blkatoff */ { &vop_valloc_desc, (VOPFUNC)err_valloc }, /* valloc */ { &vop_vfree_desc, (VOPFUNC)err_vfree }, /* vfree */ @@ -271,7 +273,30 @@ spec_open(ap) return (error); error = (*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, p); if (!error) { + u_int64_t blkcnt; + u_int32_t blksize; + set_blocksize(vp, dev); + + /* + * Cache the size in bytes of the block device for later + * use by spec_write(). + */ + vp->v_specdevsize = (u_int64_t)0; /* Default: Can't get */ + if (!VOP_IOCTL(vp, DKIOCGETBLOCKSIZE, (caddr_t)&blksize, 0, NOCRED, p)) { + /* Switch to 512 byte sectors (temporarily) */ + u_int32_t size512 = 512; + + if (!VOP_IOCTL(vp, DKIOCSETBLOCKSIZE, (caddr_t)&size512, FWRITE, NOCRED, p)) { + /* Get the number of 512 byte physical blocks. */ + if (!VOP_IOCTL(vp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, NOCRED, p)) { + vp->v_specdevsize = blkcnt * (u_int64_t)size512; + } + } + /* If it doesn't set back, we can't recover */ + if (VOP_IOCTL(vp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, NOCRED, p)) + error = ENXIO; + } } return(error); } @@ -435,11 +460,35 @@ spec_write(ap) n = min((unsigned)(bsize - on), uio->uio_resid); + /* + * Use getblk() as an optimization IFF: + * + * 1) We are reading exactly a block on a block + * aligned boundary + * 2) We know the size of the device from spec_open + * 3) The read doesn't span the end of the device + * + * Otherwise, we fall back on bread(). + */ + if (n == bsize && + vp->v_specdevsize != (u_int64_t)0 && + (uio->uio_offset + (u_int64_t)n) > vp->v_specdevsize) { + /* reduce the size of the read to what is there */ + n = (uio->uio_offset + (u_int64_t)n) - vp->v_specdevsize; + } + if (n == bsize) bp = getblk(vp, bn, bsize, 0, 0, BLK_WRITE); else error = bread(vp, bn, bsize, NOCRED, &bp); + /* Translate downstream error for upstream, if needed */ + if (!error) { + error = bp->b_error; + if (!error && (bp->b_flags & B_ERROR) != 0) { + error = EIO; + } + } if (error) { brelse(bp); return (error); @@ -554,7 +603,8 @@ loop: s = splbio(); for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { nbp = bp->b_vnbufs.le_next; - if ((bp->b_flags & B_BUSY)) + // XXXdbg - don't flush locked blocks. they may be journaled. + if ((bp->b_flags & B_BUSY) || (bp->b_flags & B_LOCKED)) continue; if ((bp->b_flags & B_DELWRI) == 0) panic("spec_fsync: not dirty"); @@ -589,8 +639,126 @@ spec_strategy(ap) struct buf *a_bp; } */ *ap; { - (*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp); - return (0); + struct buf *bp; + extern int hard_throttle_on_root; + + bp = ap->a_bp; + + if (kdebug_enable) { + int code = 0; + + if (bp->b_flags & B_READ) + code |= DKIO_READ; + if (bp->b_flags & B_ASYNC) + code |= DKIO_ASYNC; + + if (bp->b_flags & B_META) + code |= DKIO_META; + else if (bp->b_flags & (B_PGIN | B_PAGEOUT)) + code |= DKIO_PAGING; + + KERNEL_DEBUG_CONSTANT(FSDBG_CODE(DBG_DKRW, code) | DBG_FUNC_NONE, + (unsigned int)bp, bp->b_dev, bp->b_blkno, bp->b_bcount, 0); + } + if ((bp->b_flags & B_PGIN) && (bp->b_vp->v_mount->mnt_kern_flag & MNTK_ROOTDEV)) + hard_throttle_on_root = 1; + + (*bdevsw[major(bp->b_dev)].d_strategy)(bp); + return (0); +} + +/* + * Advisory record locking support + */ +int +spec_advlock(ap) + struct vop_advlock_args /* { + struct vnode *a_vp; + caddr_t a_id; + int a_op; + struct flock *a_fl; + int a_flags; + } */ *ap; +{ + register struct flock *fl = ap->a_fl; + register struct lockf *lock; + off_t start, end; + int error; + + /* + * Avoid the common case of unlocking when inode has no locks. + */ + if (ap->a_vp->v_specinfo->si_lockf == (struct lockf *)0) { + if (ap->a_op != F_SETLK) { + fl->l_type = F_UNLCK; + return (0); + } + } + /* + * Convert the flock structure into a start and end. + */ + switch (fl->l_whence) { + + case SEEK_SET: + case SEEK_CUR: + /* + * Caller is responsible for adding any necessary offset + * when SEEK_CUR is used. + */ + start = fl->l_start; + break; + + case SEEK_END: + start = ap->a_vp->v_specinfo->si_devsize + fl->l_start; + break; + + default: + return (EINVAL); + } + if (fl->l_len == 0) + end = -1; + else if (fl->l_len > 0) + end = start + fl->l_len - 1; + else { /* l_len is negative */ + end = start - 1; + start += fl->l_len; + } + if (start < 0) + return (EINVAL); + /* + * Create the lockf structure + */ + MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK); + lock->lf_start = start; + lock->lf_end = end; + lock->lf_id = ap->a_id; + lock->lf_specinfo = ap->a_vp->v_specinfo; + lock->lf_type = fl->l_type; + lock->lf_next = (struct lockf *)0; + TAILQ_INIT(&lock->lf_blkhd); + lock->lf_flags = ap->a_flags; + /* + * Do the requested operation. + */ + switch(ap->a_op) { + case F_SETLK: + return (spec_lf_setlock(lock)); + + case F_UNLCK: + error = spec_lf_clearlock(lock); + FREE(lock, M_LOCKF); + return (error); + + case F_GETLK: + error = spec_lf_getlock(lock, fl); + FREE(lock, M_LOCKF); + return (error); + + default: + _FREE(lock, M_LOCKF); + return (EINVAL); + } + /* NOTREACHED */ } /*