Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 10 Aug 2016 18:53:10 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r303938 - projects/hps_head/sys/kern
Message-ID:  <201608101853.u7AIrB9X094244@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Wed Aug 10 18:53:10 2016
New Revision: 303938
URL: https://svnweb.freebsd.org/changeset/base/303938

Log:
  Solve a LOR between the callout mutex and the sleepqueue mutex after
  recent changes. This is solved by making a custom msleep_spin()
  implementation where the sleepqueue mutex is locked first.

Modified:
  projects/hps_head/sys/kern/kern_timeout.c

Modified: projects/hps_head/sys/kern/kern_timeout.c
==============================================================================
--- projects/hps_head/sys/kern/kern_timeout.c	Wed Aug 10 18:45:26 2016	(r303937)
+++ projects/hps_head/sys/kern/kern_timeout.c	Wed Aug 10 18:53:10 2016	(r303938)
@@ -1266,22 +1266,36 @@ callout_drain(struct callout *c)
 	retval = callout_async_drain(c, &callout_drain_function);
 
 	if (retval == CALLOUT_RET_DRAINING) {
+		void *ident = &callout_drain_function;
 		struct callout_cpu *cc;
 		int direct;
+		int busy;
 
 		CTR3(KTR_CALLOUT, "need to drain %p func %p arg %p",
 		    c, c->c_func, c->c_arg);
 
-		cc = callout_lock(c);
-		direct = ((c->c_flags & CALLOUT_DIRECT) != 0);
-
-		/* Wait for drain to complete */
-		while (cc_exec_curr(cc, direct) == c) {
-			msleep_spin(&callout_drain_function,
-			    (struct mtx *)&cc->cc_lock, "codrain", 0);
-		}
+		do {
+			/*
+			 * The sleepq_lock() is lower rank than the
+			 * callout_lock() and must be locked first:
+			 */
+			sleepq_lock(ident);
+			cc = callout_lock(c);
+			direct = ((c->c_flags & CALLOUT_DIRECT) != 0);
+			busy = (cc_exec_curr(cc, direct) == c);
+			CC_UNLOCK(cc);
+			DROP_GIANT();
+
+			if (busy && !SCHEDULER_STOPPED()) {
+				/* Wait for drain to complete */
+				sleepq_add(ident, &cc->cc_lock.lock_object, "codrain", SLEEPQ_SLEEP, 0);
+				sleepq_wait(ident, 0);
+			} else {
+				sleepq_release(ident);
+			}
 
-		CC_UNLOCK(cc);
+			PICKUP_GIANT();
+		} while (busy);
 	}
 
 	CTR4(KTR_CALLOUT, "%s: %p func %p arg %p",



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201608101853.u7AIrB9X094244>