/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/malloc.h>
-#include <dev/disk.h>
+#include <sys/disk.h>
#include <miscfs/specfs/specdev.h>
+#include <miscfs/specfs/lockf.h>
#include <vfs/vfs_support.h>
+#include <sys/kdebug.h>
struct vnode *speclisth[SPECHSZ];
{ &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 */
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);
}
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);
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");
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 */
}
/*
*/
if (vcount(vp) == 2 && ap->a_p &&
vp == ap->a_p->p_session->s_ttyvp) {
- vrele(vp);
ap->a_p->p_session->s_ttyvp = NULL;
+ vrele(vp);
}
/*
* If the vnode is locked, then we are in the midst