]> granicus.if.org Git - zfs/commitdiff
Report holes when there are only metadata changes
authorBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 21 Mar 2019 17:30:15 +0000 (10:30 -0700)
committerGitHub <noreply@github.com>
Thu, 21 Mar 2019 17:30:15 +0000 (10:30 -0700)
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 <dbanerje@akamai.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #6958
Closes #8505

module/zfs/dmu.c

index 1621772840cc437ff81c99d714d47aa7b1b70af7..3d8423af335a27775472ff49308793d42cb1466f 100644 (file)
@@ -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