Index: kern/vfs_vnops.c =================================================================== --- kern/vfs_vnops.c (revision 225509) +++ kern/vfs_vnops.c (working copy) @@ -113,6 +113,8 @@ int fmode, error; accmode_t accmode; int vfslocked, mpsafe; + struct flock lf; + int lock_flags, type; mpsafe = ndp->ni_cnd.cn_flags & MPSAFE; restart: @@ -234,6 +236,36 @@ if ((error = VOP_OPEN(vp, fmode, cred, td, fp)) != 0) goto bad; + if (fmode & (O_EXLOCK | O_SHLOCK)) { + lock_flags = VOP_ISLOCKED(vp); + VOP_UNLOCK(vp, 0); + lf.l_whence = SEEK_SET; + lf.l_start = 0; + lf.l_len = 0; + if (fmode & O_EXLOCK) + lf.l_type = F_WRLCK; + else + lf.l_type = F_RDLCK; + type = F_FLOCK; + if ((fmode & FNONBLOCK) == 0) + type |= F_WAIT; + error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); + vn_lock(vp, lock_flags | LK_RETRY); + if (error == 0 && vp->v_iflag & VI_DOOMED) { + error = ENOENT; + goto bad; + } + if (error == 0 && fmode & FWRITE) + error = vn_writechk(vp); + if (error) { + VOP_UNLOCK(vp, 0); + vn_start_write(vp, &mp, V_WAIT); + vn_lock(vp, lock_flags | LK_RETRY); + (void)VOP_CLOSE(vp, fmode, cred, td); + vn_finished_write(mp); + goto bad; + } + } if (fmode & FWRITE) { vp->v_writecount++; CTR3(KTR_VFS, "%s: vp %p v_writecount increased to %d", @@ -975,19 +1007,22 @@ int error; vp = fp->f_vnode; + fp->f_ops = &badfileops; vfslocked = VFS_LOCK_GIANT(vp->v_mount); + if (fp->f_type == DTYPE_VNODE && fp->f_flag & FHASLOCK) + vref(vp); + + error = vn_close(vp, fp->f_flag, fp->f_cred, td); + if (fp->f_type == DTYPE_VNODE && fp->f_flag & FHASLOCK) { lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; lf.l_type = F_UNLCK; (void) VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK); + vrele(vp); } - - fp->f_ops = &badfileops; - - error = vn_close(vp, fp->f_flag, fp->f_cred, td); VFS_UNLOCK_GIANT(vfslocked); return (error); } Index: kern/vfs_syscalls.c =================================================================== --- kern/vfs_syscalls.c (revision 225509) +++ kern/vfs_syscalls.c (working copy) @@ -1051,8 +1051,7 @@ struct vnode *vp; int cmode; struct file *nfp; - int type, indx, error; - struct flock lf; + int indx, error; struct nameidata nd; int vfslocked; @@ -1141,22 +1140,6 @@ } VOP_UNLOCK(vp, 0); - if (fp->f_type == DTYPE_VNODE && (flags & (O_EXLOCK | O_SHLOCK)) != 0) { - lf.l_whence = SEEK_SET; - lf.l_start = 0; - lf.l_len = 0; - if (flags & O_EXLOCK) - lf.l_type = F_WRLCK; - else - lf.l_type = F_RDLCK; - type = F_FLOCK; - if ((flags & FNONBLOCK) == 0) - type |= F_WAIT; - if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, - type)) != 0) - goto bad; - atomic_set_int(&fp->f_flag, FHASLOCK); - } if (flags & O_TRUNC) { error = fo_truncate(fp, 0, td->td_ucred, td); if (error)