diff options
author | Jitendra Patidar <[email protected]> | 2022-09-28 05:04:27 +0530 |
---|---|---|
committer | GitHub <[email protected]> | 2022-09-27 16:34:27 -0700 |
commit | 3ed9d6883bcf3c55f92cdaaa6bf1aee2e6fb4115 (patch) | |
tree | d0b40df5a492cf0801a2c79ea8769b9e66664c11 /lib/libzfs/libzfs_sendrecv.c | |
parent | a2163a96ae8708bb083e8da7658c02a7047516ba (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.c | 40 |
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, |