#define MDB_TXN_SPILLS         0x08            /**< txn or a parent has spilled pages */
 /** @} */
        unsigned int    mt_flags;               /**< @ref mdb_txn */
-       /** dirty_list maxsize - # of allocated pages allowed, including in parent txns */
+       /** dirty_list room: Array size - #dirty pages visible to this txn.
+        *      Includes ancestor txns' dirty pages not hidden by other txns'
+        *      dirty/spilled pages. Thus commit(nested txn) has room to merge
+        *      dirty_list into mt_parent after freeing hidden mt_parent pages.
+        */
        unsigned int    mt_dirty_room;
        /** Tracks which of the two meta pages was used at the start
         *      of this transaction.
        rc = mdb_pages_xkeep(m0, P_DIRTY|P_KEEP, i);
 
 done:
-       if (rc == 0) {
-               if (txn->mt_parent) {
-                       txn->mt_dirty_room = txn->mt_parent->mt_dirty_room - dl[0].mid;
-                       /* dirty pages that are dirty in an ancestor don't
-                        * count against this txn's dirty_room.
-                        */
-                       for (i=1; i<=dl[0].mid; i++) {
-                               pgno_t pgno = dl[i].mid;
-                               MDB_txn *tx2;
-                               for (tx2 = txn->mt_parent; tx2; tx2 = tx2->mt_parent) {
-                                       j = mdb_mid2l_search(tx2->mt_u.dirty_list, pgno);
-                                       if (j <= tx2->mt_u.dirty_list[0].mid &&
-                                               tx2->mt_u.dirty_list[j].mid == pgno) {
-                                               txn->mt_dirty_room++;
-                                               break;
-                                       }
-                               }
-                       }
-               } else {
-                       txn->mt_dirty_room = MDB_IDL_UM_MAX - dl[0].mid;
-               }
-               txn->mt_flags |= MDB_TXN_SPILLS;
-       } else {
-               txn->mt_flags |= MDB_TXN_ERROR;
-       }
+       txn->mt_flags |= rc ? MDB_TXN_ERROR : MDB_TXN_SPILLS;
        return rc;
 }
 
                if (x <= txn->mt_spill_pgs[0] && txn->mt_spill_pgs[x] == pn) {
                        MDB_page *np;
                        int num;
+                       if (txn->mt_dirty_room == 0)
+                               return MDB_TXN_FULL;
                        if (IS_OVERFLOW(mp))
                                num = mp->mp_pages;
                        else
                                 * page remains spilled until child commits
                                 */
 
-                       if (txn->mt_parent) {
-                               MDB_txn *tx2;
-                               /* If this page is also in a parent's dirty list, then
-                                * it's already accounted in dirty_room, and we need to
-                                * cancel out the decrement that mdb_page_dirty does.
-                                */
-                               for (tx2 = txn->mt_parent; tx2; tx2 = tx2->mt_parent) {
-                                       x = mdb_mid2l_search(tx2->mt_u.dirty_list, pgno);
-                                       if (x <= tx2->mt_u.dirty_list[0].mid &&
-                                               tx2->mt_u.dirty_list[x].mid == pgno) {
-                                               tx0->mt_dirty_room++;
-                                               break;
-                                       }
-                               }
-                       }
                        mdb_page_dirty(tx0, np);
                        np->mp_flags |= P_DIRTY;
                        *ret = np;
                        }
                        dp->mp_flags &= ~P_DIRTY;
                }
-               dl[0].mid = j;
-               return MDB_SUCCESS;
+               goto done;
        }
 
        /* Write the pages */
                }
                mdb_dpage_free(env, dp);
        }
-       dl[0].mid = j;
 
+done:
+       i--;
+       txn->mt_dirty_room += i - j;
+       dl[0].mid = j;
        return MDB_SUCCESS;
 }