summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/pyzfs/libzfs_core/_constants.py1
-rw-r--r--contrib/pyzfs/libzfs_core/_error_translation.py2
-rw-r--r--contrib/pyzfs/libzfs_core/exceptions.py8
-rw-r--r--contrib/pyzfs/libzfs_core/test/test_libzfs_core.py4
-rw-r--r--include/sys/fs/zfs.h1
-rw-r--r--lib/libzfs/libzfs_sendrecv.c10
-rw-r--r--module/zfs/dmu_recv.c7
-rw-r--r--tests/zfs-tests/cmd/libzfs_input_check/libzfs_input_check.c2
8 files changed, 24 insertions, 11 deletions
diff --git a/contrib/pyzfs/libzfs_core/_constants.py b/contrib/pyzfs/libzfs_core/_constants.py
index e1364aa33..5c285164b 100644
--- a/contrib/pyzfs/libzfs_core/_constants.py
+++ b/contrib/pyzfs/libzfs_core/_constants.py
@@ -94,6 +94,7 @@ zfs_errno = enum_with_offset(1024, [
'ZFS_ERR_UNKNOWN_SEND_STREAM_FEATURE',
'ZFS_ERR_EXPORT_IN_PROGRESS',
'ZFS_ERR_BOOKMARK_SOURCE_NOT_ANCESTOR',
+ 'ZFS_ERR_STREAM_TRUNCATED',
],
{}
)
diff --git a/contrib/pyzfs/libzfs_core/_error_translation.py b/contrib/pyzfs/libzfs_core/_error_translation.py
index 7881715c9..5a063c714 100644
--- a/contrib/pyzfs/libzfs_core/_error_translation.py
+++ b/contrib/pyzfs/libzfs_core/_error_translation.py
@@ -469,6 +469,8 @@ def lzc_receive_translate_errors(
raise lzc_exc.BadStream()
if ret == ZFS_ERR_WRONG_PARENT:
raise lzc_exc.WrongParent(_fs_name(snapname))
+ if ret == zfs_errno.ZFS_ERR_STREAM_TRUNCATED:
+ raise lzc_exc.StreamTruncated()
raise lzc_exc.StreamIOError(ret)
diff --git a/contrib/pyzfs/libzfs_core/exceptions.py b/contrib/pyzfs/libzfs_core/exceptions.py
index 9eeab1d7c..6c571b7e2 100644
--- a/contrib/pyzfs/libzfs_core/exceptions.py
+++ b/contrib/pyzfs/libzfs_core/exceptions.py
@@ -29,7 +29,8 @@ from ._constants import (
ZFS_ERR_NO_CHECKPOINT,
ZFS_ERR_DEVRM_IN_PROGRESS,
ZFS_ERR_VDEV_TOO_BIG,
- ZFS_ERR_WRONG_PARENT
+ ZFS_ERR_WRONG_PARENT,
+ zfs_errno
)
@@ -351,6 +352,11 @@ class StreamFeatureIncompatible(ZFSError):
message = "Incompatible embedded feature with encrypted receive"
+class StreamTruncated(ZFSError):
+ errno = zfs_errno.ZFS_ERR_STREAM_TRUNCATED
+ message = "incomplete stream"
+
+
class ReceivePropertyFailure(MultipleOperationsFailure):
message = "Receiving of properties failed for one or more reasons"
diff --git a/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py b/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py
index f47583b83..a841f96af 100644
--- a/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py
+++ b/contrib/pyzfs/libzfs_core/test/test_libzfs_core.py
@@ -2714,7 +2714,7 @@ class ZFSTest(unittest.TestCase):
lzc.lzc_send(src, None, stream.fileno())
stream.seek(0)
stream.truncate(1024 * 3)
- with self.assertRaises(lzc_exc.BadStream):
+ with self.assertRaises(lzc_exc.StreamTruncated):
lzc.lzc_receive_resumable(dst, stream.fileno())
# Resume token code from zfs_send_resume_token_to_nvlist()
# XXX: if used more than twice move this code into an external func
@@ -2771,7 +2771,7 @@ class ZFSTest(unittest.TestCase):
lzc.lzc_send(snap2, snap1, stream.fileno())
stream.seek(0)
stream.truncate(1024 * 3)
- with self.assertRaises(lzc_exc.BadStream):
+ with self.assertRaises(lzc_exc.StreamTruncated):
lzc.lzc_receive_resumable(dst2, stream.fileno())
# Resume token code from zfs_send_resume_token_to_nvlist()
# format: <version>-<cksum>-<packed-size>-<compressed-payload>
diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h
index 2c7fd8162..3484b13e3 100644
--- a/include/sys/fs/zfs.h
+++ b/include/sys/fs/zfs.h
@@ -1330,6 +1330,7 @@ typedef enum {
ZFS_ERR_UNKNOWN_SEND_STREAM_FEATURE,
ZFS_ERR_EXPORT_IN_PROGRESS,
ZFS_ERR_BOOKMARK_SOURCE_NOT_ANCESTOR,
+ ZFS_ERR_STREAM_TRUNCATED,
} zfs_errno_t;
/*
diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c
index 39bad750a..457154171 100644
--- a/lib/libzfs/libzfs_sendrecv.c
+++ b/lib/libzfs/libzfs_sendrecv.c
@@ -4253,12 +4253,12 @@ recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
static void
recv_ecksum_set_aux(libzfs_handle_t *hdl, const char *target_snap,
- boolean_t resumable)
+ boolean_t resumable, boolean_t checksum)
{
char target_fs[ZFS_MAX_DATASET_NAME_LEN];
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "checksum mismatch or incomplete stream"));
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, (checksum ?
+ "checksum mismatch" : "incomplete stream")));
if (!resumable)
return;
@@ -5206,7 +5206,9 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
break;
case ECKSUM:
- recv_ecksum_set_aux(hdl, destsnap, flags->resumable);
+ case ZFS_ERR_STREAM_TRUNCATED:
+ recv_ecksum_set_aux(hdl, destsnap, flags->resumable,
+ ioctl_err == ECKSUM);
(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
break;
case ENOTSUP:
diff --git a/module/zfs/dmu_recv.c b/module/zfs/dmu_recv.c
index 62881753f..9c82cecc6 100644
--- a/module/zfs/dmu_recv.c
+++ b/module/zfs/dmu_recv.c
@@ -1265,10 +1265,11 @@ receive_read(dmu_recv_cookie_t *drc, int len, void *buf)
len - done, &resid);
if (resid == len - done) {
/*
- * Note: ECKSUM indicates that the receive
- * was interrupted and can potentially be resumed.
+ * Note: ECKSUM or ZFS_ERR_STREAM_TRUNCATED indicates
+ * that the receive was interrupted and can
+ * potentially be resumed.
*/
- drc->drc_err = SET_ERROR(ECKSUM);
+ drc->drc_err = SET_ERROR(ZFS_ERR_STREAM_TRUNCATED);
}
drc->drc_voff += len - done - resid;
done = len - resid;
diff --git a/tests/zfs-tests/cmd/libzfs_input_check/libzfs_input_check.c b/tests/zfs-tests/cmd/libzfs_input_check/libzfs_input_check.c
index f0c548ee4..cb73df59b 100644
--- a/tests/zfs-tests/cmd/libzfs_input_check/libzfs_input_check.c
+++ b/tests/zfs-tests/cmd/libzfs_input_check/libzfs_input_check.c
@@ -556,7 +556,7 @@ test_recv_new(const char *dataset, int fd)
fnvlist_add_boolean(optional, "resumable");
fnvlist_add_uint64(optional, "action_handle", *action_handle);
#endif
- IOC_INPUT_TEST(ZFS_IOC_RECV_NEW, dataset, required, optional, ECKSUM);
+ IOC_INPUT_TEST(ZFS_IOC_RECV_NEW, dataset, required, optional, ZFS_ERR_STREAM_TRUNCATED);
nvlist_free(props);
nvlist_free(optional);