svn commit: r184409 - head/sys/kern

Konstantin Belousov kib at FreeBSD.org
Tue Oct 28 05:08:37 PDT 2008


Author: kib
Date: Tue Oct 28 12:08:36 2008
New Revision: 184409
URL: http://svn.freebsd.org/changeset/base/184409

Log:
  Protect check for v_pollinfo == NULL and assignment of the newly allocated
  vpollinfo with vnode interlock. Fully initialize vpollinfo before putting
  pointer to it into vp->v_pollinfo.
  
  Discussed with:	dwhite
  Tested by:	pho
  MFC after:	1 week

Modified:
  head/sys/kern/vfs_subr.c

Modified: head/sys/kern/vfs_subr.c
==============================================================================
--- head/sys/kern/vfs_subr.c	Tue Oct 28 12:00:28 2008	(r184408)
+++ head/sys/kern/vfs_subr.c	Tue Oct 28 12:08:36 2008	(r184409)
@@ -113,7 +113,7 @@ static void	vgonel(struct vnode *);
 static void	vfs_knllock(void *arg);
 static void	vfs_knlunlock(void *arg);
 static int	vfs_knllocked(void *arg);
-
+static void	destroy_vpollinfo(struct vpollinfo *vi);
 
 /*
  * Enable Giant pushdown based on whether or not the vm is mpsafe in this
@@ -819,11 +819,8 @@ vdestroy(struct vnode *vp)
 #ifdef MAC
 	mac_vnode_destroy(vp);
 #endif
-	if (vp->v_pollinfo != NULL) {
-		knlist_destroy(&vp->v_pollinfo->vpi_selinfo.si_note);
-		mtx_destroy(&vp->v_pollinfo->vpi_lock);
-		uma_zfree(vnodepoll_zone, vp->v_pollinfo);
-	}
+	if (vp->v_pollinfo != NULL)
+		destroy_vpollinfo(vp->v_pollinfo);
 #ifdef INVARIANTS
 	/* XXX Elsewhere we can detect an already freed vnode via NULL v_op. */
 	vp->v_op = NULL;
@@ -3197,6 +3194,14 @@ vbusy(struct vnode *vp)
 	mtx_unlock(&vnode_free_list_mtx);
 }
 
+static void
+destroy_vpollinfo(struct vpollinfo *vi)
+{
+	knlist_destroy(&vi->vpi_selinfo.si_note);
+	mtx_destroy(&vi->vpi_lock);
+	uma_zfree(vnodepoll_zone, vi);
+}
+
 /*
  * Initalize per-vnode helper structure to hold poll-related state.
  */
@@ -3205,15 +3210,20 @@ v_addpollinfo(struct vnode *vp)
 {
 	struct vpollinfo *vi;
 
+	if (vp->v_pollinfo != NULL)
+		return;
 	vi = uma_zalloc(vnodepoll_zone, M_WAITOK);
+	mtx_init(&vi->vpi_lock, "vnode pollinfo", NULL, MTX_DEF);
+	knlist_init(&vi->vpi_selinfo.si_note, vp, vfs_knllock,
+	    vfs_knlunlock, vfs_knllocked);
+	VI_LOCK(vp);
 	if (vp->v_pollinfo != NULL) {
-		uma_zfree(vnodepoll_zone, vi);
+		VI_UNLOCK(vp);
+		destroy_vpollinfo(vi);
 		return;
 	}
 	vp->v_pollinfo = vi;
-	mtx_init(&vp->v_pollinfo->vpi_lock, "vnode pollinfo", NULL, MTX_DEF);
-	knlist_init(&vp->v_pollinfo->vpi_selinfo.si_note, vp, vfs_knllock,
-	    vfs_knlunlock, vfs_knllocked);
+	VI_UNLOCK(vp);
 }
 
 /*
@@ -3228,8 +3238,7 @@ int
 vn_pollrecord(struct vnode *vp, struct thread *td, int events)
 {
 
-	if (vp->v_pollinfo == NULL)
-		v_addpollinfo(vp);
+	v_addpollinfo(vp);
 	mtx_lock(&vp->v_pollinfo->vpi_lock);
 	if (vp->v_pollinfo->vpi_revents & events) {
 		/*
@@ -4065,8 +4074,7 @@ vfs_kqfilter(struct vop_kqfilter_args *a
 
 	kn->kn_hook = (caddr_t)vp;
 
-	if (vp->v_pollinfo == NULL)
-		v_addpollinfo(vp);
+	v_addpollinfo(vp);
 	if (vp->v_pollinfo == NULL)
 		return (ENOMEM);
 	knl = &vp->v_pollinfo->vpi_selinfo.si_note;


More information about the svn-src-all mailing list