ZFS: 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.

This was also committed to ZoL:
zfsonlinux/zfs@ebeb6f23bf

MFC after:	2 weeks
Sponsored by:	CyberSecure
This commit is contained in:
avg 2019-09-04 07:33:22 +00:00
parent 9502e5bae2
commit a3dbacfc31
2 changed files with 19 additions and 8 deletions

View File

@ -3278,11 +3278,18 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
}
} else {
/*
* if the fs does not exist, look for it based on the
* fromsnap GUID
* If the fs does not exist, look for it based on the
* fromsnap GUID.
*/
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot receive incremental stream"));
if (resuming) {
(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(zc.zc_name, zc.zc_value);
*strchr(zc.zc_name, '@') = '\0';

View File

@ -1311,19 +1311,23 @@ recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
int error;
dsl_pool_t *dp = ds->ds_dir->dd_pool;
/* temporary clone name must not exist */
/* Temporary clone name must not exist. */
error = zap_lookup(dp->dp_meta_objset,
dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, recv_clone_name,
8, 1, &val);
if (error != ENOENT)
return (error == 0 ? 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,
dsl_dataset_phys(ds)->ds_snapnames_zapobj,
drba->drba_cookie->drc_tosnap, 8, 1, &val);
if (error != ENOENT)
return (error == 0 ? EEXIST : error);
return (error == 0 ? SET_ERROR(EEXIST) : error);
/*
* Check snapshot limit before receiving. We'll recheck again at the