From b0f716a2d7f74dbc6941e9c46376f33b9ca4ff99 Mon Sep 17 00:00:00 2001 From: Jorgen Lundman Date: Thu, 27 Jun 2024 12:29:53 +0900 Subject: [PATCH] Handle short-reads in pipe recv Turns out that pipes can return short reads, especially when used with MSYS/cygwin shells. Loop until the desired amount is reached. dmu recv requires the correct amount to be read. This helps zfs recv Signed-off-by: Jorgen Lundman --- module/os/windows/zfs/zfs_file_os.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/module/os/windows/zfs/zfs_file_os.c b/module/os/windows/zfs/zfs_file_os.c index d2ee44776f32..296ca24ee1a7 100644 --- a/module/os/windows/zfs/zfs_file_os.c +++ b/module/os/windows/zfs/zfs_file_os.c @@ -203,10 +203,28 @@ zfs_file_read(zfs_file_t *fp, void *buf, size_t count, ssize_t *resid) { NTSTATUS ntstatus; IO_STATUS_BLOCK ioStatusBlock; - ntstatus = ZwReadFile(fp->f_handle, NULL, NULL, NULL, - &ioStatusBlock, buf, count, NULL, NULL); - if (STATUS_SUCCESS != ntstatus) - return (EIO); + size_t bytesRead = 0; + + while (bytesRead < count) { + ULONG remainingLength = count - bytesRead; + + /* So we can get short-reads from pipes under MSYS2 */ + ntstatus = ZwReadFile(fp->f_handle, NULL, NULL, NULL, + &ioStatusBlock, (PUCHAR)buf + bytesRead, remainingLength, + NULL, NULL); + if (STATUS_SUCCESS != ntstatus) + return (EIO); + + // No more data to read, break the loop + if (ioStatusBlock.Information == 0) + break; + + bytesRead += (ULONG)ioStatusBlock.Information; + } + + // Double check for short reads + VERIFY3U(count, ==, bytesRead); + if (resid) *resid = 0; return (0);