Print this page
FAR: generating send-streams in portable format
This commit adds a switch '-F' to  zfs send. This set, zfs send generates
a stream in FAR-format instead of the traditional zfs stream format. The
generated send stream is compatible with the stream generated from 'btrfs send'
and can in principle easily be received to any filesystem.

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 ↓ 781 lines elided ↑ open up ↑
 782  782  /*
 783  783   * Routines specific to "zfs send"
 784  784   */
 785  785  typedef struct send_dump_data {
 786  786          /* these are all just the short snapname (the part after the @) */
 787  787          const char *fromsnap;
 788  788          const char *tosnap;
 789  789          char prevsnap[ZFS_MAXNAMELEN];
 790  790          uint64_t prevsnap_obj;
 791  791          boolean_t seenfrom, seento, replicate, doall, fromorigin;
 792      -        boolean_t verbose, dryrun, parsable, progress;
      792 +        boolean_t verbose, dryrun, parsable, progress, far;
 793  793          int outfd;
 794  794          boolean_t err;
 795  795          nvlist_t *fss;
 796  796          avl_tree_t *fsavl;
 797  797          snapfilter_cb_t *filter_cb;
 798  798          void *filter_cb_arg;
 799  799          nvlist_t *debugnv;
 800  800          char holdtag[ZFS_MAXNAMELEN];
 801  801          int cleanup_fd;
 802  802          uint64_t size;
↓ open down ↓ 58 lines elided ↑ open up ↑
 861  861  
 862  862          return (0);
 863  863  }
 864  864  
 865  865  /*
 866  866   * Dumps a backup of the given snapshot (incremental from fromsnap if it's not
 867  867   * NULL) to the file descriptor specified by outfd.
 868  868   */
 869  869  static int
 870  870  dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
 871      -    boolean_t fromorigin, int outfd, nvlist_t *debugnv)
      871 +    boolean_t fromorigin, int outfd, int far, nvlist_t *debugnv)
 872  872  {
 873  873          zfs_cmd_t zc = { 0 };
 874  874          libzfs_handle_t *hdl = zhp->zfs_hdl;
 875  875          nvlist_t *thisdbg;
 876  876  
 877  877          assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
 878  878          assert(fromsnap_obj == 0 || !fromorigin);
 879  879  
 880  880          (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 881  881          zc.zc_cookie = outfd;
 882  882          zc.zc_obj = fromorigin;
 883  883          zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
 884  884          zc.zc_fromobj = fromsnap_obj;
      885 +        zc.zc_guid = far ? 2 : 0;
 885  886  
 886  887          VERIFY(0 == nvlist_alloc(&thisdbg, NV_UNIQUE_NAME, 0));
 887  888          if (fromsnap && fromsnap[0] != '\0') {
 888  889                  VERIFY(0 == nvlist_add_string(thisdbg,
 889  890                      "fromsnap", fromsnap));
 890  891          }
 891  892  
 892  893          if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
 893  894                  char errbuf[1024];
 894  895                  (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
↓ open down ↓ 267 lines elided ↑ open up ↑
1162 1163                          pa.pa_parsable = sdd->parsable;
1163 1164  
1164 1165                          if (err = pthread_create(&tid, NULL,
1165 1166                              send_progress_thread, &pa)) {
1166 1167                                  zfs_close(zhp);
1167 1168                                  return (err);
1168 1169                          }
1169 1170                  }
1170 1171  
1171 1172                  err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
1172      -                    fromorigin, sdd->outfd, sdd->debugnv);
     1173 +                    fromorigin, sdd->outfd, sdd->far, sdd->debugnv);
1173 1174  
1174 1175                  if (sdd->progress) {
1175 1176                          (void) pthread_cancel(tid);
1176 1177                          (void) pthread_join(tid, NULL);
1177 1178                  }
1178 1179          }
1179 1180  
1180 1181          (void) strcpy(sdd->prevsnap, thissnap);
1181 1182          sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
1182 1183          zfs_close(zhp);
↓ open down ↓ 271 lines elided ↑ open up ↑
1454 1455                                  *debugnvp = hdrnv;
1455 1456                          else
1456 1457                                  nvlist_free(hdrnv);
1457 1458                          if (err) {
1458 1459                                  fsavl_destroy(fsavl);
1459 1460                                  nvlist_free(fss);
1460 1461                                  goto stderr_out;
1461 1462                          }
1462 1463                  }
1463 1464  
1464      -                if (!flags->dryrun) {
     1465 +                if (!flags->dryrun && !flags->far) {
1465 1466                          /* write first begin record */
1466 1467                          drr.drr_type = DRR_BEGIN;
1467 1468                          drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
1468 1469                          DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.
1469 1470                              drr_versioninfo, DMU_COMPOUNDSTREAM);
1470 1471                          DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.
1471 1472                              drr_versioninfo, featureflags);
1472 1473                          (void) snprintf(drr.drr_u.drr_begin.drr_toname,
1473 1474                              sizeof (drr.drr_u.drr_begin.drr_toname),
1474 1475                              "%s@%s", zhp->zfs_name, tosnap);
↓ open down ↓ 38 lines elided ↑ open up ↑
1513 1514                  sdd.outfd = outfd;
1514 1515          sdd.replicate = flags->replicate;
1515 1516          sdd.doall = flags->doall;
1516 1517          sdd.fromorigin = flags->fromorigin;
1517 1518          sdd.fss = fss;
1518 1519          sdd.fsavl = fsavl;
1519 1520          sdd.verbose = flags->verbose;
1520 1521          sdd.parsable = flags->parsable;
1521 1522          sdd.progress = flags->progress;
1522 1523          sdd.dryrun = flags->dryrun;
     1524 +        sdd.far = flags->far;
1523 1525          sdd.filter_cb = filter_func;
1524 1526          sdd.filter_cb_arg = cb_arg;
1525 1527          if (debugnvp)
1526 1528                  sdd.debugnv = *debugnvp;
1527 1529  
1528 1530          /*
1529 1531           * Some flags require that we place user holds on the datasets that are
1530 1532           * being sent so they don't get destroyed during the send. We can skip
1531 1533           * this step if the pool is imported read-only since the datasets cannot
1532 1534           * be destroyed.
↓ open down ↓ 41 lines elided ↑ open up ↑
1574 1576          if (flags->dedup) {
1575 1577                  (void) close(pipefd[0]);
1576 1578                  (void) pthread_join(tid, NULL);
1577 1579          }
1578 1580  
1579 1581          if (sdd.cleanup_fd != -1) {
1580 1582                  VERIFY(0 == close(sdd.cleanup_fd));
1581 1583                  sdd.cleanup_fd = -1;
1582 1584          }
1583 1585  
1584      -        if (!flags->dryrun && (flags->replicate || flags->doall ||
1585      -            flags->props)) {
     1586 +        if (!flags->dryrun && !flags->far &&
     1587 +            (flags->replicate || flags->doall || flags->props)) {
1586 1588                  /*
1587 1589                   * write final end record.  NB: want to do this even if
1588 1590                   * there was some error, because it might not be totally
1589 1591                   * failed.
1590 1592                   */
1591 1593                  dmu_replay_record_t drr = { 0 };
1592 1594                  drr.drr_type = DRR_END;
1593 1595                  if (write(outfd, &drr, sizeof (drr)) == -1) {
1594 1596                          return (zfs_standard_error(zhp->zfs_hdl,
1595 1597                              errno, errbuf));
↓ open down ↓ 1604 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX