Fix noop receive of raw send stream
Currently, the noop receive code fails to work with raw send streams and resuming send streams. This happens because zfs_receive_impl() reads the DRR_BEGIN payload without reading the payload itself. Normally, the kernel expects to read this itself, but in this case the recv_skip() code runs instead and it is not prepared to handle the stream being left at any place other than the beginning of a record. This patch resolves this issue by manually reading the DRR_BEGIN payload in the dry-run case. This patch also includes a number of small fixups in this code path. Reviewed-by: George Melikov <mail@gmelikov.ru> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Paul Dagnelie <pcd@delphix.com> Signed-off-by: Tom Caputi <tcaputi@datto.com> Closes #9221 Closes #9173
This commit is contained in:
parent
8e2c502cf3
commit
870e7a52c1
|
@ -4042,10 +4042,11 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
|
|||
{
|
||||
dmu_replay_record_t *drr;
|
||||
void *buf = zfs_alloc(hdl, SPA_MAXBLOCKSIZE);
|
||||
uint64_t payload_size;
|
||||
char errbuf[1024];
|
||||
|
||||
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
|
||||
"cannot receive:"));
|
||||
"cannot receive"));
|
||||
|
||||
/* XXX would be great to use lseek if possible... */
|
||||
drr = buf;
|
||||
|
@ -4072,9 +4073,14 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
|
|||
drr->drr_u.drr_object.drr_bonuslen =
|
||||
BSWAP_32(drr->drr_u.drr_object.
|
||||
drr_bonuslen);
|
||||
drr->drr_u.drr_object.drr_raw_bonuslen =
|
||||
BSWAP_32(drr->drr_u.drr_object.
|
||||
drr_raw_bonuslen);
|
||||
}
|
||||
(void) recv_read(hdl, fd, buf,
|
||||
P2ROUNDUP(drr->drr_u.drr_object.drr_bonuslen, 8),
|
||||
|
||||
payload_size =
|
||||
DRR_OBJECT_PAYLOAD_SIZE(&drr->drr_u.drr_object);
|
||||
(void) recv_read(hdl, fd, buf, payload_size,
|
||||
B_FALSE, NULL);
|
||||
break;
|
||||
|
||||
|
@ -4087,7 +4093,7 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
|
|||
BSWAP_64(
|
||||
drr->drr_u.drr_write.drr_compressed_size);
|
||||
}
|
||||
uint64_t payload_size =
|
||||
payload_size =
|
||||
DRR_WRITE_PAYLOAD_SIZE(&drr->drr_u.drr_write);
|
||||
(void) recv_read(hdl, fd, buf,
|
||||
payload_size, B_FALSE, NULL);
|
||||
|
@ -4096,9 +4102,15 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
|
|||
if (byteswap) {
|
||||
drr->drr_u.drr_spill.drr_length =
|
||||
BSWAP_64(drr->drr_u.drr_spill.drr_length);
|
||||
drr->drr_u.drr_spill.drr_compressed_size =
|
||||
BSWAP_64(drr->drr_u.drr_spill.
|
||||
drr_compressed_size);
|
||||
}
|
||||
(void) recv_read(hdl, fd, buf,
|
||||
drr->drr_u.drr_spill.drr_length, B_FALSE, NULL);
|
||||
|
||||
payload_size =
|
||||
DRR_SPILL_PAYLOAD_SIZE(&drr->drr_u.drr_spill);
|
||||
(void) recv_read(hdl, fd, buf, payload_size,
|
||||
B_FALSE, NULL);
|
||||
break;
|
||||
case DRR_WRITE_EMBEDDED:
|
||||
if (byteswap) {
|
||||
|
@ -4841,6 +4853,21 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
|
|||
}
|
||||
|
||||
if (flags->dryrun) {
|
||||
void *buf = zfs_alloc(hdl, SPA_MAXBLOCKSIZE);
|
||||
|
||||
/*
|
||||
* We have read the DRR_BEGIN record, but we have
|
||||
* not yet read the payload. For non-dryrun sends
|
||||
* this will be done by the kernel, so we must
|
||||
* emulate that here, before attempting to read
|
||||
* more records.
|
||||
*/
|
||||
err = recv_read(hdl, infd, buf, drr->drr_payloadlen,
|
||||
flags->byteswap, NULL);
|
||||
free(buf);
|
||||
if (err != 0)
|
||||
goto out;
|
||||
|
||||
err = recv_skip(hdl, infd, flags->byteswap);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
# 9. Verify the key is unavailable
|
||||
# 10. Attempt to load the key and mount the dataset
|
||||
# 11. Verify the checksum of the file is the same as the original
|
||||
# 12. Verify 'zfs receive -n' works with the raw stream
|
||||
#
|
||||
|
||||
verify_runnable "both"
|
||||
|
@ -88,4 +89,6 @@ typeset cksum2=$(md5digest /$TESTPOOL/$TESTFS1/c1/$TESTFILE0)
|
|||
[[ "$cksum2" == "$checksum" ]] || \
|
||||
log_fail "Checksums differ ($cksum2 != $checksum)"
|
||||
|
||||
log_must eval "zfs send -w $snap | zfs receive -n $TESTPOOL/$TESTFS3"
|
||||
|
||||
log_pass "ZFS can receive streams from raw sends"
|
||||
|
|
Loading…
Reference in New Issue