Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 31 May 2009 17:24:04 +0100 (BST)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        jeff@FreeBSD.org
Cc:        attilio@FreeBSD.org, current@FreeBSD.org
Subject:   scheduler IPIs during shutdown (was: svn commit: r193170 - projects/pnet/sys/kern (fwd))
Message-ID:  <alpine.BSF.2.00.0905311653430.27214@fledge.watson.org>

next in thread | raw e-mail | index | archive | help
Hi Jeff--

I think the reason we're now seeing panics like the:

  spin lock 0xc08a7e80 (sched lock 1) held by 0xc508b460 (tid 100005) too long

As well as the ones occasionally reported on the lists on SMP boxes 
(kern/134584, etc) is that we're shutting down CPUs while holding their thread 
locks and then trying to start work on them.  Obviously, this is doomed to 
failure for a number of reasons :-).

Without trying to solve the general problem of CPUs coming and going for 8.0, 
I think we do need some short-term solution for the release.  The basic 
scenario, as I understand it so far, is:

- System shutdown kicks off, and CPU 0 starts IPIing CPUs to shut them down,
   which apparently can occur while holding the thread lock:

db> trace 100005
Tracing pid 11 tid 100005 td 0xc4d546c0
cpustop_handler(2,c4a53b64,c0b70cad,c0d9c680,c4a53ae4,...) at 
cpustop_handler+0x32
ipi_nmi_handler(c0d9c680,c4a53ae4,2,f,c4d52a90,...) at ipi_nmi_handler+0x2f
trap(c4a53b70) at trap+0x2d
calltrap() at calltrap+0x6
--- trap 0x13, eip = 0xc0887a61, esp = 0xc4a53bb0, ebp = 0xc4a53bdc ---
sched_switch(c4d546c0,0,60c,187,5dd9d2a1,...) at sched_switch+0x401
mi_switch(60c,0,c0c3d1ae,813,1,...) at mi_switch+0x200
sched_preempt(c4d546c0,1,c4d54d80,c4a53cb4,c0b5428e,...) at sched_preempt+0x9f
ipi_bitmap_handler(8,28,28,31,c0d8e500,...) at ipi_bitmap_handler+0x34
Xipi_intr_bitmap_handler() at Xipi_intr_bitmap_handler+0x2e
--- interrupt, eip = 0xc0856a17, esp = 0xc4a53c8c, ebp = 0xc4a53cb4 ---
_thread_lock_flags(c4d546c0,0,c0c3d1ae,a04,c4d546c0,...) at 
_thread_lock_flags+0x177
sched_idletd(0,c4a53d38,c0c36ad3,335,c4d52a90,...) at sched_idletd+0x251
fork_exit(c0888510,0,c4a53d38) at fork_exit+0xb8
fork_trampoline() at fork_trampoline+0x8
--- trap 0, eip = 0, esp = 0xc4a53d70, ebp = 0 ---


- hardclock fires on CPU 0 and tries to schedule a SWI -- typically softclock
   or netisr, which bumps into the "leaked" thread lock:

db> bt
Tracing pid 1 tid 100002 td 0xc4d54d80
kdb_enter(c0c3b5e5,c0c3b5e5,c0c39ccd,c4a49ad0,0,...) at kdb_enter+0x3a
panic(c0c39ccd,c4d546c0,c0d8eb44,c4d546c0,186a5,...) at panic+0x136
_mtx_lock_spin_failed(1,9,c0c36d52,320,0,...) at _mtx_lock_spin_failed+0x51
_thread_lock_flags(c4d54240,0,c0c36d52,320,dd313180,...) at 
_thread_lock_flags+0x175
intr_event_schedule_thread(c4a49b58,c4a49b68,c0915dc4,c4d3a180,0,...) at 
intr_event_schedule_thread+0xc7
swi_sched(c4d3a180,0,c4a49b74,c0859a2f,c0d893d4,...) at swi_sched+0x28
netisr_sched_poll(c0d893d4,c4a49b88,c0824064,0,2,...) at 
netisr_sched_poll+0x24
hardclock_device_poll(0,2) at hardclock_device_poll+0xcf
hardclock(0,c0b74a49,0,27f,5dd9e8a2,...) at hardclock+0x44
lapic_handle_timer(c4a49bb0) at lapic_handle_timer+0x9f
Xtimerint() at Xtimerint+0x1f
--- interrupt, eip = 0xc0b74a49, esp = 0xc4a49bf0, ebp = 0xc4a49c0c ---
DELAY(f4240,0,c4d40980,c4a49c2c,c08653d3,...) at DELAY+0x89
cpu_reset(f4240,c4a49c68,c0865eaf,0,0,...) at cpu_reset+0xd5
shutdown_reset(0,0,c0c3b4a3,1a7,0,...) at shutdown_reset+0x23
boot(c0d89210,0,c0c3b4a3,ad,c4a49d2c,...) at boot+0x75f
reboot(c4d54d80,c4a49cf8,4,c0c428a4,c0d1dc28,...) at reboot+0x4b
syscall(c4a49d38) at syscall+0x2a3
Xint0x80_syscall() at Xint0x80_syscall+0x20

Possibly hardclock should simply know not to kick off softclock at that point 
in the shutdown (just like I've taught it not to kick off netisr in the 
device_polling code in my branch), but more generally, sched_ule probably 
needs to not hold the per-cpu runqueue lock, and/or sched_ule needs to not try 
to start work on CPUs that aren't running.  If the SWI is pinned on or bound 
to an already shut down CPU, then we should in fact panic, but otherwise it 
seems it should preempt the current thread and run it on the CPU managing the 
shutdown.

Or, we could go with the old-world order view and not allow interrupts to 
fire, but I wonder if all our device drivers would be comfortable with that.

Robert N M Watson
Computer Laboratory
University of Cambridge

---------- Forwarded message ----------
Date: Sun, 31 May 2009 13:52:17 +0000 (UTC)
From: Robert Watson <rwatson@FreeBSD.org>
To: src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject: svn commit: r193170 - projects/pnet/sys/kern

Author: rwatson
Date: Sun May 31 13:52:17 2009
New Revision: 193170
URL: http://svn.freebsd.org/changeset/base/193170

Log:
   Add a shutdown handler for device polling -- don't issue wakeups to the
   netisr once file systems are done syncing, otherwise the scheduler may
   generate IPIs to CPUs that have already been shutdown, leading to a
   panic.

   As similar panics (spin lock 0xc0d8e500 (sched lock 1) held by
   0xc4d546c0 (tid 100005) too long) have been reported on both 7.x and 8.x
   in other code, we might want to think about whether there's some missing
   scheduler shutdown logic to handle this case for unpinned/unbound
   threads by migrating them to the CPU managing the shutdown and allowing
   them to preempt.

Modified:
   projects/pnet/sys/kern/kern_poll.c

Modified: projects/pnet/sys/kern/kern_poll.c
==============================================================================
--- projects/pnet/sys/kern/kern_poll.c	Sun May 31 12:36:14 2009	(r193169)
+++ projects/pnet/sys/kern/kern_poll.c	Sun May 31 13:52:17 2009	(r193170)
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
  #include <sys/kernel.h>
  #include <sys/kthread.h>
  #include <sys/proc.h>
+#include <sys/eventhandler.h>
  #include <sys/resourcevar.h>
  #include <sys/socket.h>			/* needed by net/if.h		*/
  #include <sys/sockio.h>
@@ -110,6 +111,7 @@ SYSCTL_UINT(_kern_polling, OID_AUTO, bur

  static int	netisr_poll_scheduled;
  static int	netisr_pollmore_scheduled;
+static int	poll_shutting_down;

  static int poll_burst_max_sysctl(SYSCTL_HANDLER_ARGS)
  {
@@ -261,10 +263,19 @@ struct pollrec {
  static struct pollrec pr[POLL_LIST_LEN];

  static void
+poll_shutdown(void *arg, int howto)
+{
+
+	poll_shutting_down = 1;
+}
+
+static void
  init_device_poll(void)
  {

  	mtx_init(&poll_mtx, "polling", NULL, MTX_DEF);
+	EVENTHANDLER_REGISTER(shutdown_post_sync, poll_shutdown, NULL,
+	    SHUTDOWN_PRI_LAST);
  }
  SYSINIT(device_poll, SI_SUB_CLOCKS, SI_ORDER_MIDDLE, init_device_poll, NULL);

@@ -288,7 +299,7 @@ hardclock_device_poll(void)
  	static struct timeval prev_t, t;
  	int delta;

-	if (poll_handlers == 0)
+	if (poll_handlers == 0 || poll_shutting_down)
  		return;

  	microuptime(&t);



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