NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/59411 (deadlock on mbuf pool)



Can you try the attached patch?

And, can you record some dtrace output to see where this busy-wait
logic takes effect?

dtrace -n '
	sdt:::pool_grow* { @[probename, stack()] = count() }
	tick-10s { printa(@) }
'
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# Date 1747442650 0
#      Sat May 17 00:44:10 2025 +0000
# Branch trunk
# Node ID f8a9f7969e74c93df131b0d1c86775697fa66e62
# Parent  e65a3a130b666dadcc0a084f312f8bb66063fa65
# EXP-Topic riastradh-pr59411-mbufpooldeadlock
pool(9): Don't busy-wait in pool_grow with PR_NOWAIT from (soft)intr.

PR kern/59411: deadlock on mbuf pool

diff -r e65a3a130b66 -r f8a9f7969e74 sys/kern/subr_pool.c
--- a/sys/kern/subr_pool.c	Fri May 16 19:01:50 2025 +0000
+++ b/sys/kern/subr_pool.c	Sat May 17 00:44:10 2025 +0000
@@ -60,6 +60,7 @@
 #include <sys/asan.h>
 #include <sys/msan.h>
 #include <sys/fault.h>
+#include <sys/sdt.h>
 
 #include <uvm/uvm_extern.h>
 
@@ -1406,14 +1407,22 @@ pool_grow(struct pool *pp, int flags)
 			} while (pp->pr_flags & PR_GROWING);
 			return ERESTART;
 		} else {
-			if (pp->pr_flags & PR_GROWINGNOWAIT) {
+			if ((pp->pr_flags & PR_GROWINGNOWAIT) &&
+			    !cpu_intr_p() && !cpu_softintr_p()) {
 				/*
 				 * This needs an unlock/relock dance so
 				 * that the other caller has a chance to
 				 * run and actually do the thing.  Note
 				 * that this is effectively a busy-wait.
+				 *
+				 * Of course, busy-wait doesn't work if
+				 * we're interrupting the thread in the
+				 * middle of pool_grow.  So only do
+				 * this if we're not in interrupt or
+				 * soft interrupt context.
 				 */
 				mutex_exit(&pp->pr_lock);
+				DTRACE_PROBE(pool_grow_busywait);
 				mutex_enter(&pp->pr_lock);
 				return ERESTART;
 			}
@@ -1421,10 +1430,11 @@ pool_grow(struct pool *pp, int flags)
 		}
 	}
 	pp->pr_flags |= PR_GROWING;
-	if (flags & PR_WAITOK)
-		mutex_exit(&pp->pr_lock);
-	else
+	if ((flags & PR_WAITOK) == 0) {
 		pp->pr_flags |= PR_GROWINGNOWAIT;
+		DTRACE_PROBE(pool_growingnowait);
+	}
+	mutex_exit(&pp->pr_lock);
 
 	storage = pool_allocator_alloc(pp, flags);
 	if (__predict_false(storage == NULL))
@@ -1436,8 +1446,7 @@ pool_grow(struct pool *pp, int flags)
 		goto out;
 	}
 
-	if (flags & PR_WAITOK)
-		mutex_enter(&pp->pr_lock);
+	mutex_enter(&pp->pr_lock);
 	pool_prime_page(pp, storage, ph);
 	pp->pr_npagealloc++;
 	KASSERT(pp->pr_flags & PR_GROWING);
@@ -1449,8 +1458,7 @@ pool_grow(struct pool *pp, int flags)
 	cv_broadcast(&pp->pr_cv);
 	return 0;
 out:
-	if (flags & PR_WAITOK)
-		mutex_enter(&pp->pr_lock);
+	mutex_enter(&pp->pr_lock);
 	KASSERT(pp->pr_flags & PR_GROWING);
 	pp->pr_flags &= ~(PR_GROWING|PR_GROWINGNOWAIT);
 	return ENOMEM;


Home | Main Index | Thread Index | Old Index