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>

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libzfs/common/libzfs_sendrecv.c
          +++ new/usr/src/lib/libzfs/common/libzfs_sendrecv.c
↓ open down ↓ 16 lines elided ↑ open up ↑
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  25   25   * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  26   26   * Copyright (c) 2013 Steven Hartland. All rights reserved.
       27 + * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
  27   28   */
  28   29  
  29   30  #include <assert.h>
  30   31  #include <ctype.h>
  31   32  #include <errno.h>
  32   33  #include <libintl.h>
  33   34  #include <stdio.h>
  34   35  #include <stdlib.h>
  35   36  #include <strings.h>
  36   37  #include <unistd.h>
↓ open down ↓ 14 lines elided ↑ open up ↑
  51   52  #include <zlib.h>
  52   53  #include <sha2.h>
  53   54  #include <sys/zio_checksum.h>
  54   55  #include <sys/ddt.h>
  55   56  
  56   57  /* in libzfs_dataset.c */
  57   58  extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
  58   59  
  59   60  static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
  60   61      recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
  61      -    uint64_t *);
       62 +    uint64_t *, const char *);
  62   63  static int guid_to_name(libzfs_handle_t *, const char *,
  63   64      uint64_t, boolean_t, char *);
  64   65  
  65   66  static const zio_cksum_t zero_cksum = { 0 };
  66   67  
  67   68  typedef struct dedup_arg {
  68   69          int     inputfd;
  69   70          int     outputfd;
  70   71          libzfs_handle_t  *dedup_hdl;
  71   72  } dedup_arg_t;
↓ open down ↓ 2482 lines elided ↑ open up ↑
2554 2555  }
2555 2556  
2556 2557  static int
2557 2558  zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
2558 2559      recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
2559 2560      char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
2560 2561  {
2561 2562          nvlist_t *stream_nv = NULL;
2562 2563          avl_tree_t *stream_avl = NULL;
2563 2564          char *fromsnap = NULL;
     2565 +        char *sendsnap = NULL;
2564 2566          char *cp;
2565 2567          char tofs[ZFS_MAXNAMELEN];
2566 2568          char sendfs[ZFS_MAXNAMELEN];
2567 2569          char errbuf[1024];
2568 2570          dmu_replay_record_t drre;
2569 2571          int error;
2570 2572          boolean_t anyerr = B_FALSE;
2571 2573          boolean_t softerr = B_FALSE;
2572 2574          boolean_t recursive;
2573 2575  
↓ open down ↓ 128 lines elided ↑ open up ↑
2702 2704                  }
2703 2705          }
2704 2706  
2705 2707          /*
2706 2708           * Get the fs specified by the first path in the stream (the top level
2707 2709           * specified by 'zfs send') and pass it to each invocation of
2708 2710           * zfs_receive_one().
2709 2711           */
2710 2712          (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
2711 2713              ZFS_MAXNAMELEN);
2712      -        if ((cp = strchr(sendfs, '@')) != NULL)
     2714 +        if ((cp = strchr(sendfs, '@')) != NULL) {
2713 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 +        }
2714 2724  
2715 2725          /* Finally, receive each contained stream */
2716 2726          do {
2717 2727                  /*
2718 2728                   * we should figure out if it has a recoverable
2719 2729                   * error, in which case do a recv_skip() and drive on.
2720 2730                   * Note, if we fail due to already having this guid,
2721 2731                   * zfs_receive_one() will take care of it (ie,
2722 2732                   * recv_skip() and return 0).
2723 2733                   */
2724 2734                  error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
2725 2735                      sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
2726      -                    action_handlep);
     2736 +                    action_handlep, sendsnap);
2727 2737                  if (error == ENODATA) {
2728 2738                          error = 0;
2729 2739                          break;
2730 2740                  }
2731 2741                  anyerr |= error;
2732 2742          } while (error == 0);
2733 2743  
2734 2744          if (drr->drr_payloadlen != 0 && fromsnap != NULL) {
2735 2745                  /*
2736 2746                   * Now that we have the fs's they sent us, try the
↓ open down ↓ 145 lines elided ↑ open up ↑
2882 2892  }
2883 2893  
2884 2894  /*
2885 2895   * Restores a backup of tosnap from the file descriptor specified by infd.
2886 2896   */
2887 2897  static int
2888 2898  zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
2889 2899      const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
2890 2900      dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,
2891 2901      avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
2892      -    uint64_t *action_handlep)
     2902 +    uint64_t *action_handlep, const char *finalsnap)
2893 2903  {
2894 2904          zfs_cmd_t zc = { 0 };
2895 2905          time_t begin_time;
2896 2906          int ioctl_err, ioctl_errno, err;
2897 2907          char *cp;
2898 2908          struct drr_begin *drrb = &drr->drr_u.drr_begin;
2899 2909          char errbuf[1024];
2900 2910          char prop_errbuf[1024];
2901 2911          const char *chopprefix;
2902 2912          boolean_t newfs = B_FALSE;
2903 2913          boolean_t stream_wantsnewfs;
2904 2914          uint64_t parent_snapguid = 0;
2905 2915          prop_changelist_t *clp = NULL;
2906 2916          nvlist_t *snapprops_nvlist = NULL;
2907 2917          zprop_errflags_t prop_errflags;
2908 2918          boolean_t recursive;
     2919 +        char *snapname = NULL;
2909 2920  
2910 2921          begin_time = time(NULL);
2911 2922  
2912 2923          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2913 2924              "cannot receive"));
2914 2925  
2915 2926          recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
2916 2927              ENOENT);
2917 2928  
2918 2929          if (stream_avl != NULL) {
2919      -                char *snapname;
2920 2930                  nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
2921 2931                      &snapname);
2922 2932                  nvlist_t *props;
2923 2933                  int ret;
2924 2934  
2925 2935                  (void) nvlist_lookup_uint64(fs, "parentfromsnap",
2926 2936                      &parent_snapguid);
2927 2937                  err = nvlist_lookup_nvlist(fs, "props", &props);
2928 2938                  if (err)
2929 2939                          VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
↓ open down ↓ 326 lines elided ↑ open up ↑
3256 3266                          char tbuf[1024];
3257 3267                          zfs_prop_t prop;
3258 3268                          int intval;
3259 3269  
3260 3270                          prop = zfs_name_to_prop(nvpair_name(prop_err));
3261 3271                          (void) nvpair_value_int32(prop_err, &intval);
3262 3272                          if (strcmp(nvpair_name(prop_err),
3263 3273                              ZPROP_N_MORE_ERRORS) == 0) {
3264 3274                                  trunc_prop_errs(intval);
3265 3275                                  break;
3266      -                        } else {
     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 +                                 */
3267 3291                                  (void) snprintf(tbuf, sizeof (tbuf),
3268 3292                                      dgettext(TEXT_DOMAIN,
3269 3293                                      "cannot receive %s property on %s"),
3270 3294                                      nvpair_name(prop_err), zc.zc_name);
3271 3295                                  zfs_setprop_error(hdl, prop, intval, tbuf);
3272 3296                          }
3273 3297                  }
3274 3298                  nvlist_free(prop_errors);
3275 3299          }
3276 3300  
↓ open down ↓ 164 lines elided ↑ open up ↑
3441 3465                      buf1, delta, buf2);
3442 3466          }
3443 3467  
3444 3468          return (0);
3445 3469  }
3446 3470  
3447 3471  static int
3448 3472  zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
3449 3473      const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
3450 3474      nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
3451      -    uint64_t *action_handlep)
     3475 +    uint64_t *action_handlep, const char *finalsnap)
3452 3476  {
3453 3477          int err;
3454 3478          dmu_replay_record_t drr, drr_noswap;
3455 3479          struct drr_begin *drrb = &drr.drr_u.drr_begin;
3456 3480          char errbuf[1024];
3457 3481          zio_cksum_t zcksum = { 0 };
3458 3482          uint64_t featureflags;
3459 3483          int hdrtype;
3460 3484  
3461 3485          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
↓ open down ↓ 75 lines elided ↑ open up ↑
3537 3561                          /*
3538 3562                           * We were not called from zfs_receive_package(). Get
3539 3563                           * the fs specified by 'zfs send'.
3540 3564                           */
3541 3565                          char *cp;
3542 3566                          (void) strlcpy(nonpackage_sendfs,
3543 3567                              drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
3544 3568                          if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
3545 3569                                  *cp = '\0';
3546 3570                          sendfs = nonpackage_sendfs;
     3571 +                        VERIFY(finalsnap == NULL);
3547 3572                  }
3548 3573                  return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
3549 3574                      &drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,
3550      -                    cleanup_fd, action_handlep));
     3575 +                    cleanup_fd, action_handlep, finalsnap));
3551 3576          } else {
3552 3577                  assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
3553 3578                      DMU_COMPOUNDSTREAM);
3554 3579                  return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
3555 3580                      &zcksum, top_zfs, cleanup_fd, action_handlep));
3556 3581          }
3557 3582  }
3558 3583  
3559 3584  /*
3560 3585   * Restores a backup of tosnap from the file descriptor specified by infd.
↓ open down ↓ 14 lines elided ↑ open up ↑
3575 3600          if (props) {
3576 3601                  err = nvlist_lookup_string(props, "origin", &originsnap);
3577 3602                  if (err && err != ENOENT)
3578 3603                          return (err);
3579 3604          }
3580 3605  
3581 3606          cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
3582 3607          VERIFY(cleanup_fd >= 0);
3583 3608  
3584 3609          err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
3585      -            stream_avl, &top_zfs, cleanup_fd, &action_handle);
     3610 +            stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL);
3586 3611  
3587 3612          VERIFY(0 == close(cleanup_fd));
3588 3613  
3589 3614          if (err == 0 && !flags->nomount && top_zfs) {
3590 3615                  zfs_handle_t *zhp;
3591 3616                  prop_changelist_t *clp;
3592 3617  
3593 3618                  zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
3594 3619                  if (zhp != NULL) {
3595 3620                          clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
↓ open down ↓ 16 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX