summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2011-07-13 21:07:41 +0000
committerkib <kib@FreeBSD.org>2011-07-13 21:07:41 +0000
commite3d33b853d78d9c9665b164f2343f53be9338b44 (patch)
tree450324ad4ac0e9626ed44ee9323a092155663468 /sys/fs
parent6620a4474b278d01edd0ca6fc446c01f9fa8b619 (diff)
downloadFreeBSD-src-e3d33b853d78d9c9665b164f2343f53be9338b44.zip
FreeBSD-src-e3d33b853d78d9c9665b164f2343f53be9338b44.tar.gz
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
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/devfs/devfs_vnops.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index bf6dab8..955bd8b 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -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;
OpenPOWER on IntegriCloud