Print this page
3819 zfs receive can fail due to processing order

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 ↓ 715 lines elided ↑ open up ↑
 716  716          /* iterate over props */
 717  717          VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0));
 718  718          send_iterate_prop(zhp, nv);
 719  719          VERIFY(0 == nvlist_add_nvlist(nvfs, "props", nv));
 720  720          nvlist_free(nv);
 721  721  
 722  722          /* iterate over snaps, and set sd->parent_fromsnap_guid */
 723  723          sd->parent_fromsnap_guid = 0;
 724  724          VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0));
 725  725          VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0));
 726      -        (void) zfs_iter_snapshots(zhp, send_iterate_snap, sd);
      726 +        (void) zfs_iter_snapshots_sorted(zhp, send_iterate_snap, sd);
 727  727          VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps));
 728  728          VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops));
 729  729          nvlist_free(sd->parent_snaps);
 730  730          nvlist_free(sd->snapprops);
 731  731  
 732  732          /* add this fs to nvlist */
 733  733          (void) snprintf(guidstring, sizeof (guidstring),
 734  734              "0x%llx", (longlong_t)guid);
 735  735          VERIFY(0 == nvlist_add_nvlist(sd->fss, guidstring, nvfs));
 736  736          nvlist_free(nvfs);
↓ open down ↓ 1192 lines elided ↑ open up ↑
1929 1929          zfs_close(guid2hdl);
1930 1930  
1931 1931          return (rv);
1932 1932  }
1933 1933  
1934 1934  static int
1935 1935  recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
1936 1936      recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
1937 1937      nvlist_t *renamed)
1938 1938  {
1939      -        nvlist_t *local_nv;
     1939 +        nvlist_t *local_nv, *deleted = NULL;
1940 1940          avl_tree_t *local_avl;
1941 1941          nvpair_t *fselem, *nextfselem;
1942 1942          char *fromsnap;
1943      -        char newname[ZFS_MAXNAMELEN];
     1943 +        char newname[ZFS_MAXNAMELEN], guidname[32];
1944 1944          int error;
1945 1945          boolean_t needagain, progress, recursive;
1946 1946          char *s1, *s2;
1947 1947  
1948 1948          VERIFY(0 == nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap));
1949 1949  
1950 1950          recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
1951 1951              ENOENT);
1952 1952  
1953 1953          if (flags->dryrun)
1954 1954                  return (0);
1955 1955  
1956 1956  again:
1957 1957          needagain = progress = B_FALSE;
1958 1958  
1959 1959          if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
1960 1960              recursive, &local_nv, &local_avl)) != 0)
1961 1961                  return (error);
1962 1962  
     1963 +        deleted = fnvlist_alloc();
     1964 +
1963 1965          /*
1964 1966           * Process deletes and renames
1965 1967           */
1966 1968          for (fselem = nvlist_next_nvpair(local_nv, NULL);
1967 1969              fselem; fselem = nextfselem) {
1968 1970                  nvlist_t *nvfs, *snaps;
1969 1971                  nvlist_t *stream_nvfs = NULL;
1970 1972                  nvpair_t *snapelem, *nextsnapelem;
1971 1973                  uint64_t fromguid = 0;
1972 1974                  uint64_t originguid = 0;
↓ open down ↓ 51 lines elided ↑ open up ↑
2024 2026                                  error = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);
2025 2027                                  if (error == 0)
2026 2028                                          progress = B_TRUE;
2027 2029                                  break;
2028 2030                          }
2029 2031                          default:
2030 2032                                  break;
2031 2033                          case -1:
2032 2034                                  fsavl_destroy(local_avl);
2033 2035                                  nvlist_free(local_nv);
     2036 +                                nvlist_free(deleted);
2034 2037                                  return (-1);
2035 2038                          }
2036 2039                          /*
2037 2040                           * We had/have the wrong origin, therefore our
2038 2041                           * list of snapshots is wrong.  Need to handle
2039 2042                           * them on the next pass.
2040 2043                           */
2041 2044                          needagain = B_TRUE;
2042 2045                          continue;
2043 2046                  }
↓ open down ↓ 19 lines elided ↑ open up ↑
2063 2066  
2064 2067                                  (void) snprintf(name, sizeof (name), "%s@%s",
2065 2068                                      fsname, nvpair_name(snapelem));
2066 2069  
2067 2070                                  error = recv_destroy(hdl, name,
2068 2071                                      strlen(fsname)+1, newname, flags);
2069 2072                                  if (error)
2070 2073                                          needagain = B_TRUE;
2071 2074                                  else
2072 2075                                          progress = B_TRUE;
     2076 +                                (void) sprintf(guidname, "%llu",
     2077 +                                    (u_longlong_t)thisguid);
     2078 +                                fnvlist_add_boolean(deleted, guidname);
2073 2079                                  continue;
2074 2080                          }
2075 2081  
2076 2082                          stream_nvfs = found;
2077 2083  
2078 2084                          if (0 == nvlist_lookup_nvlist(stream_nvfs, "snapprops",
2079 2085                              &props) && 0 == nvlist_lookup_nvlist(props,
2080 2086                              stream_snapname, &props)) {
2081 2087                                  zfs_cmd_t zc = { 0 };
2082 2088  
↓ open down ↓ 35 lines elided ↑ open up ↑
2118 2124                  if (stream_nvfs == NULL) {
2119 2125                          if (!flags->force)
2120 2126                                  continue;
2121 2127  
2122 2128                          error = recv_destroy(hdl, fsname, strlen(tofs)+1,
2123 2129                              newname, flags);
2124 2130                          if (error)
2125 2131                                  needagain = B_TRUE;
2126 2132                          else
2127 2133                                  progress = B_TRUE;
     2134 +                        (void) sprintf(guidname, "%llu",
     2135 +                            (u_longlong_t)parent_fromsnap_guid);
     2136 +                        fnvlist_add_boolean(deleted, guidname);
2128 2137                          continue;
2129 2138                  }
2130 2139  
2131 2140                  if (fromguid == 0) {
2132 2141                          if (flags->verbose) {
2133 2142                                  (void) printf("local fs %s does not have "
2134 2143                                      "fromsnap (%s in stream); must have "
2135 2144                                      "been deleted locally; ignoring\n",
2136 2145                                      fsname, fromsnap);
2137 2146                          }
↓ open down ↓ 2 lines elided ↑ open up ↑
2140 2149  
2141 2150                  VERIFY(0 == nvlist_lookup_string(stream_nvfs,
2142 2151                      "name", &stream_fsname));
2143 2152                  VERIFY(0 == nvlist_lookup_uint64(stream_nvfs,
2144 2153                      "parentfromsnap", &stream_parent_fromsnap_guid));
2145 2154  
2146 2155                  s1 = strrchr(fsname, '/');
2147 2156                  s2 = strrchr(stream_fsname, '/');
2148 2157  
2149 2158                  /*
     2159 +                 * Check if we're going to rename based on parent guid change
     2160 +                 * and the current parent guid was also deleted. If it was then
     2161 +                 * the rename will fail so avoid this and force an early retry
     2162 +                 * to determine the new parent_fromsnap_guid.
     2163 +                 */
     2164 +                if (stream_parent_fromsnap_guid != 0 &&
     2165 +                    parent_fromsnap_guid != 0 &&
     2166 +                    stream_parent_fromsnap_guid != parent_fromsnap_guid) {
     2167 +                        (void) sprintf(guidname, "%llu",
     2168 +                            (u_longlong_t)parent_fromsnap_guid);
     2169 +                        if (nvlist_exists(deleted, guidname)) {
     2170 +                                progress = B_TRUE;
     2171 +                                needagain = B_TRUE;
     2172 +                                goto doagain;
     2173 +                        }
     2174 +                }
     2175 +
     2176 +                /*
2150 2177                   * Check for rename. If the exact receive path is specified, it
2151 2178                   * does not count as a rename, but we still need to check the
2152 2179                   * datasets beneath it.
2153 2180                   */
2154 2181                  if ((stream_parent_fromsnap_guid != 0 &&
2155 2182                      parent_fromsnap_guid != 0 &&
2156 2183                      stream_parent_fromsnap_guid != parent_fromsnap_guid) ||
2157 2184                      ((flags->isprefix || strcmp(tofs, fsname) != 0) &&
2158 2185                      (s1 != NULL) && (s2 != NULL) && strcmp(s1, s2) != 0)) {
2159 2186                          nvlist_t *parent;
↓ open down ↓ 33 lines elided ↑ open up ↑
2193 2220                                      newname));
2194 2221                          }
2195 2222  
2196 2223                          if (error)
2197 2224                                  needagain = B_TRUE;
2198 2225                          else
2199 2226                                  progress = B_TRUE;
2200 2227                  }
2201 2228          }
2202 2229  
     2230 +doagain:
2203 2231          fsavl_destroy(local_avl);
2204 2232          nvlist_free(local_nv);
     2233 +        nvlist_free(deleted);
2205 2234  
2206 2235          if (needagain && progress) {
2207 2236                  /* do another pass to fix up temporary names */
2208 2237                  if (flags->verbose)
2209 2238                          (void) printf("another pass:\n");
2210 2239                  goto again;
2211 2240          }
2212 2241  
2213 2242          return (needagain);
2214 2243  }
↓ open down ↓ 981 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX