+static void
+cluster_EOT(buf_t cbp_head, buf_t cbp_tail, int zero_offset)
+{
+ cbp_head->b_validend = zero_offset;
+ cbp_tail->b_flags |= B_EOT;
+}
+
+static void
+cluster_wait_IO(buf_t cbp_head, int async)
+{
+ buf_t cbp;
+
+ if (async) {
+ /*
+ * async callback completion will not normally
+ * generate a wakeup upon I/O completion...
+ * by setting B_TWANTED, we will force a wakeup
+ * to occur as any outstanding I/Os complete...
+ * I/Os already completed will have B_TDONE already
+ * set and we won't cause us to block
+ * note that we're actually waiting for the bp to have
+ * completed the callback function... only then
+ * can we safely take back ownership of the bp
+ */
+ lck_mtx_lock_spin(cl_transaction_mtxp);
+
+ for (cbp = cbp_head; cbp; cbp = cbp->b_trans_next)
+ cbp->b_flags |= B_TWANTED;
+
+ lck_mtx_unlock(cl_transaction_mtxp);
+ }
+ for (cbp = cbp_head; cbp; cbp = cbp->b_trans_next) {
+
+ if (async) {
+ while (!ISSET(cbp->b_flags, B_TDONE)) {
+
+ lck_mtx_lock_spin(cl_transaction_mtxp);
+
+ if (!ISSET(cbp->b_flags, B_TDONE)) {
+ DTRACE_IO1(wait__start, buf_t, cbp);
+ (void) msleep(cbp, cl_transaction_mtxp, PDROP | (PRIBIO+1), "cluster_wait_IO", NULL);
+ DTRACE_IO1(wait__done, buf_t, cbp);
+ } else
+ lck_mtx_unlock(cl_transaction_mtxp);
+ }
+ } else
+ buf_biowait(cbp);
+ }
+}
+
+static void
+cluster_complete_transaction(buf_t *cbp_head, void *callback_arg, int *retval, int flags, int needwait)
+{
+ buf_t cbp;
+ int error;
+ boolean_t isswapout = FALSE;
+
+ /*
+ * cluster_complete_transaction will
+ * only be called if we've issued a complete chain in synchronous mode
+ * or, we've already done a cluster_wait_IO on an incomplete chain
+ */
+ if (needwait) {
+ for (cbp = *cbp_head; cbp; cbp = cbp->b_trans_next)
+ buf_biowait(cbp);
+ }
+ /*
+ * we've already waited on all of the I/Os in this transaction,
+ * so mark all of the buf_t's in this transaction as B_TDONE
+ * so that cluster_iodone sees the transaction as completed
+ */
+ for (cbp = *cbp_head; cbp; cbp = cbp->b_trans_next)
+ cbp->b_flags |= B_TDONE;
+ cbp = *cbp_head;
+
+ if ((flags & (CL_ASYNC | CL_PAGEOUT)) == CL_PAGEOUT && vnode_isswap(cbp->b_vp))
+ isswapout = TRUE;
+
+ error = cluster_iodone(cbp, callback_arg);
+
+ if ( !(flags & CL_ASYNC) && error && *retval == 0) {
+ if (((flags & (CL_PAGEOUT | CL_KEEPCACHED)) != CL_PAGEOUT) || (error != ENXIO))
+ *retval = error;
+ else if (isswapout == TRUE)
+ *retval = error;
+ }
+ *cbp_head = (buf_t)NULL;
+}
+
+