+#ifdef DIAGNOSTIC
+ if (checkoverlap) {
+ register struct buf *ep;
+ struct buf *ebp;
+ daddr_t start, last;
+
+ ebp = &buf[nbuf];
+ start = bp->b_blkno;
+ last = start + btodb(bp->b_bcount) - 1;
+ for (ep = buf; ep < ebp; ep++) {
+ if (ep == bp || (ep->b_flags & B_INVAL) ||
+ ep->b_vp == NULLVP)
+ continue;
+ if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0))
+ continue;
+ if (vp != ip->i_devvp)
+ continue;
+ /* look for overlap */
+ if (ep->b_bcount == 0 || ep->b_blkno > last ||
+ ep->b_blkno + btodb(ep->b_bcount) <= start)
+ continue;
+ vprint("Disk overlap", vp);
+ printf("\tstart %d, end %d overlap start %d, end %d\n",
+ start, last, ep->b_blkno,
+ ep->b_blkno + btodb(ep->b_bcount) - 1);
+ panic("Disk buffer overlap");
+ }
+ }
+#endif /* DIAGNOSTIC */
+ vp = ip->i_devvp;
+ bp->b_dev = vp->v_rdev;
+ (*(vp->v_op->vn_strategy))(bp);
+ return (0);
+}
+
+/*
+ * Print out the contents of an inode.
+ */
+ufs_print(vp)
+ struct vnode *vp;
+{
+ register struct inode *ip = VTOI(vp);
+
+ printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number,
+ major(ip->i_dev), minor(ip->i_dev));
+#ifdef FIFO
+ if (vp->v_type == VFIFO)
+ fifo_printinfo(vp);
+#endif /* FIFO */
+ printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : "");
+ if (ip->i_spare0 == 0)
+ return;
+ printf("\towner pid %d", ip->i_spare0);
+ if (ip->i_spare1)
+ printf(" waiting pid %d", ip->i_spare1);
+ printf("\n");
+}
+
+/*
+ * Read wrapper for special devices.
+ */
+ufsspec_read(vp, uio, ioflag, cred)
+ struct vnode *vp;
+ struct uio *uio;
+ int ioflag;
+ struct ucred *cred;
+{
+
+ /*
+ * Set access flag.
+ */
+ VTOI(vp)->i_flag |= IACC;
+ return (spec_read(vp, uio, ioflag, cred));
+}
+
+/*
+ * Write wrapper for special devices.
+ */
+ufsspec_write(vp, uio, ioflag, cred)
+ struct vnode *vp;
+ struct uio *uio;
+ int ioflag;
+ struct ucred *cred;
+{
+
+ /*
+ * Set update and change flags.
+ */
+ VTOI(vp)->i_flag |= IUPD|ICHG;
+ return (spec_write(vp, uio, ioflag, cred));
+}
+
+/*
+ * Close wrapper for special devices.
+ *
+ * Update the times on the inode then do device close.
+ */
+ufsspec_close(vp, fflag, cred)
+ struct vnode *vp;
+ int fflag;
+ struct ucred *cred;
+{
+ register struct inode *ip = VTOI(vp);
+
+ if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
+ ITIMES(ip, &time, &time);
+ return (spec_close(vp, fflag, cred));
+}
+
+#ifdef FIFO
+/*
+ * Read wrapper for fifo's
+ */
+ufsfifo_read(vp, uio, ioflag, cred)
+ struct vnode *vp;
+ struct uio *uio;
+ int ioflag;
+ struct ucred *cred;
+{
+
+ /*
+ * Set access flag.
+ */
+ VTOI(vp)->i_flag |= IACC;
+ return (fifo_read(vp, uio, ioflag, cred));
+}
+
+/*
+ * Write wrapper for fifo's.
+ */
+ufsfifo_write(vp, uio, ioflag, cred)
+ struct vnode *vp;
+ struct uio *uio;
+ int ioflag;
+ struct ucred *cred;
+{
+
+ /*
+ * Set update and change flags.
+ */
+ VTOI(vp)->i_flag |= IUPD|ICHG;
+ return (fifo_write(vp, uio, ioflag, cred));
+}
+
+/*
+ * Close wrapper for fifo's.
+ *
+ * Update the times on the inode then do device close.
+ */
+ufsfifo_close(vp, fflag, cred)
+ struct vnode *vp;
+ int fflag;
+ struct ucred *cred;
+{
+ register struct inode *ip = VTOI(vp);
+
+ if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
+ ITIMES(ip, &time, &time);
+ return (fifo_close(vp, fflag, cred));
+}
+#endif /* FIFO */
+
+/*
+ * Make a new file.
+ */
+maknode(mode, ndp, ipp)
+ int mode;
+ register struct nameidata *ndp;
+ struct inode **ipp;
+{
+ register struct inode *ip;
+ struct inode *tip;
+ register struct inode *pdir = VTOI(ndp->ni_dvp);
+ ino_t ipref;
+ int error;
+
+ *ipp = 0;
+ if ((mode & IFMT) == 0)
+ mode |= IFREG;
+ if ((mode & IFMT) == IFDIR)
+ ipref = dirpref(pdir->i_fs);
+ else
+ ipref = pdir->i_number;
+ if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) {
+ iput(pdir);
+ return (error);
+ }
+ ip = tip;
+ ip->i_uid = ndp->ni_cred->cr_uid;
+ ip->i_gid = pdir->i_gid;
+#ifdef QUOTA
+ if ((error = getinoquota(ip)) ||
+ (error = chkiq(ip, 1, ndp->ni_cred, 0))) {
+ ifree(ip, ip->i_number, mode);
+ iput(ip);
+ iput(pdir);
+ return (error);
+ }
+#endif
+ ip->i_flag |= IACC|IUPD|ICHG;
+ ip->i_mode = mode;
+ ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */
+ ip->i_nlink = 1;
+ if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) &&
+ suser(ndp->ni_cred, NULL))
+ ip->i_mode &= ~ISGID;
+
+ /*
+ * Make sure inode goes to disk before directory entry.
+ */
+ if (error = iupdat(ip, &time, &time, 1))
+ goto bad;
+ if (error = direnter(ip, ndp)) {
+ pdir = NULL;
+ goto bad;
+ }
+ *ipp = ip;
+ return (0);
+
+bad:
+ /*
+ * Write error occurred trying to update the inode
+ * or the directory so must deallocate the inode.
+ */
+ if (pdir)
+ iput(pdir);
+ ip->i_nlink = 0;
+ ip->i_flag |= ICHG;
+ iput(ip);
+ return (error);
+}
+
+/*
+ * Advisory record locking support
+ */
+ufs_advlock(vp, id, op, fl, flags)
+ struct vnode *vp;
+ caddr_t id;
+ int op;
+ register struct flock *fl;
+ int flags;
+{
+ register struct inode *ip = VTOI(vp);
+ register struct lockf *lock;
+ off_t start, end;
+ int error;
+
+ /*
+ * Avoid the common case of unlocking when inode has no locks.
+ */
+ if (ip->i_lockf == (struct lockf *)0) {
+ if (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 = ip->i_size + fl->l_start;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ if (start < 0)
+ return (EINVAL);
+ if (fl->l_len == 0)
+ end = -1;
+ else
+ end = start + fl->l_len - 1;
+ /*
+ * 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 = id;
+ lock->lf_inode = ip;
+ lock->lf_type = fl->l_type;
+ lock->lf_next = (struct lockf *)0;
+ lock->lf_block = (struct lockf *)0;
+ lock->lf_flags = flags;
+ /*
+ * Do the requested operation.
+ */
+ switch(op) {
+ case F_SETLK:
+ return (ufs_setlock(lock));
+
+ case F_UNLCK:
+ return (ufs_advunlock(lock));
+
+ case F_GETLK:
+ return (ufs_advgetlock(lock, fl));
+
+ default:
+ free(lock, M_LOCKF);
+ return (EINVAL);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * This variable controls the maximum number of processes that will
+ * be checked in doing deadlock detection.
+ */
+int maxlockdepth = MAXDEPTH;
+
+/*
+ * Set a byte-range lock.
+ */
+ufs_setlock(lock)
+ register struct lockf *lock;
+{
+ register struct inode *ip = lock->lf_inode;
+ register struct lockf *block;
+ static char lockstr[] = "lockf";
+ int priority, error;
+
+#ifdef LOCKF_DEBUG
+ if (lockf_debug & 4)
+ lf_print("ufs_setlock", lock);
+#endif /* LOCKF_DEBUG */
+
+ /*
+ * Set the priority
+ */
+ priority = PLOCK;
+ if ((lock->lf_type & F_WRLCK) == 0)
+ priority += 4;
+ priority |= PCATCH;
+ /*
+ * Scan lock list for this file looking for locks that would block us.
+ */
+ while (block = lf_getblock(lock)) {
+ /*
+ * Free the structure and return if nonblocking.
+ */
+ if ((lock->lf_flags & F_WAIT) == 0) {
+ free(lock, M_LOCKF);
+ return (EAGAIN);
+ }
+ /*
+ * We are blocked. Since flock style locks cover
+ * the whole file, there is no chance for deadlock.
+ * For byte-range locks we must check for deadlock.
+ *
+ * Deadlock detection is done by looking through the
+ * wait channels to see if there are any cycles that
+ * involve us. MAXDEPTH is set just to make sure we
+ * do not go off into neverland.
+ */
+ if ((lock->lf_flags & F_POSIX) &&
+ (block->lf_flags & F_POSIX)) {
+ register struct proc *wproc;
+ register struct lockf *waitblock;
+ int i = 0;
+
+ /* The block is waiting on something */
+ wproc = (struct proc *)block->lf_id;
+ while (wproc->p_wchan &&
+ (wproc->p_wmesg == lockstr) &&
+ (i++ < maxlockdepth)) {
+ waitblock = (struct lockf *)wproc->p_wchan;
+ /* Get the owner of the blocking lock */
+ waitblock = waitblock->lf_next;
+ if ((waitblock->lf_flags & F_POSIX) == 0)
+ break;
+ wproc = (struct proc *)waitblock->lf_id;
+ if (wproc == (struct proc *)lock->lf_id) {
+ free(lock, M_LOCKF);
+ return (EDEADLK);
+ }
+ }
+ }
+ /*
+ * Add our lock to the blocked
+ * list and sleep until we're free.
+ */
+#ifdef LOCKF_DEBUG
+ if (lockf_debug & 4)
+ lf_print("ufs_advlock: blocking on", block);
+#endif /* LOCKF_DEBUG */
+ /*
+ * Remember who blocked us (for deadlock detection)
+ */
+ lock->lf_next = block;
+ lf_addblock(block, lock);
+ if (error = tsleep((caddr_t *)lock, priority, lockstr, 0)) {
+ free(lock, M_LOCKF);
+ return (error);
+ }
+ }
+ /*
+ * No blocks!! Add the lock. Note that addlock will
+ * downgrade or upgrade any overlapping locks this
+ * process already owns.
+ */
+ lf_addlock(lock);
+#ifdef LOCKF_DEBUG
+ if (lockf_debug & 4) {
+ lf_print("ufs_advlock: got the lock", lock);
+ lf_printlist(lock);
+ }
+#endif /* LOCKF_DEBUG */
+ return (0);