Print this page
*** NO COMMENTS ***

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 ↓ 15 lines elided ↑ open up ↑
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  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) 2012 by Delphix. All rights reserved.
  25   25   * Copyright (c) 2012, Joyent, Inc. All rights reserved.
       26 + * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
  26   27   */
  27   28  
  28   29  #include <assert.h>
  29   30  #include <ctype.h>
  30   31  #include <errno.h>
  31   32  #include <libintl.h>
  32   33  #include <stdio.h>
  33   34  #include <stdlib.h>
  34   35  #include <strings.h>
  35   36  #include <unistd.h>
↓ open down ↓ 18 lines elided ↑ open up ↑
  54   55  extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
  55   56  
  56   57  static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t *,
  57   58      int, const char *, nvlist_t *, avl_tree_t *, char **, int, uint64_t *);
  58   59  
  59   60  static const zio_cksum_t zero_cksum = { 0 };
  60   61  
  61   62  typedef struct dedup_arg {
  62   63          int     inputfd;
  63   64          int     outputfd;
       65 +        uint64_t        dedup_data_sz;
       66 +        boolean_t       sendsize;
  64   67          libzfs_handle_t  *dedup_hdl;
  65   68  } dedup_arg_t;
  66   69  
  67   70  typedef struct progress_arg {
  68   71          zfs_handle_t *pa_zhp;
  69   72          int pa_fd;
  70   73          boolean_t pa_parsable;
  71   74  } progress_arg_t;
  72   75  
  73   76  typedef struct dataref {
↓ open down ↓ 103 lines elided ↑ open up ↑
 177  180  }
 178  181  
 179  182  static int
 180  183  cksum_and_write(const void *buf, uint64_t len, zio_cksum_t *zc, int outfd)
 181  184  {
 182  185          fletcher_4_incremental_native(buf, len, zc);
 183  186          return (write(outfd, buf, len));
 184  187  }
 185  188  
 186  189  /*
      190 + * the function used by the cksummer thread that needs to know
      191 + * about the sendsize flag
      192 + */
      193 +static int
      194 +dedup_cksum_and_write(dedup_arg_t *dda, const void *buf, uint64_t len,
      195 +    zio_cksum_t *zc, int outfd)
      196 +{
      197 +        int ret = len;
      198 +
      199 +        dda->dedup_data_sz += len;
      200 +        fletcher_4_incremental_native(buf, len, zc);
      201 +        if (!dda->sendsize)
      202 +                ret = (write(outfd, buf, len));
      203 +
      204 +        return (ret);
      205 +}
      206 +
      207 +/*
 187  208   * This function is started in a separate thread when the dedup option
 188  209   * has been requested.  The main send thread determines the list of
 189  210   * snapshots to be included in the send stream and makes the ioctl calls
 190  211   * for each one.  But instead of having the ioctl send the output to the
 191  212   * the output fd specified by the caller of zfs_send()), the
 192  213   * ioctl is told to direct the output to a pipe, which is read by the
 193  214   * alternate thread running THIS function.  This function does the
 194  215   * dedup'ing by:
 195  216   *  1. building a dedup table (the DDT)
 196  217   *  2. doing checksums on each data block and inserting a record in the DDT
↓ open down ↓ 57 lines elided ↑ open up ↑
 254  275                  {
 255  276                          int     fflags;
 256  277                          ZIO_SET_CHECKSUM(&stream_cksum, 0, 0, 0, 0);
 257  278  
 258  279                          /* set the DEDUP feature flag for this stream */
 259  280                          fflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
 260  281                          fflags |= (DMU_BACKUP_FEATURE_DEDUP |
 261  282                              DMU_BACKUP_FEATURE_DEDUPPROPS);
 262  283                          DMU_SET_FEATUREFLAGS(drrb->drr_versioninfo, fflags);
 263  284  
 264      -                        if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
      285 +                        if (dedup_cksum_and_write(dda, drr,
      286 +                            sizeof (dmu_replay_record_t),
 265  287                              &stream_cksum, outfd) == -1)
 266  288                                  goto out;
 267  289                          if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
 268  290                              DMU_COMPOUNDSTREAM && drr->drr_payloadlen != 0) {
 269  291                                  int sz = drr->drr_payloadlen;
 270  292  
 271  293                                  if (sz > 1<<20) {
 272  294                                          free(buf);
 273  295                                          buf = malloc(sz);
 274  296                                  }
 275  297                                  (void) ssread(buf, sz, ofp);
 276  298                                  if (ferror(stdin))
 277  299                                          perror("fread");
 278      -                                if (cksum_and_write(buf, sz, &stream_cksum,
 279      -                                    outfd) == -1)
      300 +                                if (dedup_cksum_and_write(dda, buf, sz,
      301 +                                    &stream_cksum, outfd) == -1)
 280  302                                          goto out;
 281  303                          }
 282  304                          break;
 283  305                  }
 284  306  
 285  307                  case DRR_END:
 286  308                  {
 287  309                          /* use the recalculated checksum */
 288  310                          ZIO_SET_CHECKSUM(&drre->drr_checksum,
 289  311                              stream_cksum.zc_word[0], stream_cksum.zc_word[1],
 290  312                              stream_cksum.zc_word[2], stream_cksum.zc_word[3]);
 291  313                          if ((write(outfd, drr,
 292  314                              sizeof (dmu_replay_record_t))) == -1)
 293  315                                  goto out;
      316 +                        dda->dedup_data_sz += sizeof (dmu_replay_record_t);
 294  317                          break;
 295  318                  }
 296  319  
 297  320                  case DRR_OBJECT:
 298  321                  {
 299      -                        if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
      322 +                        if (dedup_cksum_and_write(dda, drr,
      323 +                            sizeof (dmu_replay_record_t),
 300  324                              &stream_cksum, outfd) == -1)
 301  325                                  goto out;
 302  326                          if (drro->drr_bonuslen > 0) {
 303  327                                  (void) ssread(buf,
 304  328                                      P2ROUNDUP((uint64_t)drro->drr_bonuslen, 8),
 305  329                                      ofp);
 306      -                                if (cksum_and_write(buf,
      330 +                                if (dedup_cksum_and_write(dda, buf,
 307  331                                      P2ROUNDUP((uint64_t)drro->drr_bonuslen, 8),
 308  332                                      &stream_cksum, outfd) == -1)
 309  333                                          goto out;
 310  334                          }
 311  335                          break;
 312  336                  }
 313  337  
 314  338                  case DRR_SPILL:
 315  339                  {
 316      -                        if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
      340 +                        if (dedup_cksum_and_write(dda, drr,
      341 +                            sizeof (dmu_replay_record_t),
 317  342                              &stream_cksum, outfd) == -1)
 318  343                                  goto out;
 319  344                          (void) ssread(buf, drrs->drr_length, ofp);
 320      -                        if (cksum_and_write(buf, drrs->drr_length,
      345 +                        if (dedup_cksum_and_write(dda, buf, drrs->drr_length,
 321  346                              &stream_cksum, outfd) == -1)
 322  347                                  goto out;
 323  348                          break;
 324  349                  }
 325  350  
 326  351                  case DRR_FREEOBJECTS:
 327  352                  {
 328      -                        if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
      353 +                        if (dedup_cksum_and_write(dda, drr,
      354 +                            sizeof (dmu_replay_record_t),
 329  355                              &stream_cksum, outfd) == -1)
 330  356                                  goto out;
 331  357                          break;
 332  358                  }
 333  359  
 334  360                  case DRR_WRITE:
 335  361                  {
 336  362                          dataref_t       dataref;
 337  363  
 338  364                          (void) ssread(buf, drrw->drr_length, ofp);
↓ open down ↓ 44 lines elided ↑ open up ↑
 383  409  
 384  410                                  wbr_drrr->drr_checksumtype =
 385  411                                      drrw->drr_checksumtype;
 386  412                                  wbr_drrr->drr_checksumflags =
 387  413                                      drrw->drr_checksumtype;
 388  414                                  wbr_drrr->drr_key.ddk_cksum =
 389  415                                      drrw->drr_key.ddk_cksum;
 390  416                                  wbr_drrr->drr_key.ddk_prop =
 391  417                                      drrw->drr_key.ddk_prop;
 392  418  
 393      -                                if (cksum_and_write(&wbr_drr,
      419 +                                if (dedup_cksum_and_write(dda, &wbr_drr,
 394  420                                      sizeof (dmu_replay_record_t), &stream_cksum,
 395  421                                      outfd) == -1)
 396  422                                          goto out;
 397  423                          } else {
 398  424                                  /* block not previously seen */
 399      -                                if (cksum_and_write(drr,
      425 +                                if (dedup_cksum_and_write(dda, drr,
 400  426                                      sizeof (dmu_replay_record_t), &stream_cksum,
 401  427                                      outfd) == -1)
 402  428                                          goto out;
 403      -                                if (cksum_and_write(buf,
      429 +                                if (dedup_cksum_and_write(dda, buf,
 404  430                                      drrw->drr_length,
 405  431                                      &stream_cksum, outfd) == -1)
 406  432                                          goto out;
 407  433                          }
 408  434                          break;
 409  435                  }
 410  436  
 411  437                  case DRR_FREE:
 412  438                  {
 413      -                        if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
      439 +                        if (dedup_cksum_and_write(dda, drr,
      440 +                            sizeof (dmu_replay_record_t),
 414  441                              &stream_cksum, outfd) == -1)
 415  442                                  goto out;
 416  443                          break;
 417  444                  }
 418  445  
 419  446                  default:
 420  447                          (void) printf("INVALID record type 0x%x\n",
 421  448                              drr->drr_type);
 422  449                          /* should never happen, so assert */
 423  450                          assert(B_FALSE);
↓ open down ↓ 358 lines elided ↑ open up ↑
 782  809  /*
 783  810   * Routines specific to "zfs send"
 784  811   */
 785  812  typedef struct send_dump_data {
 786  813          /* these are all just the short snapname (the part after the @) */
 787  814          const char *fromsnap;
 788  815          const char *tosnap;
 789  816          char prevsnap[ZFS_MAXNAMELEN];
 790  817          uint64_t prevsnap_obj;
 791  818          boolean_t seenfrom, seento, replicate, doall, fromorigin;
 792      -        boolean_t verbose, dryrun, parsable, progress;
      819 +        boolean_t verbose, dryrun, dedup, parsable, progress;
      820 +        boolean_t sendsize;
      821 +        uint32_t hdr_send_sz;
      822 +        uint64_t send_sz;
 793  823          int outfd;
 794  824          boolean_t err;
 795  825          nvlist_t *fss;
 796  826          avl_tree_t *fsavl;
 797  827          snapfilter_cb_t *filter_cb;
 798  828          void *filter_cb_arg;
 799  829          nvlist_t *debugnv;
 800  830          char holdtag[ZFS_MAXNAMELEN];
 801  831          int cleanup_fd;
 802  832          uint64_t size;
↓ open down ↓ 58 lines elided ↑ open up ↑
 861  891  
 862  892          return (0);
 863  893  }
 864  894  
 865  895  /*
 866  896   * Dumps a backup of the given snapshot (incremental from fromsnap if it's not
 867  897   * NULL) to the file descriptor specified by outfd.
 868  898   */
 869  899  static int
 870  900  dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
 871      -    boolean_t fromorigin, int outfd, nvlist_t *debugnv)
      901 +    boolean_t fromorigin, int outfd, nvlist_t *debugnv,
      902 +    boolean_t sendsize, uint64_t *sendcounter)
 872  903  {
 873  904          zfs_cmd_t zc = { 0 };
 874  905          libzfs_handle_t *hdl = zhp->zfs_hdl;
 875  906          nvlist_t *thisdbg;
 876  907  
 877  908          assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
 878  909          assert(fromsnap_obj == 0 || !fromorigin);
 879  910  
 880  911          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 881  912          zc.zc_cookie = outfd;
 882  913          zc.zc_obj = fromorigin;
 883  914          zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
 884  915          zc.zc_fromobj = fromsnap_obj;
      916 +        zc.zc_sendsize = sendsize;
      917 +        zc.zc_sendcounter = 0;
 885  918  
 886  919          VERIFY(0 == nvlist_alloc(&thisdbg, NV_UNIQUE_NAME, 0));
 887  920          if (fromsnap && fromsnap[0] != '\0') {
 888  921                  VERIFY(0 == nvlist_add_string(thisdbg,
 889  922                      "fromsnap", fromsnap));
 890  923          }
 891  924  
 892  925          if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
 893  926                  char errbuf[1024];
 894  927                  (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
↓ open down ↓ 33 lines elided ↑ open up ↑
 928  961                  case EFAULT:
 929  962                  case EROFS:
 930  963                          zfs_error_aux(hdl, strerror(errno));
 931  964                          return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
 932  965  
 933  966                  default:
 934  967                          return (zfs_standard_error(hdl, errno, errbuf));
 935  968                  }
 936  969          }
 937  970  
      971 +        *sendcounter = (uint64_t)zc.zc_sendcounter;
 938  972          if (debugnv)
 939  973                  VERIFY(0 == nvlist_add_nvlist(debugnv, zhp->zfs_name, thisdbg));
 940  974          nvlist_free(thisdbg);
 941  975  
 942  976          return (0);
 943  977  }
 944  978  
 945  979  static int
 946  980  hold_for_send(zfs_handle_t *zhp, send_dump_data_t *sdd)
 947  981  {
↓ open down ↓ 162 lines elided ↑ open up ↑
1110 1144          if (err) {
1111 1145                  if (err == ENOENT)
1112 1146                          err = 0;
1113 1147                  zfs_close(zhp);
1114 1148                  return (err);
1115 1149          }
1116 1150  
1117 1151          fromorigin = sdd->prevsnap[0] == '\0' &&
1118 1152              (sdd->fromorigin || sdd->replicate);
1119 1153  
     1154 +        /* print out to-from and approximate size in verbose mode */
1120 1155          if (sdd->verbose) {
1121      -                uint64_t size;
1122      -                err = estimate_ioctl(zhp, sdd->prevsnap_obj,
1123      -                    fromorigin, &size);
1124      -
     1156 +                /* print preamble */
1125 1157                  if (sdd->parsable) {
1126 1158                          if (sdd->prevsnap[0] != '\0') {
1127 1159                                  (void) fprintf(stderr, "incremental\t%s\t%s",
1128 1160                                      sdd->prevsnap, zhp->zfs_name);
1129 1161                          } else {
1130 1162                                  (void) fprintf(stderr, "full\t%s",
1131 1163                                      zhp->zfs_name);
1132 1164                          }
1133 1165                  } else {
1134 1166                          (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1135 1167                              "send from @%s to %s"),
1136 1168                              sdd->prevsnap, zhp->zfs_name);
1137 1169                  }
1138      -                if (err == 0) {
1139      -                        if (sdd->parsable) {
1140      -                                (void) fprintf(stderr, "\t%llu\n",
1141      -                                    (longlong_t)size);
     1170 +
     1171 +                if (sdd->sendsize) {
     1172 +                        /*
     1173 +                         * we are going to print out the exact stream size info,
     1174 +                         * so skip the estimate
     1175 +                         */
     1176 +                        (void) fprintf(stderr, "\n");
     1177 +                } else {
     1178 +                        /*
     1179 +                         * provide stream size estimate otherwise
     1180 +                         */
     1181 +                        uint64_t size;
     1182 +                        err = estimate_ioctl(zhp, sdd->prevsnap_obj,
     1183 +                            fromorigin, &size);
     1184 +
     1185 +                        if (err == 0) {
     1186 +                                if (sdd->parsable) {
     1187 +                                        (void) fprintf(stderr, "\t%llu\n",
     1188 +                                            (longlong_t)size);
     1189 +                                } else {
     1190 +                                        char buf[16];
     1191 +                                        zfs_nicenum(size, buf, sizeof (buf));
     1192 +                                        (void) fprintf(stderr,
     1193 +                                            dgettext(TEXT_DOMAIN,
     1194 +                                            " estimated size is %s\n"),
     1195 +                                            buf);
     1196 +                                }
     1197 +                                sdd->size += size;
1142 1198                          } else {
1143      -                                char buf[16];
1144      -                                zfs_nicenum(size, buf, sizeof (buf));
1145      -                                (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1146      -                                    " estimated size is %s\n"), buf);
     1199 +                                /* could not estimate */
     1200 +                                (void) fprintf(stderr, "\n");
1147 1201                          }
1148      -                        sdd->size += size;
1149      -                } else {
1150      -                        (void) fprintf(stderr, "\n");
1151 1202                  }
1152 1203          }
1153 1204  
1154 1205          if (!sdd->dryrun) {
     1206 +                uint64_t sendcounter = 0;
     1207 +                boolean_t track_progress = (sdd->progress && !sdd->sendsize);
     1208 +                boolean_t sendsize = B_FALSE;
1155 1209                  /*
1156 1210                   * If progress reporting is requested, spawn a new thread to
1157 1211                   * poll ZFS_IOC_SEND_PROGRESS at a regular interval.
1158 1212                   */
1159      -                if (sdd->progress) {
     1213 +                if (track_progress) {
1160 1214                          pa.pa_zhp = zhp;
1161 1215                          pa.pa_fd = sdd->outfd;
1162 1216                          pa.pa_parsable = sdd->parsable;
1163 1217  
1164 1218                          if (err = pthread_create(&tid, NULL,
1165 1219                              send_progress_thread, &pa)) {
1166 1220                                  zfs_close(zhp);
1167 1221                                  return (err);
1168 1222                          }
1169 1223                  }
1170 1224  
     1225 +
     1226 +                /*
     1227 +                 * We need to reset the sendsize flag being sent to
     1228 +                 * kernel if sdd->dedup is set. With dedup, the file
     1229 +                 * descriptor sent to kernel is one end of the pipe,
     1230 +                 * and we would want the data back in the pipe for
     1231 +                 * cksummer() to calculate the exact size of the dedup-ed
     1232 +                 * stream. So reset the sendsize flag such that
     1233 +                 * kernel writes to the pipe.
     1234 +                 */
     1235 +
     1236 +                sendsize = sdd->dedup ? B_FALSE : sdd->sendsize;
     1237 +
1171 1238                  err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
1172      -                    fromorigin, sdd->outfd, sdd->debugnv);
     1239 +                    fromorigin, sdd->outfd, sdd->debugnv,
     1240 +                    sendsize, &sendcounter);
1173 1241  
1174      -                if (sdd->progress) {
     1242 +                sdd->send_sz += sendcounter;
     1243 +
     1244 +                if (track_progress) {
1175 1245                          (void) pthread_cancel(tid);
1176 1246                          (void) pthread_join(tid, NULL);
1177 1247                  }
1178 1248          }
1179 1249  
1180 1250          (void) strcpy(sdd->prevsnap, thissnap);
1181 1251          sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
1182 1252          zfs_close(zhp);
1183 1253          return (err);
1184 1254  }
↓ open down ↓ 222 lines elided ↑ open up ↑
1407 1477                  featureflags |= (DMU_BACKUP_FEATURE_DEDUP |
1408 1478                      DMU_BACKUP_FEATURE_DEDUPPROPS);
1409 1479                  if (err = pipe(pipefd)) {
1410 1480                          zfs_error_aux(zhp->zfs_hdl, strerror(errno));
1411 1481                          return (zfs_error(zhp->zfs_hdl, EZFS_PIPEFAILED,
1412 1482                              errbuf));
1413 1483                  }
1414 1484                  dda.outputfd = outfd;
1415 1485                  dda.inputfd = pipefd[1];
1416 1486                  dda.dedup_hdl = zhp->zfs_hdl;
     1487 +                dda.sendsize = flags->sendsize;
1417 1488                  if (err = pthread_create(&tid, NULL, cksummer, &dda)) {
1418 1489                          (void) close(pipefd[0]);
1419 1490                          (void) close(pipefd[1]);
1420 1491                          zfs_error_aux(zhp->zfs_hdl, strerror(errno));
1421 1492                          return (zfs_error(zhp->zfs_hdl,
1422 1493                              EZFS_THREADCREATEFAILED, errbuf));
1423 1494                  }
1424 1495          }
1425 1496  
1426 1497          if (flags->replicate || flags->doall || flags->props) {
↓ open down ↓ 40 lines elided ↑ open up ↑
1467 1538                          drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
1468 1539                          DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.
1469 1540                              drr_versioninfo, DMU_COMPOUNDSTREAM);
1470 1541                          DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.
1471 1542                              drr_versioninfo, featureflags);
1472 1543                          (void) snprintf(drr.drr_u.drr_begin.drr_toname,
1473 1544                              sizeof (drr.drr_u.drr_begin.drr_toname),
1474 1545                              "%s@%s", zhp->zfs_name, tosnap);
1475 1546                          drr.drr_payloadlen = buflen;
1476 1547                          err = cksum_and_write(&drr, sizeof (drr), &zc, outfd);
     1548 +                        sdd.hdr_send_sz += sizeof (drr);
1477 1549  
1478 1550                          /* write header nvlist */
1479 1551                          if (err != -1 && packbuf != NULL) {
1480 1552                                  err = cksum_and_write(packbuf, buflen, &zc,
1481 1553                                      outfd);
     1554 +                                sdd.hdr_send_sz += buflen;
1482 1555                          }
1483 1556                          free(packbuf);
1484 1557                          if (err == -1) {
1485 1558                                  fsavl_destroy(fsavl);
1486 1559                                  nvlist_free(fss);
1487 1560                                  err = errno;
1488 1561                                  goto stderr_out;
1489 1562                          }
1490 1563  
1491 1564                          /* write end record */
1492 1565                          bzero(&drr, sizeof (drr));
1493 1566                          drr.drr_type = DRR_END;
1494 1567                          drr.drr_u.drr_end.drr_checksum = zc;
1495 1568                          err = write(outfd, &drr, sizeof (drr));
     1569 +                        sdd.hdr_send_sz += sizeof (drr);
1496 1570                          if (err == -1) {
1497 1571                                  fsavl_destroy(fsavl);
1498 1572                                  nvlist_free(fss);
1499 1573                                  err = errno;
1500 1574                                  goto stderr_out;
1501 1575                          }
1502 1576  
1503 1577                          err = 0;
1504 1578                  }
1505 1579          }
↓ open down ↓ 4 lines elided ↑ open up ↑
1510 1584          if (flags->dedup)
1511 1585                  sdd.outfd = pipefd[0];
1512 1586          else
1513 1587                  sdd.outfd = outfd;
1514 1588          sdd.replicate = flags->replicate;
1515 1589          sdd.doall = flags->doall;
1516 1590          sdd.fromorigin = flags->fromorigin;
1517 1591          sdd.fss = fss;
1518 1592          sdd.fsavl = fsavl;
1519 1593          sdd.verbose = flags->verbose;
     1594 +        sdd.dedup = flags->dedup;
     1595 +        sdd.sendsize = flags->sendsize;
1520 1596          sdd.parsable = flags->parsable;
1521 1597          sdd.progress = flags->progress;
1522 1598          sdd.dryrun = flags->dryrun;
1523 1599          sdd.filter_cb = filter_func;
1524 1600          sdd.filter_cb_arg = cb_arg;
1525 1601          if (debugnvp)
1526 1602                  sdd.debugnv = *debugnvp;
1527 1603  
1528 1604          /*
1529 1605           * Some flags require that we place user holds on the datasets that are
↓ open down ↓ 10 lines elided ↑ open up ↑
1540 1616                  (void) snprintf(sdd.holdtag, sizeof (sdd.holdtag),
1541 1617                      ".send-%d-%llu", getpid(), (u_longlong_t)holdseq);
1542 1618                  sdd.cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
1543 1619                  if (sdd.cleanup_fd < 0) {
1544 1620                          err = errno;
1545 1621                          goto stderr_out;
1546 1622                  }
1547 1623          } else {
1548 1624                  sdd.cleanup_fd = -1;
1549 1625          }
1550      -        if (flags->verbose) {
     1626 +        if (flags->verbose && !flags->sendsize) {
1551 1627                  /*
1552 1628                   * Do a verbose no-op dry run to get all the verbose output
1553 1629                   * before generating any data.  Then do a non-verbose real
1554 1630                   * run to generate the streams.
1555 1631                   */
1556 1632                  sdd.dryrun = B_TRUE;
1557 1633                  err = dump_filesystems(zhp, &sdd);
1558 1634                  sdd.dryrun = flags->dryrun;
1559 1635                  sdd.verbose = B_FALSE;
1560 1636                  if (flags->parsable) {
↓ open down ↓ 6 lines elided ↑ open up ↑
1567 1643                              "total estimated size is %s\n"), buf);
1568 1644                  }
1569 1645          }
1570 1646          err = dump_filesystems(zhp, &sdd);
1571 1647          fsavl_destroy(fsavl);
1572 1648          nvlist_free(fss);
1573 1649  
1574 1650          if (flags->dedup) {
1575 1651                  (void) close(pipefd[0]);
1576 1652                  (void) pthread_join(tid, NULL);
     1653 +                sdd.send_sz = dda.dedup_data_sz;
1577 1654          }
1578 1655  
1579 1656          if (sdd.cleanup_fd != -1) {
1580 1657                  VERIFY(0 == close(sdd.cleanup_fd));
1581 1658                  sdd.cleanup_fd = -1;
1582 1659          }
1583 1660  
1584 1661          if (!flags->dryrun && (flags->replicate || flags->doall ||
1585 1662              flags->props)) {
1586 1663                  /*
1587 1664                   * write final end record.  NB: want to do this even if
1588 1665                   * there was some error, because it might not be totally
1589 1666                   * failed.
1590 1667                   */
1591 1668                  dmu_replay_record_t drr = { 0 };
1592 1669                  drr.drr_type = DRR_END;
1593 1670                  if (write(outfd, &drr, sizeof (drr)) == -1) {
1594 1671                          return (zfs_standard_error(zhp->zfs_hdl,
1595 1672                              errno, errbuf));
1596 1673                  }
     1674 +                sdd.hdr_send_sz += sizeof (drr);
1597 1675          }
     1676 +
     1677 +        if (flags->sendsize) {
     1678 +                if (flags->verbose) {
     1679 +                        fprintf(stderr, "Send stream header size (bytes): "
     1680 +                            "%u\n", sdd.hdr_send_sz);
     1681 +                        fprintf(stderr, "Send stream data size (bytes):  "
     1682 +                            "%llu\n", sdd.send_sz);
     1683 +                        fprintf(stderr, "Total send stream size (bytes):  "
     1684 +                            "%llu\n", sdd.send_sz + (uint64_t)sdd.hdr_send_sz);
     1685 +                } else {
     1686 +                        fprintf(stderr, "Total send stream size (bytes):  "
     1687 +                            "%llu\n", sdd.send_sz + (uint64_t)sdd.hdr_send_sz);
     1688 +                }
     1689 +        }
1598 1690  
1599 1691          return (err || sdd.err);
1600 1692  
1601 1693  stderr_out:
1602 1694          err = zfs_standard_error(zhp->zfs_hdl, err, errbuf);
1603 1695  err_out:
1604 1696          if (sdd.cleanup_fd != -1)
1605 1697                  VERIFY(0 == close(sdd.cleanup_fd));
1606 1698          if (flags->dedup) {
1607 1699                  (void) pthread_cancel(tid);
↓ open down ↓ 1592 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX