Skip site navigation (1)Skip section navigation (2)
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>