Print this page
4047 panic from dbuf_free_range() from dmu_free_object() while doing zfs receive
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
*** 38,47 ****
--- 38,53 ----
#include <sys/zio.h>
#include <sys/dmu_zfetch.h>
#include <sys/sa.h>
#include <sys/sa_impl.h>
+ /*
+ * Number of times that zfs_free_range() took the slow path while doing
+ * a zfs receive. A nonzero value indicates a potential performance problem.
+ */
+ uint64_t zfs_free_range_recv_miss;
+
static void dbuf_destroy(dmu_buf_impl_t *db);
static boolean_t dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx);
static void dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx);
/*
*** 817,840 ****
end = dn->dn_maxblkid;
last_l1 = end >> epbs;
}
dprintf_dnode(dn, "start=%llu end=%llu\n", start, end);
! if (dmu_objset_is_receiving(dn->dn_objset)) {
/*
! * When processing a free record from a zfs receive,
! * there should have been no previous modifications to the
! * data in this range. Therefore there should be no dbufs
! * in the range. Searching dn_dbufs for these non-existent
! * dbufs can be very expensive, so simply ignore this.
*/
! VERIFY3P(dbuf_find(dn, 0, start), ==, NULL);
! VERIFY3P(dbuf_find(dn, 0, end), ==, NULL);
! return;
}
- mutex_enter(&dn->dn_dbufs_mtx);
for (db = list_head(&dn->dn_dbufs); db; db = db_next) {
db_next = list_next(&dn->dn_dbufs, db);
ASSERT(db->db_blkid != DMU_BONUS_BLKID);
if (db->db_level == 1 &&
--- 823,848 ----
end = dn->dn_maxblkid;
last_l1 = end >> epbs;
}
dprintf_dnode(dn, "start=%llu end=%llu\n", start, end);
! mutex_enter(&dn->dn_dbufs_mtx);
! if (start >= dn->dn_unlisted_l0_blkid * dn->dn_datablksz) {
! /* There can't be any dbufs in this range; no need to search. */
! mutex_exit(&dn->dn_dbufs_mtx);
! return;
! } else if (dmu_objset_is_receiving(dn->dn_objset)) {
/*
! * If we are receiving, we expect there to be no dbufs in
! * the range to be freed, because receive modifies each
! * block at most once, and in offset order. If this is
! * not the case, it can lead to performance problems,
! * so note that we unexpectedly took the slow path.
*/
! atomic_inc_64(&zfs_free_range_recv_miss);
}
for (db = list_head(&dn->dn_dbufs); db; db = db_next) {
db_next = list_next(&dn->dn_dbufs, db);
ASSERT(db->db_blkid != DMU_BONUS_BLKID);
if (db->db_level == 1 &&
*** 1718,1727 ****
--- 1726,1738 ----
kmem_cache_free(dbuf_cache, db);
mutex_exit(&dn->dn_dbufs_mtx);
return (odb);
}
list_insert_head(&dn->dn_dbufs, db);
+ if (db->db_level == 0 && db->db_blkid >=
+ dn->dn_unlisted_l0_blkid)
+ dn->dn_unlisted_l0_blkid = db->db_blkid + 1;
db->db_state = DB_UNCACHED;
mutex_exit(&dn->dn_dbufs_mtx);
arc_space_consume(sizeof (dmu_buf_impl_t), ARC_SPACE_OTHER);
if (parent && parent != dn->dn_dbuf)