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.


 772         if (avlp != NULL && (*avlp = fsavl_create(sd.fss)) == NULL) {
 773                 nvlist_free(sd.fss);
 774                 *nvlp = NULL;
 775                 return (EZFS_NOMEM);
 776         }
 777 
 778         *nvlp = sd.fss;
 779         return (0);
 780 }
 781 
 782 /*
 783  * Routines specific to "zfs send"
 784  */
 785 typedef struct send_dump_data {
 786         /* these are all just the short snapname (the part after the @) */
 787         const char *fromsnap;
 788         const char *tosnap;
 789         char prevsnap[ZFS_MAXNAMELEN];
 790         uint64_t prevsnap_obj;
 791         boolean_t seenfrom, seento, replicate, doall, fromorigin;
 792         boolean_t verbose, dryrun, parsable, progress;
 793         int outfd;
 794         boolean_t err;
 795         nvlist_t *fss;
 796         avl_tree_t *fsavl;
 797         snapfilter_cb_t *filter_cb;
 798         void *filter_cb_arg;
 799         nvlist_t *debugnv;
 800         char holdtag[ZFS_MAXNAMELEN];
 801         int cleanup_fd;
 802         uint64_t size;
 803 } send_dump_data_t;
 804 
 805 static int
 806 estimate_ioctl(zfs_handle_t *zhp, uint64_t fromsnap_obj,
 807     boolean_t fromorigin, uint64_t *sizep)
 808 {
 809         zfs_cmd_t zc = { 0 };
 810         libzfs_handle_t *hdl = zhp->zfs_hdl;
 811 
 812         assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);


 851                 case EROFS:
 852                         zfs_error_aux(hdl, strerror(errno));
 853                         return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
 854 
 855                 default:
 856                         return (zfs_standard_error(hdl, errno, errbuf));
 857                 }
 858         }
 859 
 860         *sizep = zc.zc_objset_type;
 861 
 862         return (0);
 863 }
 864 
 865 /*
 866  * Dumps a backup of the given snapshot (incremental from fromsnap if it's not
 867  * NULL) to the file descriptor specified by outfd.
 868  */
 869 static int
 870 dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
 871     boolean_t fromorigin, int outfd, nvlist_t *debugnv)
 872 {
 873         zfs_cmd_t zc = { 0 };
 874         libzfs_handle_t *hdl = zhp->zfs_hdl;
 875         nvlist_t *thisdbg;
 876 
 877         assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
 878         assert(fromsnap_obj == 0 || !fromorigin);
 879 
 880         (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 881         zc.zc_cookie = outfd;
 882         zc.zc_obj = fromorigin;
 883         zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
 884         zc.zc_fromobj = fromsnap_obj;

 885 
 886         VERIFY(0 == nvlist_alloc(&thisdbg, NV_UNIQUE_NAME, 0));
 887         if (fromsnap && fromsnap[0] != '\0') {
 888                 VERIFY(0 == nvlist_add_string(thisdbg,
 889                     "fromsnap", fromsnap));
 890         }
 891 
 892         if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
 893                 char errbuf[1024];
 894                 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
 895                     "warning: cannot send '%s'"), zhp->zfs_name);
 896 
 897                 VERIFY(0 == nvlist_add_uint64(thisdbg, "error", errno));
 898                 if (debugnv) {
 899                         VERIFY(0 == nvlist_add_nvlist(debugnv,
 900                             zhp->zfs_name, thisdbg));
 901                 }
 902                 nvlist_free(thisdbg);
 903 
 904                 switch (errno) {


1152         }
1153 
1154         if (!sdd->dryrun) {
1155                 /*
1156                  * If progress reporting is requested, spawn a new thread to
1157                  * poll ZFS_IOC_SEND_PROGRESS at a regular interval.
1158                  */
1159                 if (sdd->progress) {
1160                         pa.pa_zhp = zhp;
1161                         pa.pa_fd = sdd->outfd;
1162                         pa.pa_parsable = sdd->parsable;
1163 
1164                         if (err = pthread_create(&tid, NULL,
1165                             send_progress_thread, &pa)) {
1166                                 zfs_close(zhp);
1167                                 return (err);
1168                         }
1169                 }
1170 
1171                 err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
1172                     fromorigin, sdd->outfd, sdd->debugnv);
1173 
1174                 if (sdd->progress) {
1175                         (void) pthread_cancel(tid);
1176                         (void) pthread_join(tid, NULL);
1177                 }
1178         }
1179 
1180         (void) strcpy(sdd->prevsnap, thissnap);
1181         sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
1182         zfs_close(zhp);
1183         return (err);
1184 }
1185 
1186 static int
1187 dump_filesystem(zfs_handle_t *zhp, void *arg)
1188 {
1189         int rv = 0;
1190         send_dump_data_t *sdd = arg;
1191         boolean_t missingfrom = B_FALSE;
1192         zfs_cmd_t zc = { 0 };


1444                         }
1445 
1446                         err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name,
1447                             fromsnap, tosnap, flags->replicate, &fss, &fsavl);
1448                         if (err)
1449                                 goto err_out;
1450                         VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss));
1451                         err = nvlist_pack(hdrnv, &packbuf, &buflen,
1452                             NV_ENCODE_XDR, 0);
1453                         if (debugnvp)
1454                                 *debugnvp = hdrnv;
1455                         else
1456                                 nvlist_free(hdrnv);
1457                         if (err) {
1458                                 fsavl_destroy(fsavl);
1459                                 nvlist_free(fss);
1460                                 goto stderr_out;
1461                         }
1462                 }
1463 
1464                 if (!flags->dryrun) {
1465                         /* write first begin record */
1466                         drr.drr_type = DRR_BEGIN;
1467                         drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
1468                         DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.
1469                             drr_versioninfo, DMU_COMPOUNDSTREAM);
1470                         DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.
1471                             drr_versioninfo, featureflags);
1472                         (void) snprintf(drr.drr_u.drr_begin.drr_toname,
1473                             sizeof (drr.drr_u.drr_begin.drr_toname),
1474                             "%s@%s", zhp->zfs_name, tosnap);
1475                         drr.drr_payloadlen = buflen;
1476                         err = cksum_and_write(&drr, sizeof (drr), &zc, outfd);
1477 
1478                         /* write header nvlist */
1479                         if (err != -1 && packbuf != NULL) {
1480                                 err = cksum_and_write(packbuf, buflen, &zc,
1481                                     outfd);
1482                         }
1483                         free(packbuf);
1484                         if (err == -1) {


1503                         err = 0;
1504                 }
1505         }
1506 
1507         /* dump each stream */
1508         sdd.fromsnap = fromsnap;
1509         sdd.tosnap = tosnap;
1510         if (flags->dedup)
1511                 sdd.outfd = pipefd[0];
1512         else
1513                 sdd.outfd = outfd;
1514         sdd.replicate = flags->replicate;
1515         sdd.doall = flags->doall;
1516         sdd.fromorigin = flags->fromorigin;
1517         sdd.fss = fss;
1518         sdd.fsavl = fsavl;
1519         sdd.verbose = flags->verbose;
1520         sdd.parsable = flags->parsable;
1521         sdd.progress = flags->progress;
1522         sdd.dryrun = flags->dryrun;

1523         sdd.filter_cb = filter_func;
1524         sdd.filter_cb_arg = cb_arg;
1525         if (debugnvp)
1526                 sdd.debugnv = *debugnvp;
1527 
1528         /*
1529          * Some flags require that we place user holds on the datasets that are
1530          * being sent so they don't get destroyed during the send. We can skip
1531          * this step if the pool is imported read-only since the datasets cannot
1532          * be destroyed.
1533          */
1534         if (!flags->dryrun && !zpool_get_prop_int(zfs_get_pool_handle(zhp),
1535             ZPOOL_PROP_READONLY, NULL) &&
1536             zfs_spa_version(zhp, &spa_version) == 0 &&
1537             spa_version >= SPA_VERSION_USERREFS &&
1538             (flags->doall || flags->replicate)) {
1539                 ++holdseq;
1540                 (void) snprintf(sdd.holdtag, sizeof (sdd.holdtag),
1541                     ".send-%d-%llu", getpid(), (u_longlong_t)holdseq);
1542                 sdd.cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);


1564                         char buf[16];
1565                         zfs_nicenum(sdd.size, buf, sizeof (buf));
1566                         (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1567                             "total estimated size is %s\n"), buf);
1568                 }
1569         }
1570         err = dump_filesystems(zhp, &sdd);
1571         fsavl_destroy(fsavl);
1572         nvlist_free(fss);
1573 
1574         if (flags->dedup) {
1575                 (void) close(pipefd[0]);
1576                 (void) pthread_join(tid, NULL);
1577         }
1578 
1579         if (sdd.cleanup_fd != -1) {
1580                 VERIFY(0 == close(sdd.cleanup_fd));
1581                 sdd.cleanup_fd = -1;
1582         }
1583 
1584         if (!flags->dryrun && (flags->replicate || flags->doall ||
1585             flags->props)) {
1586                 /*
1587                  * write final end record.  NB: want to do this even if
1588                  * there was some error, because it might not be totally
1589                  * failed.
1590                  */
1591                 dmu_replay_record_t drr = { 0 };
1592                 drr.drr_type = DRR_END;
1593                 if (write(outfd, &drr, sizeof (drr)) == -1) {
1594                         return (zfs_standard_error(zhp->zfs_hdl,
1595                             errno, errbuf));
1596                 }
1597         }
1598 
1599         return (err || sdd.err);
1600 
1601 stderr_out:
1602         err = zfs_standard_error(zhp->zfs_hdl, err, errbuf);
1603 err_out:
1604         if (sdd.cleanup_fd != -1)
1605                 VERIFY(0 == close(sdd.cleanup_fd));




 772         if (avlp != NULL && (*avlp = fsavl_create(sd.fss)) == NULL) {
 773                 nvlist_free(sd.fss);
 774                 *nvlp = NULL;
 775                 return (EZFS_NOMEM);
 776         }
 777 
 778         *nvlp = sd.fss;
 779         return (0);
 780 }
 781 
 782 /*
 783  * Routines specific to "zfs send"
 784  */
 785 typedef struct send_dump_data {
 786         /* these are all just the short snapname (the part after the @) */
 787         const char *fromsnap;
 788         const char *tosnap;
 789         char prevsnap[ZFS_MAXNAMELEN];
 790         uint64_t prevsnap_obj;
 791         boolean_t seenfrom, seento, replicate, doall, fromorigin;
 792         boolean_t verbose, dryrun, parsable, progress, far;
 793         int outfd;
 794         boolean_t err;
 795         nvlist_t *fss;
 796         avl_tree_t *fsavl;
 797         snapfilter_cb_t *filter_cb;
 798         void *filter_cb_arg;
 799         nvlist_t *debugnv;
 800         char holdtag[ZFS_MAXNAMELEN];
 801         int cleanup_fd;
 802         uint64_t size;
 803 } send_dump_data_t;
 804 
 805 static int
 806 estimate_ioctl(zfs_handle_t *zhp, uint64_t fromsnap_obj,
 807     boolean_t fromorigin, uint64_t *sizep)
 808 {
 809         zfs_cmd_t zc = { 0 };
 810         libzfs_handle_t *hdl = zhp->zfs_hdl;
 811 
 812         assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);


 851                 case EROFS:
 852                         zfs_error_aux(hdl, strerror(errno));
 853                         return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
 854 
 855                 default:
 856                         return (zfs_standard_error(hdl, errno, errbuf));
 857                 }
 858         }
 859 
 860         *sizep = zc.zc_objset_type;
 861 
 862         return (0);
 863 }
 864 
 865 /*
 866  * Dumps a backup of the given snapshot (incremental from fromsnap if it's not
 867  * NULL) to the file descriptor specified by outfd.
 868  */
 869 static int
 870 dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
 871     boolean_t fromorigin, int outfd, int far, nvlist_t *debugnv)
 872 {
 873         zfs_cmd_t zc = { 0 };
 874         libzfs_handle_t *hdl = zhp->zfs_hdl;
 875         nvlist_t *thisdbg;
 876 
 877         assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
 878         assert(fromsnap_obj == 0 || !fromorigin);
 879 
 880         (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 881         zc.zc_cookie = outfd;
 882         zc.zc_obj = fromorigin;
 883         zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
 884         zc.zc_fromobj = fromsnap_obj;
 885         zc.zc_guid = far ? 2 : 0;
 886 
 887         VERIFY(0 == nvlist_alloc(&thisdbg, NV_UNIQUE_NAME, 0));
 888         if (fromsnap && fromsnap[0] != '\0') {
 889                 VERIFY(0 == nvlist_add_string(thisdbg,
 890                     "fromsnap", fromsnap));
 891         }
 892 
 893         if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
 894                 char errbuf[1024];
 895                 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
 896                     "warning: cannot send '%s'"), zhp->zfs_name);
 897 
 898                 VERIFY(0 == nvlist_add_uint64(thisdbg, "error", errno));
 899                 if (debugnv) {
 900                         VERIFY(0 == nvlist_add_nvlist(debugnv,
 901                             zhp->zfs_name, thisdbg));
 902                 }
 903                 nvlist_free(thisdbg);
 904 
 905                 switch (errno) {


1153         }
1154 
1155         if (!sdd->dryrun) {
1156                 /*
1157                  * If progress reporting is requested, spawn a new thread to
1158                  * poll ZFS_IOC_SEND_PROGRESS at a regular interval.
1159                  */
1160                 if (sdd->progress) {
1161                         pa.pa_zhp = zhp;
1162                         pa.pa_fd = sdd->outfd;
1163                         pa.pa_parsable = sdd->parsable;
1164 
1165                         if (err = pthread_create(&tid, NULL,
1166                             send_progress_thread, &pa)) {
1167                                 zfs_close(zhp);
1168                                 return (err);
1169                         }
1170                 }
1171 
1172                 err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
1173                     fromorigin, sdd->outfd, sdd->far, sdd->debugnv);
1174 
1175                 if (sdd->progress) {
1176                         (void) pthread_cancel(tid);
1177                         (void) pthread_join(tid, NULL);
1178                 }
1179         }
1180 
1181         (void) strcpy(sdd->prevsnap, thissnap);
1182         sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
1183         zfs_close(zhp);
1184         return (err);
1185 }
1186 
1187 static int
1188 dump_filesystem(zfs_handle_t *zhp, void *arg)
1189 {
1190         int rv = 0;
1191         send_dump_data_t *sdd = arg;
1192         boolean_t missingfrom = B_FALSE;
1193         zfs_cmd_t zc = { 0 };


1445                         }
1446 
1447                         err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name,
1448                             fromsnap, tosnap, flags->replicate, &fss, &fsavl);
1449                         if (err)
1450                                 goto err_out;
1451                         VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss));
1452                         err = nvlist_pack(hdrnv, &packbuf, &buflen,
1453                             NV_ENCODE_XDR, 0);
1454                         if (debugnvp)
1455                                 *debugnvp = hdrnv;
1456                         else
1457                                 nvlist_free(hdrnv);
1458                         if (err) {
1459                                 fsavl_destroy(fsavl);
1460                                 nvlist_free(fss);
1461                                 goto stderr_out;
1462                         }
1463                 }
1464 
1465                 if (!flags->dryrun && !flags->far) {
1466                         /* write first begin record */
1467                         drr.drr_type = DRR_BEGIN;
1468                         drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
1469                         DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.
1470                             drr_versioninfo, DMU_COMPOUNDSTREAM);
1471                         DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.
1472                             drr_versioninfo, featureflags);
1473                         (void) snprintf(drr.drr_u.drr_begin.drr_toname,
1474                             sizeof (drr.drr_u.drr_begin.drr_toname),
1475                             "%s@%s", zhp->zfs_name, tosnap);
1476                         drr.drr_payloadlen = buflen;
1477                         err = cksum_and_write(&drr, sizeof (drr), &zc, outfd);
1478 
1479                         /* write header nvlist */
1480                         if (err != -1 && packbuf != NULL) {
1481                                 err = cksum_and_write(packbuf, buflen, &zc,
1482                                     outfd);
1483                         }
1484                         free(packbuf);
1485                         if (err == -1) {


1504                         err = 0;
1505                 }
1506         }
1507 
1508         /* dump each stream */
1509         sdd.fromsnap = fromsnap;
1510         sdd.tosnap = tosnap;
1511         if (flags->dedup)
1512                 sdd.outfd = pipefd[0];
1513         else
1514                 sdd.outfd = outfd;
1515         sdd.replicate = flags->replicate;
1516         sdd.doall = flags->doall;
1517         sdd.fromorigin = flags->fromorigin;
1518         sdd.fss = fss;
1519         sdd.fsavl = fsavl;
1520         sdd.verbose = flags->verbose;
1521         sdd.parsable = flags->parsable;
1522         sdd.progress = flags->progress;
1523         sdd.dryrun = flags->dryrun;
1524         sdd.far = flags->far;
1525         sdd.filter_cb = filter_func;
1526         sdd.filter_cb_arg = cb_arg;
1527         if (debugnvp)
1528                 sdd.debugnv = *debugnvp;
1529 
1530         /*
1531          * Some flags require that we place user holds on the datasets that are
1532          * being sent so they don't get destroyed during the send. We can skip
1533          * this step if the pool is imported read-only since the datasets cannot
1534          * be destroyed.
1535          */
1536         if (!flags->dryrun && !zpool_get_prop_int(zfs_get_pool_handle(zhp),
1537             ZPOOL_PROP_READONLY, NULL) &&
1538             zfs_spa_version(zhp, &spa_version) == 0 &&
1539             spa_version >= SPA_VERSION_USERREFS &&
1540             (flags->doall || flags->replicate)) {
1541                 ++holdseq;
1542                 (void) snprintf(sdd.holdtag, sizeof (sdd.holdtag),
1543                     ".send-%d-%llu", getpid(), (u_longlong_t)holdseq);
1544                 sdd.cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);


1566                         char buf[16];
1567                         zfs_nicenum(sdd.size, buf, sizeof (buf));
1568                         (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1569                             "total estimated size is %s\n"), buf);
1570                 }
1571         }
1572         err = dump_filesystems(zhp, &sdd);
1573         fsavl_destroy(fsavl);
1574         nvlist_free(fss);
1575 
1576         if (flags->dedup) {
1577                 (void) close(pipefd[0]);
1578                 (void) pthread_join(tid, NULL);
1579         }
1580 
1581         if (sdd.cleanup_fd != -1) {
1582                 VERIFY(0 == close(sdd.cleanup_fd));
1583                 sdd.cleanup_fd = -1;
1584         }
1585 
1586         if (!flags->dryrun && !flags->far &&
1587             (flags->replicate || flags->doall || flags->props)) {
1588                 /*
1589                  * write final end record.  NB: want to do this even if
1590                  * there was some error, because it might not be totally
1591                  * failed.
1592                  */
1593                 dmu_replay_record_t drr = { 0 };
1594                 drr.drr_type = DRR_END;
1595                 if (write(outfd, &drr, sizeof (drr)) == -1) {
1596                         return (zfs_standard_error(zhp->zfs_hdl,
1597                             errno, errbuf));
1598                 }
1599         }
1600 
1601         return (err || sdd.err);
1602 
1603 stderr_out:
1604         err = zfs_standard_error(zhp->zfs_hdl, err, errbuf);
1605 err_out:
1606         if (sdd.cleanup_fd != -1)
1607                 VERIFY(0 == close(sdd.cleanup_fd));