mdb_cursorpages_mark(m0, P_DIRTY|P_KEEP);
 
        if (rc == 0) {
-               txn->mt_dirty_room = MDB_IDL_UM_MAX - dl[0].mid;
+               if (txn->mt_parent) {
+                       MDB_txn *tx2;
+                       pgno_t pgno = dl[i].mid;
+                       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++) {
+                               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;
        }
        return rc;
                        }       /* otherwise, if belonging to a parent txn, the
                                 * 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) {
+                                               txn->mt_dirty_room++;
+                                               break;
+                                       }
+                               }
+                       }
                        mdb_page_dirty(tx0, np);
                        np->mp_flags |= P_DIRTY;
                        *ret = np;