}
}
- 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;