summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/zfs/dbuf.c
diff options
context:
space:
mode:
authorKeith M Wesolowski <wesolows@foobazco.org>2013-08-21 23:54:45 +0000
committerKeith M Wesolowski <wesolows@foobazco.org>2013-08-21 23:54:45 +0000
commit84a6527d59b307f3925d3dbac3728fd0d1db4706 (patch)
tree0f87ef159a57043733b2ad0f861e14d22d635942 /usr/src/uts/common/fs/zfs/dbuf.c
parent7d7a5b1f6447ad858fd291d2b95da27e7c690325 (diff)
parent2a12f85ad140e332791b4bad1208a734c3f26bf3 (diff)
downloadillumos-joyent-release-20130822.tar.gz
[illumos-gate merge]20130822release-20130822
commit 2a12f85ad140e332791b4bad1208a734c3f26bf3 3946 ::gcore commit 840b2722e5294ae44aa3af6189002f521d7c50e0 3915 Add adjuncts support to the build (fix lint) commit afffa6e9b45cbe9b33943e26568d8ac69b899252 4062 libscf: memory leaks in scf_simple_app_props_get() commit 2fbdf8dbf01ec1c85fcd3827cdf9e9f5f46c4c8a 4061 libzfs: memory leak in iter_dependents_cb() commit 713d6c208802cfbb806329ec0d154b641b80c355 4047 panic from dbuf_free_range() from dmu_free_object() while doing zfs receive
Diffstat (limited to 'usr/src/uts/common/fs/zfs/dbuf.c')
-rw-r--r--usr/src/uts/common/fs/zfs/dbuf.c31
1 files changed, 21 insertions, 10 deletions
diff --git a/usr/src/uts/common/fs/zfs/dbuf.c b/usr/src/uts/common/fs/zfs/dbuf.c
index d4acbb5b3c..b688e6794d 100644
--- a/usr/src/uts/common/fs/zfs/dbuf.c
+++ b/usr/src/uts/common/fs/zfs/dbuf.c
@@ -41,6 +41,12 @@
#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);
@@ -831,20 +837,22 @@ dbuf_free_range(dnode_t *dn, uint64_t start, uint64_t end, dmu_tx_t *tx)
}
dprintf_dnode(dn, "start=%llu end=%llu\n", start, end);
- if (dmu_objset_is_receiving(dn->dn_objset)) {
+ 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)) {
/*
- * 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.
+ * 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.
*/
- VERIFY3P(dbuf_find(dn, 0, start), ==, NULL);
- VERIFY3P(dbuf_find(dn, 0, end), ==, NULL);
- return;
+ atomic_inc_64(&zfs_free_range_recv_miss);
}
- 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);
@@ -1732,6 +1740,9 @@ dbuf_create(dnode_t *dn, uint8_t level, uint64_t blkid,
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);