DF-2842 / fix.diff
--- vnode_pager.c.orig +++ vnode_pager.c @@ -200,11 +200,31 @@ vnode_pager_alloc(void *handle, off_t len vm_object_t vnode_pager_reference(struct vnode *vp) { vm_object_t object; - if ((object = vp->v_object) != NULL) - vm_object_reference_quick(object); /* also vref's vnode */ + /* + * DF-2842: Serialize against vnode_pager_dealloc() clearing + * vp->v_object (vclean -> vm_object_terminate -> kfree_obj), + * which can execute concurrently with us for a still-referenced + * vnode during a forced unmount or revoke. Mirror the interlock + * used by vnode_pager_alloc(). + * + *dealloc() runs under an exclusive vm_object hold, so once our + * hold is acquired either it has already completed (OBJ_DEAD or + * vp->v_object changed) or it cannot start until we drop. + */ + lwkt_gettoken(&vp->v_token); + object = vp->v_object; + if (object) { + vm_object_hold(object); + if ((object->flags & OBJ_DEAD) || + vp->v_object != object) { + vm_object_drop(object); + object = NULL; + } else { + vm_object_reference_quick(object); /* vref's vnode */ + vm_object_drop(object); + } + } + lwkt_reltoken(&vp->v_token); return (object); } /* * NOTE: (from original source, unchanged context) *** NOTE: diff is against sys/vm/vnode_pager.c only. Apply with: patch < fix.diff inside a copy of sys/vm/ (offset-tolerant). (Authored after verification; never applied to the audit tree.) |