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
This commit is contained in:
Konstantin Belousov 2008-10-28 12:08:36 +00:00
parent 5400fa16b4
commit ae53539e21

View File

@ -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 *ap)
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;