mirror of
				https://git.proxmox.com/git/mirror_zfs.git
				synced 2025-10-26 18:05:04 +03:00 
			
		
		
		
	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
							
								
									cea50025fd
								
							
						
					
					
						commit
						ffe29e7e3d
					
				@ -3438,10 +3438,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;
 | 
			
		||||
@ -3468,9 +3469,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;
 | 
			
		||||
 | 
			
		||||
@ -3483,7 +3489,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);
 | 
			
		||||
@ -3492,9 +3498,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) {
 | 
			
		||||
@ -4232,6 +4244,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
	
	Block a user