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.

@@ -170,10 +170,11 @@
 #include <sys/zfs_onexit.h>
 #include <sys/zvol.h>
 #include <sys/dsl_scan.h>
 #include <sharefs/share.h>
 #include <sys/dmu_objset.h>
+#include <sys/far.h>
 
 #include "zfs_namecheck.h"
 #include "zfs_prop.h"
 #include "zfs_deleg.h"
 #include "zfs_comutil.h"

@@ -4040,12 +4041,13 @@
  * zc_name      name of snapshot to send
  * zc_cookie    file descriptor to send stream to
  * zc_obj       fromorigin flag (mutually exclusive with zc_fromobj)
  * zc_sendobj   objsetid of snapshot to send
  * zc_fromobj   objsetid of incremental fromsnap (may be zero)
- * zc_guid      if set, estimate size of stream only.  zc_cookie is ignored.
- *              output size in zc_objset_type.
+ * zc_guid      bit 0: if set, estimate size of stream only. zc_cookie is
+ *              ignored. output size in zc_objset_type.
+ * zc_guid      bit 1: if set, send output in FAR-format
  *
  * outputs: none
  */
 static int
 zfs_ioc_send(zfs_cmd_t *zc)

@@ -4056,11 +4058,12 @@
         offset_t off;
         dsl_dataset_t *ds;
         dsl_dataset_t *dsfrom = NULL;
         spa_t *spa;
         dsl_pool_t *dp;
-        boolean_t estimate = (zc->zc_guid != 0);
+        boolean_t estimate = ((zc->zc_guid & 1) != 0);
+        boolean_t far = ((zc->zc_guid & 2) != 0);
 
         error = spa_open(zc->zc_name, &spa, FTAG);
         if (error)
                 return (error);
 

@@ -4132,12 +4135,16 @@
                                 dsl_dataset_rele(dsfrom, FTAG);
                         return (EBADF);
                 }
 
                 off = fp->f_offset;
+                if (!far)
                 error = dmu_send(tosnap, fromsnap,
                     zc->zc_cookie, fp->f_vnode, &off);
+                else
+                        error = far_send(tosnap, fromsnap,
+                            zc->zc_cookie, fp->f_vnode, &off);
 
                 if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
                         fp->f_offset = off;
                 releasef(zc->zc_cookie);
         }

@@ -5090,15 +5097,20 @@
         objset_t *tosnap;
         int error;
         offset_t off;
         char *fromname;
         int fd;
+        int far;
 
         error = nvlist_lookup_int32(innvl, "fd", &fd);
         if (error != 0)
                 return (EINVAL);
 
+        error = nvlist_lookup_int32(innvl, "far", &far);
+        if (error != 0 && error != ENOENT)
+                return (EINVAL);
+
         error = dmu_objset_hold(snapname, FTAG, &tosnap);
         if (error)
                 return (error);
 
         error = nvlist_lookup_string(innvl, "fromsnap", &fromname);

@@ -5117,11 +5129,14 @@
                         dmu_objset_rele(fromsnap, FTAG);
                 return (EBADF);
         }
 
         off = fp->f_offset;
+        if (!far)
         error = dmu_send(tosnap, fromsnap, fd, fp->f_vnode, &off);
+        else
+                error = far_send(tosnap, fromsnap, fd, fp->f_vnode, &off);
 
         if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
                 fp->f_offset = off;
         releasef(fd);
         if (fromsnap != NULL)