Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_vnops.c
Show First 20 Lines • Show All 222 Lines • ▼ Show 20 Lines | vn_open_cred(struct nameidata *ndp, int *flagp, int cmode, u_int vn_open_flags, | ||||
struct ucred *cred, struct file *fp) | struct ucred *cred, struct file *fp) | ||||
{ | { | ||||
struct vnode *vp; | struct vnode *vp; | ||||
struct mount *mp; | struct mount *mp; | ||||
struct thread *td = ndp->ni_cnd.cn_thread; | struct thread *td = ndp->ni_cnd.cn_thread; | ||||
struct vattr vat; | struct vattr vat; | ||||
struct vattr *vap = &vat; | struct vattr *vap = &vat; | ||||
int fmode, error; | int fmode, error; | ||||
bool first_open; | |||||
restart: | restart: | ||||
first_open = false; | |||||
fmode = *flagp; | fmode = *flagp; | ||||
if ((fmode & (O_CREAT | O_EXCL | O_DIRECTORY)) == (O_CREAT | | if ((fmode & (O_CREAT | O_EXCL | O_DIRECTORY)) == (O_CREAT | | ||||
O_EXCL | O_DIRECTORY)) | O_EXCL | O_DIRECTORY)) | ||||
return (EINVAL); | return (EINVAL); | ||||
else if ((fmode & (O_CREAT | O_DIRECTORY)) == O_CREAT) { | else if ((fmode & (O_CREAT | O_DIRECTORY)) == O_CREAT) { | ||||
ndp->ni_cnd.cn_nameiop = CREATE; | ndp->ni_cnd.cn_nameiop = CREATE; | ||||
ndp->ni_cnd.cn_flags = open2nameif(fmode, vn_open_flags); | ndp->ni_cnd.cn_flags = open2nameif(fmode, vn_open_flags); | ||||
/* | /* | ||||
Show All 29 Lines | if (ndp->ni_vp == NULL) { | ||||
ndp->ni_cnd.cn_flags |= MAKEENTRY; | ndp->ni_cnd.cn_flags |= MAKEENTRY; | ||||
#ifdef MAC | #ifdef MAC | ||||
error = mac_vnode_check_create(cred, ndp->ni_dvp, | error = mac_vnode_check_create(cred, ndp->ni_dvp, | ||||
&ndp->ni_cnd, vap); | &ndp->ni_cnd, vap); | ||||
if (error == 0) | if (error == 0) | ||||
#endif | #endif | ||||
error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, | error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp, | ||||
&ndp->ni_cnd, vap); | &ndp->ni_cnd, vap); | ||||
VOP_VPUT_PAIR(ndp->ni_dvp, error == 0 ? &ndp->ni_vp : | vp = ndp->ni_vp; | ||||
NULL, false); | if (error == 0 && (fmode & O_EXCL) != 0 && | ||||
(fmode & (O_EXLOCK | O_SHLOCK)) != 0) { | |||||
VI_LOCK(vp); | |||||
vp->v_iflag |= VI_FOPENING; | |||||
VI_UNLOCK(vp); | |||||
first_open = true; | |||||
} | |||||
VOP_VPUT_PAIR(ndp->ni_dvp, error == 0 ? &vp : NULL, | |||||
markj: So VOP_VPUT_PAIR may update `vp`, so that `ndp->ni_vp != vp`. Is it intentional? | |||||
Done Inline ActionsExcept for sillyness in clearing VI_FOPENING that you pointed out, I do not think that code uses ndp->ni_vp at all in this path after assignment to vp. Other pathes do use ni_vp, but not the path where VOP_VPUT_PAIR() is executed. Am I missing something? kib: Except for sillyness in clearing VI_FOPENING that you pointed out, I do not think that code… | |||||
Not Done Inline ActionsI think it is ok now, I was just trying to see if VI_FOPENING may be leaked somehow. markj: I think it is ok now, I was just trying to see if VI_FOPENING may be leaked somehow. | |||||
false); | |||||
vn_finished_write(mp); | vn_finished_write(mp); | ||||
if (error) { | if (error) { | ||||
NDFREE(ndp, NDF_ONLY_PNBUF); | NDFREE(ndp, NDF_ONLY_PNBUF); | ||||
if (error == ERELOOKUP) { | if (error == ERELOOKUP) { | ||||
NDREINIT(ndp); | NDREINIT(ndp); | ||||
goto restart; | goto restart; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
fmode &= ~O_TRUNC; | fmode &= ~O_TRUNC; | ||||
vp = ndp->ni_vp; | |||||
} else { | } else { | ||||
if (ndp->ni_dvp == ndp->ni_vp) | if (ndp->ni_dvp == ndp->ni_vp) | ||||
vrele(ndp->ni_dvp); | vrele(ndp->ni_dvp); | ||||
else | else | ||||
vput(ndp->ni_dvp); | vput(ndp->ni_dvp); | ||||
ndp->ni_dvp = NULL; | ndp->ni_dvp = NULL; | ||||
vp = ndp->ni_vp; | vp = ndp->ni_vp; | ||||
if (fmode & O_EXCL) { | if (fmode & O_EXCL) { | ||||
Show All 13 Lines | ndp->ni_cnd.cn_flags |= (fmode & O_NOFOLLOW) != 0 ? NOFOLLOW : | ||||
FOLLOW; | FOLLOW; | ||||
if ((fmode & FWRITE) == 0) | if ((fmode & FWRITE) == 0) | ||||
ndp->ni_cnd.cn_flags |= LOCKSHARED; | ndp->ni_cnd.cn_flags |= LOCKSHARED; | ||||
if ((error = namei(ndp)) != 0) | if ((error = namei(ndp)) != 0) | ||||
return (error); | return (error); | ||||
vp = ndp->ni_vp; | vp = ndp->ni_vp; | ||||
} | } | ||||
error = vn_open_vnode(vp, fmode, cred, td, fp); | error = vn_open_vnode(vp, fmode, cred, td, fp); | ||||
if (first_open) { | |||||
VI_LOCK(vp); | |||||
vp->v_iflag &= ~VI_FOPENING; | |||||
Done Inline ActionsWhy do you use both ndp->ni_vp and vp here? markj: Why do you use both `ndp->ni_vp` and `vp` here? | |||||
Done Inline ActionsIt was thinko from copy/paste. kib: It was thinko from copy/paste. | |||||
wakeup(vp); | |||||
VI_UNLOCK(vp); | |||||
} | |||||
if (error) | if (error) | ||||
goto bad; | goto bad; | ||||
*flagp = fmode; | *flagp = fmode; | ||||
return (0); | return (0); | ||||
bad: | bad: | ||||
NDFREE(ndp, NDF_ONLY_PNBUF); | NDFREE(ndp, NDF_ONLY_PNBUF); | ||||
vput(vp); | vput(vp); | ||||
*flagp = fmode; | *flagp = fmode; | ||||
Show All 19 Lines | vn_open_vnode_advlock(struct vnode *vp, int fmode, struct file *fp) | ||||
lf.l_whence = SEEK_SET; | lf.l_whence = SEEK_SET; | ||||
lf.l_start = 0; | lf.l_start = 0; | ||||
lf.l_len = 0; | lf.l_len = 0; | ||||
lf.l_type = (fmode & O_EXLOCK) != 0 ? F_WRLCK : F_RDLCK; | lf.l_type = (fmode & O_EXLOCK) != 0 ? F_WRLCK : F_RDLCK; | ||||
type = F_FLOCK; | type = F_FLOCK; | ||||
if ((fmode & FNONBLOCK) == 0) | if ((fmode & FNONBLOCK) == 0) | ||||
type |= F_WAIT; | type |= F_WAIT; | ||||
if ((fmode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | |||||
type |= F_FIRSTOPEN; | |||||
error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); | error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); | ||||
if (error == 0) | if (error == 0) | ||||
fp->f_flag |= FHASLOCK; | fp->f_flag |= FHASLOCK; | ||||
vn_lock(vp, lock_flags | LK_RETRY); | vn_lock(vp, lock_flags | LK_RETRY); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 3,074 Lines • Show Last 20 Lines |
So VOP_VPUT_PAIR may update vp, so that ndp->ni_vp != vp. Is it intentional?