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.


 155 #include <sys/dsl_deleg.h>
 156 #include <sys/dmu_objset.h>
 157 #include <sys/dmu_impl.h>
 158 #include <sys/ddi.h>
 159 #include <sys/sunddi.h>
 160 #include <sys/sunldi.h>
 161 #include <sys/policy.h>
 162 #include <sys/zone.h>
 163 #include <sys/nvpair.h>
 164 #include <sys/pathname.h>
 165 #include <sys/mount.h>
 166 #include <sys/sdt.h>
 167 #include <sys/fs/zfs.h>
 168 #include <sys/zfs_ctldir.h>
 169 #include <sys/zfs_dir.h>
 170 #include <sys/zfs_onexit.h>
 171 #include <sys/zvol.h>
 172 #include <sys/dsl_scan.h>
 173 #include <sharefs/share.h>
 174 #include <sys/dmu_objset.h>

 175 
 176 #include "zfs_namecheck.h"
 177 #include "zfs_prop.h"
 178 #include "zfs_deleg.h"
 179 #include "zfs_comutil.h"
 180 
 181 extern struct modlfs zfs_modlfs;
 182 
 183 extern void zfs_init(void);
 184 extern void zfs_fini(void);
 185 
 186 ldi_ident_t zfs_li = NULL;
 187 dev_info_t *zfs_dip;
 188 
 189 uint_t zfs_fsyncer_key;
 190 extern uint_t rrw_tsd_key;
 191 static uint_t zfs_allow_log_key;
 192 
 193 typedef int zfs_ioc_legacy_func_t(zfs_cmd_t *);
 194 typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *);


4025         }
4026 out:
4027         nvlist_free(props);
4028         nvlist_free(origprops);
4029         nvlist_free(errors);
4030         releasef(fd);
4031 
4032         if (error == 0)
4033                 error = props_error;
4034 
4035         return (error);
4036 }
4037 
4038 /*
4039  * inputs:
4040  * zc_name      name of snapshot to send
4041  * zc_cookie    file descriptor to send stream to
4042  * zc_obj       fromorigin flag (mutually exclusive with zc_fromobj)
4043  * zc_sendobj   objsetid of snapshot to send
4044  * zc_fromobj   objsetid of incremental fromsnap (may be zero)
4045  * zc_guid      if set, estimate size of stream only.  zc_cookie is ignored.
4046  *              output size in zc_objset_type.

4047  *
4048  * outputs: none
4049  */
4050 static int
4051 zfs_ioc_send(zfs_cmd_t *zc)
4052 {
4053         objset_t *fromsnap = NULL;
4054         objset_t *tosnap;
4055         int error;
4056         offset_t off;
4057         dsl_dataset_t *ds;
4058         dsl_dataset_t *dsfrom = NULL;
4059         spa_t *spa;
4060         dsl_pool_t *dp;
4061         boolean_t estimate = (zc->zc_guid != 0);

4062 
4063         error = spa_open(zc->zc_name, &spa, FTAG);
4064         if (error)
4065                 return (error);
4066 
4067         dp = spa_get_dsl(spa);
4068         rw_enter(&dp->dp_config_rwlock, RW_READER);
4069         error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds);
4070         rw_exit(&dp->dp_config_rwlock);
4071         spa_close(spa, FTAG);
4072         if (error)
4073                 return (error);
4074 
4075         error = dmu_objset_from_ds(ds, &tosnap);
4076         if (error) {
4077                 dsl_dataset_rele(ds, FTAG);
4078                 return (error);
4079         }
4080 
4081         if (zc->zc_fromobj != 0) {


4117                                 dsl_dataset_rele(dsfrom, FTAG);
4118                                 dsl_dataset_rele(ds, FTAG);
4119                                 return (error);
4120                         }
4121                 }
4122         }
4123 
4124         if (estimate) {
4125                 error = dmu_send_estimate(tosnap, fromsnap,
4126                     &zc->zc_objset_type);
4127         } else {
4128                 file_t *fp = getf(zc->zc_cookie);
4129                 if (fp == NULL) {
4130                         dsl_dataset_rele(ds, FTAG);
4131                         if (dsfrom)
4132                                 dsl_dataset_rele(dsfrom, FTAG);
4133                         return (EBADF);
4134                 }
4135 
4136                 off = fp->f_offset;

4137                 error = dmu_send(tosnap, fromsnap,
4138                     zc->zc_cookie, fp->f_vnode, &off);



4139 
4140                 if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
4141                         fp->f_offset = off;
4142                 releasef(zc->zc_cookie);
4143         }
4144         if (dsfrom)
4145                 dsl_dataset_rele(dsfrom, FTAG);
4146         dsl_dataset_rele(ds, FTAG);
4147         return (error);
4148 }
4149 
4150 /*
4151  * inputs:
4152  * zc_name      name of snapshot on which to report progress
4153  * zc_cookie    file descriptor of send stream
4154  *
4155  * outputs:
4156  * zc_cookie    number of bytes written in send stream thus far
4157  */
4158 static int


5075 }
5076 
5077 /*
5078  * innvl: {
5079  *     "fd" -> file descriptor to write stream to (int32)
5080  *     (optional) "fromsnap" -> full snap name to send an incremental from
5081  * }
5082  *
5083  * outnvl is unused
5084  */
5085 /* ARGSUSED */
5086 static int
5087 zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
5088 {
5089         objset_t *fromsnap = NULL;
5090         objset_t *tosnap;
5091         int error;
5092         offset_t off;
5093         char *fromname;
5094         int fd;

5095 
5096         error = nvlist_lookup_int32(innvl, "fd", &fd);
5097         if (error != 0)
5098                 return (EINVAL);
5099 




5100         error = dmu_objset_hold(snapname, FTAG, &tosnap);
5101         if (error)
5102                 return (error);
5103 
5104         error = nvlist_lookup_string(innvl, "fromsnap", &fromname);
5105         if (error == 0) {
5106                 error = dmu_objset_hold(fromname, FTAG, &fromsnap);
5107                 if (error) {
5108                         dmu_objset_rele(tosnap, FTAG);
5109                         return (error);
5110                 }
5111         }
5112 
5113         file_t *fp = getf(fd);
5114         if (fp == NULL) {
5115                 dmu_objset_rele(tosnap, FTAG);
5116                 if (fromsnap != NULL)
5117                         dmu_objset_rele(fromsnap, FTAG);
5118                 return (EBADF);
5119         }
5120 
5121         off = fp->f_offset;

5122         error = dmu_send(tosnap, fromsnap, fd, fp->f_vnode, &off);


5123 
5124         if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
5125                 fp->f_offset = off;
5126         releasef(fd);
5127         if (fromsnap != NULL)
5128                 dmu_objset_rele(fromsnap, FTAG);
5129         dmu_objset_rele(tosnap, FTAG);
5130         return (error);
5131 }
5132 
5133 /*
5134  * Determine approximately how large a zfs send stream will be -- the number
5135  * of bytes that will be written to the fd supplied to zfs_ioc_send_new().
5136  *
5137  * innvl: {
5138  *     (optional) "fromsnap" -> full snap name to send an incremental from
5139  * }
5140  *
5141  * outnvl: {
5142  *     "space" -> bytes of space (uint64)




 155 #include <sys/dsl_deleg.h>
 156 #include <sys/dmu_objset.h>
 157 #include <sys/dmu_impl.h>
 158 #include <sys/ddi.h>
 159 #include <sys/sunddi.h>
 160 #include <sys/sunldi.h>
 161 #include <sys/policy.h>
 162 #include <sys/zone.h>
 163 #include <sys/nvpair.h>
 164 #include <sys/pathname.h>
 165 #include <sys/mount.h>
 166 #include <sys/sdt.h>
 167 #include <sys/fs/zfs.h>
 168 #include <sys/zfs_ctldir.h>
 169 #include <sys/zfs_dir.h>
 170 #include <sys/zfs_onexit.h>
 171 #include <sys/zvol.h>
 172 #include <sys/dsl_scan.h>
 173 #include <sharefs/share.h>
 174 #include <sys/dmu_objset.h>
 175 #include <sys/far.h>
 176 
 177 #include "zfs_namecheck.h"
 178 #include "zfs_prop.h"
 179 #include "zfs_deleg.h"
 180 #include "zfs_comutil.h"
 181 
 182 extern struct modlfs zfs_modlfs;
 183 
 184 extern void zfs_init(void);
 185 extern void zfs_fini(void);
 186 
 187 ldi_ident_t zfs_li = NULL;
 188 dev_info_t *zfs_dip;
 189 
 190 uint_t zfs_fsyncer_key;
 191 extern uint_t rrw_tsd_key;
 192 static uint_t zfs_allow_log_key;
 193 
 194 typedef int zfs_ioc_legacy_func_t(zfs_cmd_t *);
 195 typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *);


4026         }
4027 out:
4028         nvlist_free(props);
4029         nvlist_free(origprops);
4030         nvlist_free(errors);
4031         releasef(fd);
4032 
4033         if (error == 0)
4034                 error = props_error;
4035 
4036         return (error);
4037 }
4038 
4039 /*
4040  * inputs:
4041  * zc_name      name of snapshot to send
4042  * zc_cookie    file descriptor to send stream to
4043  * zc_obj       fromorigin flag (mutually exclusive with zc_fromobj)
4044  * zc_sendobj   objsetid of snapshot to send
4045  * zc_fromobj   objsetid of incremental fromsnap (may be zero)
4046  * zc_guid      bit 0: if set, estimate size of stream only. zc_cookie is
4047  *              ignored. output size in zc_objset_type.
4048  * zc_guid      bit 1: if set, send output in FAR-format
4049  *
4050  * outputs: none
4051  */
4052 static int
4053 zfs_ioc_send(zfs_cmd_t *zc)
4054 {
4055         objset_t *fromsnap = NULL;
4056         objset_t *tosnap;
4057         int error;
4058         offset_t off;
4059         dsl_dataset_t *ds;
4060         dsl_dataset_t *dsfrom = NULL;
4061         spa_t *spa;
4062         dsl_pool_t *dp;
4063         boolean_t estimate = ((zc->zc_guid & 1) != 0);
4064         boolean_t far = ((zc->zc_guid & 2) != 0);
4065 
4066         error = spa_open(zc->zc_name, &spa, FTAG);
4067         if (error)
4068                 return (error);
4069 
4070         dp = spa_get_dsl(spa);
4071         rw_enter(&dp->dp_config_rwlock, RW_READER);
4072         error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds);
4073         rw_exit(&dp->dp_config_rwlock);
4074         spa_close(spa, FTAG);
4075         if (error)
4076                 return (error);
4077 
4078         error = dmu_objset_from_ds(ds, &tosnap);
4079         if (error) {
4080                 dsl_dataset_rele(ds, FTAG);
4081                 return (error);
4082         }
4083 
4084         if (zc->zc_fromobj != 0) {


4120                                 dsl_dataset_rele(dsfrom, FTAG);
4121                                 dsl_dataset_rele(ds, FTAG);
4122                                 return (error);
4123                         }
4124                 }
4125         }
4126 
4127         if (estimate) {
4128                 error = dmu_send_estimate(tosnap, fromsnap,
4129                     &zc->zc_objset_type);
4130         } else {
4131                 file_t *fp = getf(zc->zc_cookie);
4132                 if (fp == NULL) {
4133                         dsl_dataset_rele(ds, FTAG);
4134                         if (dsfrom)
4135                                 dsl_dataset_rele(dsfrom, FTAG);
4136                         return (EBADF);
4137                 }
4138 
4139                 off = fp->f_offset;
4140                 if (!far)
4141                         error = dmu_send(tosnap, fromsnap,
4142                             zc->zc_cookie, fp->f_vnode, &off);
4143                 else
4144                         error = far_send(tosnap, fromsnap,
4145                             zc->zc_cookie, fp->f_vnode, &off);
4146 
4147                 if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
4148                         fp->f_offset = off;
4149                 releasef(zc->zc_cookie);
4150         }
4151         if (dsfrom)
4152                 dsl_dataset_rele(dsfrom, FTAG);
4153         dsl_dataset_rele(ds, FTAG);
4154         return (error);
4155 }
4156 
4157 /*
4158  * inputs:
4159  * zc_name      name of snapshot on which to report progress
4160  * zc_cookie    file descriptor of send stream
4161  *
4162  * outputs:
4163  * zc_cookie    number of bytes written in send stream thus far
4164  */
4165 static int


5082 }
5083 
5084 /*
5085  * innvl: {
5086  *     "fd" -> file descriptor to write stream to (int32)
5087  *     (optional) "fromsnap" -> full snap name to send an incremental from
5088  * }
5089  *
5090  * outnvl is unused
5091  */
5092 /* ARGSUSED */
5093 static int
5094 zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
5095 {
5096         objset_t *fromsnap = NULL;
5097         objset_t *tosnap;
5098         int error;
5099         offset_t off;
5100         char *fromname;
5101         int fd;
5102         int far;
5103 
5104         error = nvlist_lookup_int32(innvl, "fd", &fd);
5105         if (error != 0)
5106                 return (EINVAL);
5107 
5108         error = nvlist_lookup_int32(innvl, "far", &far);
5109         if (error != 0 && error != ENOENT)
5110                 return (EINVAL);
5111 
5112         error = dmu_objset_hold(snapname, FTAG, &tosnap);
5113         if (error)
5114                 return (error);
5115 
5116         error = nvlist_lookup_string(innvl, "fromsnap", &fromname);
5117         if (error == 0) {
5118                 error = dmu_objset_hold(fromname, FTAG, &fromsnap);
5119                 if (error) {
5120                         dmu_objset_rele(tosnap, FTAG);
5121                         return (error);
5122                 }
5123         }
5124 
5125         file_t *fp = getf(fd);
5126         if (fp == NULL) {
5127                 dmu_objset_rele(tosnap, FTAG);
5128                 if (fromsnap != NULL)
5129                         dmu_objset_rele(fromsnap, FTAG);
5130                 return (EBADF);
5131         }
5132 
5133         off = fp->f_offset;
5134         if (!far)
5135                 error = dmu_send(tosnap, fromsnap, fd, fp->f_vnode, &off);
5136         else
5137                 error = far_send(tosnap, fromsnap, fd, fp->f_vnode, &off);
5138 
5139         if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
5140                 fp->f_offset = off;
5141         releasef(fd);
5142         if (fromsnap != NULL)
5143                 dmu_objset_rele(fromsnap, FTAG);
5144         dmu_objset_rele(tosnap, FTAG);
5145         return (error);
5146 }
5147 
5148 /*
5149  * Determine approximately how large a zfs send stream will be -- the number
5150  * of bytes that will be written to the fd supplied to zfs_ioc_send_new().
5151  *
5152  * innvl: {
5153  *     (optional) "fromsnap" -> full snap name to send an incremental from
5154  * }
5155  *
5156  * outnvl: {
5157  *     "space" -> bytes of space (uint64)