aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libzfs/libzfs_sendrecv.c39
-rwxr-xr-xtests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw.ksh3
2 files changed, 36 insertions, 6 deletions
diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c
index e63404b8a..33d3eb6a5 100644
--- a/lib/libzfs/libzfs_sendrecv.c
+++ b/lib/libzfs/libzfs_sendrecv.c
@@ -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;
}
diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw.ksh
index 7d5606ace..9740caf72 100755
--- a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw.ksh
+++ b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw.ksh
@@ -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"