/* ARGSUSED */ int sys_flock(struct lwp *l, const struct sys_flock_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(int) how; } */ int fd, how, error; file_t *fp; vnode_t *vp; struct flock lf; fd = SCARG(uap, fd); how = SCARG(uap, how); error = 0; if ((fp = fd_getfile(fd)) == NULL) { return EBADF; } if (fp->f_type != DTYPE_VNODE) { fd_putfile(fd); return EOPNOTSUPP; } vp = fp->f_vnode; lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; switch (how & ~LOCK_NB) { case LOCK_UN: lf.l_type = F_UNLCK; atomic_and_uint(&fp->f_flag, ~FHASLOCK); error = VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK); fd_putfile(fd); return error; case LOCK_EX: lf.l_type = F_WRLCK; break; case LOCK_SH: lf.l_type = F_RDLCK; break; default: fd_putfile(fd); return EINVAL; } atomic_or_uint(&fp->f_flag, FHASLOCK); if (how & LOCK_NB) { error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK); } else { error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK|F_WAIT); } fd_putfile(fd); return error; }
static int unionfs_advlock(void *v) { struct vop_advlock_args *ap = v; int error; struct unionfs_node *unp; struct unionfs_node_status *unsp; struct vnode *vp; struct vnode *uvp; kauth_cred_t cred; UNIONFS_INTERNAL_DEBUG("unionfs_advlock: enter\n"); vp = ap->a_vp; cred = kauth_cred_get(); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); unp = VTOUNIONFS(ap->a_vp); uvp = unp->un_uppervp; if (uvp == NULLVP) { error = unionfs_copyfile(unp, 1, cred); if (error != 0) goto unionfs_advlock_abort; uvp = unp->un_uppervp; unionfs_get_node_status(unp, &unsp); if (unsp->uns_lower_opencnt > 0) { /* try reopen the vnode */ error = VOP_OPEN(uvp, unsp->uns_lower_openmode, cred); if (error) goto unionfs_advlock_abort; unsp->uns_upper_opencnt++; VOP_CLOSE(unp->un_lowervp, unsp->uns_lower_openmode, cred); unsp->uns_lower_opencnt--; } else unionfs_tryrem_node_status(unp, unsp); } VOP_UNLOCK(vp); error = VOP_ADVLOCK(uvp, ap->a_id, ap->a_op, ap->a_fl, ap->a_flags); UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); return error; unionfs_advlock_abort: VOP_UNLOCK(vp); UNIONFS_INTERNAL_DEBUG("unionfs_advlock: leave (%d)\n", error); return error; }
int RUMP_VOP_ADVLOCK(struct vnode *vp, void *id, int op, struct flock *fl, int flags) { int error; rump_schedule(); error = VOP_ADVLOCK(vp, id, op, fl, flags); rump_unschedule(); return error; }
/* * File table vnode close routine. */ int vn_closefile(struct file *fp, struct proc *p) { struct vnode *vp = fp->f_data; struct flock lf; if ((fp->f_iflags & FIF_HASLOCK)) { lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; lf.l_type = F_UNLCK; (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK); } return (vn_close(vp, fp->f_flag, fp->f_cred, p)); }
int do_fcntl_lock(int fd, int cmd, struct flock *fl) { file_t *fp; vnode_t *vp; proc_t *p; int error, flg; if ((fp = fd_getfile(fd)) == NULL) return EBADF; if (fp->f_type != DTYPE_VNODE) { fd_putfile(fd); return EINVAL; } vp = fp->f_vnode; if (fl->l_whence == SEEK_CUR) fl->l_start += fp->f_offset; flg = F_POSIX; p = curproc; switch (cmd) { case F_SETLKW: flg |= F_WAIT; /* Fall into F_SETLK */ case F_SETLK: switch (fl->l_type) { case F_RDLCK: if ((fp->f_flag & FREAD) == 0) { error = EBADF; break; } if ((p->p_flag & PK_ADVLOCK) == 0) { mutex_enter(p->p_lock); p->p_flag |= PK_ADVLOCK; mutex_exit(p->p_lock); } error = VOP_ADVLOCK(vp, p, F_SETLK, fl, flg); break; case F_WRLCK: if ((fp->f_flag & FWRITE) == 0) { error = EBADF; break; } if ((p->p_flag & PK_ADVLOCK) == 0) { mutex_enter(p->p_lock); p->p_flag |= PK_ADVLOCK; mutex_exit(p->p_lock); } error = VOP_ADVLOCK(vp, p, F_SETLK, fl, flg); break; case F_UNLCK: error = VOP_ADVLOCK(vp, p, F_UNLCK, fl, F_POSIX); break; default: error = EINVAL; break; } break; case F_GETLK: if (fl->l_type != F_RDLCK && fl->l_type != F_WRLCK && fl->l_type != F_UNLCK) { error = EINVAL; break; } error = VOP_ADVLOCK(vp, p, F_GETLK, fl, F_POSIX); break; default: error = EINVAL; break; } fd_putfile(fd); return error; }