DragonFlyBSD Kernel Audit
DF-2688 / fix.diff
← back to finding ↓ download raw
--- a/sys/vm/vm_pageout.c
+++ b/sys/vm/vm_pageout.c
@@ -1825,13 +1825,33 @@
 		info.bigsize = 0;
 		allproc_scan(vm_pageout_scan_callback, &info, 0);
 		if (info.bigproc != NULL) {
+			struct proc *bp = info.bigproc;
+			struct lwp *blp;
+
 			kprintf("Try to kill process %d %s\n",
-				info.bigproc->p_pid, info.bigproc->p_comm);
-			info.bigproc->p_nice = PRIO_MIN;
-			info.bigproc->p_usched->resetpriority(
-				FIRST_LWP_IN_PROC(info.bigproc));
-			atomic_set_int(&info.bigproc->p_flags, P_LOWMEMKILL);
-			killproc(info.bigproc, "out of swap space");
+				bp->p_pid, bp->p_comm);
+
+			/*
+			 * Re-acquire the token and re-validate liveness.
+			 * The callback ran under p_token but released it
+			 * before we got here; the proc may be exiting or
+			 * already zombified, and FIRST_LWP_IN_PROC() is
+			 * an un-serialized rb-tree walk if p_token is not
+			 * held.
+			 */
+			lwkt_gettoken(&bp->p_token);
+			if (bp->p_stat == SACTIVE || bp->p_stat == SSTOP ||
+			    bp->p_stat == SCORE) {
+				bp->p_nice = PRIO_MIN;
+				blp = FIRST_LWP_IN_PROC(bp);
+				if (blp)
+					bp->p_usched->resetpriority(blp);
+				atomic_set_int(&bp->p_flags, P_LOWMEMKILL);
+				lwkt_reltoken(&bp->p_token);
+				killproc(bp, "out of swap space");
+			} else {
+				lwkt_reltoken(&bp->p_token);
+			}
 			wakeup(&vmstats.v_free_count);
 			PRELE(info.bigproc);
 		}