Fix issues with truncated files in raw sends

This patch fixes a few issues with raw receives involving
truncated files:

* dnode_reallocate() now calls dnode_set_blksz() instead of
  dnode_setdblksz(). This ensures that any remaining dbufs with
  blkid 0 are resized along with their containing dnode upon
  reallocation.

* One of the calls to dmu_free_long_range() in receive_object()
  needs to check that the object it is about to free some contents
  or hasn't been completely removed already by a previous call to
  dmu_free_long_object() in the same function.

* The same call to dmu_free_long_range() in the previous point
  needs to ensure it uses the object's current block size and
  not the new block size. This ensures the blocks of the object
  that are supposed to be freed are completely removed and not
  simply partially zeroed out.

This patch also adds handling for DRR_OBJECT_RANGE records to
dprintf_drr() for debugging purposes.

Reviewed-by: Matt Ahrens <mahrens@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tom Caputi <tcaputi@datto.com>
Closes #7378 
Closes #8528
This commit is contained in:
Tom Caputi
2019-03-27 14:30:48 -04:00
committed by Brian Behlendorf
parent 85a150ce1e
commit 5dbf8b4edd
7 changed files with 157 additions and 50 deletions
+1
View File
@@ -1737,6 +1737,7 @@ dmu_assign_arcbuf_by_dnode(dnode_t *dn, uint64_t offset, arc_buf_t *buf,
/* compressed bufs must always be assignable to their dbuf */
ASSERT3U(arc_get_compression(buf), ==, ZIO_COMPRESS_OFF);
ASSERT(!(buf->b_flags & ARC_BUF_FLAG_COMPRESSED));
ASSERT(!arc_is_encrypted(buf));
dbuf_rele(db, FTAG);
dmu_write(os, object, offset, blksz, buf->b_data, tx);
+22 -12
View File
@@ -1235,11 +1235,13 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
* processed. However, for raw receives we manually set the
* maxblkid from the drr_maxblkid and so we must first free
* everything above that blkid to ensure the DMU is always
* consistent with itself.
* consistent with itself. We will never free the first block
* of the object here because a maxblkid of 0 could indicate
* an object with a single block or one with no blocks.
*/
if (rwa->raw) {
if (rwa->raw && object != DMU_NEW_OBJECT) {
err = dmu_free_long_range(rwa->os, drro->drr_object,
(drro->drr_maxblkid + 1) * drro->drr_blksz,
(drro->drr_maxblkid + 1) * doi.doi_data_block_size,
DMU_OBJECT_END);
if (err != 0)
return (SET_ERROR(EINVAL));
@@ -1375,11 +1377,8 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
drro->drr_nlevels, tx));
/*
* Set the maxblkid. We will never free the first block of
* an object here because a maxblkid of 0 could indicate
* an object with a single block or one with no blocks.
* This will always succeed because we freed all blocks
* beyond the new maxblkid above.
* Set the maxblkid. This will always succeed because
* we freed all blocks beyond the new maxblkid above.
*/
VERIFY0(dmu_object_set_maxblkid(rwa->os, drro->drr_object,
drro->drr_maxblkid, tx));
@@ -2185,7 +2184,7 @@ dprintf_drr(struct receive_record_arg *rrd, int err)
{
struct drr_write *drrw = &rrd->header.drr_u.drr_write;
dprintf("drr_type = WRITE obj = %llu type = %u offset = %llu "
"lsize = %llu cksumtype = %u cksumflags = %u "
"lsize = %llu cksumtype = %u flags = %u "
"compress = %u psize = %llu err = %d\n",
drrw->drr_object, drrw->drr_type, drrw->drr_offset,
drrw->drr_logical_size, drrw->drr_checksumtype,
@@ -2200,7 +2199,7 @@ dprintf_drr(struct receive_record_arg *rrd, int err)
dprintf("drr_type = WRITE_BYREF obj = %llu offset = %llu "
"length = %llu toguid = %llx refguid = %llx "
"refobject = %llu refoffset = %llu cksumtype = %u "
"cksumflags = %u err = %d\n",
"flags = %u err = %d\n",
drrwbr->drr_object, drrwbr->drr_offset,
drrwbr->drr_length, drrwbr->drr_toguid,
drrwbr->drr_refguid, drrwbr->drr_refobject,
@@ -2236,6 +2235,16 @@ dprintf_drr(struct receive_record_arg *rrd, int err)
"err = %d\n", drrs->drr_object, drrs->drr_length, err);
break;
}
case DRR_OBJECT_RANGE:
{
struct drr_object_range *drror =
&rrd->header.drr_u.drr_object_range;
dprintf("drr_type = OBJECT_RANGE firstobj = %llu "
"numslots = %llu flags = %u err = %d\n",
drror->drr_firstobj, drror->drr_numslots,
drror->drr_flags, err);
break;
}
default:
return;
}
@@ -2319,10 +2328,11 @@ receive_process_record(struct receive_writer_arg *rwa,
{
struct drr_object_range *drror =
&rrd->header.drr_u.drr_object_range;
return (receive_object_range(rwa, drror));
err = receive_object_range(rwa, drror);
break;
}
default:
return (SET_ERROR(EINVAL));
err = (SET_ERROR(EINVAL));
}
if (err != 0)
+5 -6
View File
@@ -689,12 +689,9 @@ dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
dnode_setdirty(dn, tx);
if (dn->dn_datablksz != blocksize) {
/* change blocksize */
ASSERT(dn->dn_maxblkid == 0 &&
(BP_IS_HOLE(&dn->dn_phys->dn_blkptr[0]) ||
dnode_block_freed(dn, 0)));
dnode_setdblksz(dn, blocksize);
dn->dn_next_blksz[tx->tx_txg&TXG_MASK] = blocksize;
ASSERT0(dn->dn_maxblkid);
ASSERT(BP_IS_HOLE(&dn->dn_phys->dn_blkptr[0]) ||
dnode_block_freed(dn, 0));
}
if (dn->dn_bonuslen != bonuslen)
dn->dn_next_bonuslen[tx->tx_txg&TXG_MASK] = bonuslen;
@@ -715,6 +712,8 @@ dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
}
rw_exit(&dn->dn_struct_rwlock);
VERIFY0(dnode_set_blksz(dn, blocksize, 0, tx));
/* change type */
dn->dn_type = ot;