diff options
author | dg <dg@FreeBSD.org> | 1995-07-06 11:48:48 +0000 |
---|---|---|
committer | dg <dg@FreeBSD.org> | 1995-07-06 11:48:48 +0000 |
commit | 21036bccfd267479c2ca00a9753138d46d94d41e (patch) | |
tree | ce873fc5ea1381810ca2b25a516e0da6f4c2366b /sys/vm | |
parent | fa8de9933bb206fd1d26887990a414aa1b781904 (diff) | |
download | FreeBSD-src-21036bccfd267479c2ca00a9753138d46d94d41e.zip FreeBSD-src-21036bccfd267479c2ca00a9753138d46d94d41e.tar.gz |
Fixed an object allocation race condition that was causing a "object
deallocated too many times" panic when using NFS.
Reviewed by: John Dyson
Diffstat (limited to 'sys/vm')
-rw-r--r-- | sys/vm/vnode_pager.c | 47 |
1 files changed, 34 insertions, 13 deletions
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index ed785f9..b29b4ff 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * from: @(#)vnode_pager.c 7.5 (Berkeley) 4/20/91 - * $Id: vnode_pager.c,v 1.40 1995/05/30 08:16:23 rgrimes Exp $ + * $Id: vnode_pager.c,v 1.41 1995/06/28 12:01:13 davidg Exp $ */ /* @@ -136,13 +136,23 @@ vnode_pager_alloc(handle, size, prot, offset) if (handle == NULL) return (NULL); + vp = (struct vnode *) handle; + /* - * Vnodes keep a pointer to any associated pager so no need to lookup - * with vm_pager_lookup. + * Prevent race condition when allocating the object. This + * can happen with NFS vnodes since the nfsnode isn't locked. */ - vp = (struct vnode *) handle; - while ((object = vp->v_object) && - (object->flags & OBJ_DEAD)) + while (vp->v_flag & VOLOCK) { + vp->v_flag |= VOWANT; + tsleep(vp, PVM, "vnpobj", 0); + } + vp->v_flag |= VOLOCK; + + /* + * If the object is being terminated, wait for it to + * go away. + */ + while (((object = vp->v_object) != NULL) && (object->flags & OBJ_DEAD)) tsleep(object, PVM, "vadead", 0); pager = NULL; @@ -154,13 +164,8 @@ vnode_pager_alloc(handle, size, prot, offset) * Allocate pager structures */ pager = (vm_pager_t) malloc(sizeof *pager, M_VMPAGER, M_WAITOK); - if (pager == NULL) - return (NULL); vnp = (vn_pager_t) malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK); - if (vnp == NULL) { - free((caddr_t) pager, M_VMPAGER); - return (NULL); - } + /* * And an object of the appropriate size */ @@ -170,6 +175,15 @@ vnode_pager_alloc(handle, size, prot, offset) vm_object_enter(object, pager); object->pager = pager; } else { + /* + * The VOP_GETATTR failed... + * Unlock, wakeup any waiters, free pagers, and exit. + */ + vp->v_flag &= ~VOLOCK; + if (vp->v_flag & VOWANT) { + vp->v_flag &= ~VOWANT; + wakeup(vp); + } free((caddr_t) vnp, M_VMPGDATA); free((caddr_t) pager, M_VMPAGER); return (NULL); @@ -197,8 +211,15 @@ vnode_pager_alloc(handle, size, prot, offset) */ (void) vm_object_lookup(pager); } - if( vp->v_type == VREG) + + if (vp->v_type == VREG) vp->v_flag |= VVMIO; + + vp->v_flag &= ~VOLOCK; + if (vp->v_flag & VOWANT) { + vp->v_flag &= ~VOWANT; + wakeup(vp); + } return (pager); } |