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()) {