Always refuse receving non-resume stream when resume state exists

This fixes a hole in the situation where the resume state is left from
receiving a new dataset and, so, the state is set on the dataset itself
(as opposed to %recv child).

Additionally, distinguish incremental and resume streams in error
messages.

Reviewed-by: Matt Ahrens <matt@delphix.com>
Reviewed-by: Tom Caputi <tcaputi@datto.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Andriy Gapon <avg@FreeBSD.org>
Closes #9252
This commit is contained in:
Andriy Gapon 2019-09-03 20:56:55 +03:00 committed by Brian Behlendorf
parent 1a504d27df
commit ebeb6f23bf
2 changed files with 18 additions and 7 deletions

View File

@ -4598,11 +4598,18 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
} }
} else { } else {
/* /*
* if the fs does not exist, look for it based on the * If the fs does not exist, look for it based on the
* fromsnap GUID * fromsnap GUID.
*/ */
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, if (resuming) {
"cannot receive incremental stream")); (void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN,
"cannot receive resume stream"));
} else {
(void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN,
"cannot receive incremental stream"));
}
(void) strcpy(name, destsnap); (void) strcpy(name, destsnap);
*strchr(name, '@') = '\0'; *strchr(name, '@') = '\0';

View File

@ -350,21 +350,25 @@ recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
boolean_t raw = (featureflags & DMU_BACKUP_FEATURE_RAW) != 0; boolean_t raw = (featureflags & DMU_BACKUP_FEATURE_RAW) != 0;
boolean_t embed = (featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) != 0; boolean_t embed = (featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) != 0;
/* temporary clone name must not exist */ /* Temporary clone name must not exist. */
error = zap_lookup(dp->dp_meta_objset, error = zap_lookup(dp->dp_meta_objset,
dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, recv_clone_name, dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, recv_clone_name,
8, 1, &val); 8, 1, &val);
if (error != ENOENT) if (error != ENOENT)
return (error == 0 ? SET_ERROR(EBUSY) : error); return (error == 0 ? SET_ERROR(EBUSY) : error);
/* new snapshot name must not exist */ /* Resume state must not be set. */
if (dsl_dataset_has_resume_receive_state(ds))
return (SET_ERROR(EBUSY));
/* New snapshot name must not exist. */
error = zap_lookup(dp->dp_meta_objset, error = zap_lookup(dp->dp_meta_objset,
dsl_dataset_phys(ds)->ds_snapnames_zapobj, dsl_dataset_phys(ds)->ds_snapnames_zapobj,
drba->drba_cookie->drc_tosnap, 8, 1, &val); drba->drba_cookie->drc_tosnap, 8, 1, &val);
if (error != ENOENT) if (error != ENOENT)
return (error == 0 ? SET_ERROR(EEXIST) : error); return (error == 0 ? SET_ERROR(EEXIST) : error);
/* must not have children if receiving a ZVOL */ /* Must not have children if receiving a ZVOL. */
error = zap_count(dp->dp_meta_objset, error = zap_count(dp->dp_meta_objset,
dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, &children); dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, &children);
if (error != 0) if (error != 0)