From ec4f9b8f30391a3fb46c8d4a31c2dc9250dca1bb Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Thu, 21 Mar 2019 10:30:15 -0700 Subject: [PATCH] Report holes when there are only metadata changes Update the dirty check in dmu_offset_next() such that dnode's are only considered dirty for the purpose or reporting holes when there are pending data blocks or frees to be synced. This ensures that when there are only metadata updates to be synced (atime) that holes are reported. Reviewed-by: Debabrata Banerjee Signed-off-by: Brian Behlendorf Closes #6958 Closes #8505 --- module/zfs/dmu.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 1621772840cc..3d8423af335a 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -2366,14 +2366,39 @@ dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole, uint64_t *off) return (err); /* - * Check if dnode is dirty + * Check if there are dirty data blocks or frees which have not been + * synced. Dirty spill and bonus blocks which are external to the + * object can ignored when reporting holes. */ + mutex_enter(&dn->dn_mtx); for (i = 0; i < TXG_SIZE; i++) { if (multilist_link_active(&dn->dn_dirty_link[i])) { - clean = B_FALSE; - break; + + if (dn->dn_free_ranges[i] != NULL) { + clean = B_FALSE; + break; + } + + list_t *list = &dn->dn_dirty_records[i]; + dbuf_dirty_record_t *dr; + + for (dr = list_head(list); dr != NULL; + dr = list_next(list, dr)) { + dmu_buf_impl_t *db = dr->dr_dbuf; + + if (db->db_blkid == DMU_SPILL_BLKID || + db->db_blkid == DMU_BONUS_BLKID) + continue; + + clean = B_FALSE; + break; + } } + + if (clean == B_FALSE) + break; } + mutex_exit(&dn->dn_mtx); /* * If compatibility option is on, sync any current changes before