Print this page
4986 receiving replication stream fails if any snapshot exceeds refquota
Reviewed by: John Kennedy <john.kennedy@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>


   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  25  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  26  * Copyright (c) 2013 Steven Hartland. All rights reserved.

  27  */
  28 
  29 #include <assert.h>
  30 #include <ctype.h>
  31 #include <errno.h>
  32 #include <libintl.h>
  33 #include <stdio.h>
  34 #include <stdlib.h>
  35 #include <strings.h>
  36 #include <unistd.h>
  37 #include <stddef.h>
  38 #include <fcntl.h>
  39 #include <sys/mount.h>
  40 #include <pthread.h>
  41 #include <umem.h>
  42 #include <time.h>
  43 
  44 #include <libzfs.h>
  45 #include <libzfs_core.h>
  46 
  47 #include "zfs_namecheck.h"
  48 #include "zfs_prop.h"
  49 #include "zfs_fletcher.h"
  50 #include "libzfs_impl.h"
  51 #include <zlib.h>
  52 #include <sha2.h>
  53 #include <sys/zio_checksum.h>
  54 #include <sys/ddt.h>
  55 
  56 /* in libzfs_dataset.c */
  57 extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
  58 
  59 static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
  60     recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
  61     uint64_t *);
  62 static int guid_to_name(libzfs_handle_t *, const char *,
  63     uint64_t, boolean_t, char *);
  64 
  65 static const zio_cksum_t zero_cksum = { 0 };
  66 
  67 typedef struct dedup_arg {
  68         int     inputfd;
  69         int     outputfd;
  70         libzfs_handle_t  *dedup_hdl;
  71 } dedup_arg_t;
  72 
  73 typedef struct progress_arg {
  74         zfs_handle_t *pa_zhp;
  75         int pa_fd;
  76         boolean_t pa_parsable;
  77 } progress_arg_t;
  78 
  79 typedef struct dataref {
  80         uint64_t ref_guid;
  81         uint64_t ref_object;


2544         nvlist_free(local_nv);
2545 
2546         if (needagain && progress) {
2547                 /* do another pass to fix up temporary names */
2548                 if (flags->verbose)
2549                         (void) printf("another pass:\n");
2550                 goto again;
2551         }
2552 
2553         return (needagain);
2554 }
2555 
2556 static int
2557 zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
2558     recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
2559     char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
2560 {
2561         nvlist_t *stream_nv = NULL;
2562         avl_tree_t *stream_avl = NULL;
2563         char *fromsnap = NULL;

2564         char *cp;
2565         char tofs[ZFS_MAXNAMELEN];
2566         char sendfs[ZFS_MAXNAMELEN];
2567         char errbuf[1024];
2568         dmu_replay_record_t drre;
2569         int error;
2570         boolean_t anyerr = B_FALSE;
2571         boolean_t softerr = B_FALSE;
2572         boolean_t recursive;
2573 
2574         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2575             "cannot receive"));
2576 
2577         assert(drr->drr_type == DRR_BEGIN);
2578         assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC);
2579         assert(DMU_GET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo) ==
2580             DMU_COMPOUNDSTREAM);
2581 
2582         /*
2583          * Read in the nvlist from the stream.


2692                                         zfs_close(zhp);
2693                                         if (clp != NULL) {
2694                                                 softerr |=
2695                                                     changelist_prefix(clp);
2696                                                 changelist_free(clp);
2697                                         }
2698                                 }
2699                         }
2700 
2701                         nvlist_free(renamed);
2702                 }
2703         }
2704 
2705         /*
2706          * Get the fs specified by the first path in the stream (the top level
2707          * specified by 'zfs send') and pass it to each invocation of
2708          * zfs_receive_one().
2709          */
2710         (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
2711             ZFS_MAXNAMELEN);
2712         if ((cp = strchr(sendfs, '@')) != NULL)
2713                 *cp = '\0';








2714 
2715         /* Finally, receive each contained stream */
2716         do {
2717                 /*
2718                  * we should figure out if it has a recoverable
2719                  * error, in which case do a recv_skip() and drive on.
2720                  * Note, if we fail due to already having this guid,
2721                  * zfs_receive_one() will take care of it (ie,
2722                  * recv_skip() and return 0).
2723                  */
2724                 error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
2725                     sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
2726                     action_handlep);
2727                 if (error == ENODATA) {
2728                         error = 0;
2729                         break;
2730                 }
2731                 anyerr |= error;
2732         } while (error == 0);
2733 
2734         if (drr->drr_payloadlen != 0 && fromsnap != NULL) {
2735                 /*
2736                  * Now that we have the fs's they sent us, try the
2737                  * renames again.
2738                  */
2739                 softerr = recv_incremental_replication(hdl, tofs, flags,
2740                     stream_nv, stream_avl, NULL);
2741         }
2742 
2743 out:
2744         fsavl_destroy(stream_avl);
2745         if (stream_nv)
2746                 nvlist_free(stream_nv);


2872         if (error == 0) {
2873                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2874                     "checksum mismatch or incomplete stream.\n"
2875                     "Partially received snapshot is saved.\n"
2876                     "A resuming stream can be generated on the sending "
2877                     "system by running:\n"
2878                     "    zfs send -t %s"),
2879                     token_buf);
2880         }
2881         zfs_close(zhp);
2882 }
2883 
2884 /*
2885  * Restores a backup of tosnap from the file descriptor specified by infd.
2886  */
2887 static int
2888 zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
2889     const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
2890     dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,
2891     avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
2892     uint64_t *action_handlep)
2893 {
2894         zfs_cmd_t zc = { 0 };
2895         time_t begin_time;
2896         int ioctl_err, ioctl_errno, err;
2897         char *cp;
2898         struct drr_begin *drrb = &drr->drr_u.drr_begin;
2899         char errbuf[1024];
2900         char prop_errbuf[1024];
2901         const char *chopprefix;
2902         boolean_t newfs = B_FALSE;
2903         boolean_t stream_wantsnewfs;
2904         uint64_t parent_snapguid = 0;
2905         prop_changelist_t *clp = NULL;
2906         nvlist_t *snapprops_nvlist = NULL;
2907         zprop_errflags_t prop_errflags;
2908         boolean_t recursive;

2909 
2910         begin_time = time(NULL);
2911 
2912         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2913             "cannot receive"));
2914 
2915         recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
2916             ENOENT);
2917 
2918         if (stream_avl != NULL) {
2919                 char *snapname;
2920                 nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
2921                     &snapname);
2922                 nvlist_t *props;
2923                 int ret;
2924 
2925                 (void) nvlist_lookup_uint64(fs, "parentfromsnap",
2926                     &parent_snapguid);
2927                 err = nvlist_lookup_nvlist(fs, "props", &props);
2928                 if (err)
2929                         VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
2930 
2931                 if (flags->canmountoff) {
2932                         VERIFY(0 == nvlist_add_uint64(props,
2933                             zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
2934                 }
2935                 ret = zcmd_write_src_nvlist(hdl, &zc, props);
2936                 if (err)
2937                         nvlist_free(props);
2938 
2939                 if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {


3246 
3247         if (err == 0) {
3248                 nvlist_t *prop_errors;
3249                 VERIFY(0 == nvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
3250                     zc.zc_nvlist_dst_size, &prop_errors, 0));
3251 
3252                 nvpair_t *prop_err = NULL;
3253 
3254                 while ((prop_err = nvlist_next_nvpair(prop_errors,
3255                     prop_err)) != NULL) {
3256                         char tbuf[1024];
3257                         zfs_prop_t prop;
3258                         int intval;
3259 
3260                         prop = zfs_name_to_prop(nvpair_name(prop_err));
3261                         (void) nvpair_value_int32(prop_err, &intval);
3262                         if (strcmp(nvpair_name(prop_err),
3263                             ZPROP_N_MORE_ERRORS) == 0) {
3264                                 trunc_prop_errs(intval);
3265                                 break;
3266                         } else {














3267                                 (void) snprintf(tbuf, sizeof (tbuf),
3268                                     dgettext(TEXT_DOMAIN,
3269                                     "cannot receive %s property on %s"),
3270                                     nvpair_name(prop_err), zc.zc_name);
3271                                 zfs_setprop_error(hdl, prop, intval, tbuf);
3272                         }
3273                 }
3274                 nvlist_free(prop_errors);
3275         }
3276 
3277         zc.zc_nvlist_dst = 0;
3278         zc.zc_nvlist_dst_size = 0;
3279         zcmd_free_nvlists(&zc);
3280 
3281         if (err == 0 && snapprops_nvlist) {
3282                 zfs_cmd_t zc2 = { 0 };
3283 
3284                 (void) strcpy(zc2.zc_name, zc.zc_value);
3285                 zc2.zc_cookie = B_TRUE; /* received */
3286                 if (zcmd_write_src_nvlist(hdl, &zc2, snapprops_nvlist) == 0) {


3431                 char buf1[64];
3432                 char buf2[64];
3433                 uint64_t bytes = zc.zc_cookie;
3434                 time_t delta = time(NULL) - begin_time;
3435                 if (delta == 0)
3436                         delta = 1;
3437                 zfs_nicenum(bytes, buf1, sizeof (buf1));
3438                 zfs_nicenum(bytes/delta, buf2, sizeof (buf1));
3439 
3440                 (void) printf("received %sB stream in %lu seconds (%sB/sec)\n",
3441                     buf1, delta, buf2);
3442         }
3443 
3444         return (0);
3445 }
3446 
3447 static int
3448 zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
3449     const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
3450     nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
3451     uint64_t *action_handlep)
3452 {
3453         int err;
3454         dmu_replay_record_t drr, drr_noswap;
3455         struct drr_begin *drrb = &drr.drr_u.drr_begin;
3456         char errbuf[1024];
3457         zio_cksum_t zcksum = { 0 };
3458         uint64_t featureflags;
3459         int hdrtype;
3460 
3461         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3462             "cannot receive"));
3463 
3464         if (flags->isprefix &&
3465             !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
3466                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
3467                     "(%s) does not exist"), tosnap);
3468                 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3469         }
3470         if (originsnap &&
3471             !zfs_dataset_exists(hdl, originsnap, ZFS_TYPE_DATASET)) {


3527 
3528         if (strchr(drrb->drr_toname, '@') == NULL) {
3529                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
3530                     "stream (bad snapshot name)"));
3531                 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
3532         }
3533 
3534         if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {
3535                 char nonpackage_sendfs[ZFS_MAXNAMELEN];
3536                 if (sendfs == NULL) {
3537                         /*
3538                          * We were not called from zfs_receive_package(). Get
3539                          * the fs specified by 'zfs send'.
3540                          */
3541                         char *cp;
3542                         (void) strlcpy(nonpackage_sendfs,
3543                             drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
3544                         if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
3545                                 *cp = '\0';
3546                         sendfs = nonpackage_sendfs;

3547                 }
3548                 return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
3549                     &drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,
3550                     cleanup_fd, action_handlep));
3551         } else {
3552                 assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
3553                     DMU_COMPOUNDSTREAM);
3554                 return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
3555                     &zcksum, top_zfs, cleanup_fd, action_handlep));
3556         }
3557 }
3558 
3559 /*
3560  * Restores a backup of tosnap from the file descriptor specified by infd.
3561  * Return 0 on total success, -2 if some things couldn't be
3562  * destroyed/renamed/promoted, -1 if some things couldn't be received.
3563  * (-1 will override -2, if -1 and the resumable flag was specified the
3564  * transfer can be resumed if the sending side supports it).
3565  */
3566 int
3567 zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
3568     recvflags_t *flags, int infd, avl_tree_t *stream_avl)
3569 {
3570         char *top_zfs = NULL;
3571         int err;
3572         int cleanup_fd;
3573         uint64_t action_handle = 0;
3574         char *originsnap = NULL;
3575         if (props) {
3576                 err = nvlist_lookup_string(props, "origin", &originsnap);
3577                 if (err && err != ENOENT)
3578                         return (err);
3579         }
3580 
3581         cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
3582         VERIFY(cleanup_fd >= 0);
3583 
3584         err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
3585             stream_avl, &top_zfs, cleanup_fd, &action_handle);
3586 
3587         VERIFY(0 == close(cleanup_fd));
3588 
3589         if (err == 0 && !flags->nomount && top_zfs) {
3590                 zfs_handle_t *zhp;
3591                 prop_changelist_t *clp;
3592 
3593                 zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
3594                 if (zhp != NULL) {
3595                         clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
3596                             CL_GATHER_MOUNT_ALWAYS, 0);
3597                         zfs_close(zhp);
3598                         if (clp != NULL) {
3599                                 /* mount and share received datasets */
3600                                 err = changelist_postfix(clp);
3601                                 changelist_free(clp);
3602                         }
3603                 }
3604                 if (zhp == NULL || clp == NULL || err)
3605                         err = -1;


   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  25  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  26  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  27  * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
  28  */
  29 
  30 #include <assert.h>
  31 #include <ctype.h>
  32 #include <errno.h>
  33 #include <libintl.h>
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 #include <strings.h>
  37 #include <unistd.h>
  38 #include <stddef.h>
  39 #include <fcntl.h>
  40 #include <sys/mount.h>
  41 #include <pthread.h>
  42 #include <umem.h>
  43 #include <time.h>
  44 
  45 #include <libzfs.h>
  46 #include <libzfs_core.h>
  47 
  48 #include "zfs_namecheck.h"
  49 #include "zfs_prop.h"
  50 #include "zfs_fletcher.h"
  51 #include "libzfs_impl.h"
  52 #include <zlib.h>
  53 #include <sha2.h>
  54 #include <sys/zio_checksum.h>
  55 #include <sys/ddt.h>
  56 
  57 /* in libzfs_dataset.c */
  58 extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
  59 
  60 static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
  61     recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
  62     uint64_t *, const char *);
  63 static int guid_to_name(libzfs_handle_t *, const char *,
  64     uint64_t, boolean_t, char *);
  65 
  66 static const zio_cksum_t zero_cksum = { 0 };
  67 
  68 typedef struct dedup_arg {
  69         int     inputfd;
  70         int     outputfd;
  71         libzfs_handle_t  *dedup_hdl;
  72 } dedup_arg_t;
  73 
  74 typedef struct progress_arg {
  75         zfs_handle_t *pa_zhp;
  76         int pa_fd;
  77         boolean_t pa_parsable;
  78 } progress_arg_t;
  79 
  80 typedef struct dataref {
  81         uint64_t ref_guid;
  82         uint64_t ref_object;


2545         nvlist_free(local_nv);
2546 
2547         if (needagain && progress) {
2548                 /* do another pass to fix up temporary names */
2549                 if (flags->verbose)
2550                         (void) printf("another pass:\n");
2551                 goto again;
2552         }
2553 
2554         return (needagain);
2555 }
2556 
2557 static int
2558 zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
2559     recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
2560     char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
2561 {
2562         nvlist_t *stream_nv = NULL;
2563         avl_tree_t *stream_avl = NULL;
2564         char *fromsnap = NULL;
2565         char *sendsnap = NULL;
2566         char *cp;
2567         char tofs[ZFS_MAXNAMELEN];
2568         char sendfs[ZFS_MAXNAMELEN];
2569         char errbuf[1024];
2570         dmu_replay_record_t drre;
2571         int error;
2572         boolean_t anyerr = B_FALSE;
2573         boolean_t softerr = B_FALSE;
2574         boolean_t recursive;
2575 
2576         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2577             "cannot receive"));
2578 
2579         assert(drr->drr_type == DRR_BEGIN);
2580         assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC);
2581         assert(DMU_GET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo) ==
2582             DMU_COMPOUNDSTREAM);
2583 
2584         /*
2585          * Read in the nvlist from the stream.


2694                                         zfs_close(zhp);
2695                                         if (clp != NULL) {
2696                                                 softerr |=
2697                                                     changelist_prefix(clp);
2698                                                 changelist_free(clp);
2699                                         }
2700                                 }
2701                         }
2702 
2703                         nvlist_free(renamed);
2704                 }
2705         }
2706 
2707         /*
2708          * Get the fs specified by the first path in the stream (the top level
2709          * specified by 'zfs send') and pass it to each invocation of
2710          * zfs_receive_one().
2711          */
2712         (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
2713             ZFS_MAXNAMELEN);
2714         if ((cp = strchr(sendfs, '@')) != NULL) {
2715                 *cp = '\0';
2716                 /*
2717                  * Find the "sendsnap", the final snapshot in a replication
2718                  * stream.  zfs_receive_one() handles certain errors
2719                  * differently, depending on if the contained stream is the
2720                  * last one or not.
2721                  */
2722                 sendsnap = (cp + 1);
2723         }
2724 
2725         /* Finally, receive each contained stream */
2726         do {
2727                 /*
2728                  * we should figure out if it has a recoverable
2729                  * error, in which case do a recv_skip() and drive on.
2730                  * Note, if we fail due to already having this guid,
2731                  * zfs_receive_one() will take care of it (ie,
2732                  * recv_skip() and return 0).
2733                  */
2734                 error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
2735                     sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
2736                     action_handlep, sendsnap);
2737                 if (error == ENODATA) {
2738                         error = 0;
2739                         break;
2740                 }
2741                 anyerr |= error;
2742         } while (error == 0);
2743 
2744         if (drr->drr_payloadlen != 0 && fromsnap != NULL) {
2745                 /*
2746                  * Now that we have the fs's they sent us, try the
2747                  * renames again.
2748                  */
2749                 softerr = recv_incremental_replication(hdl, tofs, flags,
2750                     stream_nv, stream_avl, NULL);
2751         }
2752 
2753 out:
2754         fsavl_destroy(stream_avl);
2755         if (stream_nv)
2756                 nvlist_free(stream_nv);


2882         if (error == 0) {
2883                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2884                     "checksum mismatch or incomplete stream.\n"
2885                     "Partially received snapshot is saved.\n"
2886                     "A resuming stream can be generated on the sending "
2887                     "system by running:\n"
2888                     "    zfs send -t %s"),
2889                     token_buf);
2890         }
2891         zfs_close(zhp);
2892 }
2893 
2894 /*
2895  * Restores a backup of tosnap from the file descriptor specified by infd.
2896  */
2897 static int
2898 zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
2899     const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
2900     dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,
2901     avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
2902     uint64_t *action_handlep, const char *finalsnap)
2903 {
2904         zfs_cmd_t zc = { 0 };
2905         time_t begin_time;
2906         int ioctl_err, ioctl_errno, err;
2907         char *cp;
2908         struct drr_begin *drrb = &drr->drr_u.drr_begin;
2909         char errbuf[1024];
2910         char prop_errbuf[1024];
2911         const char *chopprefix;
2912         boolean_t newfs = B_FALSE;
2913         boolean_t stream_wantsnewfs;
2914         uint64_t parent_snapguid = 0;
2915         prop_changelist_t *clp = NULL;
2916         nvlist_t *snapprops_nvlist = NULL;
2917         zprop_errflags_t prop_errflags;
2918         boolean_t recursive;
2919         char *snapname = NULL;
2920 
2921         begin_time = time(NULL);
2922 
2923         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2924             "cannot receive"));
2925 
2926         recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
2927             ENOENT);
2928 
2929         if (stream_avl != NULL) {

2930                 nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
2931                     &snapname);
2932                 nvlist_t *props;
2933                 int ret;
2934 
2935                 (void) nvlist_lookup_uint64(fs, "parentfromsnap",
2936                     &parent_snapguid);
2937                 err = nvlist_lookup_nvlist(fs, "props", &props);
2938                 if (err)
2939                         VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
2940 
2941                 if (flags->canmountoff) {
2942                         VERIFY(0 == nvlist_add_uint64(props,
2943                             zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
2944                 }
2945                 ret = zcmd_write_src_nvlist(hdl, &zc, props);
2946                 if (err)
2947                         nvlist_free(props);
2948 
2949                 if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {


3256 
3257         if (err == 0) {
3258                 nvlist_t *prop_errors;
3259                 VERIFY(0 == nvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
3260                     zc.zc_nvlist_dst_size, &prop_errors, 0));
3261 
3262                 nvpair_t *prop_err = NULL;
3263 
3264                 while ((prop_err = nvlist_next_nvpair(prop_errors,
3265                     prop_err)) != NULL) {
3266                         char tbuf[1024];
3267                         zfs_prop_t prop;
3268                         int intval;
3269 
3270                         prop = zfs_name_to_prop(nvpair_name(prop_err));
3271                         (void) nvpair_value_int32(prop_err, &intval);
3272                         if (strcmp(nvpair_name(prop_err),
3273                             ZPROP_N_MORE_ERRORS) == 0) {
3274                                 trunc_prop_errs(intval);
3275                                 break;
3276                         } else if (snapname == NULL || finalsnap == NULL ||
3277                             strcmp(finalsnap, snapname) == 0 ||
3278                             strcmp(nvpair_name(prop_err),
3279                             zfs_prop_to_name(ZFS_PROP_REFQUOTA)) != 0) {
3280                                 /*
3281                                  * Skip the special case of, for example,
3282                                  * "refquota", errors on intermediate
3283                                  * snapshots leading up to a final one.
3284                                  * That's why we have all of the checks above.
3285                                  *
3286                                  * See zfs_ioctl.c's extract_delay_props() for
3287                                  * a list of props which can fail on
3288                                  * intermediate snapshots, but shouldn't
3289                                  * affect the overall receive.
3290                                  */
3291                                 (void) snprintf(tbuf, sizeof (tbuf),
3292                                     dgettext(TEXT_DOMAIN,
3293                                     "cannot receive %s property on %s"),
3294                                     nvpair_name(prop_err), zc.zc_name);
3295                                 zfs_setprop_error(hdl, prop, intval, tbuf);
3296                         }
3297                 }
3298                 nvlist_free(prop_errors);
3299         }
3300 
3301         zc.zc_nvlist_dst = 0;
3302         zc.zc_nvlist_dst_size = 0;
3303         zcmd_free_nvlists(&zc);
3304 
3305         if (err == 0 && snapprops_nvlist) {
3306                 zfs_cmd_t zc2 = { 0 };
3307 
3308                 (void) strcpy(zc2.zc_name, zc.zc_value);
3309                 zc2.zc_cookie = B_TRUE; /* received */
3310                 if (zcmd_write_src_nvlist(hdl, &zc2, snapprops_nvlist) == 0) {


3455                 char buf1[64];
3456                 char buf2[64];
3457                 uint64_t bytes = zc.zc_cookie;
3458                 time_t delta = time(NULL) - begin_time;
3459                 if (delta == 0)
3460                         delta = 1;
3461                 zfs_nicenum(bytes, buf1, sizeof (buf1));
3462                 zfs_nicenum(bytes/delta, buf2, sizeof (buf1));
3463 
3464                 (void) printf("received %sB stream in %lu seconds (%sB/sec)\n",
3465                     buf1, delta, buf2);
3466         }
3467 
3468         return (0);
3469 }
3470 
3471 static int
3472 zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
3473     const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
3474     nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
3475     uint64_t *action_handlep, const char *finalsnap)
3476 {
3477         int err;
3478         dmu_replay_record_t drr, drr_noswap;
3479         struct drr_begin *drrb = &drr.drr_u.drr_begin;
3480         char errbuf[1024];
3481         zio_cksum_t zcksum = { 0 };
3482         uint64_t featureflags;
3483         int hdrtype;
3484 
3485         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3486             "cannot receive"));
3487 
3488         if (flags->isprefix &&
3489             !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
3490                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
3491                     "(%s) does not exist"), tosnap);
3492                 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3493         }
3494         if (originsnap &&
3495             !zfs_dataset_exists(hdl, originsnap, ZFS_TYPE_DATASET)) {


3551 
3552         if (strchr(drrb->drr_toname, '@') == NULL) {
3553                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
3554                     "stream (bad snapshot name)"));
3555                 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
3556         }
3557 
3558         if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {
3559                 char nonpackage_sendfs[ZFS_MAXNAMELEN];
3560                 if (sendfs == NULL) {
3561                         /*
3562                          * We were not called from zfs_receive_package(). Get
3563                          * the fs specified by 'zfs send'.
3564                          */
3565                         char *cp;
3566                         (void) strlcpy(nonpackage_sendfs,
3567                             drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
3568                         if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
3569                                 *cp = '\0';
3570                         sendfs = nonpackage_sendfs;
3571                         VERIFY(finalsnap == NULL);
3572                 }
3573                 return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
3574                     &drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,
3575                     cleanup_fd, action_handlep, finalsnap));
3576         } else {
3577                 assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
3578                     DMU_COMPOUNDSTREAM);
3579                 return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
3580                     &zcksum, top_zfs, cleanup_fd, action_handlep));
3581         }
3582 }
3583 
3584 /*
3585  * Restores a backup of tosnap from the file descriptor specified by infd.
3586  * Return 0 on total success, -2 if some things couldn't be
3587  * destroyed/renamed/promoted, -1 if some things couldn't be received.
3588  * (-1 will override -2, if -1 and the resumable flag was specified the
3589  * transfer can be resumed if the sending side supports it).
3590  */
3591 int
3592 zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
3593     recvflags_t *flags, int infd, avl_tree_t *stream_avl)
3594 {
3595         char *top_zfs = NULL;
3596         int err;
3597         int cleanup_fd;
3598         uint64_t action_handle = 0;
3599         char *originsnap = NULL;
3600         if (props) {
3601                 err = nvlist_lookup_string(props, "origin", &originsnap);
3602                 if (err && err != ENOENT)
3603                         return (err);
3604         }
3605 
3606         cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
3607         VERIFY(cleanup_fd >= 0);
3608 
3609         err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
3610             stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL);
3611 
3612         VERIFY(0 == close(cleanup_fd));
3613 
3614         if (err == 0 && !flags->nomount && top_zfs) {
3615                 zfs_handle_t *zhp;
3616                 prop_changelist_t *clp;
3617 
3618                 zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
3619                 if (zhp != NULL) {
3620                         clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
3621                             CL_GATHER_MOUNT_ALWAYS, 0);
3622                         zfs_close(zhp);
3623                         if (clp != NULL) {
3624                                 /* mount and share received datasets */
3625                                 err = changelist_postfix(clp);
3626                                 changelist_free(clp);
3627                         }
3628                 }
3629                 if (zhp == NULL || clp == NULL || err)
3630                         err = -1;