+
+/*
+ * If the getnewbuf() calls bcleanbuf() on the same thread
+ * there is a potential for stack overrun and deadlocks.
+ * So we always handoff the work to worker thread for completion
+ */
+
+static void
+bcleanbuf_thread_init()
+{
+ static void bcleanbuf_thread();
+
+ /* create worker thread */
+ kernel_thread(kernel_task, bcleanbuf_thread);
+}
+
+static void
+bcleanbuf_thread()
+{
+ boolean_t funnel_state;
+ struct buf *bp;
+
+ funnel_state = thread_funnel_set(kernel_flock, TRUE);
+
+doit:
+ while (blaundrycnt == 0)
+ (void)tsleep((void *)&blaundrycnt, PRIBIO, "blaundry", 60 * hz);
+ bp = TAILQ_FIRST(&bufqueues[BQ_LAUNDRY]);
+ /* Remove from the queue */
+ bremfree(bp);
+ blaundrycnt--;
+ /* do the IO */
+ bawrite(bp);
+ /* start again */
+ goto doit;
+
+ (void) thread_funnel_set(kernel_flock, funnel_state);
+}
+