From: Matthew Ahrens Date: Mon, 29 Aug 2016 18:40:16 +0000 (-0700) Subject: OpenZFS 7086 - ztest attempts dva_get_dsize_sync on an embedded blockpointer X-Git-Tag: zfs-0.7.0-rc1~16 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=98ace739bd89b541af30d9d627ee42622fbbd861;p=zfs OpenZFS 7086 - ztest attempts dva_get_dsize_sync on an embedded blockpointer In dbuf_dirty(), we need to grab the dn_struct_rwlock before looking at the db_blkptr, to prevent it from being changed by syncing context. Reviewed by: Prakash Surya Reviewed by: George Wilson Signed-off-by: Brian Behlendorf OpenZFS-issue: https://www.illumos.org/issues/7086 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/98fa317 Closes #5039 --- diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index d297506e9..e452fd23a 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -1468,7 +1468,20 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx) dnode_setdirty(dn, tx); DB_DNODE_EXIT(db); return (dr); - } else if (do_free_accounting) { + } + + /* + * The dn_struct_rwlock prevents db_blkptr from changing + * due to a write from syncing context completing + * while we are running, so we want to acquire it before + * looking at db_blkptr. + */ + if (!RW_WRITE_HELD(&dn->dn_struct_rwlock)) { + rw_enter(&dn->dn_struct_rwlock, RW_READER); + drop_struct_lock = TRUE; + } + + if (do_free_accounting) { blkptr_t *bp = db->db_blkptr; int64_t willfree = (bp && !BP_IS_HOLE(bp)) ? bp_get_dsize(os->os_spa, bp) : db->db.db_size; @@ -1484,11 +1497,6 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx) dnode_willuse_space(dn, -willfree, tx); } - if (!RW_WRITE_HELD(&dn->dn_struct_rwlock)) { - rw_enter(&dn->dn_struct_rwlock, RW_READER); - drop_struct_lock = TRUE; - } - if (db->db_level == 0) { dnode_new_blkid(dn, db->db_blkid, tx, drop_struct_lock); ASSERT(dn->dn_maxblkid >= db->db_blkid);