DragonFlyBSD Kernel Audit
DF-2842 / fix.diff
← back to finding ↓ download raw
--- 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.)