Print this page
4986 receiving replication stream fails if any snapshot exceeds refquota
        
*** 22,31 ****
--- 22,32 ----
  /*
   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
   * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
   * Copyright (c) 2012, Joyent, Inc. All rights reserved.
   * Copyright (c) 2013 Steven Hartland. All rights reserved.
+  * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
   */
  
  #include <assert.h>
  #include <ctype.h>
  #include <errno.h>
*** 56,66 ****
  /* in libzfs_dataset.c */
  extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
  
  static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
      recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
!     uint64_t *);
  static int guid_to_name(libzfs_handle_t *, const char *,
      uint64_t, boolean_t, char *);
  
  static const zio_cksum_t zero_cksum = { 0 };
  
--- 57,67 ----
  /* in libzfs_dataset.c */
  extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
  
  static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
      recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
!     uint64_t *, const char *);
  static int guid_to_name(libzfs_handle_t *, const char *,
      uint64_t, boolean_t, char *);
  
  static const zio_cksum_t zero_cksum = { 0 };
  
*** 2559,2568 ****
--- 2560,2570 ----
      char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
  {
          nvlist_t *stream_nv = NULL;
          avl_tree_t *stream_avl = NULL;
          char *fromsnap = NULL;
+         char *sendsnap = NULL;
          char *cp;
          char tofs[ZFS_MAXNAMELEN];
          char sendfs[ZFS_MAXNAMELEN];
          char errbuf[1024];
          dmu_replay_record_t drre;
*** 2707,2718 ****
           * specified by 'zfs send') and pass it to each invocation of
           * zfs_receive_one().
           */
          (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
              ZFS_MAXNAMELEN);
!         if ((cp = strchr(sendfs, '@')) != NULL)
                  *cp = '\0';
  
          /* Finally, receive each contained stream */
          do {
                  /*
                   * we should figure out if it has a recoverable
--- 2709,2727 ----
           * specified by 'zfs send') and pass it to each invocation of
           * zfs_receive_one().
           */
          (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
              ZFS_MAXNAMELEN);
!         if ((cp = strchr(sendfs, '@')) != NULL) {
                  *cp = '\0';
+                 /*
+                  * Find the "sendsnap", the final snapshot in a replication
+                  * stream, so zfs_receive_one() can set filesystem properties
+                  * ONLY when receiving that final snapshot.
+                  */
+                 sendsnap = (cp + 1);
+         }
  
          /* Finally, receive each contained stream */
          do {
                  /*
                   * we should figure out if it has a recoverable
*** 2721,2731 ****
                   * zfs_receive_one() will take care of it (ie,
                   * recv_skip() and return 0).
                   */
                  error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
                      sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
!                     action_handlep);
                  if (error == ENODATA) {
                          error = 0;
                          break;
                  }
                  anyerr |= error;
--- 2730,2740 ----
                   * zfs_receive_one() will take care of it (ie,
                   * recv_skip() and return 0).
                   */
                  error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
                      sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
!                     action_handlep, sendsnap);
                  if (error == ENODATA) {
                          error = 0;
                          break;
                  }
                  anyerr |= error;
*** 2885,2897 ****
   * Restores a backup of tosnap from the file descriptor specified by infd.
   */
  static int
  zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
      const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
!     dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,
      avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
!     uint64_t *action_handlep)
  {
          zfs_cmd_t zc = { 0 };
          time_t begin_time;
          int ioctl_err, ioctl_errno, err;
          char *cp;
--- 2894,2906 ----
   * Restores a backup of tosnap from the file descriptor specified by infd.
   */
  static int
  zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
      const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
!     dmu_replay_record_t *drr_noswap, const char *sendfs,
      avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
!     uint64_t *action_handlep, const char *finalsnap)
  {
          zfs_cmd_t zc = { 0 };
          time_t begin_time;
          int ioctl_err, ioctl_errno, err;
          char *cp;
*** 2903,2941 ****
          boolean_t stream_wantsnewfs;
          uint64_t parent_snapguid = 0;
          prop_changelist_t *clp = NULL;
          nvlist_t *snapprops_nvlist = NULL;
          zprop_errflags_t prop_errflags;
-         boolean_t recursive;
  
          begin_time = time(NULL);
  
          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
              "cannot receive"));
  
-         recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
-             ENOENT);
- 
          if (stream_avl != NULL) {
                  char *snapname;
                  nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
                      &snapname);
                  nvlist_t *props;
                  int ret;
  
                  (void) nvlist_lookup_uint64(fs, "parentfromsnap",
                      &parent_snapguid);
                  err = nvlist_lookup_nvlist(fs, "props", &props);
!                 if (err)
                          VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
  
                  if (flags->canmountoff) {
                          VERIFY(0 == nvlist_add_uint64(props,
                              zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
                  }
                  ret = zcmd_write_src_nvlist(hdl, &zc, props);
!                 if (err)
                          nvlist_free(props);
  
                  if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {
                          VERIFY(0 == nvlist_lookup_nvlist(props,
                              snapname, &snapprops_nvlist));
--- 2912,2955 ----
          boolean_t stream_wantsnewfs;
          uint64_t parent_snapguid = 0;
          prop_changelist_t *clp = NULL;
          nvlist_t *snapprops_nvlist = NULL;
          zprop_errflags_t prop_errflags;
  
          begin_time = time(NULL);
  
          (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
              "cannot receive"));
  
          if (stream_avl != NULL) {
                  char *snapname;
                  nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
                      &snapname);
                  nvlist_t *props;
                  int ret;
+                 boolean_t is_finalsnap;
  
+                 VERIFY(fs != NULL);
                  (void) nvlist_lookup_uint64(fs, "parentfromsnap",
                      &parent_snapguid);
+                 /*
+                  * Can safely use strcmp because at least "snapname" has been
+                  * verified.
+                  */
+                 is_finalsnap = (strcmp(snapname, finalsnap) == 0);
+ 
+                 if (is_finalsnap)
                          err = nvlist_lookup_nvlist(fs, "props", &props);
!                 if (!is_finalsnap || err)
                          VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
  
                  if (flags->canmountoff) {
                          VERIFY(0 == nvlist_add_uint64(props,
                              zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
                  }
                  ret = zcmd_write_src_nvlist(hdl, &zc, props);
!                 if (!is_finalsnap || err)
                          nvlist_free(props);
  
                  if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {
                          VERIFY(0 == nvlist_lookup_nvlist(props,
                              snapname, &snapprops_nvlist));
*** 3002,3012 ****
                   * tack on everything after the fs specified by 'zfs send'.
                   */
                  chopprefix = drrb->drr_toname + strlen(sendfs);
          } else {
                  /* A snapshot was specified as an exact path (no -d or -e). */
!                 if (recursive) {
                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                              "cannot specify snapshot name for multi-snapshot "
                              "stream"));
                          return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
                  }
--- 3016,3026 ----
                   * tack on everything after the fs specified by 'zfs send'.
                   */
                  chopprefix = drrb->drr_toname + strlen(sendfs);
          } else {
                  /* A snapshot was specified as an exact path (no -d or -e). */
!                 if (flags->recursive) {
                          zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                              "cannot specify snapshot name for multi-snapshot "
                              "stream"));
                          return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
                  }
*** 3446,3456 ****
  
  static int
  zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
      const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
      nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
!     uint64_t *action_handlep)
  {
          int err;
          dmu_replay_record_t drr, drr_noswap;
          struct drr_begin *drrb = &drr.drr_u.drr_begin;
          char errbuf[1024];
--- 3460,3470 ----
  
  static int
  zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
      const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
      nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
!     uint64_t *action_handlep, const char *finalsnap)
  {
          int err;
          dmu_replay_record_t drr, drr_noswap;
          struct drr_begin *drrb = &drr.drr_u.drr_begin;
          char errbuf[1024];
*** 3542,3555 ****
                          (void) strlcpy(nonpackage_sendfs,
                              drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
                          if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
                                  *cp = '\0';
                          sendfs = nonpackage_sendfs;
                  }
!                 return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
!                     &drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,
!                     cleanup_fd, action_handlep));
          } else {
                  assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
                      DMU_COMPOUNDSTREAM);
                  return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
                      &zcksum, top_zfs, cleanup_fd, action_handlep));
--- 3556,3576 ----
                          (void) strlcpy(nonpackage_sendfs,
                              drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
                          if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
                                  *cp = '\0';
                          sendfs = nonpackage_sendfs;
+                         VERIFY(finalsnap == NULL);
                  }
!                 flags->recursive =
!                     (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
!                     ENOENT);
!                 err = zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
!                     &drr, &drr_noswap, sendfs, stream_avl, top_zfs,
!                     cleanup_fd, action_handlep, finalsnap);
!                 /* Clear out internal-only flags. */
!                 flags->recursive = B_FALSE;
!                 return (err);
          } else {
                  assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
                      DMU_COMPOUNDSTREAM);
                  return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
                      &zcksum, top_zfs, cleanup_fd, action_handlep));
*** 3580,3590 ****
  
          cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
          VERIFY(cleanup_fd >= 0);
  
          err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
!             stream_avl, &top_zfs, cleanup_fd, &action_handle);
  
          VERIFY(0 == close(cleanup_fd));
  
          if (err == 0 && !flags->nomount && top_zfs) {
                  zfs_handle_t *zhp;
--- 3601,3611 ----
  
          cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
          VERIFY(cleanup_fd >= 0);
  
          err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
!             stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL);
  
          VERIFY(0 == close(cleanup_fd));
  
          if (err == 0 && !flags->nomount && top_zfs) {
                  zfs_handle_t *zhp;