+ return (tv->tv_err != 0 ? tv->tv_err : tv->tv_lasterr);
+}
+
+/*
+ * Due to limited stack space recursive functions are frowned upon in
+ * the Linux kernel. However, they often are the most elegant solution
+ * to a problem. The following code preserves the recursive function
+ * traverse_visitbp() but moves the local variables AND function
+ * arguments to the heap to minimize the stack frame size. Enough
+ * space is initially allocated on the stack for 16 levels of recursion.
+ * This change does ugly-up-the-code but it reduces the worst case
+ * usage from roughly 2496 bytes to 576 bytes on x86_64 archs.
+ */
+static int
+traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
+ arc_buf_t *pbuf, blkptr_t *bp, const zbookmark_t *zb)
+{
+ traverse_visitbp_data_t *tv;
+ int error;
+
+ tv = kmem_zalloc(sizeof(traverse_visitbp_data_t) *
+ TRAVERSE_VISITBP_MAX_DEPTH, KM_SLEEP);
+ __traverse_visitbp_init(tv, td, dnp, pbuf, bp, zb, 0);
+
+ error = __traverse_visitbp(tv);
+
+ kmem_free(tv, sizeof(traverse_visitbp_data_t) *
+ TRAVERSE_VISITBP_MAX_DEPTH);
+
+ return (error);
+}
+
+static int
+traverse_dnode(traverse_data_t *td, const dnode_phys_t *dnp,
+ arc_buf_t *buf, uint64_t objset, uint64_t object)
+{
+ int j, err = 0, lasterr = 0;
+ zbookmark_t czb;
+ boolean_t hard = (td->td_flags & TRAVERSE_HARD);
+
+ for (j = 0; j < dnp->dn_nblkptr; j++) {
+ SET_BOOKMARK(&czb, objset, object, dnp->dn_nlevels - 1, j);
+ err = traverse_visitbp(td, dnp, buf,
+ (blkptr_t *)&dnp->dn_blkptr[j], &czb);
+ if (err) {
+ if (!hard)
+ break;
+ lasterr = err;
+ }
+ }
+
+ if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) {
+ SET_BOOKMARK(&czb, objset,
+ object, 0, DMU_SPILL_BLKID);
+ err = traverse_visitbp(td, dnp, buf,
+ (blkptr_t *)&dnp->dn_spill, &czb);
+ if (err) {
+ if (!hard)
+ return (err);
+ lasterr = err;
+ }
+ }
+ return (err != 0 ? err : lasterr);