Don't chan_release() from an RCU callback
RCU callbacks are not allowed to block. chan_release(), which is triggered
by decreffing a chan, can be triggered from an RCU callback.
Here's an example of a callchain that would have panicked:
#01 [<0xffffffffc200b7c2>] in sem_down (block here)
#02 [<0xffffffffc200c221>] in cv_wait
#03 [<0xffffffffc204ee05>] in rendez_sleep (this actually panics now)
#04 [<0xffffffffc2039fa4>] in __qbread
#05 [<0xffffffffc207c014>] in doread
#06 [<0xffffffffc207c901>] in mntrpcread
#07 [<0xffffffffc207d1a5>] in mountio
#08 [<0xffffffffc207d3b5>] in mountrpc
#09 [<0xffffffffc207dbfd>] in mntclunk
#10 [<0xffffffffc2031448>] in chan_release
#11 [<0xffffffffc2030bcb>] in kref_put
#12 [<0xffffffffc2078be0>] in gtfs_tf_free
#13 [<0xffffffffc2042125>] in __tf_free
#14 [<0xffffffffc204f7e2>] in rcu_mgmt_ktask
#15 [<0xffffffffc200acc0>] in __ktask_wrapper
#16 [<0xffffffffc205981f>] in process_routine_kmsg
#17 [<0xffffffffc20534a8>] in __smp_idle
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/src/ns/chan.c b/kern/src/ns/chan.c
index 9e42ff9..b7d6a1d 100644
--- a/kern/src/ns/chan.c
+++ b/kern/src/ns/chan.c
@@ -158,6 +158,13 @@
{
struct chan *c = container_of(kref, struct chan, ref);
ERRSTACK(1);
+
+ /* We can be called from RCU callbacks, but close methods can block. In
+ * those cases, we need to defer our work to a kernel message. */
+ if (in_rcu_cb_ctx(this_pcpui_ptr())) {
+ run_as_rkm(chan_release, kref);
+ return;
+ }
/* this style discards the error from close(). picture it as
* if (waserror()) { } else { close(); } chanfree_no_matter_what(); */
if (!waserror()) {