Date: Wed, 13 Jul 2011 21:07:41 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r223988 - head/sys/fs/devfs Message-ID: <201107132107.p6DL7fMH099858@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Wed Jul 13 21:07:41 2011 New Revision: 223988 URL: http://svn.freebsd.org/changeset/base/223988 Log: 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 Modified: head/sys/fs/devfs/devfs_vnops.c Modified: head/sys/fs/devfs/devfs_vnops.c ============================================================================== --- head/sys/fs/devfs/devfs_vnops.c Wed Jul 13 21:06:46 2011 (r223987) +++ head/sys/fs/devfs/devfs_vnops.c Wed Jul 13 21:07:41 2011 (r223988) @@ -397,6 +397,7 @@ devfs_allocv(struct devfs_dirent *de, st 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, st 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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201107132107.p6DL7fMH099858>