+/*
+ * 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;
+ /*
+ * 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.
+ */
+#ifdef LOCKF_DEBUG
+ if (lockf_debug & 4)
+ lf_print("ufs_advlock: got the lock", lock);
+#endif /* LOCKF_DEBUG */
+ lf_addlock(lock);
+ return (0);
+}
+
+/*
+ * Remove a byte-range lock on an inode.
+ */
+ufs_advunlock(lock)
+ struct lockf *lock;
+{
+ struct lockf *blocklist;
+
+ if (lock->lf_inode->i_lockf == (struct lockf *)0)
+ return (0);
+#ifdef LOCKF_DEBUG
+ if (lockf_debug & 4)
+ lf_print("ufs_advunlock", lock);
+#endif /* LOCKF_DEBUG */
+ /*
+ * Generally, find the lock (or an overlap to that lock)
+ * and remove it (or shrink it), then wakeup anyone we can.
+ */
+ blocklist = lf_remove(lock);
+ FREE(lock, M_LOCKF);
+ lf_wakelock(blocklist);
+ return (0);
+}
+
+/*
+ * Return the blocking pid
+ */
+ufs_advgetlock(lock, fl)
+ register struct lockf *lock;
+ register struct flock *fl;
+{
+ register struct lockf *block;
+ off_t start, end;
+
+#ifdef LOCKF_DEBUG
+ if (lockf_debug & 4)
+ lf_print("ufs_advgetlock", lock);
+#endif /* LOCKF_DEBUG */
+
+ if (block = lf_getblock(lock)) {
+ fl->l_type = block->lf_type;
+ fl->l_whence = SEEK_SET;
+ fl->l_start = block->lf_start;
+ if (block->lf_end == -1)
+ fl->l_len = 0;
+ else
+ fl->l_len = block->lf_end - block->lf_start;
+ if (block->lf_flags & F_POSIX)
+ fl->l_pid = ((struct proc *)(block->lf_id))->p_pid;
+ else
+ fl->l_pid = -1;
+ }
+ FREE(lock, M_LOCKF);
+ return (0);