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>
Approved by: Gordon Ross <gordon.ross@nexenta.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, 2014 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 <sha2.h>
  52 #include <sys/zio_checksum.h>
  53 #include <sys/ddt.h>
  54 
  55 /* in libzfs_dataset.c */
  56 extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
  57 
  58 static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t *,
  59     int, const char *, nvlist_t *, avl_tree_t *, char **, int, uint64_t *);

  60 
  61 static const zio_cksum_t zero_cksum = { 0 };
  62 
  63 typedef struct dedup_arg {
  64         int     inputfd;
  65         int     outputfd;
  66         libzfs_handle_t  *dedup_hdl;
  67 } dedup_arg_t;
  68 
  69 typedef struct progress_arg {
  70         zfs_handle_t *pa_zhp;
  71         int pa_fd;
  72         boolean_t pa_parsable;
  73 } progress_arg_t;
  74 
  75 typedef struct dataref {
  76         uint64_t ref_guid;
  77         uint64_t ref_object;
  78         uint64_t ref_offset;
  79 } dataref_t;


2288         nvlist_free(local_nv);
2289 
2290         if (needagain && progress) {
2291                 /* do another pass to fix up temporary names */
2292                 if (flags->verbose)
2293                         (void) printf("another pass:\n");
2294                 goto again;
2295         }
2296 
2297         return (needagain);
2298 }
2299 
2300 static int
2301 zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
2302     recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
2303     char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
2304 {
2305         nvlist_t *stream_nv = NULL;
2306         avl_tree_t *stream_avl = NULL;
2307         char *fromsnap = NULL;

2308         char *cp;
2309         char tofs[ZFS_MAXNAMELEN];
2310         char sendfs[ZFS_MAXNAMELEN];
2311         char errbuf[1024];
2312         dmu_replay_record_t drre;
2313         int error;
2314         boolean_t anyerr = B_FALSE;
2315         boolean_t softerr = B_FALSE;
2316         boolean_t recursive;
2317 
2318         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2319             "cannot receive"));
2320 
2321         assert(drr->drr_type == DRR_BEGIN);
2322         assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC);
2323         assert(DMU_GET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo) ==
2324             DMU_COMPOUNDSTREAM);
2325 
2326         /*
2327          * Read in the nvlist from the stream.


2436                                         zfs_close(zhp);
2437                                         if (clp != NULL) {
2438                                                 softerr |=
2439                                                     changelist_prefix(clp);
2440                                                 changelist_free(clp);
2441                                         }
2442                                 }
2443                         }
2444 
2445                         nvlist_free(renamed);
2446                 }
2447         }
2448 
2449         /*
2450          * Get the fs specified by the first path in the stream (the top level
2451          * specified by 'zfs send') and pass it to each invocation of
2452          * zfs_receive_one().
2453          */
2454         (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
2455             ZFS_MAXNAMELEN);
2456         if ((cp = strchr(sendfs, '@')) != NULL)
2457                 *cp = '\0';








2458 
2459         /* Finally, receive each contained stream */
2460         do {
2461                 /*
2462                  * we should figure out if it has a recoverable
2463                  * error, in which case do a recv_skip() and drive on.
2464                  * Note, if we fail due to already having this guid,
2465                  * zfs_receive_one() will take care of it (ie,
2466                  * recv_skip() and return 0).
2467                  */
2468                 error = zfs_receive_impl(hdl, destname, flags, fd,
2469                     sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
2470                     action_handlep);
2471                 if (error == ENODATA) {
2472                         error = 0;
2473                         break;
2474                 }
2475                 anyerr |= error;
2476         } while (error == 0);
2477 
2478         if (drr->drr_payloadlen != 0 && fromsnap != NULL) {
2479                 /*
2480                  * Now that we have the fs's they sent us, try the
2481                  * renames again.
2482                  */
2483                 softerr = recv_incremental_replication(hdl, tofs, flags,
2484                     stream_nv, stream_avl, NULL);
2485         }
2486 
2487 out:
2488         fsavl_destroy(stream_avl);
2489         if (stream_nv)
2490                 nvlist_free(stream_nv);


2584 
2585                 default:
2586                         zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2587                             "invalid record type"));
2588                         return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2589                 }
2590         }
2591 
2592         free(buf);
2593         return (-1);
2594 }
2595 
2596 /*
2597  * Restores a backup of tosnap from the file descriptor specified by infd.
2598  */
2599 static int
2600 zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
2601     recvflags_t *flags, dmu_replay_record_t *drr,
2602     dmu_replay_record_t *drr_noswap, const char *sendfs,
2603     nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
2604     uint64_t *action_handlep)
2605 {
2606         zfs_cmd_t zc = { 0 };
2607         time_t begin_time;
2608         int ioctl_err, ioctl_errno, err;
2609         char *cp;
2610         struct drr_begin *drrb = &drr->drr_u.drr_begin;
2611         char errbuf[1024];
2612         char prop_errbuf[1024];
2613         const char *chopprefix;
2614         boolean_t newfs = B_FALSE;
2615         boolean_t stream_wantsnewfs;
2616         uint64_t parent_snapguid = 0;
2617         prop_changelist_t *clp = NULL;
2618         nvlist_t *snapprops_nvlist = NULL;
2619         zprop_errflags_t prop_errflags;
2620         boolean_t recursive;

2621 
2622         begin_time = time(NULL);
2623 
2624         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2625             "cannot receive"));
2626 
2627         recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
2628             ENOENT);
2629 
2630         if (stream_avl != NULL) {
2631                 char *snapname;
2632                 nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
2633                     &snapname);
2634                 nvlist_t *props;
2635                 int ret;
2636 
2637                 (void) nvlist_lookup_uint64(fs, "parentfromsnap",
2638                     &parent_snapguid);
2639                 err = nvlist_lookup_nvlist(fs, "props", &props);
2640                 if (err)
2641                         VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
2642 
2643                 if (flags->canmountoff) {
2644                         VERIFY(0 == nvlist_add_uint64(props,
2645                             zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
2646                 }
2647                 ret = zcmd_write_src_nvlist(hdl, &zc, props);
2648                 if (err)
2649                         nvlist_free(props);
2650 
2651                 if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {


2937 
2938         if (err == 0) {
2939                 nvlist_t *prop_errors;
2940                 VERIFY(0 == nvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
2941                     zc.zc_nvlist_dst_size, &prop_errors, 0));
2942 
2943                 nvpair_t *prop_err = NULL;
2944 
2945                 while ((prop_err = nvlist_next_nvpair(prop_errors,
2946                     prop_err)) != NULL) {
2947                         char tbuf[1024];
2948                         zfs_prop_t prop;
2949                         int intval;
2950 
2951                         prop = zfs_name_to_prop(nvpair_name(prop_err));
2952                         (void) nvpair_value_int32(prop_err, &intval);
2953                         if (strcmp(nvpair_name(prop_err),
2954                             ZPROP_N_MORE_ERRORS) == 0) {
2955                                 trunc_prop_errs(intval);
2956                                 break;
2957                         } else {














2958                                 (void) snprintf(tbuf, sizeof (tbuf),
2959                                     dgettext(TEXT_DOMAIN,
2960                                     "cannot receive %s property on %s"),
2961                                     nvpair_name(prop_err), zc.zc_name);
2962                                 zfs_setprop_error(hdl, prop, intval, tbuf);
2963                         }
2964                 }
2965                 nvlist_free(prop_errors);
2966         }
2967 
2968         zc.zc_nvlist_dst = 0;
2969         zc.zc_nvlist_dst_size = 0;
2970         zcmd_free_nvlists(&zc);
2971 
2972         if (err == 0 && snapprops_nvlist) {
2973                 zfs_cmd_t zc2 = { 0 };
2974 
2975                 (void) strcpy(zc2.zc_name, zc.zc_value);
2976                 zc2.zc_cookie = B_TRUE; /* received */
2977                 if (zcmd_write_src_nvlist(hdl, &zc2, snapprops_nvlist) == 0) {


3122         if (flags->verbose) {
3123                 char buf1[64];
3124                 char buf2[64];
3125                 uint64_t bytes = zc.zc_cookie;
3126                 time_t delta = time(NULL) - begin_time;
3127                 if (delta == 0)
3128                         delta = 1;
3129                 zfs_nicenum(bytes, buf1, sizeof (buf1));
3130                 zfs_nicenum(bytes/delta, buf2, sizeof (buf1));
3131 
3132                 (void) printf("received %sB stream in %lu seconds (%sB/sec)\n",
3133                     buf1, delta, buf2);
3134         }
3135 
3136         return (0);
3137 }
3138 
3139 static int
3140 zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
3141     int infd, const char *sendfs, nvlist_t *stream_nv, avl_tree_t *stream_avl,
3142     char **top_zfs, int cleanup_fd, uint64_t *action_handlep)

3143 {
3144         int err;
3145         dmu_replay_record_t drr, drr_noswap;
3146         struct drr_begin *drrb = &drr.drr_u.drr_begin;
3147         char errbuf[1024];
3148         zio_cksum_t zcksum = { 0 };
3149         uint64_t featureflags;
3150         int hdrtype;
3151 
3152         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3153             "cannot receive"));
3154 
3155         if (flags->isprefix &&
3156             !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
3157                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
3158                     "(%s) does not exist"), tosnap);
3159                 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3160         }
3161 
3162         /* read in the BEGIN record */


3212 
3213         if (strchr(drrb->drr_toname, '@') == NULL) {
3214                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
3215                     "stream (bad snapshot name)"));
3216                 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
3217         }
3218 
3219         if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {
3220                 char nonpackage_sendfs[ZFS_MAXNAMELEN];
3221                 if (sendfs == NULL) {
3222                         /*
3223                          * We were not called from zfs_receive_package(). Get
3224                          * the fs specified by 'zfs send'.
3225                          */
3226                         char *cp;
3227                         (void) strlcpy(nonpackage_sendfs,
3228                             drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
3229                         if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
3230                                 *cp = '\0';
3231                         sendfs = nonpackage_sendfs;

3232                 }
3233                 return (zfs_receive_one(hdl, infd, tosnap, flags,
3234                     &drr, &drr_noswap, sendfs, stream_nv, stream_avl,
3235                     top_zfs, cleanup_fd, action_handlep));
3236         } else {
3237                 assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
3238                     DMU_COMPOUNDSTREAM);
3239                 return (zfs_receive_package(hdl, infd, tosnap, flags,
3240                     &drr, &zcksum, top_zfs, cleanup_fd, action_handlep));
3241         }
3242 }
3243 
3244 /*
3245  * Restores a backup of tosnap from the file descriptor specified by infd.
3246  * Return 0 on total success, -2 if some things couldn't be
3247  * destroyed/renamed/promoted, -1 if some things couldn't be received.
3248  * (-1 will override -2).
3249  */
3250 int
3251 zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
3252     int infd, avl_tree_t *stream_avl)
3253 {
3254         char *top_zfs = NULL;
3255         int err;
3256         int cleanup_fd;
3257         uint64_t action_handle = 0;
3258 
3259         cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
3260         VERIFY(cleanup_fd >= 0);
3261 
3262         err = zfs_receive_impl(hdl, tosnap, flags, infd, NULL, NULL,
3263             stream_avl, &top_zfs, cleanup_fd, &action_handle);
3264 
3265         VERIFY(0 == close(cleanup_fd));
3266 
3267         if (err == 0 && !flags->nomount && top_zfs) {
3268                 zfs_handle_t *zhp;
3269                 prop_changelist_t *clp;
3270 
3271                 zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
3272                 if (zhp != NULL) {
3273                         clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
3274                             CL_GATHER_MOUNT_ALWAYS, 0);
3275                         zfs_close(zhp);
3276                         if (clp != NULL) {
3277                                 /* mount and share received datasets */
3278                                 err = changelist_postfix(clp);
3279                                 changelist_free(clp);
3280                         }
3281                 }
3282                 if (zhp == NULL || clp == NULL || err)
3283                         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, 2014 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 <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 *, recvflags_t *,
  60     int, const char *, nvlist_t *, avl_tree_t *, char **, int, uint64_t *,
  61     const char *);
  62 
  63 static const zio_cksum_t zero_cksum = { 0 };
  64 
  65 typedef struct dedup_arg {
  66         int     inputfd;
  67         int     outputfd;
  68         libzfs_handle_t  *dedup_hdl;
  69 } dedup_arg_t;
  70 
  71 typedef struct progress_arg {
  72         zfs_handle_t *pa_zhp;
  73         int pa_fd;
  74         boolean_t pa_parsable;
  75 } progress_arg_t;
  76 
  77 typedef struct dataref {
  78         uint64_t ref_guid;
  79         uint64_t ref_object;
  80         uint64_t ref_offset;
  81 } dataref_t;


2290         nvlist_free(local_nv);
2291 
2292         if (needagain && progress) {
2293                 /* do another pass to fix up temporary names */
2294                 if (flags->verbose)
2295                         (void) printf("another pass:\n");
2296                 goto again;
2297         }
2298 
2299         return (needagain);
2300 }
2301 
2302 static int
2303 zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
2304     recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
2305     char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
2306 {
2307         nvlist_t *stream_nv = NULL;
2308         avl_tree_t *stream_avl = NULL;
2309         char *fromsnap = NULL;
2310         char *sendsnap = NULL;
2311         char *cp;
2312         char tofs[ZFS_MAXNAMELEN];
2313         char sendfs[ZFS_MAXNAMELEN];
2314         char errbuf[1024];
2315         dmu_replay_record_t drre;
2316         int error;
2317         boolean_t anyerr = B_FALSE;
2318         boolean_t softerr = B_FALSE;
2319         boolean_t recursive;
2320 
2321         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2322             "cannot receive"));
2323 
2324         assert(drr->drr_type == DRR_BEGIN);
2325         assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC);
2326         assert(DMU_GET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo) ==
2327             DMU_COMPOUNDSTREAM);
2328 
2329         /*
2330          * Read in the nvlist from the stream.


2439                                         zfs_close(zhp);
2440                                         if (clp != NULL) {
2441                                                 softerr |=
2442                                                     changelist_prefix(clp);
2443                                                 changelist_free(clp);
2444                                         }
2445                                 }
2446                         }
2447 
2448                         nvlist_free(renamed);
2449                 }
2450         }
2451 
2452         /*
2453          * Get the fs specified by the first path in the stream (the top level
2454          * specified by 'zfs send') and pass it to each invocation of
2455          * zfs_receive_one().
2456          */
2457         (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
2458             ZFS_MAXNAMELEN);
2459         if ((cp = strchr(sendfs, '@')) != NULL) {
2460                 *cp = '\0';
2461                 /*
2462                  * Find the "sendsnap", the final snapshot in a replication
2463                  * stream.  zfs_receive_one() handles certain errors
2464                  * differently, depending on if the contained stream is the
2465                  * last one or not.
2466                  */
2467                 sendsnap = (cp + 1);
2468         }
2469 
2470         /* Finally, receive each contained stream */
2471         do {
2472                 /*
2473                  * we should figure out if it has a recoverable
2474                  * error, in which case do a recv_skip() and drive on.
2475                  * Note, if we fail due to already having this guid,
2476                  * zfs_receive_one() will take care of it (ie,
2477                  * recv_skip() and return 0).
2478                  */
2479                 error = zfs_receive_impl(hdl, destname, flags, fd,
2480                     sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
2481                     action_handlep, sendsnap);
2482                 if (error == ENODATA) {
2483                         error = 0;
2484                         break;
2485                 }
2486                 anyerr |= error;
2487         } while (error == 0);
2488 
2489         if (drr->drr_payloadlen != 0 && fromsnap != NULL) {
2490                 /*
2491                  * Now that we have the fs's they sent us, try the
2492                  * renames again.
2493                  */
2494                 softerr = recv_incremental_replication(hdl, tofs, flags,
2495                     stream_nv, stream_avl, NULL);
2496         }
2497 
2498 out:
2499         fsavl_destroy(stream_avl);
2500         if (stream_nv)
2501                 nvlist_free(stream_nv);


2595 
2596                 default:
2597                         zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2598                             "invalid record type"));
2599                         return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2600                 }
2601         }
2602 
2603         free(buf);
2604         return (-1);
2605 }
2606 
2607 /*
2608  * Restores a backup of tosnap from the file descriptor specified by infd.
2609  */
2610 static int
2611 zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
2612     recvflags_t *flags, dmu_replay_record_t *drr,
2613     dmu_replay_record_t *drr_noswap, const char *sendfs,
2614     nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
2615     uint64_t *action_handlep, const char *finalsnap)
2616 {
2617         zfs_cmd_t zc = { 0 };
2618         time_t begin_time;
2619         int ioctl_err, ioctl_errno, err;
2620         char *cp;
2621         struct drr_begin *drrb = &drr->drr_u.drr_begin;
2622         char errbuf[1024];
2623         char prop_errbuf[1024];
2624         const char *chopprefix;
2625         boolean_t newfs = B_FALSE;
2626         boolean_t stream_wantsnewfs;
2627         uint64_t parent_snapguid = 0;
2628         prop_changelist_t *clp = NULL;
2629         nvlist_t *snapprops_nvlist = NULL;
2630         zprop_errflags_t prop_errflags;
2631         boolean_t recursive;
2632         char *snapname = NULL;
2633 
2634         begin_time = time(NULL);
2635 
2636         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2637             "cannot receive"));
2638 
2639         recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
2640             ENOENT);
2641 
2642         if (stream_avl != NULL) {

2643                 nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
2644                     &snapname);
2645                 nvlist_t *props;
2646                 int ret;
2647 
2648                 (void) nvlist_lookup_uint64(fs, "parentfromsnap",
2649                     &parent_snapguid);
2650                 err = nvlist_lookup_nvlist(fs, "props", &props);
2651                 if (err)
2652                         VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
2653 
2654                 if (flags->canmountoff) {
2655                         VERIFY(0 == nvlist_add_uint64(props,
2656                             zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
2657                 }
2658                 ret = zcmd_write_src_nvlist(hdl, &zc, props);
2659                 if (err)
2660                         nvlist_free(props);
2661 
2662                 if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {


2948 
2949         if (err == 0) {
2950                 nvlist_t *prop_errors;
2951                 VERIFY(0 == nvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
2952                     zc.zc_nvlist_dst_size, &prop_errors, 0));
2953 
2954                 nvpair_t *prop_err = NULL;
2955 
2956                 while ((prop_err = nvlist_next_nvpair(prop_errors,
2957                     prop_err)) != NULL) {
2958                         char tbuf[1024];
2959                         zfs_prop_t prop;
2960                         int intval;
2961 
2962                         prop = zfs_name_to_prop(nvpair_name(prop_err));
2963                         (void) nvpair_value_int32(prop_err, &intval);
2964                         if (strcmp(nvpair_name(prop_err),
2965                             ZPROP_N_MORE_ERRORS) == 0) {
2966                                 trunc_prop_errs(intval);
2967                                 break;
2968                         } else if (snapname == NULL || finalsnap == NULL ||
2969                             strcmp(finalsnap, snapname) == 0 ||
2970                             strcmp(nvpair_name(prop_err),
2971                             zfs_prop_to_name(ZFS_PROP_REFQUOTA)) != 0) {
2972                                 /*
2973                                  * Skip the special case of, for example,
2974                                  * "refquota", errors on intermediate
2975                                  * snapshots leading up to a final one.
2976                                  * That's why we have all of the checks above.
2977                                  *
2978                                  * See zfs_ioctl.c's extract_delay_props() for
2979                                  * a list of props which can fail on
2980                                  * intermediate snapshots, but shouldn't
2981                                  * affect the overall receive.
2982                                  */
2983                                 (void) snprintf(tbuf, sizeof (tbuf),
2984                                     dgettext(TEXT_DOMAIN,
2985                                     "cannot receive %s property on %s"),
2986                                     nvpair_name(prop_err), zc.zc_name);
2987                                 zfs_setprop_error(hdl, prop, intval, tbuf);
2988                         }
2989                 }
2990                 nvlist_free(prop_errors);
2991         }
2992 
2993         zc.zc_nvlist_dst = 0;
2994         zc.zc_nvlist_dst_size = 0;
2995         zcmd_free_nvlists(&zc);
2996 
2997         if (err == 0 && snapprops_nvlist) {
2998                 zfs_cmd_t zc2 = { 0 };
2999 
3000                 (void) strcpy(zc2.zc_name, zc.zc_value);
3001                 zc2.zc_cookie = B_TRUE; /* received */
3002                 if (zcmd_write_src_nvlist(hdl, &zc2, snapprops_nvlist) == 0) {


3147         if (flags->verbose) {
3148                 char buf1[64];
3149                 char buf2[64];
3150                 uint64_t bytes = zc.zc_cookie;
3151                 time_t delta = time(NULL) - begin_time;
3152                 if (delta == 0)
3153                         delta = 1;
3154                 zfs_nicenum(bytes, buf1, sizeof (buf1));
3155                 zfs_nicenum(bytes/delta, buf2, sizeof (buf1));
3156 
3157                 (void) printf("received %sB stream in %lu seconds (%sB/sec)\n",
3158                     buf1, delta, buf2);
3159         }
3160 
3161         return (0);
3162 }
3163 
3164 static int
3165 zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
3166     int infd, const char *sendfs, nvlist_t *stream_nv, avl_tree_t *stream_avl,
3167     char **top_zfs, int cleanup_fd, uint64_t *action_handlep,
3168     const char *finalsnap)
3169 {
3170         int err;
3171         dmu_replay_record_t drr, drr_noswap;
3172         struct drr_begin *drrb = &drr.drr_u.drr_begin;
3173         char errbuf[1024];
3174         zio_cksum_t zcksum = { 0 };
3175         uint64_t featureflags;
3176         int hdrtype;
3177 
3178         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3179             "cannot receive"));
3180 
3181         if (flags->isprefix &&
3182             !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
3183                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
3184                     "(%s) does not exist"), tosnap);
3185                 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3186         }
3187 
3188         /* read in the BEGIN record */


3238 
3239         if (strchr(drrb->drr_toname, '@') == NULL) {
3240                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
3241                     "stream (bad snapshot name)"));
3242                 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
3243         }
3244 
3245         if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {
3246                 char nonpackage_sendfs[ZFS_MAXNAMELEN];
3247                 if (sendfs == NULL) {
3248                         /*
3249                          * We were not called from zfs_receive_package(). Get
3250                          * the fs specified by 'zfs send'.
3251                          */
3252                         char *cp;
3253                         (void) strlcpy(nonpackage_sendfs,
3254                             drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
3255                         if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
3256                                 *cp = '\0';
3257                         sendfs = nonpackage_sendfs;
3258                         VERIFY(finalsnap == NULL);
3259                 }
3260                 return (zfs_receive_one(hdl, infd, tosnap, flags,
3261                     &drr, &drr_noswap, sendfs, stream_nv, stream_avl,
3262                     top_zfs, cleanup_fd, action_handlep, finalsnap));
3263         } else {
3264                 assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
3265                     DMU_COMPOUNDSTREAM);
3266                 return (zfs_receive_package(hdl, infd, tosnap, flags,
3267                     &drr, &zcksum, top_zfs, cleanup_fd, action_handlep));
3268         }
3269 }
3270 
3271 /*
3272  * Restores a backup of tosnap from the file descriptor specified by infd.
3273  * Return 0 on total success, -2 if some things couldn't be
3274  * destroyed/renamed/promoted, -1 if some things couldn't be received.
3275  * (-1 will override -2).
3276  */
3277 int
3278 zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
3279     int infd, avl_tree_t *stream_avl)
3280 {
3281         char *top_zfs = NULL;
3282         int err;
3283         int cleanup_fd;
3284         uint64_t action_handle = 0;
3285 
3286         cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
3287         VERIFY(cleanup_fd >= 0);
3288 
3289         err = zfs_receive_impl(hdl, tosnap, flags, infd, NULL, NULL,
3290             stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL);
3291 
3292         VERIFY(0 == close(cleanup_fd));
3293 
3294         if (err == 0 && !flags->nomount && top_zfs) {
3295                 zfs_handle_t *zhp;
3296                 prop_changelist_t *clp;
3297 
3298                 zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
3299                 if (zhp != NULL) {
3300                         clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
3301                             CL_GATHER_MOUNT_ALWAYS, 0);
3302                         zfs_close(zhp);
3303                         if (clp != NULL) {
3304                                 /* mount and share received datasets */
3305                                 err = changelist_postfix(clp);
3306                                 changelist_free(clp);
3307                         }
3308                 }
3309                 if (zhp == NULL || clp == NULL || err)
3310                         err = -1;