Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_vnops.c
Show First 20 Lines • Show All 288 Lines • ▼ Show 20 Lines | |||||
bad: | bad: | ||||
NDFREE(ndp, NDF_ONLY_PNBUF); | NDFREE(ndp, NDF_ONLY_PNBUF); | ||||
vput(vp); | vput(vp); | ||||
*flagp = fmode; | *flagp = fmode; | ||||
ndp->ni_vp = NULL; | ndp->ni_vp = NULL; | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | |||||
vn_open_vnode_advlock(struct vnode *vp, int fmode, struct file *fp) | |||||
{ | |||||
struct flock lf; | |||||
int error, lock_flags, type; | |||||
ASSERT_VOP_LOCKED(vp, "vn_open_vnode_advlock"); | |||||
if ((fmode & (O_EXLOCK | O_SHLOCK)) == 0) | |||||
return (0); | |||||
KASSERT(fp != NULL, ("open with flock requires fp")); | |||||
if (fp->f_type != DTYPE_NONE && fp->f_type != DTYPE_VNODE) | |||||
return (EOPNOTSUPP); | |||||
lock_flags = VOP_ISLOCKED(vp); | |||||
VOP_UNLOCK(vp, 0); | |||||
lf.l_whence = SEEK_SET; | |||||
lf.l_start = 0; | |||||
lf.l_len = 0; | |||||
lf.l_type = (fmode & O_EXLOCK) != 0 ? F_WRLCK : F_RDLCK; | |||||
type = F_FLOCK; | |||||
if ((fmode & FNONBLOCK) == 0) | |||||
type |= F_WAIT; | |||||
error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); | |||||
if (error == 0) | |||||
fp->f_flag |= FHASLOCK; | |||||
vn_lock(vp, lock_flags | LK_RETRY); | |||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0) | |||||
error = ENOENT; | |||||
return (error); | |||||
} | |||||
/* | /* | ||||
* Common code for vnode open operations once a vnode is located. | * Common code for vnode open operations once a vnode is located. | ||||
* Check permissions, and call the VOP_OPEN routine. | * Check permissions, and call the VOP_OPEN routine. | ||||
*/ | */ | ||||
int | int | ||||
vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred, | vn_open_vnode(struct vnode *vp, int fmode, struct ucred *cred, | ||||
struct thread *td, struct file *fp) | struct thread *td, struct file *fp) | ||||
{ | { | ||||
accmode_t accmode; | accmode_t accmode; | ||||
struct flock lf; | int error; | ||||
int error, lock_flags, type; | |||||
if (vp->v_type == VLNK) | if (vp->v_type == VLNK) | ||||
return (EMLINK); | return (EMLINK); | ||||
if (vp->v_type == VSOCK) | if (vp->v_type == VSOCK) | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
if (vp->v_type != VDIR && fmode & O_DIRECTORY) | if (vp->v_type != VDIR && fmode & O_DIRECTORY) | ||||
return (ENOTDIR); | return (ENOTDIR); | ||||
accmode = 0; | accmode = 0; | ||||
Show All 14 Lines | #ifdef MAC | ||||
if (fmode & O_VERIFY) | if (fmode & O_VERIFY) | ||||
accmode |= VVERIFY; | accmode |= VVERIFY; | ||||
error = mac_vnode_check_open(cred, vp, accmode); | error = mac_vnode_check_open(cred, vp, accmode); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
accmode &= ~(VCREAT | VVERIFY); | accmode &= ~(VCREAT | VVERIFY); | ||||
#endif | #endif | ||||
if ((fmode & O_CREAT) == 0) { | if ((fmode & O_CREAT) == 0 && accmode != 0) { | ||||
if (accmode & VWRITE) { | |||||
error = vn_writechk(vp); | |||||
if (error) | |||||
return (error); | |||||
} | |||||
if (accmode) { | |||||
error = VOP_ACCESS(vp, accmode, cred, td); | error = VOP_ACCESS(vp, accmode, cred, td); | ||||
if (error) | if (error != 0) | ||||
return (error); | return (error); | ||||
} | } | ||||
} | |||||
if (vp->v_type == VFIFO && VOP_ISLOCKED(vp) != LK_EXCLUSIVE) | if (vp->v_type == VFIFO && VOP_ISLOCKED(vp) != LK_EXCLUSIVE) | ||||
vn_lock(vp, LK_UPGRADE | LK_RETRY); | vn_lock(vp, LK_UPGRADE | LK_RETRY); | ||||
if ((error = VOP_OPEN(vp, fmode, cred, td, fp)) != 0) | error = VOP_OPEN(vp, fmode, cred, td, fp); | ||||
if (error != 0) | |||||
return (error); | return (error); | ||||
while ((fmode & (O_EXLOCK | O_SHLOCK)) != 0) { | error = vn_open_vnode_advlock(vp, fmode, fp); | ||||
KASSERT(fp != NULL, ("open with flock requires fp")); | if (error == 0 && (fmode & FWRITE) != 0) { | ||||
if (fp->f_type != DTYPE_NONE && fp->f_type != DTYPE_VNODE) { | error = VOP_ADD_WRITECOUNT(vp, 1); | ||||
error = EOPNOTSUPP; | if (error == 0) { | ||||
break; | CTR3(KTR_VFS, "%s: vp %p v_writecount increased to %d", | ||||
__func__, vp, vp->v_writecount); | |||||
} | } | ||||
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); | |||||
if (error == 0) | |||||
fp->f_flag |= FHASLOCK; | |||||
vn_lock(vp, lock_flags | LK_RETRY); | |||||
if (error != 0) | |||||
break; | |||||
if ((vp->v_iflag & VI_DOOMED) != 0) { | |||||
error = ENOENT; | |||||
break; | |||||
} | } | ||||
/* | /* | ||||
* Another thread might have used this vnode as an | * Error from advlock or VOP_ADD_WRITECOUNT() still requires | ||||
* executable while the vnode lock was dropped. | * calling VOP_CLOSE() to pair with earlier VOP_OPEN(). | ||||
* Ensure the vnode is still able to be opened for | * Arrange for that by having fdrop() to use vn_closefile(). | ||||
* writing after the lock has been obtained. | |||||
*/ | */ | ||||
if ((accmode & VWRITE) != 0) | |||||
error = vn_writechk(vp); | |||||
break; | |||||
} | |||||
if (error != 0) { | if (error != 0) { | ||||
fp->f_flag |= FOPENFAILED; | fp->f_flag |= FOPENFAILED; | ||||
fp->f_vnode = vp; | fp->f_vnode = vp; | ||||
if (fp->f_ops == &badfileops) { | if (fp->f_ops == &badfileops) { | ||||
fp->f_type = DTYPE_VNODE; | fp->f_type = DTYPE_VNODE; | ||||
fp->f_ops = &vnops; | fp->f_ops = &vnops; | ||||
} | } | ||||
vref(vp); | vref(vp); | ||||
} else if ((fmode & FWRITE) != 0) { | |||||
VOP_ADD_WRITECOUNT(vp, 1); | |||||
CTR3(KTR_VFS, "%s: vp %p v_writecount increased to %d", | |||||
__func__, vp, vp->v_writecount); | |||||
} | } | ||||
ASSERT_VOP_LOCKED(vp, "vn_open_vnode"); | ASSERT_VOP_LOCKED(vp, "vn_open_vnode"); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Check for write permissions on the specified vnode. | * Check for write permissions on the specified vnode. | ||||
* Prototype text segments cannot be written. | * Prototype text segments cannot be written. | ||||
* It is racy. | |||||
*/ | */ | ||||
int | int | ||||
vn_writechk(struct vnode *vp) | vn_writechk(struct vnode *vp) | ||||
{ | { | ||||
ASSERT_VOP_LOCKED(vp, "vn_writechk"); | ASSERT_VOP_LOCKED(vp, "vn_writechk"); | ||||
/* | /* | ||||
* If there's shared text associated with | * If there's shared text associated with | ||||
Show All 16 Lines | vn_close1(struct vnode *vp, int flags, struct ucred *file_cred, | ||||
struct mount *mp; | struct mount *mp; | ||||
int error, lock_flags; | int error, lock_flags; | ||||
if (vp->v_type != VFIFO && (flags & FWRITE) == 0 && | if (vp->v_type != VFIFO && (flags & FWRITE) == 0 && | ||||
MNT_EXTENDED_SHARED(vp->v_mount)) | MNT_EXTENDED_SHARED(vp->v_mount)) | ||||
lock_flags = LK_SHARED; | lock_flags = LK_SHARED; | ||||
else | else | ||||
lock_flags = LK_EXCLUSIVE; | lock_flags = LK_EXCLUSIVE; | ||||
markj: This is a dead store. | |||||
Done Inline ActionsYes, I already removed it in my branch, to reduce the diff. kib: Yes, I already removed it in my branch, to reduce the diff. | |||||
vn_start_write(vp, &mp, V_WAIT); | vn_start_write(vp, &mp, V_WAIT); | ||||
vn_lock(vp, lock_flags | LK_RETRY); | vn_lock(vp, lock_flags | LK_RETRY); | ||||
AUDIT_ARG_VNODE1(vp); | AUDIT_ARG_VNODE1(vp); | ||||
if ((flags & (FWRITE | FOPENFAILED)) == FWRITE) { | if ((flags & (FWRITE | FOPENFAILED)) == FWRITE) { | ||||
VNASSERT(vp->v_writecount > 0, vp, | VOP_ADD_WRITECOUNT_CHECKED(vp, -1); | ||||
("vn_close: negative writecount")); | |||||
VOP_ADD_WRITECOUNT(vp, -1); | |||||
CTR3(KTR_VFS, "%s: vp %p v_writecount decreased to %d", | CTR3(KTR_VFS, "%s: vp %p v_writecount decreased to %d", | ||||
__func__, vp, vp->v_writecount); | __func__, vp, vp->v_writecount); | ||||
} | } | ||||
error = VOP_CLOSE(vp, flags, file_cred, td); | error = VOP_CLOSE(vp, flags, file_cred, td); | ||||
if (keep_ref) | if (keep_ref) | ||||
VOP_UNLOCK(vp, 0); | VOP_UNLOCK(vp, 0); | ||||
else | else | ||||
vput(vp); | vput(vp); | ||||
▲ Show 20 Lines • Show All 851 Lines • ▼ Show 20 Lines | if (vp->v_type == VDIR) { | ||||
error = EISDIR; | error = EISDIR; | ||||
goto out; | goto out; | ||||
} | } | ||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_vnode_check_write(active_cred, fp->f_cred, vp); | error = mac_vnode_check_write(active_cred, fp->f_cred, vp); | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
#endif | #endif | ||||
error = vn_writechk(vp); | error = VOP_ADD_WRITECOUNT(vp, 1); | ||||
if (error == 0) { | if (error == 0) { | ||||
VATTR_NULL(&vattr); | VATTR_NULL(&vattr); | ||||
vattr.va_size = length; | vattr.va_size = length; | ||||
if ((fp->f_flag & O_FSYNC) != 0) | if ((fp->f_flag & O_FSYNC) != 0) | ||||
vattr.va_vaflags |= VA_SYNC; | vattr.va_vaflags |= VA_SYNC; | ||||
error = VOP_SETATTR(vp, &vattr, fp->f_cred); | error = VOP_SETATTR(vp, &vattr, fp->f_cred); | ||||
VOP_ADD_WRITECOUNT_CHECKED(vp, -1); | |||||
} | } | ||||
out: | out: | ||||
VOP_UNLOCK(vp, 0); | VOP_UNLOCK(vp, 0); | ||||
vn_finished_write(mp); | vn_finished_write(mp); | ||||
out1: | out1: | ||||
vn_rangelock_unlock(vp, rl_cookie); | vn_rangelock_unlock(vp, rl_cookie); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,255 Lines • Show Last 20 Lines |
This is a dead store.