]> granicus.if.org Git - zfs/commitdiff
'zfs receive' fails with "dataset is busy"
authorLOLi <loli10K@users.noreply.github.com>
Mon, 12 Feb 2018 20:28:59 +0000 (21:28 +0100)
committerTony Hutter <hutter2@llnl.gov>
Wed, 14 Mar 2018 23:10:37 +0000 (16:10 -0700)
Receiving an incremental stream after an interrupted "zfs receive -s"
fails with the message "dataset is busy": this is because we still have
the hidden clone ../%recv from the resumable receive.

Improve the error message suggesting the existence of a partially
complete resumable stream from "zfs receive -s" which can be either
aborted ("zfs receive -A") or resumed ("zfs send -t").

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Signed-off-by: loli10K <ezomori.nozomu@gmail.com>
Closes #7129
Closes #7154

cmd/zfs/zfs_main.c
lib/libzfs/libzfs_sendrecv.c

index e8fe6a9fa9bfb60c66a4f956c82b5643f53d1c4c..f57df8581f3c13ec07f15fa2894e7d9d0136f3f6 100644 (file)
@@ -6072,7 +6072,7 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
 
                (void) fprintf(stderr, gettext("cannot %s '%s': "
                    "Contains partially-completed state from "
-                   "\"zfs receive -r\", which can be resumed with "
+                   "\"zfs receive -s\", which can be resumed with "
                    "\"zfs send -t\"\n"),
                    cmdname, zfs_get_name(zhp));
                return (1);
index ec190022f0af73d25818d45b1adde5d7589900c9..66d89067bcee984207a0db215799f59958e49142 100644 (file)
@@ -3254,6 +3254,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
        zfs_type_t type;
        boolean_t toplevel = B_FALSE;
        boolean_t zoned = B_FALSE;
+       boolean_t hastoken = B_FALSE;
 
        begin_time = time(NULL);
        bzero(origin, MAXNAMELEN);
@@ -3535,6 +3536,11 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
                /* we want to know if we're zoned when validating -o|-x props */
                zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
 
+               /* may need this info later, get it now we have zhp around */
+               if (zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN, NULL, 0,
+                   NULL, NULL, 0, B_TRUE) == 0)
+                       hastoken = B_TRUE;
+
                /* gather existing properties on destination */
                origprops = fnvlist_alloc();
                fnvlist_merge(origprops, zhp->zfs_props);
@@ -3741,9 +3747,19 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
                        break;
                case EDQUOT:
                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-                           "destination %s space quota exceeded"), name);
+                           "destination %s space quota exceeded."), name);
                        (void) zfs_error(hdl, EZFS_NOSPC, errbuf);
                        break;
+               case EBUSY:
+                       if (hastoken) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "destination %s contains "
+                                   "partially-complete state from "
+                                   "\"zfs receive -s\"."), name);
+                               (void) zfs_error(hdl, EZFS_BUSY, errbuf);
+                               break;
+                       }
+                       /* fallthru */
                default:
                        (void) zfs_standard_error(hdl, ioctl_errno, errbuf);
                }