Avoid double-unlock or double unreference for ndp->ni_dvp when the vnode dp
lock upgrade right after the 'success' label fails. In collaboration with: pho MFC after: 1 week
This commit is contained in:
parent
f8f33f6ab6
commit
cdb7a43117
@ -508,12 +508,14 @@ lookup(struct nameidata *ndp)
|
|||||||
int dvfslocked; /* VFS Giant state for parent */
|
int dvfslocked; /* VFS Giant state for parent */
|
||||||
int tvfslocked;
|
int tvfslocked;
|
||||||
int lkflags_save;
|
int lkflags_save;
|
||||||
|
int ni_dvp_unlocked;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup: break out flag bits into variables.
|
* Setup: break out flag bits into variables.
|
||||||
*/
|
*/
|
||||||
dvfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
|
dvfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
|
||||||
vfslocked = 0;
|
vfslocked = 0;
|
||||||
|
ni_dvp_unlocked = 0;
|
||||||
ndp->ni_cnd.cn_flags &= ~GIANTHELD;
|
ndp->ni_cnd.cn_flags &= ~GIANTHELD;
|
||||||
wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
|
wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
|
||||||
KASSERT(cnp->cn_nameiop == LOOKUP || wantparent,
|
KASSERT(cnp->cn_nameiop == LOOKUP || wantparent,
|
||||||
@ -861,8 +863,10 @@ lookup(struct nameidata *ndp)
|
|||||||
/*
|
/*
|
||||||
* Symlink code always expects an unlocked dvp.
|
* Symlink code always expects an unlocked dvp.
|
||||||
*/
|
*/
|
||||||
if (ndp->ni_dvp != ndp->ni_vp)
|
if (ndp->ni_dvp != ndp->ni_vp) {
|
||||||
VOP_UNLOCK(ndp->ni_dvp, 0);
|
VOP_UNLOCK(ndp->ni_dvp, 0);
|
||||||
|
ni_dvp_unlocked = 1;
|
||||||
|
}
|
||||||
goto success;
|
goto success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -909,14 +913,17 @@ lookup(struct nameidata *ndp)
|
|||||||
VREF(ndp->ni_startdir);
|
VREF(ndp->ni_startdir);
|
||||||
}
|
}
|
||||||
if (!wantparent) {
|
if (!wantparent) {
|
||||||
|
ni_dvp_unlocked = 2;
|
||||||
if (ndp->ni_dvp != dp)
|
if (ndp->ni_dvp != dp)
|
||||||
vput(ndp->ni_dvp);
|
vput(ndp->ni_dvp);
|
||||||
else
|
else
|
||||||
vrele(ndp->ni_dvp);
|
vrele(ndp->ni_dvp);
|
||||||
VFS_UNLOCK_GIANT(dvfslocked);
|
VFS_UNLOCK_GIANT(dvfslocked);
|
||||||
dvfslocked = 0;
|
dvfslocked = 0;
|
||||||
} else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp)
|
} else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp) {
|
||||||
VOP_UNLOCK(ndp->ni_dvp, 0);
|
VOP_UNLOCK(ndp->ni_dvp, 0);
|
||||||
|
ni_dvp_unlocked = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (cnp->cn_flags & AUDITVNODE1)
|
if (cnp->cn_flags & AUDITVNODE1)
|
||||||
AUDIT_ARG_VNODE1(dp);
|
AUDIT_ARG_VNODE1(dp);
|
||||||
@ -945,10 +952,12 @@ lookup(struct nameidata *ndp)
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
bad2:
|
bad2:
|
||||||
if (dp != ndp->ni_dvp)
|
if (ni_dvp_unlocked != 2) {
|
||||||
vput(ndp->ni_dvp);
|
if (dp != ndp->ni_dvp && !ni_dvp_unlocked)
|
||||||
else
|
vput(ndp->ni_dvp);
|
||||||
vrele(ndp->ni_dvp);
|
else
|
||||||
|
vrele(ndp->ni_dvp);
|
||||||
|
}
|
||||||
bad:
|
bad:
|
||||||
if (!dpunlocked)
|
if (!dpunlocked)
|
||||||
vput(dp);
|
vput(dp);
|
||||||
|
Loading…
Reference in New Issue
Block a user