arena/slab: warn when destroying unfreed items

Instead of panicking.  This leaks resources, but keeps the machine
running.  It's a little hokey, since any attempt to free the objects
will run into issues.  Though if someone forgot to free it, hopefully
they won't free it before we can use the machine for some last minute
diagnostics.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/src/arena.c b/kern/src/arena.c
index ca624aa..a4f9d4e 100644
--- a/kern/src/arena.c
+++ b/kern/src/arena.c
@@ -218,8 +218,15 @@
 	if (arena->source)
 		del_importing_arena(arena->source, arena);
 
-	for (int i = 0; i < arena->hh.nr_hash_lists; i++)
-		assert(BSD_LIST_EMPTY(&arena->alloc_hash[i]));
+	for (int i = 0; i < arena->hh.nr_hash_lists; i++) {
+		/* Marginal at best.  The qcaches are destroyed already; if
+		 * someone tries to free this later, we're in trouble. */
+		if (!BSD_LIST_EMPTY(&arena->alloc_hash[i])) {
+			warn("Arena %s has unfreed items!  Will not destroy.",
+			     arena->name);
+			return;
+		}
+	}
 	if (arena->alloc_hash != arena->static_hash)
 		kfree(arena->alloc_hash);
 	/* We shouldn't have any spans left.  We can tell we messed up if we had
diff --git a/kern/src/slab.c b/kern/src/slab.c
index fecffcd..55b7776 100644
--- a/kern/src/slab.c
+++ b/kern/src/slab.c
@@ -458,8 +458,16 @@
 	drain_pcpu_caches(cp);
 	depot_destroy(cp);
 	spin_lock_irqsave(&cp->cache_lock);
-	assert(TAILQ_EMPTY(&cp->full_slab_list));
-	assert(TAILQ_EMPTY(&cp->partial_slab_list));
+	/* This is a little debatable.  We leak the cache and whatnot, but even
+	 * worse, someone has the object still, and they might free it, after
+	 * we've already torn down the depot.  At best this is a marginal way to
+	 * continue.  See similar code in arena.c. */
+	if (!TAILQ_EMPTY(&cp->full_slab_list) ||
+	    !TAILQ_EMPTY(&cp->partial_slab_list)) {
+		warn("KMC %s has unfreed items!  Will not destroy.", cp->name);
+		spin_unlock_irqsave(&cp->cache_lock);
+		return;
+	}
 	/* Clean out the empty list.  We can't use a regular FOREACH here, since
 	 * the link element is stored in the slab struct, which is stored on the
 	 * page that we are freeing. */