diff options
author | mav <mav@FreeBSD.org> | 2015-11-13 09:18:33 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2015-11-13 09:18:33 +0000 |
commit | d3cb7008539f594b4314e8646c794fe0c6905737 (patch) | |
tree | 4d0f38987e623c0069dd5b4284b2c1afd61724d9 | |
parent | e7bc2aced507b7e942a58282c9aab5543d0b3d04 (diff) | |
download | FreeBSD-src-d3cb7008539f594b4314e8646c794fe0c6905737.zip FreeBSD-src-d3cb7008539f594b4314e8646c794fe0c6905737.tar.gz |
MFC r289297: 6288 dmu_buf_will_dirty could be faster
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Justin Gibbs <gibbs@scsiguy.com>
Reviewed by: Richard Elling <Richard.Elling@RichardElling.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Author: Matthew Ahrens <mahrens@delphix.com>
illumos/illumos-gate@0f2e7d03b8f588387cb8dd8dd500cbe5ff4484e0
-rw-r--r-- | sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c | 61 |
1 files changed, 51 insertions, 10 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c index a28d866..ba630a5 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c @@ -1110,6 +1110,32 @@ dbuf_release_bp(dmu_buf_impl_t *db) (void) arc_release(db->db_buf, db); } +/* + * We already have a dirty record for this TXG, and we are being + * dirtied again. + */ +static void +dbuf_redirty(dbuf_dirty_record_t *dr) +{ + dmu_buf_impl_t *db = dr->dr_dbuf; + + ASSERT(MUTEX_HELD(&db->db_mtx)); + + if (db->db_level == 0 && db->db_blkid != DMU_BONUS_BLKID) { + /* + * If this buffer has already been written out, + * we now need to reset its state. + */ + dbuf_unoverride(dr); + if (db->db.db_object != DMU_META_DNODE_OBJECT && + db->db_state != DB_NOFILL) { + /* Already released on initial dirty, so just thaw. */ + ASSERT(arc_released(db->db_buf)); + arc_buf_thaw(db->db_buf); + } + } +} + dbuf_dirty_record_t * dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx) { @@ -1182,16 +1208,7 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx) if (dr && dr->dr_txg == tx->tx_txg) { DB_DNODE_EXIT(db); - if (db->db_level == 0 && db->db_blkid != DMU_BONUS_BLKID) { - /* - * If this buffer has already been written out, - * we now need to reset its state. - */ - dbuf_unoverride(dr); - if (db->db.db_object != DMU_META_DNODE_OBJECT && - db->db_state != DB_NOFILL) - arc_buf_thaw(db->db_buf); - } + dbuf_redirty(dr); mutex_exit(&db->db_mtx); return (dr); } @@ -1495,6 +1512,30 @@ dmu_buf_will_dirty(dmu_buf_t *db_fake, dmu_tx_t *tx) ASSERT(tx->tx_txg != 0); ASSERT(!refcount_is_zero(&db->db_holds)); + /* + * Quick check for dirtyness. For already dirty blocks, this + * reduces runtime of this function by >90%, and overall performance + * by 50% for some workloads (e.g. file deletion with indirect blocks + * cached). + */ + mutex_enter(&db->db_mtx); + dbuf_dirty_record_t *dr; + for (dr = db->db_last_dirty; + dr != NULL && dr->dr_txg >= tx->tx_txg; dr = dr->dr_next) { + /* + * It's possible that it is already dirty but not cached, + * because there are some calls to dbuf_dirty() that don't + * go through dmu_buf_will_dirty(). + */ + if (dr->dr_txg == tx->tx_txg && db->db_state == DB_CACHED) { + /* This dbuf is already dirty and cached. */ + dbuf_redirty(dr); + mutex_exit(&db->db_mtx); + return; + } + } + mutex_exit(&db->db_mtx); + DB_DNODE_ENTER(db); if (RW_WRITE_HELD(&DB_DNODE(db)->dn_struct_rwlock)) rf |= DB_RF_HAVESTRUCT; |