aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libzfs/libzfs_sendrecv.c
diff options
context:
space:
mode:
authorJitendra Patidar <[email protected]>2022-09-28 05:04:27 +0530
committerGitHub <[email protected]>2022-09-27 16:34:27 -0700
commit3ed9d6883bcf3c55f92cdaaa6bf1aee2e6fb4115 (patch)
treed0b40df5a492cf0801a2c79ea8769b9e66664c11 /lib/libzfs/libzfs_sendrecv.c
parenta2163a96ae8708bb083e8da7658c02a7047516ba (diff)
Enforce "-F" flag on resuming recv of full/newfs on existing dataset
When receiving full/newfs on existing dataset, then it should be done with "-F" flag. Its enforced for initial receive in checks done in zfs_receive_one function of libzfs. Similarly, on resuming full/newfs recv on existing dataset, it should be done with "-F" flag. When dataset doesn't exist, then full/new recv is done on newly created dataset and it's marked INCONSISTENT. But when receiving on existing dataset, recv is first done on %recv and its marked INCONSISTENT. Existing dataset is not marked INCONSISTENT. Resume of full/newfs receive with dataset not INCONSISTENT indicates that its resuming newfs on existing dataset. So, enforce "-F" flag in this case. Also return an error from dmu_recv_resume_begin_check() in zfs kernel, when its resuming full/newfs recv without force. Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Chunwei Chen <[email protected]> Signed-off-by: Jitendra Patidar <[email protected]> Closes #13856 Closes #13857
Diffstat (limited to 'lib/libzfs/libzfs_sendrecv.c')
-rw-r--r--lib/libzfs/libzfs_sendrecv.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c
index 577ebf6aa..9d514a37e 100644
--- a/lib/libzfs/libzfs_sendrecv.c
+++ b/lib/libzfs/libzfs_sendrecv.c
@@ -4638,6 +4638,33 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
goto out;
}
+ /*
+ * When receiving full/newfs on existing dataset, then it
+ * should be done with "-F" flag. Its enforced for initial
+ * receive in previous checks in this function.
+ * Similarly, on resuming full/newfs recv on existing dataset,
+ * it should be done with "-F" flag.
+ *
+ * When dataset doesn't exist, then full/newfs recv is done on
+ * newly created dataset and it's marked INCONSISTENT. But
+ * When receiving on existing dataset, recv is first done on
+ * %recv and its marked INCONSISTENT. Existing dataset is not
+ * marked INCONSISTENT.
+ * Resume of full/newfs receive with dataset not INCONSISTENT
+ * indicates that its resuming newfs on existing dataset. So,
+ * enforce "-F" flag in this case.
+ */
+ if (stream_resumingnewfs &&
+ !zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
+ !flags->force) {
+ zfs_close(zhp);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "Resuming recv on existing destination '%s'\n"
+ "must specify -F to overwrite it"), name);
+ err = zfs_error(hdl, EZFS_RESUME_EXISTS, errbuf);
+ goto out;
+ }
+
if (stream_wantsnewfs &&
zhp->zfs_dmustats.dds_origin[0]) {
zfs_close(zhp);
@@ -5078,6 +5105,19 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
"be updated."));
(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
break;
+ case ZFS_ERR_RESUME_EXISTS:
+ cp = strchr(destsnap, '@');
+ if (newfs) {
+ /* it's the containing fs that exists */
+ *cp = '\0';
+ }
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "Resuming recv on existing dataset without force"));
+ (void) zfs_error_fmt(hdl, EZFS_RESUME_EXISTS,
+ dgettext(TEXT_DOMAIN, "cannot resume recv %s"),
+ destsnap);
+ *cp = '@';
+ break;
case EBUSY:
if (hastoken) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,