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 <behlendorf1@llnl.gov>
Reviewed-by: Chunwei Chen <david.chen@nutanix.com>
Signed-off-by: Jitendra Patidar <jitendra.patidar@nutanix.com>
Closes #13856
Closes #13857
This commit is contained in:
Jitendra Patidar
2022-09-28 05:04:27 +05:30
committed by GitHub
parent a2163a96ae
commit 3ed9d6883b
9 changed files with 127 additions and 3 deletions
+40
View File
@@ -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,
+3
View File
@@ -304,6 +304,9 @@ libzfs_error_description(libzfs_handle_t *hdl)
case EZFS_NOT_USER_NAMESPACE:
return (dgettext(TEXT_DOMAIN, "the provided file "
"was not a user namespace file"));
case EZFS_RESUME_EXISTS:
return (dgettext(TEXT_DOMAIN, "Resuming recv on existing "
"dataset without force"));
case EZFS_UNKNOWN:
return (dgettext(TEXT_DOMAIN, "unknown error"));
default: