52 /* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */ |
53 /* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */ |
53 int zfs_send_corrupt_data = B_FALSE; |
54 int zfs_send_corrupt_data = B_FALSE; |
54 |
55 |
55 static char *dmu_recv_tag = "dmu_recv_tag"; |
56 static char *dmu_recv_tag = "dmu_recv_tag"; |
56 |
57 |
57 /* |
58 static int |
58 * The list of data whose inclusion in a send stream can be pending from |
59 dump_bytes(dmu_sendarg_t *dsp, void *buf, int len) |
59 * one call to backup_cb to another. Multiple calls to dump_free() and |
60 { |
60 * dump_freeobjects() can be aggregated into a single DRR_FREE or |
61 dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset; |
61 * DRR_FREEOBJECTS replay record. |
|
62 */ |
|
63 typedef enum { |
|
64 PENDING_NONE, |
|
65 PENDING_FREE, |
|
66 PENDING_FREEOBJECTS |
|
67 } pendop_t; |
|
68 |
|
69 struct backuparg { |
|
70 dmu_replay_record_t *drr; |
|
71 vnode_t *vp; |
|
72 offset_t *off; |
|
73 objset_t *os; |
|
74 zio_cksum_t zc; |
|
75 uint64_t toguid; |
|
76 int err; |
|
77 pendop_t pending_op; |
|
78 }; |
|
79 |
|
80 static int |
|
81 dump_bytes(struct backuparg *ba, void *buf, int len) |
|
82 { |
|
83 ssize_t resid; /* have to get resid to get detailed errno */ |
62 ssize_t resid; /* have to get resid to get detailed errno */ |
84 ASSERT3U(len % 8, ==, 0); |
63 ASSERT3U(len % 8, ==, 0); |
85 |
64 |
86 fletcher_4_incremental_native(buf, len, &ba->zc); |
65 fletcher_4_incremental_native(buf, len, &dsp->dsa_zc); |
87 ba->err = vn_rdwr(UIO_WRITE, ba->vp, |
66 dsp->dsa_err = vn_rdwr(UIO_WRITE, dsp->dsa_vp, |
88 (caddr_t)buf, len, |
67 (caddr_t)buf, len, |
89 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid); |
68 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid); |
90 *ba->off += len; |
69 |
91 return (ba->err); |
70 mutex_enter(&ds->ds_sendstream_lock); |
92 } |
71 *dsp->dsa_off += len; |
93 |
72 mutex_exit(&ds->ds_sendstream_lock); |
94 static int |
73 |
95 dump_free(struct backuparg *ba, uint64_t object, uint64_t offset, |
74 return (dsp->dsa_err); |
|
75 } |
|
76 |
|
77 static int |
|
78 dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset, |
96 uint64_t length) |
79 uint64_t length) |
97 { |
80 { |
98 struct drr_free *drrf = &(ba->drr->drr_u.drr_free); |
81 struct drr_free *drrf = &(dsp->dsa_drr->drr_u.drr_free); |
99 |
82 |
100 /* |
83 /* |
101 * If there is a pending op, but it's not PENDING_FREE, push it out, |
84 * If there is a pending op, but it's not PENDING_FREE, push it out, |
102 * since free block aggregation can only be done for blocks of the |
85 * since free block aggregation can only be done for blocks of the |
103 * same type (i.e., DRR_FREE records can only be aggregated with |
86 * same type (i.e., DRR_FREE records can only be aggregated with |
104 * other DRR_FREE records. DRR_FREEOBJECTS records can only be |
87 * other DRR_FREE records. DRR_FREEOBJECTS records can only be |
105 * aggregated with other DRR_FREEOBJECTS records. |
88 * aggregated with other DRR_FREEOBJECTS records. |
106 */ |
89 */ |
107 if (ba->pending_op != PENDING_NONE && ba->pending_op != PENDING_FREE) { |
90 if (dsp->dsa_pending_op != PENDING_NONE && |
108 if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t)) != 0) |
91 dsp->dsa_pending_op != PENDING_FREE) { |
|
92 if (dump_bytes(dsp, dsp->dsa_drr, |
|
93 sizeof (dmu_replay_record_t)) != 0) |
109 return (EINTR); |
94 return (EINTR); |
110 ba->pending_op = PENDING_NONE; |
95 dsp->dsa_pending_op = PENDING_NONE; |
111 } |
96 } |
112 |
97 |
113 if (ba->pending_op == PENDING_FREE) { |
98 if (dsp->dsa_pending_op == PENDING_FREE) { |
114 /* |
99 /* |
115 * There should never be a PENDING_FREE if length is -1 |
100 * There should never be a PENDING_FREE if length is -1 |
116 * (because dump_dnode is the only place where this |
101 * (because dump_dnode is the only place where this |
117 * function is called with a -1, and only after flushing |
102 * function is called with a -1, and only after flushing |
118 * any pending record). |
103 * any pending record). |
126 drrf->drr_length == offset) { |
111 drrf->drr_length == offset) { |
127 drrf->drr_length += length; |
112 drrf->drr_length += length; |
128 return (0); |
113 return (0); |
129 } else { |
114 } else { |
130 /* not a continuation. Push out pending record */ |
115 /* not a continuation. Push out pending record */ |
131 if (dump_bytes(ba, ba->drr, |
116 if (dump_bytes(dsp, dsp->dsa_drr, |
132 sizeof (dmu_replay_record_t)) != 0) |
117 sizeof (dmu_replay_record_t)) != 0) |
133 return (EINTR); |
118 return (EINTR); |
134 ba->pending_op = PENDING_NONE; |
119 dsp->dsa_pending_op = PENDING_NONE; |
135 } |
120 } |
136 } |
121 } |
137 /* create a FREE record and make it pending */ |
122 /* create a FREE record and make it pending */ |
138 bzero(ba->drr, sizeof (dmu_replay_record_t)); |
123 bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); |
139 ba->drr->drr_type = DRR_FREE; |
124 dsp->dsa_drr->drr_type = DRR_FREE; |
140 drrf->drr_object = object; |
125 drrf->drr_object = object; |
141 drrf->drr_offset = offset; |
126 drrf->drr_offset = offset; |
142 drrf->drr_length = length; |
127 drrf->drr_length = length; |
143 drrf->drr_toguid = ba->toguid; |
128 drrf->drr_toguid = dsp->dsa_toguid; |
144 if (length == -1ULL) { |
129 if (length == -1ULL) { |
145 if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t)) != 0) |
130 if (dump_bytes(dsp, dsp->dsa_drr, |
|
131 sizeof (dmu_replay_record_t)) != 0) |
146 return (EINTR); |
132 return (EINTR); |
147 } else { |
133 } else { |
148 ba->pending_op = PENDING_FREE; |
134 dsp->dsa_pending_op = PENDING_FREE; |
149 } |
135 } |
150 |
136 |
151 return (0); |
137 return (0); |
152 } |
138 } |
153 |
139 |
154 static int |
140 static int |
155 dump_data(struct backuparg *ba, dmu_object_type_t type, |
141 dump_data(dmu_sendarg_t *dsp, dmu_object_type_t type, |
156 uint64_t object, uint64_t offset, int blksz, const blkptr_t *bp, void *data) |
142 uint64_t object, uint64_t offset, int blksz, const blkptr_t *bp, void *data) |
157 { |
143 { |
158 struct drr_write *drrw = &(ba->drr->drr_u.drr_write); |
144 struct drr_write *drrw = &(dsp->dsa_drr->drr_u.drr_write); |
159 |
145 |
160 |
146 |
161 /* |
147 /* |
162 * If there is any kind of pending aggregation (currently either |
148 * If there is any kind of pending aggregation (currently either |
163 * a grouping of free objects or free blocks), push it out to |
149 * a grouping of free objects or free blocks), push it out to |
164 * the stream, since aggregation can't be done across operations |
150 * the stream, since aggregation can't be done across operations |
165 * of different types. |
151 * of different types. |
166 */ |
152 */ |
167 if (ba->pending_op != PENDING_NONE) { |
153 if (dsp->dsa_pending_op != PENDING_NONE) { |
168 if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t)) != 0) |
154 if (dump_bytes(dsp, dsp->dsa_drr, |
|
155 sizeof (dmu_replay_record_t)) != 0) |
169 return (EINTR); |
156 return (EINTR); |
170 ba->pending_op = PENDING_NONE; |
157 dsp->dsa_pending_op = PENDING_NONE; |
171 } |
158 } |
172 /* write a DATA record */ |
159 /* write a DATA record */ |
173 bzero(ba->drr, sizeof (dmu_replay_record_t)); |
160 bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); |
174 ba->drr->drr_type = DRR_WRITE; |
161 dsp->dsa_drr->drr_type = DRR_WRITE; |
175 drrw->drr_object = object; |
162 drrw->drr_object = object; |
176 drrw->drr_type = type; |
163 drrw->drr_type = type; |
177 drrw->drr_offset = offset; |
164 drrw->drr_offset = offset; |
178 drrw->drr_length = blksz; |
165 drrw->drr_length = blksz; |
179 drrw->drr_toguid = ba->toguid; |
166 drrw->drr_toguid = dsp->dsa_toguid; |
180 drrw->drr_checksumtype = BP_GET_CHECKSUM(bp); |
167 drrw->drr_checksumtype = BP_GET_CHECKSUM(bp); |
181 if (zio_checksum_table[drrw->drr_checksumtype].ci_dedup) |
168 if (zio_checksum_table[drrw->drr_checksumtype].ci_dedup) |
182 drrw->drr_checksumflags |= DRR_CHECKSUM_DEDUP; |
169 drrw->drr_checksumflags |= DRR_CHECKSUM_DEDUP; |
183 DDK_SET_LSIZE(&drrw->drr_key, BP_GET_LSIZE(bp)); |
170 DDK_SET_LSIZE(&drrw->drr_key, BP_GET_LSIZE(bp)); |
184 DDK_SET_PSIZE(&drrw->drr_key, BP_GET_PSIZE(bp)); |
171 DDK_SET_PSIZE(&drrw->drr_key, BP_GET_PSIZE(bp)); |
185 DDK_SET_COMPRESS(&drrw->drr_key, BP_GET_COMPRESS(bp)); |
172 DDK_SET_COMPRESS(&drrw->drr_key, BP_GET_COMPRESS(bp)); |
186 drrw->drr_key.ddk_cksum = bp->blk_cksum; |
173 drrw->drr_key.ddk_cksum = bp->blk_cksum; |
187 |
174 |
188 if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t)) != 0) |
175 if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) |
189 return (EINTR); |
176 return (EINTR); |
190 if (dump_bytes(ba, data, blksz) != 0) |
177 if (dump_bytes(dsp, data, blksz) != 0) |
191 return (EINTR); |
178 return (EINTR); |
192 return (0); |
179 return (0); |
193 } |
180 } |
194 |
181 |
195 static int |
182 static int |
196 dump_spill(struct backuparg *ba, uint64_t object, int blksz, void *data) |
183 dump_spill(dmu_sendarg_t *dsp, uint64_t object, int blksz, void *data) |
197 { |
184 { |
198 struct drr_spill *drrs = &(ba->drr->drr_u.drr_spill); |
185 struct drr_spill *drrs = &(dsp->dsa_drr->drr_u.drr_spill); |
199 |
186 |
200 if (ba->pending_op != PENDING_NONE) { |
187 if (dsp->dsa_pending_op != PENDING_NONE) { |
201 if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t)) != 0) |
188 if (dump_bytes(dsp, dsp->dsa_drr, |
|
189 sizeof (dmu_replay_record_t)) != 0) |
202 return (EINTR); |
190 return (EINTR); |
203 ba->pending_op = PENDING_NONE; |
191 dsp->dsa_pending_op = PENDING_NONE; |
204 } |
192 } |
205 |
193 |
206 /* write a SPILL record */ |
194 /* write a SPILL record */ |
207 bzero(ba->drr, sizeof (dmu_replay_record_t)); |
195 bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); |
208 ba->drr->drr_type = DRR_SPILL; |
196 dsp->dsa_drr->drr_type = DRR_SPILL; |
209 drrs->drr_object = object; |
197 drrs->drr_object = object; |
210 drrs->drr_length = blksz; |
198 drrs->drr_length = blksz; |
211 drrs->drr_toguid = ba->toguid; |
199 drrs->drr_toguid = dsp->dsa_toguid; |
212 |
200 |
213 if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) |
201 if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t))) |
214 return (EINTR); |
202 return (EINTR); |
215 if (dump_bytes(ba, data, blksz)) |
203 if (dump_bytes(dsp, data, blksz)) |
216 return (EINTR); |
204 return (EINTR); |
217 return (0); |
205 return (0); |
218 } |
206 } |
219 |
207 |
220 static int |
208 static int |
221 dump_freeobjects(struct backuparg *ba, uint64_t firstobj, uint64_t numobjs) |
209 dump_freeobjects(dmu_sendarg_t *dsp, uint64_t firstobj, uint64_t numobjs) |
222 { |
210 { |
223 struct drr_freeobjects *drrfo = &(ba->drr->drr_u.drr_freeobjects); |
211 struct drr_freeobjects *drrfo = &(dsp->dsa_drr->drr_u.drr_freeobjects); |
224 |
212 |
225 /* |
213 /* |
226 * If there is a pending op, but it's not PENDING_FREEOBJECTS, |
214 * If there is a pending op, but it's not PENDING_FREEOBJECTS, |
227 * push it out, since free block aggregation can only be done for |
215 * push it out, since free block aggregation can only be done for |
228 * blocks of the same type (i.e., DRR_FREE records can only be |
216 * blocks of the same type (i.e., DRR_FREE records can only be |
229 * aggregated with other DRR_FREE records. DRR_FREEOBJECTS records |
217 * aggregated with other DRR_FREE records. DRR_FREEOBJECTS records |
230 * can only be aggregated with other DRR_FREEOBJECTS records. |
218 * can only be aggregated with other DRR_FREEOBJECTS records. |
231 */ |
219 */ |
232 if (ba->pending_op != PENDING_NONE && |
220 if (dsp->dsa_pending_op != PENDING_NONE && |
233 ba->pending_op != PENDING_FREEOBJECTS) { |
221 dsp->dsa_pending_op != PENDING_FREEOBJECTS) { |
234 if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t)) != 0) |
222 if (dump_bytes(dsp, dsp->dsa_drr, |
|
223 sizeof (dmu_replay_record_t)) != 0) |
235 return (EINTR); |
224 return (EINTR); |
236 ba->pending_op = PENDING_NONE; |
225 dsp->dsa_pending_op = PENDING_NONE; |
237 } |
226 } |
238 if (ba->pending_op == PENDING_FREEOBJECTS) { |
227 if (dsp->dsa_pending_op == PENDING_FREEOBJECTS) { |
239 /* |
228 /* |
240 * See whether this free object array can be aggregated |
229 * See whether this free object array can be aggregated |
241 * with pending one |
230 * with pending one |
242 */ |
231 */ |
243 if (drrfo->drr_firstobj + drrfo->drr_numobjs == firstobj) { |
232 if (drrfo->drr_firstobj + drrfo->drr_numobjs == firstobj) { |
244 drrfo->drr_numobjs += numobjs; |
233 drrfo->drr_numobjs += numobjs; |
245 return (0); |
234 return (0); |
246 } else { |
235 } else { |
247 /* can't be aggregated. Push out pending record */ |
236 /* can't be aggregated. Push out pending record */ |
248 if (dump_bytes(ba, ba->drr, |
237 if (dump_bytes(dsp, dsp->dsa_drr, |
249 sizeof (dmu_replay_record_t)) != 0) |
238 sizeof (dmu_replay_record_t)) != 0) |
250 return (EINTR); |
239 return (EINTR); |
251 ba->pending_op = PENDING_NONE; |
240 dsp->dsa_pending_op = PENDING_NONE; |
252 } |
241 } |
253 } |
242 } |
254 |
243 |
255 /* write a FREEOBJECTS record */ |
244 /* write a FREEOBJECTS record */ |
256 bzero(ba->drr, sizeof (dmu_replay_record_t)); |
245 bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); |
257 ba->drr->drr_type = DRR_FREEOBJECTS; |
246 dsp->dsa_drr->drr_type = DRR_FREEOBJECTS; |
258 drrfo->drr_firstobj = firstobj; |
247 drrfo->drr_firstobj = firstobj; |
259 drrfo->drr_numobjs = numobjs; |
248 drrfo->drr_numobjs = numobjs; |
260 drrfo->drr_toguid = ba->toguid; |
249 drrfo->drr_toguid = dsp->dsa_toguid; |
261 |
250 |
262 ba->pending_op = PENDING_FREEOBJECTS; |
251 dsp->dsa_pending_op = PENDING_FREEOBJECTS; |
263 |
252 |
264 return (0); |
253 return (0); |
265 } |
254 } |
266 |
255 |
267 static int |
256 static int |
268 dump_dnode(struct backuparg *ba, uint64_t object, dnode_phys_t *dnp) |
257 dump_dnode(dmu_sendarg_t *dsp, uint64_t object, dnode_phys_t *dnp) |
269 { |
258 { |
270 struct drr_object *drro = &(ba->drr->drr_u.drr_object); |
259 struct drr_object *drro = &(dsp->dsa_drr->drr_u.drr_object); |
271 |
260 |
272 if (dnp == NULL || dnp->dn_type == DMU_OT_NONE) |
261 if (dnp == NULL || dnp->dn_type == DMU_OT_NONE) |
273 return (dump_freeobjects(ba, object, 1)); |
262 return (dump_freeobjects(dsp, object, 1)); |
274 |
263 |
275 if (ba->pending_op != PENDING_NONE) { |
264 if (dsp->dsa_pending_op != PENDING_NONE) { |
276 if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t)) != 0) |
265 if (dump_bytes(dsp, dsp->dsa_drr, |
|
266 sizeof (dmu_replay_record_t)) != 0) |
277 return (EINTR); |
267 return (EINTR); |
278 ba->pending_op = PENDING_NONE; |
268 dsp->dsa_pending_op = PENDING_NONE; |
279 } |
269 } |
280 |
270 |
281 /* write an OBJECT record */ |
271 /* write an OBJECT record */ |
282 bzero(ba->drr, sizeof (dmu_replay_record_t)); |
272 bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); |
283 ba->drr->drr_type = DRR_OBJECT; |
273 dsp->dsa_drr->drr_type = DRR_OBJECT; |
284 drro->drr_object = object; |
274 drro->drr_object = object; |
285 drro->drr_type = dnp->dn_type; |
275 drro->drr_type = dnp->dn_type; |
286 drro->drr_bonustype = dnp->dn_bonustype; |
276 drro->drr_bonustype = dnp->dn_bonustype; |
287 drro->drr_blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; |
277 drro->drr_blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; |
288 drro->drr_bonuslen = dnp->dn_bonuslen; |
278 drro->drr_bonuslen = dnp->dn_bonuslen; |
289 drro->drr_checksumtype = dnp->dn_checksum; |
279 drro->drr_checksumtype = dnp->dn_checksum; |
290 drro->drr_compress = dnp->dn_compress; |
280 drro->drr_compress = dnp->dn_compress; |
291 drro->drr_toguid = ba->toguid; |
281 drro->drr_toguid = dsp->dsa_toguid; |
292 |
282 |
293 if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t)) != 0) |
283 if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) |
294 return (EINTR); |
284 return (EINTR); |
295 |
285 |
296 if (dump_bytes(ba, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0) |
286 if (dump_bytes(dsp, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0) |
297 return (EINTR); |
287 return (EINTR); |
298 |
288 |
299 /* free anything past the end of the file */ |
289 /* free anything past the end of the file */ |
300 if (dump_free(ba, object, (dnp->dn_maxblkid + 1) * |
290 if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) * |
301 (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL)) |
291 (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL)) |
302 return (EINTR); |
292 return (EINTR); |
303 if (ba->err) |
293 if (dsp->dsa_err) |
304 return (EINTR); |
294 return (EINTR); |
305 return (0); |
295 return (0); |
306 } |
296 } |
307 |
297 |
308 #define BP_SPAN(dnp, level) \ |
298 #define BP_SPAN(dnp, level) \ |
471 if (fromds) |
463 if (fromds) |
472 fromtxg = fromds->ds_phys->ds_creation_txg; |
464 fromtxg = fromds->ds_phys->ds_creation_txg; |
473 if (fromorigin) |
465 if (fromorigin) |
474 dsl_dataset_rele(fromds, FTAG); |
466 dsl_dataset_rele(fromds, FTAG); |
475 |
467 |
476 ba.drr = drr; |
468 dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP); |
477 ba.vp = vp; |
469 |
478 ba.os = tosnap; |
470 dsp->dsa_drr = drr; |
479 ba.off = off; |
471 dsp->dsa_vp = vp; |
480 ba.toguid = ds->ds_phys->ds_guid; |
472 dsp->dsa_outfd = outfd; |
481 ZIO_SET_CHECKSUM(&ba.zc, 0, 0, 0, 0); |
473 dsp->dsa_proc = curproc; |
482 ba.pending_op = PENDING_NONE; |
474 dsp->dsa_os = tosnap; |
483 |
475 dsp->dsa_off = off; |
484 if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t)) != 0) { |
476 dsp->dsa_toguid = ds->ds_phys->ds_guid; |
485 kmem_free(drr, sizeof (dmu_replay_record_t)); |
477 ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0); |
486 return (ba.err); |
478 dsp->dsa_pending_op = PENDING_NONE; |
|
479 |
|
480 mutex_enter(&ds->ds_sendstream_lock); |
|
481 list_insert_head(&ds->ds_sendstreams, dsp); |
|
482 mutex_exit(&ds->ds_sendstream_lock); |
|
483 |
|
484 if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { |
|
485 err = dsp->dsa_err; |
|
486 goto out; |
487 } |
487 } |
488 |
488 |
489 err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH, |
489 err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH, |
490 backup_cb, &ba); |
490 backup_cb, dsp); |
491 |
491 |
492 if (ba.pending_op != PENDING_NONE) |
492 if (dsp->dsa_pending_op != PENDING_NONE) |
493 if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t)) != 0) |
493 if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) |
494 err = EINTR; |
494 err = EINTR; |
495 |
495 |
496 if (err) { |
496 if (err) { |
497 if (err == EINTR && ba.err) |
497 if (err == EINTR && dsp->dsa_err) |
498 err = ba.err; |
498 err = dsp->dsa_err; |
499 kmem_free(drr, sizeof (dmu_replay_record_t)); |
499 goto out; |
500 return (err); |
|
501 } |
500 } |
502 |
501 |
503 bzero(drr, sizeof (dmu_replay_record_t)); |
502 bzero(drr, sizeof (dmu_replay_record_t)); |
504 drr->drr_type = DRR_END; |
503 drr->drr_type = DRR_END; |
505 drr->drr_u.drr_end.drr_checksum = ba.zc; |
504 drr->drr_u.drr_end.drr_checksum = dsp->dsa_zc; |
506 drr->drr_u.drr_end.drr_toguid = ba.toguid; |
505 drr->drr_u.drr_end.drr_toguid = dsp->dsa_toguid; |
507 |
506 |
508 if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t)) != 0) { |
507 if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { |
509 kmem_free(drr, sizeof (dmu_replay_record_t)); |
508 err = dsp->dsa_err; |
510 return (ba.err); |
509 goto out; |
511 } |
510 } |
|
511 |
|
512 out: |
|
513 mutex_enter(&ds->ds_sendstream_lock); |
|
514 list_remove(&ds->ds_sendstreams, dsp); |
|
515 mutex_exit(&ds->ds_sendstream_lock); |
512 |
516 |
513 kmem_free(drr, sizeof (dmu_replay_record_t)); |
517 kmem_free(drr, sizeof (dmu_replay_record_t)); |
514 |
518 kmem_free(dsp, sizeof (dmu_sendarg_t)); |
515 return (0); |
519 |
|
520 return (err); |
516 } |
521 } |
517 |
522 |
518 int |
523 int |
519 dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin, |
524 dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin, |
520 uint64_t *sizep) |
525 uint64_t *sizep) |