Deleted Added
full compact
dmu_send.c (177698) dmu_send.c (185029)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE

--- 5 unchanged lines hidden (view full) ---

14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE

--- 5 unchanged lines hidden (view full) ---

14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident "%Z%%M% %I% %E% SMI"
27
28#include <sys/dmu.h>
29#include <sys/dmu_impl.h>
30#include <sys/dmu_tx.h>

--- 5 unchanged lines hidden (view full) ---

36#include <sys/dsl_dataset.h>
37#include <sys/dsl_dir.h>
38#include <sys/dsl_pool.h>
39#include <sys/dsl_synctask.h>
40#include <sys/zfs_ioctl.h>
41#include <sys/zap.h>
42#include <sys/zio_checksum.h>
43
23 * Use is subject to license terms.
24 */
25
26#pragma ident "%Z%%M% %I% %E% SMI"
27
28#include <sys/dmu.h>
29#include <sys/dmu_impl.h>
30#include <sys/dmu_tx.h>

--- 5 unchanged lines hidden (view full) ---

36#include <sys/dsl_dataset.h>
37#include <sys/dsl_dir.h>
38#include <sys/dsl_pool.h>
39#include <sys/dsl_synctask.h>
40#include <sys/zfs_ioctl.h>
41#include <sys/zap.h>
42#include <sys/zio_checksum.h>
43
44static char *dmu_recv_tag = "dmu_recv_tag";
45
44struct backuparg {
45 dmu_replay_record_t *drr;
46 kthread_t *td;
47 struct file *fp;
46struct backuparg {
47 dmu_replay_record_t *drr;
48 kthread_t *td;
49 struct file *fp;
50 offset_t *off;
48 objset_t *os;
49 zio_cksum_t zc;
50 int err;
51};
52
53static int
54dump_bytes(struct backuparg *ba, void *buf, int len)
55{

--- 16 unchanged lines hidden (view full) ---

72#ifdef _KERNEL
73 if (ba->fp->f_type == DTYPE_VNODE)
74 bwillwrite();
75 ba->err = fo_write(ba->fp, &auio, ba->td->td_ucred, 0, ba->td);
76#else
77 fprintf(stderr, "%s: returning EOPNOTSUPP\n", __func__);
78 ba->err = EOPNOTSUPP;
79#endif
51 objset_t *os;
52 zio_cksum_t zc;
53 int err;
54};
55
56static int
57dump_bytes(struct backuparg *ba, void *buf, int len)
58{

--- 16 unchanged lines hidden (view full) ---

75#ifdef _KERNEL
76 if (ba->fp->f_type == DTYPE_VNODE)
77 bwillwrite();
78 ba->err = fo_write(ba->fp, &auio, ba->td->td_ucred, 0, ba->td);
79#else
80 fprintf(stderr, "%s: returning EOPNOTSUPP\n", __func__);
81 ba->err = EOPNOTSUPP;
82#endif
83 *ba->off += len;
80
81 return (ba->err);
82}
83
84static int
85dump_free(struct backuparg *ba, uint64_t object, uint64_t offset,
86 uint64_t length)
87{

--- 86 unchanged lines hidden (view full) ---

174 uint64_t object = bc->bc_bookmark.zb_object;
175 int level = bc->bc_bookmark.zb_level;
176 uint64_t blkid = bc->bc_bookmark.zb_blkid;
177 blkptr_t *bp = bc->bc_blkptr.blk_birth ? &bc->bc_blkptr : NULL;
178 dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE;
179 void *data = bc->bc_data;
180 int err = 0;
181
84
85 return (ba->err);
86}
87
88static int
89dump_free(struct backuparg *ba, uint64_t object, uint64_t offset,
90 uint64_t length)
91{

--- 86 unchanged lines hidden (view full) ---

178 uint64_t object = bc->bc_bookmark.zb_object;
179 int level = bc->bc_bookmark.zb_level;
180 uint64_t blkid = bc->bc_bookmark.zb_blkid;
181 blkptr_t *bp = bc->bc_blkptr.blk_birth ? &bc->bc_blkptr : NULL;
182 dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE;
183 void *data = bc->bc_data;
184 int err = 0;
185
182 if (SIGPENDING(curthread))
186 if (issig(JUSTLOOKING) && issig(FORREAL))
183 return (EINTR);
184
185 ASSERT(data || bp == NULL);
186
187 if (bp == NULL && object == 0) {
188 uint64_t span = BP_SPAN(bc->bc_dnode, level);
189 uint64_t dnobj = (blkid * span) >> DNODE_SHIFT;
190 err = dump_freeobjects(ba, dnobj, span >> DNODE_SHIFT);

--- 19 unchanged lines hidden (view full) ---

210 uint32_t aflags = ARC_WAIT;
211 arc_buf_t *abuf;
212 zbookmark_t zb;
213
214 zb.zb_objset = ba->os->os->os_dsl_dataset->ds_object;
215 zb.zb_object = object;
216 zb.zb_level = level;
217 zb.zb_blkid = blkid;
187 return (EINTR);
188
189 ASSERT(data || bp == NULL);
190
191 if (bp == NULL && object == 0) {
192 uint64_t span = BP_SPAN(bc->bc_dnode, level);
193 uint64_t dnobj = (blkid * span) >> DNODE_SHIFT;
194 err = dump_freeobjects(ba, dnobj, span >> DNODE_SHIFT);

--- 19 unchanged lines hidden (view full) ---

214 uint32_t aflags = ARC_WAIT;
215 arc_buf_t *abuf;
216 zbookmark_t zb;
217
218 zb.zb_objset = ba->os->os->os_dsl_dataset->ds_object;
219 zb.zb_object = object;
220 zb.zb_level = level;
221 zb.zb_blkid = blkid;
218 (void) arc_read(NULL, spa, bp,
219 dmu_ot[type].ot_byteswap, arc_getbuf_func, &abuf,
220 ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_MUSTSUCCEED,
221 &aflags, &zb);
222 (void) arc_read_nolock(NULL, spa, bp,
223 arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ,
224 ZIO_FLAG_MUSTSUCCEED, &aflags, &zb);
222
223 if (abuf) {
224 err = dump_data(ba, type, object, blkid * blksz,
225 blksz, abuf->b_data);
226 (void) arc_buf_remove_ref(abuf, &abuf);
227 }
228 } else {
229 err = dump_data(ba, type, object, blkid * blksz,
230 blksz, data);
231 }
232 }
233
234 ASSERT(err == 0 || err == EINTR);
235 return (err);
236}
237
238int
225
226 if (abuf) {
227 err = dump_data(ba, type, object, blkid * blksz,
228 blksz, abuf->b_data);
229 (void) arc_buf_remove_ref(abuf, &abuf);
230 }
231 } else {
232 err = dump_data(ba, type, object, blkid * blksz,
233 blksz, data);
234 }
235 }
236
237 ASSERT(err == 0 || err == EINTR);
238 return (err);
239}
240
241int
239dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, struct file *fp)
242dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
243 struct file *fp, offset_t *off)
240{
241 dsl_dataset_t *ds = tosnap->os->os_dsl_dataset;
242 dsl_dataset_t *fromds = fromsnap ? fromsnap->os->os_dsl_dataset : NULL;
243 dmu_replay_record_t *drr;
244 struct backuparg ba;
245 int err;
244{
245 dsl_dataset_t *ds = tosnap->os->os_dsl_dataset;
246 dsl_dataset_t *fromds = fromsnap ? fromsnap->os->os_dsl_dataset : NULL;
247 dmu_replay_record_t *drr;
248 struct backuparg ba;
249 int err;
250 uint64_t fromtxg = 0;
246
247 /* tosnap must be a snapshot */
248 if (ds->ds_phys->ds_next_snap_obj == 0)
249 return (EINVAL);
250
251 /* fromsnap must be an earlier snapshot from the same fs as tosnap */
252 if (fromds && (ds->ds_dir != fromds->ds_dir ||
251
252 /* tosnap must be a snapshot */
253 if (ds->ds_phys->ds_next_snap_obj == 0)
254 return (EINVAL);
255
256 /* fromsnap must be an earlier snapshot from the same fs as tosnap */
257 if (fromds && (ds->ds_dir != fromds->ds_dir ||
253 fromds->ds_phys->ds_creation_txg >=
254 ds->ds_phys->ds_creation_txg))
258 fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg))
255 return (EXDEV);
256
259 return (EXDEV);
260
261 if (fromorigin) {
262 dsl_pool_t *dp = ds->ds_dir->dd_pool;
263
264 if (fromsnap)
265 return (EINVAL);
266
267 if (dsl_dir_is_clone(ds->ds_dir)) {
268 rw_enter(&dp->dp_config_rwlock, RW_READER);
269 err = dsl_dataset_hold_obj(dp,
270 ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds);
271 rw_exit(&dp->dp_config_rwlock);
272 if (err)
273 return (err);
274 } else {
275 fromorigin = B_FALSE;
276 }
277 }
278
279
257 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
258 drr->drr_type = DRR_BEGIN;
259 drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
280 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
281 drr->drr_type = DRR_BEGIN;
282 drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
260 drr->drr_u.drr_begin.drr_version = DMU_BACKUP_VERSION;
283 drr->drr_u.drr_begin.drr_version = DMU_BACKUP_STREAM_VERSION;
261 drr->drr_u.drr_begin.drr_creation_time =
262 ds->ds_phys->ds_creation_time;
263 drr->drr_u.drr_begin.drr_type = tosnap->os->os_phys->os_type;
284 drr->drr_u.drr_begin.drr_creation_time =
285 ds->ds_phys->ds_creation_time;
286 drr->drr_u.drr_begin.drr_type = tosnap->os->os_phys->os_type;
287 if (fromorigin)
288 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE;
264 drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid;
289 drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid;
290 if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
291 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA;
292
265 if (fromds)
266 drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid;
267 dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname);
268
293 if (fromds)
294 drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid;
295 dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname);
296
297 if (fromds)
298 fromtxg = fromds->ds_phys->ds_creation_txg;
299 if (fromorigin)
300 dsl_dataset_rele(fromds, FTAG);
301
269 ba.drr = drr;
270 ba.td = curthread;
271 ba.fp = fp;
272 ba.os = tosnap;
302 ba.drr = drr;
303 ba.td = curthread;
304 ba.fp = fp;
305 ba.os = tosnap;
306 ba.off = off;
273 ZIO_SET_CHECKSUM(&ba.zc, 0, 0, 0, 0);
274
275 if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) {
276 kmem_free(drr, sizeof (dmu_replay_record_t));
277 return (ba.err);
278 }
279
307 ZIO_SET_CHECKSUM(&ba.zc, 0, 0, 0, 0);
308
309 if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) {
310 kmem_free(drr, sizeof (dmu_replay_record_t));
311 return (ba.err);
312 }
313
280 err = traverse_dsl_dataset(ds,
281 fromds ? fromds->ds_phys->ds_creation_txg : 0,
314 err = traverse_dsl_dataset(ds, fromtxg,
282 ADVANCE_PRE | ADVANCE_HOLES | ADVANCE_DATA | ADVANCE_NOLOCK,
283 backup_cb, &ba);
284
285 if (err) {
286 if (err == EINTR && ba.err)
287 err = ba.err;
288 kmem_free(drr, sizeof (dmu_replay_record_t));
289 return (err);

--- 8 unchanged lines hidden (view full) ---

298 return (ba.err);
299 }
300
301 kmem_free(drr, sizeof (dmu_replay_record_t));
302
303 return (0);
304}
305
315 ADVANCE_PRE | ADVANCE_HOLES | ADVANCE_DATA | ADVANCE_NOLOCK,
316 backup_cb, &ba);
317
318 if (err) {
319 if (err == EINTR && ba.err)
320 err = ba.err;
321 kmem_free(drr, sizeof (dmu_replay_record_t));
322 return (err);

--- 8 unchanged lines hidden (view full) ---

331 return (ba.err);
332 }
333
334 kmem_free(drr, sizeof (dmu_replay_record_t));
335
336 return (0);
337}
338
306struct restorearg {
307 int err;
308 int byteswap;
309 kthread_t *td;
310 struct file *fp;
311 char *buf;
312 uint64_t voff;
313 int buflen; /* number of valid bytes in buf */
314 int bufoff; /* next offset to read */
315 int bufsize; /* amount of memory allocated for buf */
316 zio_cksum_t zc;
339struct recvbeginsyncarg {
340 const char *tofs;
341 const char *tosnap;
342 dsl_dataset_t *origin;
343 uint64_t fromguid;
344 dmu_objset_type_t type;
345 void *tag;
346 boolean_t force;
347 uint64_t dsflags;
348 char clonelastname[MAXNAMELEN];
349 dsl_dataset_t *ds; /* the ds to recv into; returned from the syncfunc */
317};
318
350};
351
352static dsl_dataset_t *
353recv_full_sync_impl(dsl_pool_t *dp, uint64_t dsobj, dmu_objset_type_t type,
354 cred_t *cr, dmu_tx_t *tx)
355{
356 dsl_dataset_t *ds;
357
358 /* This should always work, since we just created it */
359 /* XXX - create should return an owned ds */
360 VERIFY(0 == dsl_dataset_own_obj(dp, dsobj,
361 DS_MODE_INCONSISTENT, dmu_recv_tag, &ds));
362
363 if (type != DMU_OST_NONE) {
364 (void) dmu_objset_create_impl(dp->dp_spa,
365 ds, &ds->ds_phys->ds_bp, type, tx);
366 }
367
368 spa_history_internal_log(LOG_DS_REPLAY_FULL_SYNC,
369 dp->dp_spa, tx, cr, "dataset = %lld", dsobj);
370
371 return (ds);
372}
373
319/* ARGSUSED */
320static int
374/* ARGSUSED */
375static int
321replay_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx)
376recv_full_check(void *arg1, void *arg2, dmu_tx_t *tx)
322{
377{
323 dsl_dataset_t *ds = arg1;
324 struct drr_begin *drrb = arg2;
325 const char *snapname;
326 int err;
378 dsl_dir_t *dd = arg1;
379 struct recvbeginsyncarg *rbsa = arg2;
380 objset_t *mos = dd->dd_pool->dp_meta_objset;
327 uint64_t val;
381 uint64_t val;
382 int err;
328
383
329 /* must already be a snapshot of this fs */
330 if (ds->ds_phys->ds_prev_snap_obj == 0)
331 return (ENODEV);
384 err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj,
385 strrchr(rbsa->tofs, '/') + 1, sizeof (uint64_t), 1, &val);
332
386
333 /* most recent snapshot must match fromguid */
334 if (ds->ds_prev->ds_phys->ds_guid != drrb->drr_fromguid)
335 return (ENODEV);
336 /* must not have any changes since most recent snapshot */
337 if (ds->ds_phys->ds_bp.blk_birth >
338 ds->ds_prev->ds_phys->ds_creation_txg)
339 return (ETXTBSY);
387 if (err != ENOENT)
388 return (err ? err : EEXIST);
340
389
341 /* new snapshot name must not exist */
342 snapname = strrchr(drrb->drr_toname, '@');
343 if (snapname == NULL)
344 return (EEXIST);
390 if (rbsa->origin) {
391 /* make sure it's a snap in the same pool */
392 if (rbsa->origin->ds_dir->dd_pool != dd->dd_pool)
393 return (EXDEV);
394 if (rbsa->origin->ds_phys->ds_num_children == 0)
395 return (EINVAL);
396 if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid)
397 return (ENODEV);
398 }
345
399
346 snapname++;
347 err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
348 ds->ds_phys->ds_snapnames_zapobj, snapname, 8, 1, &val);
349 if (err == 0)
350 return (EEXIST);
351 if (err != ENOENT)
400 return (0);
401}
402
403static void
404recv_full_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
405{
406 dsl_dir_t *dd = arg1;
407 struct recvbeginsyncarg *rbsa = arg2;
408 uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
409 uint64_t dsobj;
410
411 dsobj = dsl_dataset_create_sync(dd, strrchr(rbsa->tofs, '/') + 1,
412 rbsa->origin, flags, cr, tx);
413
414 rbsa->ds = recv_full_sync_impl(dd->dd_pool, dsobj,
415 rbsa->origin ? DMU_OST_NONE : rbsa->type, cr, tx);
416}
417
418static int
419recv_full_existing_check(void *arg1, void *arg2, dmu_tx_t *tx)
420{
421 dsl_dataset_t *ds = arg1;
422 struct recvbeginsyncarg *rbsa = arg2;
423 int err;
424
425 /* must be a head ds */
426 if (ds->ds_phys->ds_next_snap_obj != 0)
427 return (EINVAL);
428
429 /* must not be a clone ds */
430 if (dsl_dir_is_clone(ds->ds_dir))
431 return (EINVAL);
432
433 err = dsl_dataset_destroy_check(ds, rbsa->tag, tx);
434 if (err)
352 return (err);
353
435 return (err);
436
437 if (rbsa->origin) {
438 /* make sure it's a snap in the same pool */
439 if (rbsa->origin->ds_dir->dd_pool != ds->ds_dir->dd_pool)
440 return (EXDEV);
441 if (rbsa->origin->ds_phys->ds_num_children == 0)
442 return (EINVAL);
443 if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid)
444 return (ENODEV);
445 }
446
354 return (0);
355}
356
447 return (0);
448}
449
357/* ARGSUSED */
358static void
450static void
359replay_incremental_sync(void *arg1, void *arg2, dmu_tx_t *tx)
451recv_full_existing_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
360{
361 dsl_dataset_t *ds = arg1;
452{
453 dsl_dataset_t *ds = arg1;
362 dmu_buf_will_dirty(ds->ds_dbuf, tx);
363 ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
454 struct recvbeginsyncarg *rbsa = arg2;
455 dsl_dir_t *dd = ds->ds_dir;
456 uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
457 uint64_t dsobj;
458
459 /*
460 * NB: caller must provide an extra hold on the dsl_dir_t, so it
461 * won't go away when dsl_dataset_destroy_sync() closes the
462 * dataset.
463 */
464 dsl_dataset_destroy_sync(ds, rbsa->tag, cr, tx);
465
466 dsobj = dsl_dataset_create_sync_dd(dd, rbsa->origin, flags, tx);
467
468 rbsa->ds = recv_full_sync_impl(dd->dd_pool, dsobj,
469 rbsa->origin ? DMU_OST_NONE : rbsa->type, cr, tx);
364}
365
366/* ARGSUSED */
367static int
470}
471
472/* ARGSUSED */
473static int
368replay_full_check(void *arg1, void *arg2, dmu_tx_t *tx)
474recv_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx)
369{
475{
370 dsl_dir_t *dd = arg1;
371 struct drr_begin *drrb = arg2;
372 objset_t *mos = dd->dd_pool->dp_meta_objset;
373 char *cp;
374 uint64_t val;
476 dsl_dataset_t *ds = arg1;
477 struct recvbeginsyncarg *rbsa = arg2;
375 int err;
478 int err;
479 uint64_t val;
376
480
377 cp = strchr(drrb->drr_toname, '@');
378 *cp = '\0';
379 err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj,
380 strrchr(drrb->drr_toname, '/') + 1,
381 sizeof (uint64_t), 1, &val);
382 *cp = '@';
481 /* must not have any changes since most recent snapshot */
482 if (!rbsa->force && dsl_dataset_modified_since_lastsnap(ds))
483 return (ETXTBSY);
383
484
485 /* must already be a snapshot of this fs */
486 if (ds->ds_phys->ds_prev_snap_obj == 0)
487 return (ENODEV);
488
489 /* most recent snapshot must match fromguid */
490 if (ds->ds_prev->ds_phys->ds_guid != rbsa->fromguid)
491 return (ENODEV);
492
493 /* temporary clone name must not exist */
494 err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
495 ds->ds_dir->dd_phys->dd_child_dir_zapobj,
496 rbsa->clonelastname, 8, 1, &val);
497 if (err == 0)
498 return (EEXIST);
384 if (err != ENOENT)
499 if (err != ENOENT)
385 return (err ? err : EEXIST);
500 return (err);
386
501
502 /* new snapshot name must not exist */
503 err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
504 ds->ds_phys->ds_snapnames_zapobj, rbsa->tosnap, 8, 1, &val);
505 if (err == 0)
506 return (EEXIST);
507 if (err != ENOENT)
508 return (err);
387 return (0);
388}
389
509 return (0);
510}
511
512/* ARGSUSED */
390static void
513static void
391replay_full_sync(void *arg1, void *arg2, dmu_tx_t *tx)
514recv_online_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
392{
515{
393 dsl_dir_t *dd = arg1;
394 struct drr_begin *drrb = arg2;
395 char *cp;
396 dsl_dataset_t *ds;
516 dsl_dataset_t *ohds = arg1;
517 struct recvbeginsyncarg *rbsa = arg2;
518 dsl_pool_t *dp = ohds->ds_dir->dd_pool;
519 dsl_dataset_t *ods, *cds;
520 uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
397 uint64_t dsobj;
398
521 uint64_t dsobj;
522
399 cp = strchr(drrb->drr_toname, '@');
400 *cp = '\0';
401 dsobj = dsl_dataset_create_sync(dd, strrchr(drrb->drr_toname, '/') + 1,
402 NULL, tx);
403 *cp = '@';
523 /* create the temporary clone */
524 VERIFY(0 == dsl_dataset_hold_obj(dp, ohds->ds_phys->ds_prev_snap_obj,
525 FTAG, &ods));
526 dsobj = dsl_dataset_create_sync(ohds->ds_dir,
527 rbsa->clonelastname, ods, flags, cr, tx);
528 dsl_dataset_rele(ods, FTAG);
404
529
405 VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, dsobj, NULL,
406 DS_MODE_EXCLUSIVE, FTAG, &ds));
530 /* open the temporary clone */
531 VERIFY(0 == dsl_dataset_own_obj(dp, dsobj,
532 DS_MODE_INCONSISTENT, dmu_recv_tag, &cds));
407
533
408 (void) dmu_objset_create_impl(dsl_dataset_get_spa(ds),
409 ds, &ds->ds_phys->ds_bp, drrb->drr_type, tx);
534 /* copy the refquota from the target fs to the clone */
535 if (ohds->ds_quota > 0)
536 dsl_dataset_set_quota_sync(cds, &ohds->ds_quota, cr, tx);
410
537
538 rbsa->ds = cds;
539
540 spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC,
541 dp->dp_spa, tx, cr, "dataset = %lld", dsobj);
542}
543
544/* ARGSUSED */
545static void
546recv_offline_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
547{
548 dsl_dataset_t *ds = arg1;
549
411 dmu_buf_will_dirty(ds->ds_dbuf, tx);
412 ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
413
550 dmu_buf_will_dirty(ds->ds_dbuf, tx);
551 ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
552
414 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
553 spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC,
554 ds->ds_dir->dd_pool->dp_spa, tx, cr, "dataset = %lld",
555 ds->ds_object);
415}
416
556}
557
417static int
418replay_end_check(void *arg1, void *arg2, dmu_tx_t *tx)
558/*
559 * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin()
560 * succeeds; otherwise we will leak the holds on the datasets.
561 */
562int
563dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb,
564 boolean_t force, objset_t *origin, boolean_t online, dmu_recv_cookie_t *drc)
419{
565{
420 objset_t *os = arg1;
421 struct drr_begin *drrb = arg2;
422 char *snapname;
566 int err = 0;
567 boolean_t byteswap;
568 struct recvbeginsyncarg rbsa;
569 uint64_t version;
570 int flags;
571 dsl_dataset_t *ds;
423
572
424 /* XXX verify that drr_toname is in dd */
573 if (drrb->drr_magic == DMU_BACKUP_MAGIC)
574 byteswap = FALSE;
575 else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC))
576 byteswap = TRUE;
577 else
578 return (EINVAL);
425
579
426 snapname = strchr(drrb->drr_toname, '@');
427 if (snapname == NULL)
580 rbsa.tofs = tofs;
581 rbsa.tosnap = tosnap;
582 rbsa.origin = origin ? origin->os->os_dsl_dataset : NULL;
583 rbsa.fromguid = drrb->drr_fromguid;
584 rbsa.type = drrb->drr_type;
585 rbsa.tag = FTAG;
586 rbsa.dsflags = 0;
587 version = drrb->drr_version;
588 flags = drrb->drr_flags;
589
590 if (byteswap) {
591 rbsa.type = BSWAP_32(rbsa.type);
592 rbsa.fromguid = BSWAP_64(rbsa.fromguid);
593 version = BSWAP_64(version);
594 flags = BSWAP_32(flags);
595 }
596
597 if (version != DMU_BACKUP_STREAM_VERSION ||
598 rbsa.type >= DMU_OST_NUMTYPES ||
599 ((flags & DRR_FLAG_CLONE) && origin == NULL))
428 return (EINVAL);
600 return (EINVAL);
429 snapname++;
430
601
431 return (dsl_dataset_snapshot_check(os, snapname, tx));
432}
602 if (flags & DRR_FLAG_CI_DATA)
603 rbsa.dsflags = DS_FLAG_CI_DATASET;
433
604
434static void
435replay_end_sync(void *arg1, void *arg2, dmu_tx_t *tx)
436{
437 objset_t *os = arg1;
438 struct drr_begin *drrb = arg2;
439 char *snapname;
440 dsl_dataset_t *ds, *hds;
605 bzero(drc, sizeof (dmu_recv_cookie_t));
606 drc->drc_drrb = drrb;
607 drc->drc_tosnap = tosnap;
608 drc->drc_force = force;
441
609
442 snapname = strchr(drrb->drr_toname, '@') + 1;
610 /*
611 * Process the begin in syncing context.
612 */
613 if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE) && !online) {
614 /* offline incremental receive */
615 err = dsl_dataset_own(tofs, 0, dmu_recv_tag, &ds);
616 if (err)
617 return (err);
443
618
444 dsl_dataset_snapshot_sync(os, snapname, tx);
619 /*
620 * Only do the rollback if the most recent snapshot
621 * matches the incremental source
622 */
623 if (force) {
624 if (ds->ds_prev == NULL ||
625 ds->ds_prev->ds_phys->ds_guid !=
626 rbsa.fromguid) {
627 dsl_dataset_disown(ds, dmu_recv_tag);
628 return (ENODEV);
629 }
630 (void) dsl_dataset_rollback(ds, DMU_OST_NONE);
631 }
632 rbsa.force = B_FALSE;
633 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
634 recv_incremental_check,
635 recv_offline_incremental_sync, ds, &rbsa, 1);
636 if (err) {
637 dsl_dataset_disown(ds, dmu_recv_tag);
638 return (err);
639 }
640 drc->drc_logical_ds = drc->drc_real_ds = ds;
641 } else if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE)) {
642 /* online incremental receive */
445
643
446 /* set snapshot's creation time and guid */
447 hds = os->os->os_dsl_dataset;
448 VERIFY(0 == dsl_dataset_open_obj(hds->ds_dir->dd_pool,
449 hds->ds_phys->ds_prev_snap_obj, NULL,
450 DS_MODE_PRIMARY | DS_MODE_READONLY | DS_MODE_INCONSISTENT,
451 FTAG, &ds));
644 /* tmp clone name is: tofs/%tosnap" */
645 (void) snprintf(rbsa.clonelastname, sizeof (rbsa.clonelastname),
646 "%%%s", tosnap);
452
647
453 dmu_buf_will_dirty(ds->ds_dbuf, tx);
454 ds->ds_phys->ds_creation_time = drrb->drr_creation_time;
455 ds->ds_phys->ds_guid = drrb->drr_toguid;
456 ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
648 /* open the dataset we are logically receiving into */
649 err = dsl_dataset_hold(tofs, dmu_recv_tag, &ds);
650 if (err)
651 return (err);
457
652
458 dsl_dataset_close(ds, DS_MODE_PRIMARY, FTAG);
653 rbsa.force = force;
654 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
655 recv_incremental_check,
656 recv_online_incremental_sync, ds, &rbsa, 5);
657 if (err) {
658 dsl_dataset_rele(ds, dmu_recv_tag);
659 return (err);
660 }
661 drc->drc_logical_ds = ds;
662 drc->drc_real_ds = rbsa.ds;
663 } else {
664 /* create new fs -- full backup or clone */
665 dsl_dir_t *dd = NULL;
666 const char *tail;
459
667
460 dmu_buf_will_dirty(hds->ds_dbuf, tx);
461 hds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
668 err = dsl_dir_open(tofs, FTAG, &dd, &tail);
669 if (err)
670 return (err);
671 if (tail == NULL) {
672 if (!force) {
673 dsl_dir_close(dd, FTAG);
674 return (EEXIST);
675 }
676
677 rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
678 err = dsl_dataset_own_obj(dd->dd_pool,
679 dd->dd_phys->dd_head_dataset_obj,
680 DS_MODE_INCONSISTENT, FTAG, &ds);
681 rw_exit(&dd->dd_pool->dp_config_rwlock);
682 if (err) {
683 dsl_dir_close(dd, FTAG);
684 return (err);
685 }
686
687 dsl_dataset_make_exclusive(ds, FTAG);
688 err = dsl_sync_task_do(dd->dd_pool,
689 recv_full_existing_check,
690 recv_full_existing_sync, ds, &rbsa, 5);
691 dsl_dataset_disown(ds, FTAG);
692 } else {
693 err = dsl_sync_task_do(dd->dd_pool, recv_full_check,
694 recv_full_sync, dd, &rbsa, 5);
695 }
696 dsl_dir_close(dd, FTAG);
697 if (err)
698 return (err);
699 drc->drc_logical_ds = drc->drc_real_ds = rbsa.ds;
700 drc->drc_newfs = B_TRUE;
701 }
702
703 return (0);
462}
463
704}
705
706struct restorearg {
707 int err;
708 int byteswap;
709 kthread_t *td;
710 struct file *fp;
711 char *buf;
712 uint64_t voff;
713 int bufsize; /* amount of memory allocated for buf */
714 zio_cksum_t cksum;
715};
716
464static int
465restore_bytes(struct restorearg *ra, void *buf, int len, off_t off, int *resid)
466{
467 struct uio auio;
468 struct iovec aiov;
469 int error;
470
471 aiov.iov_base = buf;

--- 14 unchanged lines hidden (view full) ---

486 *resid = auio.uio_resid;
487 return (error);
488}
489
490static void *
491restore_read(struct restorearg *ra, int len)
492{
493 void *rv;
717static int
718restore_bytes(struct restorearg *ra, void *buf, int len, off_t off, int *resid)
719{
720 struct uio auio;
721 struct iovec aiov;
722 int error;
723
724 aiov.iov_base = buf;

--- 14 unchanged lines hidden (view full) ---

739 *resid = auio.uio_resid;
740 return (error);
741}
742
743static void *
744restore_read(struct restorearg *ra, int len)
745{
746 void *rv;
747 int done = 0;
494
495 /* some things will require 8-byte alignment, so everything must */
496 ASSERT3U(len % 8, ==, 0);
497
748
749 /* some things will require 8-byte alignment, so everything must */
750 ASSERT3U(len % 8, ==, 0);
751
498 while (ra->buflen - ra->bufoff < len) {
752 while (done < len) {
499 int resid;
753 int resid;
500 int leftover = ra->buflen - ra->bufoff;
501
754
502 (void) memmove(ra->buf, ra->buf + ra->bufoff, leftover);
755 ra->err = restore_bytes(ra, (caddr_t)ra->buf + done,
756 len - done, ra->voff, &resid);
503
757
504 ra->err = restore_bytes(ra, (caddr_t)ra->buf + leftover,
505 ra->bufsize - leftover, ra->voff, &resid);
506
507 ra->voff += ra->bufsize - leftover - resid;
508 ra->buflen = ra->bufsize - resid;
509 ra->bufoff = 0;
510 if (resid == ra->bufsize - leftover)
758 if (resid == len - done)
511 ra->err = EINVAL;
759 ra->err = EINVAL;
760 ra->voff += len - done - resid;
761 done = len - resid;
512 if (ra->err)
513 return (NULL);
762 if (ra->err)
763 return (NULL);
514 /* Could compute checksum here? */
515 }
516
764 }
765
517 ASSERT3U(ra->bufoff % 8, ==, 0);
518 ASSERT3U(ra->buflen - ra->bufoff, >=, len);
519 rv = ra->buf + ra->bufoff;
520 ra->bufoff += len;
766 ASSERT3U(done, ==, len);
767 rv = ra->buf;
521 if (ra->byteswap)
768 if (ra->byteswap)
522 fletcher_4_incremental_byteswap(rv, len, &ra->zc);
769 fletcher_4_incremental_byteswap(rv, len, &ra->cksum);
523 else
770 else
524 fletcher_4_incremental_native(rv, len, &ra->zc);
771 fletcher_4_incremental_native(rv, len, &ra->cksum);
525 return (rv);
526}
527
528static void
529backup_byteswap(dmu_replay_record_t *drr)
530{
531#define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X))
532#define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X))
533 drr->drr_type = BSWAP_32(drr->drr_type);
772 return (rv);
773}
774
775static void
776backup_byteswap(dmu_replay_record_t *drr)
777{
778#define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X))
779#define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X))
780 drr->drr_type = BSWAP_32(drr->drr_type);
781 drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen);
534 switch (drr->drr_type) {
535 case DRR_BEGIN:
536 DO64(drr_begin.drr_magic);
537 DO64(drr_begin.drr_version);
538 DO64(drr_begin.drr_creation_time);
539 DO32(drr_begin.drr_type);
782 switch (drr->drr_type) {
783 case DRR_BEGIN:
784 DO64(drr_begin.drr_magic);
785 DO64(drr_begin.drr_version);
786 DO64(drr_begin.drr_creation_time);
787 DO32(drr_begin.drr_type);
788 DO32(drr_begin.drr_flags);
540 DO64(drr_begin.drr_toguid);
541 DO64(drr_begin.drr_fromguid);
542 break;
543 case DRR_OBJECT:
544 DO64(drr_object.drr_object);
545 /* DO64(drr_object.drr_allocation_txg); */
546 DO32(drr_object.drr_type);
547 DO32(drr_object.drr_bonustype);

--- 90 unchanged lines hidden (view full) ---

638 dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx);
639
640 if (drro->drr_bonuslen) {
641 dmu_buf_t *db;
642 void *data;
643 VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db));
644 dmu_buf_will_dirty(db, tx);
645
789 DO64(drr_begin.drr_toguid);
790 DO64(drr_begin.drr_fromguid);
791 break;
792 case DRR_OBJECT:
793 DO64(drr_object.drr_object);
794 /* DO64(drr_object.drr_allocation_txg); */
795 DO32(drr_object.drr_type);
796 DO32(drr_object.drr_bonustype);

--- 90 unchanged lines hidden (view full) ---

887 dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx);
888
889 if (drro->drr_bonuslen) {
890 dmu_buf_t *db;
891 void *data;
892 VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db));
893 dmu_buf_will_dirty(db, tx);
894
646 ASSERT3U(db->db_size, ==, drro->drr_bonuslen);
647 data = restore_read(ra, P2ROUNDUP(db->db_size, 8));
895 ASSERT3U(db->db_size, >=, drro->drr_bonuslen);
896 data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8));
648 if (data == NULL) {
649 dmu_tx_commit(tx);
650 return (ra->err);
651 }
897 if (data == NULL) {
898 dmu_tx_commit(tx);
899 return (ra->err);
900 }
652 bcopy(data, db->db_data, db->db_size);
901 bcopy(data, db->db_data, drro->drr_bonuslen);
653 if (ra->byteswap) {
654 dmu_ot[drro->drr_bonustype].ot_byteswap(db->db_data,
655 drro->drr_bonuslen);
656 }
657 dmu_buf_rele(db, FTAG);
658 }
659 dmu_tx_commit(tx);
660 return (0);

--- 7 unchanged lines hidden (view full) ---

668 uint64_t obj;
669
670 if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj)
671 return (EINVAL);
672
673 for (obj = drrfo->drr_firstobj;
674 obj < drrfo->drr_firstobj + drrfo->drr_numobjs;
675 (void) dmu_object_next(os, &obj, FALSE, 0)) {
902 if (ra->byteswap) {
903 dmu_ot[drro->drr_bonustype].ot_byteswap(db->db_data,
904 drro->drr_bonuslen);
905 }
906 dmu_buf_rele(db, FTAG);
907 }
908 dmu_tx_commit(tx);
909 return (0);

--- 7 unchanged lines hidden (view full) ---

917 uint64_t obj;
918
919 if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj)
920 return (EINVAL);
921
922 for (obj = drrfo->drr_firstobj;
923 obj < drrfo->drr_firstobj + drrfo->drr_numobjs;
924 (void) dmu_object_next(os, &obj, FALSE, 0)) {
676 dmu_tx_t *tx;
677 int err;
678
679 if (dmu_object_info(os, obj, NULL) != 0)
680 continue;
681
925 int err;
926
927 if (dmu_object_info(os, obj, NULL) != 0)
928 continue;
929
682 tx = dmu_tx_create(os);
683 dmu_tx_hold_bonus(tx, obj);
684 err = dmu_tx_assign(tx, TXG_WAIT);
685 if (err) {
686 dmu_tx_abort(tx);
930 err = dmu_free_object(os, obj);
931 if (err)
687 return (err);
932 return (err);
688 }
689 err = dmu_object_free(os, obj, tx);
690 dmu_tx_commit(tx);
691 if (err && err != ENOENT)
692 return (EINVAL);
693 }
694 return (0);
695}
696
697static int
698restore_write(struct restorearg *ra, objset_t *os,
699 struct drr_write *drrw)
700{

--- 29 unchanged lines hidden (view full) ---

730 return (0);
731}
732
733/* ARGSUSED */
734static int
735restore_free(struct restorearg *ra, objset_t *os,
736 struct drr_free *drrf)
737{
933 }
934 return (0);
935}
936
937static int
938restore_write(struct restorearg *ra, objset_t *os,
939 struct drr_write *drrw)
940{

--- 29 unchanged lines hidden (view full) ---

970 return (0);
971}
972
973/* ARGSUSED */
974static int
975restore_free(struct restorearg *ra, objset_t *os,
976 struct drr_free *drrf)
977{
738 dmu_tx_t *tx;
739 int err;
740
741 if (drrf->drr_length != -1ULL &&
742 drrf->drr_offset + drrf->drr_length < drrf->drr_offset)
743 return (EINVAL);
744
745 if (dmu_object_info(os, drrf->drr_object, NULL) != 0)
746 return (EINVAL);
747
978 int err;
979
980 if (drrf->drr_length != -1ULL &&
981 drrf->drr_offset + drrf->drr_length < drrf->drr_offset)
982 return (EINVAL);
983
984 if (dmu_object_info(os, drrf->drr_object, NULL) != 0)
985 return (EINVAL);
986
748 tx = dmu_tx_create(os);
749
750 dmu_tx_hold_free(tx, drrf->drr_object,
987 err = dmu_free_long_range(os, drrf->drr_object,
751 drrf->drr_offset, drrf->drr_length);
988 drrf->drr_offset, drrf->drr_length);
752 err = dmu_tx_assign(tx, TXG_WAIT);
753 if (err) {
754 dmu_tx_abort(tx);
755 return (err);
756 }
757 err = dmu_free_range(os, drrf->drr_object,
758 drrf->drr_offset, drrf->drr_length, tx);
759 dmu_tx_commit(tx);
760 return (err);
761}
762
989 return (err);
990}
991
992void
993dmu_recv_abort_cleanup(dmu_recv_cookie_t *drc)
994{
995 if (drc->drc_newfs || drc->drc_real_ds != drc->drc_logical_ds) {
996 /*
997 * online incremental or new fs: destroy the fs (which
998 * may be a clone) that we created
999 */
1000 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag);
1001 if (drc->drc_real_ds != drc->drc_logical_ds)
1002 dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag);
1003 } else {
1004 /*
1005 * offline incremental: rollback to most recent snapshot.
1006 */
1007 (void) dsl_dataset_rollback(drc->drc_real_ds, DMU_OST_NONE);
1008 dsl_dataset_disown(drc->drc_real_ds, dmu_recv_tag);
1009 }
1010}
1011
1012/*
1013 * NB: callers *must* call dmu_recv_end() if this succeeds.
1014 */
763int
1015int
764dmu_recvbackup(char *tosnap, struct drr_begin *drrb, uint64_t *sizep,
765 boolean_t force, struct file *fp, uint64_t voffset)
1016dmu_recv_stream(dmu_recv_cookie_t *drc, struct file *fp, offset_t *voffp)
766{
767 kthread_t *td = curthread;
1017{
1018 kthread_t *td = curthread;
768 struct restorearg ra;
1019 struct restorearg ra = { 0 };
769 dmu_replay_record_t *drr;
1020 dmu_replay_record_t *drr;
770 char *cp;
771 objset_t *os = NULL;
772 zio_cksum_t pzc;
1021 objset_t *os;
1022 zio_cksum_t pcksum;
773
1023
774 bzero(&ra, sizeof (ra));
775 ra.td = td;
776 ra.fp = fp;
777 ra.voff = voffset;
778 ra.bufsize = 1<<20;
779 ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP);
780
781 if (drrb->drr_magic == DMU_BACKUP_MAGIC) {
782 ra.byteswap = FALSE;
783 } else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
1024 if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC))
784 ra.byteswap = TRUE;
1025 ra.byteswap = TRUE;
785 } else {
786 ra.err = EINVAL;
787 goto out;
788 }
789
1026
790 /*
791 * NB: this assumes that struct drr_begin will be the largest in
792 * dmu_replay_record_t's drr_u, and thus we don't need to pad it
793 * with zeros to make it the same length as we wrote out.
794 */
795 ((dmu_replay_record_t *)ra.buf)->drr_type = DRR_BEGIN;
796 ((dmu_replay_record_t *)ra.buf)->drr_pad = 0;
797 ((dmu_replay_record_t *)ra.buf)->drr_u.drr_begin = *drrb;
798 if (ra.byteswap) {
799 fletcher_4_incremental_byteswap(ra.buf,
800 sizeof (dmu_replay_record_t), &ra.zc);
801 } else {
802 fletcher_4_incremental_native(ra.buf,
803 sizeof (dmu_replay_record_t), &ra.zc);
1027 {
1028 /* compute checksum of drr_begin record */
1029 dmu_replay_record_t *drr;
1030 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
1031
1032 drr->drr_type = DRR_BEGIN;
1033 drr->drr_u.drr_begin = *drc->drc_drrb;
1034 if (ra.byteswap) {
1035 fletcher_4_incremental_byteswap(drr,
1036 sizeof (dmu_replay_record_t), &ra.cksum);
1037 } else {
1038 fletcher_4_incremental_native(drr,
1039 sizeof (dmu_replay_record_t), &ra.cksum);
1040 }
1041 kmem_free(drr, sizeof (dmu_replay_record_t));
804 }
1042 }
805 (void) strcpy(drrb->drr_toname, tosnap); /* for the sync funcs */
806
807 if (ra.byteswap) {
1043
1044 if (ra.byteswap) {
1045 struct drr_begin *drrb = drc->drc_drrb;
808 drrb->drr_magic = BSWAP_64(drrb->drr_magic);
809 drrb->drr_version = BSWAP_64(drrb->drr_version);
810 drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time);
811 drrb->drr_type = BSWAP_32(drrb->drr_type);
812 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
813 drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid);
814 }
815
1046 drrb->drr_magic = BSWAP_64(drrb->drr_magic);
1047 drrb->drr_version = BSWAP_64(drrb->drr_version);
1048 drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time);
1049 drrb->drr_type = BSWAP_32(drrb->drr_type);
1050 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
1051 drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid);
1052 }
1053
816 ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
1054 ra.td = td;
1055 ra.fp = fp;
1056 ra.voff = *voffp;
1057 ra.bufsize = 1<<20;
1058 ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP);
817
1059
818 if (drrb->drr_version != DMU_BACKUP_VERSION ||
819 drrb->drr_type >= DMU_OST_NUMTYPES ||
820 strchr(drrb->drr_toname, '@') == NULL) {
821 ra.err = EINVAL;
822 goto out;
823 }
1060 /* these were verified in dmu_recv_begin */
1061 ASSERT(drc->drc_drrb->drr_version == DMU_BACKUP_STREAM_VERSION);
1062 ASSERT(drc->drc_drrb->drr_type < DMU_OST_NUMTYPES);
824
825 /*
1063
1064 /*
826 * Process the begin in syncing context.
827 */
828 if (drrb->drr_fromguid) {
829 /* incremental backup */
830 dsl_dataset_t *ds = NULL;
831
832 cp = strchr(tosnap, '@');
833 *cp = '\0';
834 ra.err = dsl_dataset_open(tosnap, DS_MODE_EXCLUSIVE, FTAG, &ds);
835 *cp = '@';
836 if (ra.err)
837 goto out;
838
839 /*
840 * Only do the rollback if the most recent snapshot
841 * matches the incremental source
842 */
843 if (force) {
844 if (ds->ds_prev == NULL ||
845 ds->ds_prev->ds_phys->ds_guid !=
846 drrb->drr_fromguid) {
847 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
848 kmem_free(ra.buf, ra.bufsize);
849 return (ENODEV);
850 }
851 (void) dsl_dataset_rollback(ds);
852 }
853 ra.err = dsl_sync_task_do(ds->ds_dir->dd_pool,
854 replay_incremental_check, replay_incremental_sync,
855 ds, drrb, 1);
856 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
857 } else {
858 /* full backup */
859 dsl_dir_t *dd = NULL;
860 const char *tail;
861
862 /* can't restore full backup into topmost fs, for now */
863 if (strrchr(drrb->drr_toname, '/') == NULL) {
864 ra.err = EINVAL;
865 goto out;
866 }
867
868 cp = strchr(tosnap, '@');
869 *cp = '\0';
870 ra.err = dsl_dir_open(tosnap, FTAG, &dd, &tail);
871 *cp = '@';
872 if (ra.err)
873 goto out;
874 if (tail == NULL) {
875 ra.err = EEXIST;
876 goto out;
877 }
878
879 ra.err = dsl_sync_task_do(dd->dd_pool, replay_full_check,
880 replay_full_sync, dd, drrb, 5);
881 dsl_dir_close(dd, FTAG);
882 }
883 if (ra.err)
884 goto out;
885
886 /*
887 * Open the objset we are modifying.
888 */
1065 * Open the objset we are modifying.
1066 */
1067 VERIFY(dmu_objset_open_ds(drc->drc_real_ds, DMU_OST_ANY, &os) == 0);
889
1068
890 cp = strchr(tosnap, '@');
891 *cp = '\0';
892 ra.err = dmu_objset_open(tosnap, DMU_OST_ANY,
893 DS_MODE_PRIMARY | DS_MODE_INCONSISTENT, &os);
894 *cp = '@';
895 ASSERT3U(ra.err, ==, 0);
1069 ASSERT(drc->drc_real_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT);
896
897 /*
898 * Read records and process them.
899 */
1070
1071 /*
1072 * Read records and process them.
1073 */
900 pzc = ra.zc;
1074 pcksum = ra.cksum;
901 while (ra.err == 0 &&
902 NULL != (drr = restore_read(&ra, sizeof (*drr)))) {
1075 while (ra.err == 0 &&
1076 NULL != (drr = restore_read(&ra, sizeof (*drr)))) {
903 if (SIGPENDING(td)) {
1077 if (issig(JUSTLOOKING) && issig(FORREAL)) {
904 ra.err = EINTR;
905 goto out;
906 }
907
908 if (ra.byteswap)
909 backup_byteswap(drr);
910
911 switch (drr->drr_type) {

--- 30 unchanged lines hidden (view full) ---

942 case DRR_END:
943 {
944 struct drr_end drre = drr->drr_u.drr_end;
945 /*
946 * We compare against the *previous* checksum
947 * value, because the stored checksum is of
948 * everything before the DRR_END record.
949 */
1078 ra.err = EINTR;
1079 goto out;
1080 }
1081
1082 if (ra.byteswap)
1083 backup_byteswap(drr);
1084
1085 switch (drr->drr_type) {

--- 30 unchanged lines hidden (view full) ---

1116 case DRR_END:
1117 {
1118 struct drr_end drre = drr->drr_u.drr_end;
1119 /*
1120 * We compare against the *previous* checksum
1121 * value, because the stored checksum is of
1122 * everything before the DRR_END record.
1123 */
950 if (drre.drr_checksum.zc_word[0] != 0 &&
951 !ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pzc)) {
1124 if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum))
952 ra.err = ECKSUM;
1125 ra.err = ECKSUM;
953 goto out;
954 }
955
956 ra.err = dsl_sync_task_do(dmu_objset_ds(os)->
957 ds_dir->dd_pool, replay_end_check, replay_end_sync,
958 os, drrb, 3);
959 goto out;
960 }
961 default:
962 ra.err = EINVAL;
963 goto out;
964 }
1126 goto out;
1127 }
1128 default:
1129 ra.err = EINVAL;
1130 goto out;
1131 }
965 pzc = ra.zc;
1132 pcksum = ra.cksum;
966 }
1133 }
1134 ASSERT(ra.err != 0);
967
968out:
1135
1136out:
969 if (os)
970 dmu_objset_close(os);
1137 dmu_objset_close(os);
971
1138
972 /*
973 * Make sure we don't rollback/destroy unless we actually
974 * processed the begin properly. 'os' will only be set if this
975 * is the case.
976 */
977 if (ra.err && os && tosnap && strchr(tosnap, '@')) {
1139 if (ra.err != 0) {
978 /*
979 * rollback or destroy what we created, so we don't
980 * leave it in the restoring state.
981 */
1140 /*
1141 * rollback or destroy what we created, so we don't
1142 * leave it in the restoring state.
1143 */
982 dsl_dataset_t *ds;
983 int err;
984
985 cp = strchr(tosnap, '@');
986 *cp = '\0';
987 err = dsl_dataset_open(tosnap,
988 DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT,
989 FTAG, &ds);
990 if (err == 0) {
991 txg_wait_synced(ds->ds_dir->dd_pool, 0);
992 if (drrb->drr_fromguid) {
993 /* incremental: rollback to most recent snap */
994 (void) dsl_dataset_rollback(ds);
995 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
996 } else {
997 /* full: destroy whole fs */
998 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
999 (void) dsl_dataset_destroy(tosnap);
1000 }
1001 }
1002 *cp = '@';
1144 txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0);
1145 dmu_recv_abort_cleanup(drc);
1003 }
1004
1005 kmem_free(ra.buf, ra.bufsize);
1146 }
1147
1148 kmem_free(ra.buf, ra.bufsize);
1006 if (sizep)
1007 *sizep = ra.voff;
1149 *voffp = ra.voff;
1008 return (ra.err);
1009}
1150 return (ra.err);
1151}
1152
1153struct recvendsyncarg {
1154 char *tosnap;
1155 uint64_t creation_time;
1156 uint64_t toguid;
1157};
1158
1159static int
1160recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx)
1161{
1162 dsl_dataset_t *ds = arg1;
1163 struct recvendsyncarg *resa = arg2;
1164
1165 return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx));
1166}
1167
1168static void
1169recv_end_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
1170{
1171 dsl_dataset_t *ds = arg1;
1172 struct recvendsyncarg *resa = arg2;
1173
1174 dsl_dataset_snapshot_sync(ds, resa->tosnap, cr, tx);
1175
1176 /* set snapshot's creation time and guid */
1177 dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
1178 ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time;
1179 ds->ds_prev->ds_phys->ds_guid = resa->toguid;
1180 ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1181
1182 dmu_buf_will_dirty(ds->ds_dbuf, tx);
1183 ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1184}
1185
1186int
1187dmu_recv_end(dmu_recv_cookie_t *drc)
1188{
1189 struct recvendsyncarg resa;
1190 dsl_dataset_t *ds = drc->drc_logical_ds;
1191 int err;
1192
1193 /*
1194 * XXX hack; seems the ds is still dirty and
1195 * dsl_pool_zil_clean() expects it to have a ds_user_ptr
1196 * (and zil), but clone_swap() can close it.
1197 */
1198 txg_wait_synced(ds->ds_dir->dd_pool, 0);
1199
1200 if (ds != drc->drc_real_ds) {
1201 /* we are doing an online recv */
1202 if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) {
1203 err = dsl_dataset_clone_swap(drc->drc_real_ds, ds,
1204 drc->drc_force);
1205 if (err)
1206 dsl_dataset_disown(ds, dmu_recv_tag);
1207 } else {
1208 err = EBUSY;
1209 dsl_dataset_rele(ds, dmu_recv_tag);
1210 }
1211 /* dsl_dataset_destroy() will disown the ds */
1212 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag);
1213 if (err)
1214 return (err);
1215 }
1216
1217 resa.creation_time = drc->drc_drrb->drr_creation_time;
1218 resa.toguid = drc->drc_drrb->drr_toguid;
1219 resa.tosnap = drc->drc_tosnap;
1220
1221 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1222 recv_end_check, recv_end_sync, ds, &resa, 3);
1223 if (err) {
1224 if (drc->drc_newfs) {
1225 ASSERT(ds == drc->drc_real_ds);
1226 (void) dsl_dataset_destroy(ds, dmu_recv_tag);
1227 return (err);
1228 } else {
1229 (void) dsl_dataset_rollback(ds, DMU_OST_NONE);
1230 }
1231 }
1232
1233 /* release the hold from dmu_recv_begin */
1234 dsl_dataset_disown(ds, dmu_recv_tag);
1235 return (err);
1236}