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>

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, 2014 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 ↓ 12 lines elided ↑ open up ↑
  49   50  #include "zfs_fletcher.h"
  50   51  #include "libzfs_impl.h"
  51   52  #include <sha2.h>
  52   53  #include <sys/zio_checksum.h>
  53   54  #include <sys/ddt.h>
  54   55  
  55   56  /* in libzfs_dataset.c */
  56   57  extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
  57   58  
  58   59  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 +    int, const char *, nvlist_t *, avl_tree_t *, char **, int, uint64_t *,
       61 +    const char *);
  60   62  
  61   63  static const zio_cksum_t zero_cksum = { 0 };
  62   64  
  63   65  typedef struct dedup_arg {
  64   66          int     inputfd;
  65   67          int     outputfd;
  66   68          libzfs_handle_t  *dedup_hdl;
  67   69  } dedup_arg_t;
  68   70  
  69   71  typedef struct progress_arg {
↓ open down ↓ 2228 lines elided ↑ open up ↑
2298 2300  }
2299 2301  
2300 2302  static int
2301 2303  zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
2302 2304      recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
2303 2305      char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
2304 2306  {
2305 2307          nvlist_t *stream_nv = NULL;
2306 2308          avl_tree_t *stream_avl = NULL;
2307 2309          char *fromsnap = NULL;
     2310 +        char *sendsnap = NULL;
2308 2311          char *cp;
2309 2312          char tofs[ZFS_MAXNAMELEN];
2310 2313          char sendfs[ZFS_MAXNAMELEN];
2311 2314          char errbuf[1024];
2312 2315          dmu_replay_record_t drre;
2313 2316          int error;
2314 2317          boolean_t anyerr = B_FALSE;
2315 2318          boolean_t softerr = B_FALSE;
2316 2319          boolean_t recursive;
2317 2320  
↓ open down ↓ 128 lines elided ↑ open up ↑
2446 2449                  }
2447 2450          }
2448 2451  
2449 2452          /*
2450 2453           * Get the fs specified by the first path in the stream (the top level
2451 2454           * specified by 'zfs send') and pass it to each invocation of
2452 2455           * zfs_receive_one().
2453 2456           */
2454 2457          (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
2455 2458              ZFS_MAXNAMELEN);
2456      -        if ((cp = strchr(sendfs, '@')) != NULL)
     2459 +        if ((cp = strchr(sendfs, '@')) != NULL) {
2457 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 +        }
2458 2469  
2459 2470          /* Finally, receive each contained stream */
2460 2471          do {
2461 2472                  /*
2462 2473                   * we should figure out if it has a recoverable
2463 2474                   * error, in which case do a recv_skip() and drive on.
2464 2475                   * Note, if we fail due to already having this guid,
2465 2476                   * zfs_receive_one() will take care of it (ie,
2466 2477                   * recv_skip() and return 0).
2467 2478                   */
2468 2479                  error = zfs_receive_impl(hdl, destname, flags, fd,
2469 2480                      sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
2470      -                    action_handlep);
     2481 +                    action_handlep, sendsnap);
2471 2482                  if (error == ENODATA) {
2472 2483                          error = 0;
2473 2484                          break;
2474 2485                  }
2475 2486                  anyerr |= error;
2476 2487          } while (error == 0);
2477 2488  
2478 2489          if (drr->drr_payloadlen != 0 && fromsnap != NULL) {
2479 2490                  /*
2480 2491                   * Now that we have the fs's they sent us, try the
↓ open down ↓ 113 lines elided ↑ open up ↑
2594 2605  }
2595 2606  
2596 2607  /*
2597 2608   * Restores a backup of tosnap from the file descriptor specified by infd.
2598 2609   */
2599 2610  static int
2600 2611  zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
2601 2612      recvflags_t *flags, dmu_replay_record_t *drr,
2602 2613      dmu_replay_record_t *drr_noswap, const char *sendfs,
2603 2614      nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
2604      -    uint64_t *action_handlep)
     2615 +    uint64_t *action_handlep, const char *finalsnap)
2605 2616  {
2606 2617          zfs_cmd_t zc = { 0 };
2607 2618          time_t begin_time;
2608 2619          int ioctl_err, ioctl_errno, err;
2609 2620          char *cp;
2610 2621          struct drr_begin *drrb = &drr->drr_u.drr_begin;
2611 2622          char errbuf[1024];
2612 2623          char prop_errbuf[1024];
2613 2624          const char *chopprefix;
2614 2625          boolean_t newfs = B_FALSE;
2615 2626          boolean_t stream_wantsnewfs;
2616 2627          uint64_t parent_snapguid = 0;
2617 2628          prop_changelist_t *clp = NULL;
2618 2629          nvlist_t *snapprops_nvlist = NULL;
2619 2630          zprop_errflags_t prop_errflags;
2620 2631          boolean_t recursive;
     2632 +        char *snapname = NULL;
2621 2633  
2622 2634          begin_time = time(NULL);
2623 2635  
2624 2636          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2625 2637              "cannot receive"));
2626 2638  
2627 2639          recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
2628 2640              ENOENT);
2629 2641  
2630 2642          if (stream_avl != NULL) {
2631      -                char *snapname;
2632 2643                  nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
2633 2644                      &snapname);
2634 2645                  nvlist_t *props;
2635 2646                  int ret;
2636 2647  
2637 2648                  (void) nvlist_lookup_uint64(fs, "parentfromsnap",
2638 2649                      &parent_snapguid);
2639 2650                  err = nvlist_lookup_nvlist(fs, "props", &props);
2640 2651                  if (err)
2641 2652                          VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
↓ open down ↓ 305 lines elided ↑ open up ↑
2947 2958                          char tbuf[1024];
2948 2959                          zfs_prop_t prop;
2949 2960                          int intval;
2950 2961  
2951 2962                          prop = zfs_name_to_prop(nvpair_name(prop_err));
2952 2963                          (void) nvpair_value_int32(prop_err, &intval);
2953 2964                          if (strcmp(nvpair_name(prop_err),
2954 2965                              ZPROP_N_MORE_ERRORS) == 0) {
2955 2966                                  trunc_prop_errs(intval);
2956 2967                                  break;
2957      -                        } else {
     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 +                                 */
2958 2983                                  (void) snprintf(tbuf, sizeof (tbuf),
2959 2984                                      dgettext(TEXT_DOMAIN,
2960 2985                                      "cannot receive %s property on %s"),
2961 2986                                      nvpair_name(prop_err), zc.zc_name);
2962 2987                                  zfs_setprop_error(hdl, prop, intval, tbuf);
2963 2988                          }
2964 2989                  }
2965 2990                  nvlist_free(prop_errors);
2966 2991          }
2967 2992  
↓ open down ↓ 164 lines elided ↑ open up ↑
3132 3157                  (void) printf("received %sB stream in %lu seconds (%sB/sec)\n",
3133 3158                      buf1, delta, buf2);
3134 3159          }
3135 3160  
3136 3161          return (0);
3137 3162  }
3138 3163  
3139 3164  static int
3140 3165  zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
3141 3166      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)
     3167 +    char **top_zfs, int cleanup_fd, uint64_t *action_handlep,
     3168 +    const char *finalsnap)
3143 3169  {
3144 3170          int err;
3145 3171          dmu_replay_record_t drr, drr_noswap;
3146 3172          struct drr_begin *drrb = &drr.drr_u.drr_begin;
3147 3173          char errbuf[1024];
3148 3174          zio_cksum_t zcksum = { 0 };
3149 3175          uint64_t featureflags;
3150 3176          int hdrtype;
3151 3177  
3152 3178          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
↓ open down ↓ 69 lines elided ↑ open up ↑
3222 3248                          /*
3223 3249                           * We were not called from zfs_receive_package(). Get
3224 3250                           * the fs specified by 'zfs send'.
3225 3251                           */
3226 3252                          char *cp;
3227 3253                          (void) strlcpy(nonpackage_sendfs,
3228 3254                              drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
3229 3255                          if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
3230 3256                                  *cp = '\0';
3231 3257                          sendfs = nonpackage_sendfs;
     3258 +                        VERIFY(finalsnap == NULL);
3232 3259                  }
3233 3260                  return (zfs_receive_one(hdl, infd, tosnap, flags,
3234 3261                      &drr, &drr_noswap, sendfs, stream_nv, stream_avl,
3235      -                    top_zfs, cleanup_fd, action_handlep));
     3262 +                    top_zfs, cleanup_fd, action_handlep, finalsnap));
3236 3263          } else {
3237 3264                  assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
3238 3265                      DMU_COMPOUNDSTREAM);
3239 3266                  return (zfs_receive_package(hdl, infd, tosnap, flags,
3240 3267                      &drr, &zcksum, top_zfs, cleanup_fd, action_handlep));
3241 3268          }
3242 3269  }
3243 3270  
3244 3271  /*
3245 3272   * Restores a backup of tosnap from the file descriptor specified by infd.
↓ open down ↓ 7 lines elided ↑ open up ↑
3253 3280  {
3254 3281          char *top_zfs = NULL;
3255 3282          int err;
3256 3283          int cleanup_fd;
3257 3284          uint64_t action_handle = 0;
3258 3285  
3259 3286          cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
3260 3287          VERIFY(cleanup_fd >= 0);
3261 3288  
3262 3289          err = zfs_receive_impl(hdl, tosnap, flags, infd, NULL, NULL,
3263      -            stream_avl, &top_zfs, cleanup_fd, &action_handle);
     3290 +            stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL);
3264 3291  
3265 3292          VERIFY(0 == close(cleanup_fd));
3266 3293  
3267 3294          if (err == 0 && !flags->nomount && top_zfs) {
3268 3295                  zfs_handle_t *zhp;
3269 3296                  prop_changelist_t *clp;
3270 3297  
3271 3298                  zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
3272 3299                  if (zhp != NULL) {
3273 3300                          clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
↓ open down ↓ 16 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX