1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-05 09:14:03 +00:00

While fixing the looping of a thread while devfs vnode is reclaimed,

r179247 introduced a possibility of devfs_allocv() returning spurious
ENOENT. If the vnode is selected by vnlru daemon for reclamation, then
devfs_allocv() can get ENOENT from vget() due to devfs_close() dropping
vnode lock around the call to cdevsw d_close method.

Use LK_RETRY in the vget() call, and do some part of the devfs_reclaim()
work in devfs_allocv(), clearing vp->v_data and de->de_vnode. Retry the
allocation of the vnode, now with de->de_vnode == NULL.

The check vp->v_data == NULL at the start of devfs_close() cannot be
affected by the change, since vnode lock must be held while VI_DOOMED
is set, and only dropped after the check.

Reported and tested by:	Kohji Okuno <okuno.kohji jp panasonic com>
Reviewed by:	attilio
MFC after:	3 weeks
This commit is contained in:
Konstantin Belousov 2011-07-13 21:07:41 +00:00
parent fcdbb666c0
commit 724ce55b5b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=223988

View File

@ -397,6 +397,7 @@ devfs_allocv(struct devfs_dirent *de, struct mount *mp, int lockmode,
sx_xunlock(&dmp->dm_lock);
return (ENOENT);
}
loop:
DEVFS_DE_HOLD(de);
DEVFS_DMP_HOLD(dmp);
mtx_lock(&devfs_de_interlock);
@ -405,16 +406,21 @@ devfs_allocv(struct devfs_dirent *de, struct mount *mp, int lockmode,
VI_LOCK(vp);
mtx_unlock(&devfs_de_interlock);
sx_xunlock(&dmp->dm_lock);
error = vget(vp, lockmode | LK_INTERLOCK, curthread);
vget(vp, lockmode | LK_INTERLOCK | LK_RETRY, curthread);
sx_xlock(&dmp->dm_lock);
if (devfs_allocv_drop_refs(0, dmp, de)) {
if (error == 0)
vput(vp);
vput(vp);
return (ENOENT);
}
else if (error) {
sx_xunlock(&dmp->dm_lock);
return (error);
else if ((vp->v_iflag & VI_DOOMED) != 0) {
mtx_lock(&devfs_de_interlock);
if (de->de_vnode == vp) {
de->de_vnode = NULL;
vp->v_data = NULL;
}
mtx_unlock(&devfs_de_interlock);
vput(vp);
goto loop;
}
sx_xunlock(&dmp->dm_lock);
*vpp = vp;