]> granicus.if.org Git - zfs/commitdiff
Always refuse receving non-resume stream when resume state exists
authorAndriy Gapon <avg@FreeBSD.org>
Tue, 3 Sep 2019 17:56:55 +0000 (20:56 +0300)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 3 Sep 2019 17:56:55 +0000 (10:56 -0700)
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

lib/libzfs/libzfs_sendrecv.c
module/zfs/dmu_recv.c

index c178296f654f632c6ccaaa4484530acc073b9dbc..e63404b8ad3ef7d4f6e85bf4b9327bebc617b023 100644 (file)
@@ -4598,11 +4598,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(name, destsnap);
                *strchr(name, '@') = '\0';
index fe401ec2ee742fdce0dae6396a1a6a2f3d9511f8..49b8c0acf7103c0b375ba8af1ab7cec209b7937c 100644 (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 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,
            dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, recv_clone_name,
            8, 1, &val);
        if (error != ENOENT)
                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 ? 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,
            dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, &children);
        if (error != 0)