]> granicus.if.org Git - zfs/commitdiff
Reinstate raw receive check when truncating
authorTom Caputi <tcaputi@datto.com>
Thu, 6 Jun 2019 20:47:34 +0000 (16:47 -0400)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 6 Jun 2019 20:47:33 +0000 (13:47 -0700)
This patch re-adds a check that was removed in 369aa50. The check
confirms that a raw receive is not occuring before truncating an
object's dn_maxblkid. At the time, it was believed that all cases
that would hit this code path would be handled in other places,
but that was not the case.

Reviewed-by: Matt Ahrens <mahrens@delphix.com>
Reviewed-by: Paul Dagnelie <pcd@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tom Caputi <tcaputi@datto.com>
Closes #8852
Closes #8857

module/zfs/dnode_sync.c

index 581f812a14d15e41c4c87e1ccbdb124cacd3e202..d3acf1baaeaa3f2e7f690ae8ab265c327d451d40 100644 (file)
@@ -384,7 +384,21 @@ dnode_sync_free_range_impl(dnode_t *dn, uint64_t blkid, uint64_t nblks,
                }
        }
 
-       if (trunc) {
+       /*
+        * Do not truncate the maxblkid if we are performing a raw
+        * receive. The raw receive sets the maxblkid manually and
+        * must not be overridden. Usually, the last DRR_FREE record
+        * will be at the maxblkid, because the source system sets
+        * the maxblkid when truncating. However, if the last block
+        * was freed by overwriting with zeros and being compressed
+        * away to a hole, the source system will generate a DRR_FREE
+        * record while leaving the maxblkid after the end of that
+        * record. In this case we need to leave the maxblkid as
+        * indicated in the DRR_OBJECT record, so that it matches the
+        * source system, ensuring that the cryptographic hashes will
+        * match.
+        */
+       if (trunc && !dn->dn_objset->os_raw_receive) {
                ASSERTV(uint64_t off);
                dn->dn_phys->dn_maxblkid = blkid == 0 ? 0 : blkid - 1;