Deleted Added
full compact
dmu_send.c (246666) dmu_send.c (248571)
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

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

42#include <sys/zfs_ioctl.h>
43#include <sys/zap.h>
44#include <sys/zio_checksum.h>
45#include <sys/zfs_znode.h>
46#include <zfs_fletcher.h>
47#include <sys/avl.h>
48#include <sys/ddt.h>
49#include <sys/zfs_onexit.h>
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

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

42#include <sys/zfs_ioctl.h>
43#include <sys/zap.h>
44#include <sys/zio_checksum.h>
45#include <sys/zfs_znode.h>
46#include <zfs_fletcher.h>
47#include <sys/avl.h>
48#include <sys/ddt.h>
49#include <sys/zfs_onexit.h>
50#include <sys/dmu_send.h>
51#include <sys/dsl_destroy.h>
50
51/* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */
52int zfs_send_corrupt_data = B_FALSE;
53
54static char *dmu_recv_tag = "dmu_recv_tag";
52
53/* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */
54int zfs_send_corrupt_data = B_FALSE;
55
56static char *dmu_recv_tag = "dmu_recv_tag";
57static const char *recv_clone_name = "%recv";
55
56static int
57dump_bytes(dmu_sendarg_t *dsp, void *buf, int len)
58{
59 dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset;
60 struct uio auio;
61 struct iovec aiov;
62 ASSERT0(len % 8);

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

301
302 if (dump_bytes(dsp, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0)
303 return (EINTR);
304
305 /* free anything past the end of the file */
306 if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) *
307 (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL))
308 return (EINTR);
58
59static int
60dump_bytes(dmu_sendarg_t *dsp, void *buf, int len)
61{
62 dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset;
63 struct uio auio;
64 struct iovec aiov;
65 ASSERT0(len % 8);

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

304
305 if (dump_bytes(dsp, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0)
306 return (EINTR);
307
308 /* free anything past the end of the file */
309 if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) *
310 (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL))
311 return (EINTR);
309 if (dsp->dsa_err)
312 if (dsp->dsa_err != 0)
310 return (EINTR);
311 return (0);
312}
313
314#define BP_SPAN(dnp, level) \
315 (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \
316 (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT)))
317

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

351 &aflags, zb) != 0)
352 return (EIO);
353
354 blk = abuf->b_data;
355 for (i = 0; i < blksz >> DNODE_SHIFT; i++) {
356 uint64_t dnobj = (zb->zb_blkid <<
357 (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i;
358 err = dump_dnode(dsp, dnobj, blk+i);
313 return (EINTR);
314 return (0);
315}
316
317#define BP_SPAN(dnp, level) \
318 (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \
319 (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT)))
320

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

354 &aflags, zb) != 0)
355 return (EIO);
356
357 blk = abuf->b_data;
358 for (i = 0; i < blksz >> DNODE_SHIFT; i++) {
359 uint64_t dnobj = (zb->zb_blkid <<
360 (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i;
361 err = dump_dnode(dsp, dnobj, blk+i);
359 if (err)
362 if (err != 0)
360 break;
361 }
362 (void) arc_buf_remove_ref(abuf, &abuf);
363 } else if (type == DMU_OT_SA) {
364 uint32_t aflags = ARC_WAIT;
365 arc_buf_t *abuf;
366 int blksz = BP_GET_LSIZE(bp);
367

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

398 blksz, bp, abuf->b_data);
399 (void) arc_buf_remove_ref(abuf, &abuf);
400 }
401
402 ASSERT(err == 0 || err == EINTR);
403 return (err);
404}
405
363 break;
364 }
365 (void) arc_buf_remove_ref(abuf, &abuf);
366 } else if (type == DMU_OT_SA) {
367 uint32_t aflags = ARC_WAIT;
368 arc_buf_t *abuf;
369 int blksz = BP_GET_LSIZE(bp);
370

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

401 blksz, bp, abuf->b_data);
402 (void) arc_buf_remove_ref(abuf, &abuf);
403 }
404
405 ASSERT(err == 0 || err == EINTR);
406 return (err);
407}
408
406int
407dmu_send(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
408 int outfd, struct file *fp, offset_t *off)
409/*
410 * Releases dp, ds, and fromds, using the specified tag.
411 */
412static int
413dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds,
414#ifdef illumos
415 dsl_dataset_t *fromds, int outfd, vnode_t *vp, offset_t *off)
416#else
417 dsl_dataset_t *fromds, int outfd, struct file *fp, offset_t *off)
418#endif
409{
419{
410 dsl_dataset_t *ds = tosnap->os_dsl_dataset;
411 dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL;
420 objset_t *os;
412 dmu_replay_record_t *drr;
413 dmu_sendarg_t *dsp;
414 int err;
415 uint64_t fromtxg = 0;
416
421 dmu_replay_record_t *drr;
422 dmu_sendarg_t *dsp;
423 int err;
424 uint64_t fromtxg = 0;
425
417 /* tosnap must be a snapshot */
418 if (ds->ds_phys->ds_next_snap_obj == 0)
419 return (EINVAL);
420
421 /* fromsnap must be an earlier snapshot from the same fs as tosnap */
422 if (fromds && (ds->ds_dir != fromds->ds_dir ||
423 fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg))
426 if (fromds != NULL && !dsl_dataset_is_before(ds, fromds)) {
427 dsl_dataset_rele(fromds, tag);
428 dsl_dataset_rele(ds, tag);
429 dsl_pool_rele(dp, tag);
424 return (EXDEV);
430 return (EXDEV);
431 }
425
432
426 if (fromorigin) {
427 dsl_pool_t *dp = ds->ds_dir->dd_pool;
428
429 if (fromsnap)
430 return (EINVAL);
431
432 if (dsl_dir_is_clone(ds->ds_dir)) {
433 rw_enter(&dp->dp_config_rwlock, RW_READER);
434 err = dsl_dataset_hold_obj(dp,
435 ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds);
436 rw_exit(&dp->dp_config_rwlock);
437 if (err)
438 return (err);
439 } else {
440 fromorigin = B_FALSE;
441 }
433 err = dmu_objset_from_ds(ds, &os);
434 if (err != 0) {
435 if (fromds != NULL)
436 dsl_dataset_rele(fromds, tag);
437 dsl_dataset_rele(ds, tag);
438 dsl_pool_rele(dp, tag);
439 return (err);
442 }
443
440 }
441
444
445 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
446 drr->drr_type = DRR_BEGIN;
447 drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
448 DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo,
449 DMU_SUBSTREAM);
450
451#ifdef _KERNEL
442 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
443 drr->drr_type = DRR_BEGIN;
444 drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
445 DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo,
446 DMU_SUBSTREAM);
447
448#ifdef _KERNEL
452 if (dmu_objset_type(tosnap) == DMU_OST_ZFS) {
449 if (dmu_objset_type(os) == DMU_OST_ZFS) {
453 uint64_t version;
450 uint64_t version;
454 if (zfs_get_zplprop(tosnap, ZFS_PROP_VERSION, &version) != 0) {
451 if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &version) != 0) {
455 kmem_free(drr, sizeof (dmu_replay_record_t));
452 kmem_free(drr, sizeof (dmu_replay_record_t));
453 if (fromds != NULL)
454 dsl_dataset_rele(fromds, tag);
455 dsl_dataset_rele(ds, tag);
456 dsl_pool_rele(dp, tag);
456 return (EINVAL);
457 }
457 return (EINVAL);
458 }
458 if (version == ZPL_VERSION_SA) {
459 if (version >= ZPL_VERSION_SA) {
459 DMU_SET_FEATUREFLAGS(
460 drr->drr_u.drr_begin.drr_versioninfo,
461 DMU_BACKUP_FEATURE_SA_SPILL);
462 }
463 }
464#endif
465
466 drr->drr_u.drr_begin.drr_creation_time =
467 ds->ds_phys->ds_creation_time;
460 DMU_SET_FEATUREFLAGS(
461 drr->drr_u.drr_begin.drr_versioninfo,
462 DMU_BACKUP_FEATURE_SA_SPILL);
463 }
464 }
465#endif
466
467 drr->drr_u.drr_begin.drr_creation_time =
468 ds->ds_phys->ds_creation_time;
468 drr->drr_u.drr_begin.drr_type = tosnap->os_phys->os_type;
469 if (fromorigin)
469 drr->drr_u.drr_begin.drr_type = dmu_objset_type(os);
470 if (fromds != NULL && ds->ds_dir != fromds->ds_dir)
470 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE;
471 drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid;
472 if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
473 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA;
474
471 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE;
472 drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid;
473 if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
474 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA;
475
475 if (fromds)
476 if (fromds != NULL)
476 drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid;
477 dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname);
478
477 drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid;
478 dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname);
479
479 if (fromds)
480 if (fromds != NULL) {
480 fromtxg = fromds->ds_phys->ds_creation_txg;
481 fromtxg = fromds->ds_phys->ds_creation_txg;
481 if (fromorigin)
482 dsl_dataset_rele(fromds, FTAG);
482 dsl_dataset_rele(fromds, tag);
483 fromds = NULL;
484 }
483
484 dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP);
485
486 dsp->dsa_drr = drr;
487 dsp->dsa_outfd = outfd;
488 dsp->dsa_proc = curproc;
489 dsp->dsa_td = curthread;
490 dsp->dsa_fp = fp;
485
486 dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP);
487
488 dsp->dsa_drr = drr;
489 dsp->dsa_outfd = outfd;
490 dsp->dsa_proc = curproc;
491 dsp->dsa_td = curthread;
492 dsp->dsa_fp = fp;
491 dsp->dsa_os = tosnap;
493 dsp->dsa_os = os;
492 dsp->dsa_off = off;
493 dsp->dsa_toguid = ds->ds_phys->ds_guid;
494 ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0);
495 dsp->dsa_pending_op = PENDING_NONE;
496
497 mutex_enter(&ds->ds_sendstream_lock);
498 list_insert_head(&ds->ds_sendstreams, dsp);
499 mutex_exit(&ds->ds_sendstream_lock);
500
501 if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) {
502 err = dsp->dsa_err;
503 goto out;
504 }
505
494 dsp->dsa_off = off;
495 dsp->dsa_toguid = ds->ds_phys->ds_guid;
496 ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0);
497 dsp->dsa_pending_op = PENDING_NONE;
498
499 mutex_enter(&ds->ds_sendstream_lock);
500 list_insert_head(&ds->ds_sendstreams, dsp);
501 mutex_exit(&ds->ds_sendstream_lock);
502
503 if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) {
504 err = dsp->dsa_err;
505 goto out;
506 }
507
508 dsl_dataset_long_hold(ds, FTAG);
509 dsl_pool_rele(dp, tag);
510
506 err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH,
507 backup_cb, dsp);
508
509 if (dsp->dsa_pending_op != PENDING_NONE)
510 if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0)
511 err = EINTR;
512
511 err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH,
512 backup_cb, dsp);
513
514 if (dsp->dsa_pending_op != PENDING_NONE)
515 if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0)
516 err = EINTR;
517
513 if (err) {
514 if (err == EINTR && dsp->dsa_err)
518 if (err != 0) {
519 if (err == EINTR && dsp->dsa_err != 0)
515 err = dsp->dsa_err;
516 goto out;
517 }
518
519 bzero(drr, sizeof (dmu_replay_record_t));
520 drr->drr_type = DRR_END;
521 drr->drr_u.drr_end.drr_checksum = dsp->dsa_zc;
522 drr->drr_u.drr_end.drr_toguid = dsp->dsa_toguid;

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

529out:
530 mutex_enter(&ds->ds_sendstream_lock);
531 list_remove(&ds->ds_sendstreams, dsp);
532 mutex_exit(&ds->ds_sendstream_lock);
533
534 kmem_free(drr, sizeof (dmu_replay_record_t));
535 kmem_free(dsp, sizeof (dmu_sendarg_t));
536
520 err = dsp->dsa_err;
521 goto out;
522 }
523
524 bzero(drr, sizeof (dmu_replay_record_t));
525 drr->drr_type = DRR_END;
526 drr->drr_u.drr_end.drr_checksum = dsp->dsa_zc;
527 drr->drr_u.drr_end.drr_toguid = dsp->dsa_toguid;

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

534out:
535 mutex_enter(&ds->ds_sendstream_lock);
536 list_remove(&ds->ds_sendstreams, dsp);
537 mutex_exit(&ds->ds_sendstream_lock);
538
539 kmem_free(drr, sizeof (dmu_replay_record_t));
540 kmem_free(dsp, sizeof (dmu_sendarg_t));
541
542 dsl_dataset_long_rele(ds, FTAG);
543 dsl_dataset_rele(ds, tag);
544
537 return (err);
538}
539
540int
545 return (err);
546}
547
548int
541dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
542 uint64_t *sizep)
549dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
550#ifdef illumos
551 int outfd, vnode_t *vp, offset_t *off)
552#else
553 int outfd, struct file *fp, offset_t *off)
554#endif
543{
555{
544 dsl_dataset_t *ds = tosnap->os_dsl_dataset;
545 dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL;
546 dsl_pool_t *dp = ds->ds_dir->dd_pool;
556 dsl_pool_t *dp;
557 dsl_dataset_t *ds;
558 dsl_dataset_t *fromds = NULL;
547 int err;
559 int err;
548 uint64_t size;
549
560
550 /* tosnap must be a snapshot */
551 if (ds->ds_phys->ds_next_snap_obj == 0)
561 err = dsl_pool_hold(pool, FTAG, &dp);
562 if (err != 0)
563 return (err);
564
565 err = dsl_dataset_hold_obj(dp, tosnap, FTAG, &ds);
566 if (err != 0) {
567 dsl_pool_rele(dp, FTAG);
568 return (err);
569 }
570
571 if (fromsnap != 0) {
572 err = dsl_dataset_hold_obj(dp, fromsnap, FTAG, &fromds);
573 if (err != 0) {
574 dsl_dataset_rele(ds, FTAG);
575 dsl_pool_rele(dp, FTAG);
576 return (err);
577 }
578 }
579
580 return (dmu_send_impl(FTAG, dp, ds, fromds, outfd, fp, off));
581}
582
583int
584dmu_send(const char *tosnap, const char *fromsnap,
585#ifdef illumos
586 int outfd, vnode_t *vp, offset_t *off)
587#else
588 int outfd, struct file *fp, offset_t *off)
589#endif
590{
591 dsl_pool_t *dp;
592 dsl_dataset_t *ds;
593 dsl_dataset_t *fromds = NULL;
594 int err;
595
596 if (strchr(tosnap, '@') == NULL)
552 return (EINVAL);
597 return (EINVAL);
598 if (fromsnap != NULL && strchr(fromsnap, '@') == NULL)
599 return (EINVAL);
553
600
554 /* fromsnap must be an earlier snapshot from the same fs as tosnap */
555 if (fromds && (ds->ds_dir != fromds->ds_dir ||
556 fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg))
557 return (EXDEV);
601 err = dsl_pool_hold(tosnap, FTAG, &dp);
602 if (err != 0)
603 return (err);
558
604
559 if (fromorigin) {
560 if (fromsnap)
561 return (EINVAL);
605 err = dsl_dataset_hold(dp, tosnap, FTAG, &ds);
606 if (err != 0) {
607 dsl_pool_rele(dp, FTAG);
608 return (err);
609 }
562
610
563 if (dsl_dir_is_clone(ds->ds_dir)) {
564 rw_enter(&dp->dp_config_rwlock, RW_READER);
565 err = dsl_dataset_hold_obj(dp,
566 ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds);
567 rw_exit(&dp->dp_config_rwlock);
568 if (err)
569 return (err);
570 } else {
571 fromorigin = B_FALSE;
611 if (fromsnap != NULL) {
612 err = dsl_dataset_hold(dp, fromsnap, FTAG, &fromds);
613 if (err != 0) {
614 dsl_dataset_rele(ds, FTAG);
615 dsl_pool_rele(dp, FTAG);
616 return (err);
572 }
573 }
617 }
618 }
619 return (dmu_send_impl(FTAG, dp, ds, fromds, outfd, fp, off));
620}
574
621
622int
623dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep)
624{
625 dsl_pool_t *dp = ds->ds_dir->dd_pool;
626 int err;
627 uint64_t size;
628
629 ASSERT(dsl_pool_config_held(dp));
630
631 /* tosnap must be a snapshot */
632 if (!dsl_dataset_is_snapshot(ds))
633 return (EINVAL);
634
635 /*
636 * fromsnap must be an earlier snapshot from the same fs as tosnap,
637 * or the origin's fs.
638 */
639 if (fromds != NULL && !dsl_dataset_is_before(ds, fromds))
640 return (EXDEV);
641
575 /* Get uncompressed size estimate of changed data. */
576 if (fromds == NULL) {
577 size = ds->ds_phys->ds_uncompressed_bytes;
578 } else {
579 uint64_t used, comp;
580 err = dsl_dataset_space_written(fromds, ds,
581 &used, &comp, &size);
642 /* Get uncompressed size estimate of changed data. */
643 if (fromds == NULL) {
644 size = ds->ds_phys->ds_uncompressed_bytes;
645 } else {
646 uint64_t used, comp;
647 err = dsl_dataset_space_written(fromds, ds,
648 &used, &comp, &size);
582 if (fromorigin)
583 dsl_dataset_rele(fromds, FTAG);
584 if (err)
649 if (err != 0)
585 return (err);
586 }
587
588 /*
589 * Assume that space (both on-disk and in-stream) is dominated by
590 * data. We will adjust for indirect blocks and the copies property,
591 * but ignore per-object space used (eg, dnodes and DRR_OBJECT records).
592 */
593
594 /*
595 * Subtract out approximate space used by indirect blocks.
596 * Assume most space is used by data blocks (non-indirect, non-dnode).
597 * Assume all blocks are recordsize. Assume ditto blocks and
598 * internal fragmentation counter out compression.
599 *
600 * Therefore, space used by indirect blocks is sizeof(blkptr_t) per
601 * block, which we observe in practice.
602 */
603 uint64_t recordsize;
650 return (err);
651 }
652
653 /*
654 * Assume that space (both on-disk and in-stream) is dominated by
655 * data. We will adjust for indirect blocks and the copies property,
656 * but ignore per-object space used (eg, dnodes and DRR_OBJECT records).
657 */
658
659 /*
660 * Subtract out approximate space used by indirect blocks.
661 * Assume most space is used by data blocks (non-indirect, non-dnode).
662 * Assume all blocks are recordsize. Assume ditto blocks and
663 * internal fragmentation counter out compression.
664 *
665 * Therefore, space used by indirect blocks is sizeof(blkptr_t) per
666 * block, which we observe in practice.
667 */
668 uint64_t recordsize;
604 rw_enter(&dp->dp_config_rwlock, RW_READER);
605 err = dsl_prop_get_ds(ds, "recordsize",
606 sizeof (recordsize), 1, &recordsize, NULL);
607 rw_exit(&dp->dp_config_rwlock);
608 if (err)
669 err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize);
670 if (err != 0)
609 return (err);
610 size -= size / recordsize * sizeof (blkptr_t);
611
612 /* Add in the space for the record associated with each block. */
613 size += size / recordsize * sizeof (dmu_replay_record_t);
614
615 *sizep = size;
616
617 return (0);
618}
619
671 return (err);
672 size -= size / recordsize * sizeof (blkptr_t);
673
674 /* Add in the space for the record associated with each block. */
675 size += size / recordsize * sizeof (dmu_replay_record_t);
676
677 *sizep = size;
678
679 return (0);
680}
681
620struct recvbeginsyncarg {
621 const char *tofs;
622 const char *tosnap;
623 dsl_dataset_t *origin;
624 uint64_t fromguid;
625 dmu_objset_type_t type;
626 void *tag;
627 boolean_t force;
628 uint64_t dsflags;
629 char clonelastname[MAXNAMELEN];
630 dsl_dataset_t *ds; /* the ds to recv into; returned from the syncfunc */
631 cred_t *cr;
632};
682typedef struct dmu_recv_begin_arg {
683 const char *drba_origin;
684 dmu_recv_cookie_t *drba_cookie;
685 cred_t *drba_cred;
686} dmu_recv_begin_arg_t;
633
687
634/* ARGSUSED */
635static int
688static int
636recv_new_check(void *arg1, void *arg2, dmu_tx_t *tx)
689recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
690 uint64_t fromguid)
637{
691{
638 dsl_dir_t *dd = arg1;
639 struct recvbeginsyncarg *rbsa = arg2;
640 objset_t *mos = dd->dd_pool->dp_meta_objset;
641 uint64_t val;
692 uint64_t val;
642 int err;
693 int error;
694 dsl_pool_t *dp = ds->ds_dir->dd_pool;
643
695
644 err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj,
645 strrchr(rbsa->tofs, '/') + 1, sizeof (uint64_t), 1, &val);
646
647 if (err != ENOENT)
648 return (err ? err : EEXIST);
649
650 if (rbsa->origin) {
651 /* make sure it's a snap in the same pool */
652 if (rbsa->origin->ds_dir->dd_pool != dd->dd_pool)
653 return (EXDEV);
654 if (!dsl_dataset_is_snapshot(rbsa->origin))
655 return (EINVAL);
656 if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid)
657 return (ENODEV);
658 }
659
660 return (0);
661}
662
663static void
664recv_new_sync(void *arg1, void *arg2, dmu_tx_t *tx)
665{
666 dsl_dir_t *dd = arg1;
667 struct recvbeginsyncarg *rbsa = arg2;
668 uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
669 uint64_t dsobj;
670
671 /* Create and open new dataset. */
672 dsobj = dsl_dataset_create_sync(dd, strrchr(rbsa->tofs, '/') + 1,
673 rbsa->origin, flags, rbsa->cr, tx);
674 VERIFY(0 == dsl_dataset_own_obj(dd->dd_pool, dsobj,
675 B_TRUE, dmu_recv_tag, &rbsa->ds));
676
677 if (rbsa->origin == NULL) {
678 (void) dmu_objset_create_impl(dd->dd_pool->dp_spa,
679 rbsa->ds, &rbsa->ds->ds_phys->ds_bp, rbsa->type, tx);
680 }
681
682 spa_history_log_internal(LOG_DS_REPLAY_FULL_SYNC,
683 dd->dd_pool->dp_spa, tx, "dataset = %lld", dsobj);
684}
685
686/* ARGSUSED */
687static int
688recv_existing_check(void *arg1, void *arg2, dmu_tx_t *tx)
689{
690 dsl_dataset_t *ds = arg1;
691 struct recvbeginsyncarg *rbsa = arg2;
692 int err;
693 uint64_t val;
694
695 /* must not have any changes since most recent snapshot */
696 /* must not have any changes since most recent snapshot */
696 if (!rbsa->force && dsl_dataset_modified_since_lastsnap(ds))
697 if (!drba->drba_cookie->drc_force &&
698 dsl_dataset_modified_since_lastsnap(ds))
697 return (ETXTBSY);
698
699 return (ETXTBSY);
700
701 /* temporary clone name must not exist */
702 error = zap_lookup(dp->dp_meta_objset,
703 ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name,
704 8, 1, &val);
705 if (error != ENOENT)
706 return (error == 0 ? EBUSY : error);
707
699 /* new snapshot name must not exist */
708 /* new snapshot name must not exist */
700 err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
701 ds->ds_phys->ds_snapnames_zapobj, rbsa->tosnap, 8, 1, &val);
702 if (err == 0)
703 return (EEXIST);
704 if (err != ENOENT)
705 return (err);
709 error = zap_lookup(dp->dp_meta_objset,
710 ds->ds_phys->ds_snapnames_zapobj, drba->drba_cookie->drc_tosnap,
711 8, 1, &val);
712 if (error != ENOENT)
713 return (error == 0 ? EEXIST : error);
706
714
707 if (rbsa->fromguid) {
715 if (fromguid != 0) {
708 /* if incremental, most recent snapshot must match fromguid */
709 if (ds->ds_prev == NULL)
710 return (ENODEV);
711
712 /*
713 * most recent snapshot must match fromguid, or there are no
714 * changes since the fromguid one
715 */
716 /* if incremental, most recent snapshot must match fromguid */
717 if (ds->ds_prev == NULL)
718 return (ENODEV);
719
720 /*
721 * most recent snapshot must match fromguid, or there are no
722 * changes since the fromguid one
723 */
716 if (ds->ds_prev->ds_phys->ds_guid != rbsa->fromguid) {
724 if (ds->ds_prev->ds_phys->ds_guid != fromguid) {
717 uint64_t birth = ds->ds_prev->ds_phys->ds_bp.blk_birth;
718 uint64_t obj = ds->ds_prev->ds_phys->ds_prev_snap_obj;
719 while (obj != 0) {
720 dsl_dataset_t *snap;
725 uint64_t birth = ds->ds_prev->ds_phys->ds_bp.blk_birth;
726 uint64_t obj = ds->ds_prev->ds_phys->ds_prev_snap_obj;
727 while (obj != 0) {
728 dsl_dataset_t *snap;
721 err = dsl_dataset_hold_obj(ds->ds_dir->dd_pool,
722 obj, FTAG, &snap);
723 if (err)
729 error = dsl_dataset_hold_obj(dp, obj, FTAG,
730 &snap);
731 if (error != 0)
724 return (ENODEV);
725 if (snap->ds_phys->ds_creation_txg < birth) {
726 dsl_dataset_rele(snap, FTAG);
727 return (ENODEV);
728 }
732 return (ENODEV);
733 if (snap->ds_phys->ds_creation_txg < birth) {
734 dsl_dataset_rele(snap, FTAG);
735 return (ENODEV);
736 }
729 if (snap->ds_phys->ds_guid == rbsa->fromguid) {
737 if (snap->ds_phys->ds_guid == fromguid) {
730 dsl_dataset_rele(snap, FTAG);
731 break; /* it's ok */
732 }
733 obj = snap->ds_phys->ds_prev_snap_obj;
734 dsl_dataset_rele(snap, FTAG);
735 }
736 if (obj == 0)
737 return (ENODEV);
738 }
739 } else {
740 /* if full, most recent snapshot must be $ORIGIN */
741 if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL)
742 return (ENODEV);
743 }
744
738 dsl_dataset_rele(snap, FTAG);
739 break; /* it's ok */
740 }
741 obj = snap->ds_phys->ds_prev_snap_obj;
742 dsl_dataset_rele(snap, FTAG);
743 }
744 if (obj == 0)
745 return (ENODEV);
746 }
747 } else {
748 /* if full, most recent snapshot must be $ORIGIN */
749 if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL)
750 return (ENODEV);
751 }
752
745 /* temporary clone name must not exist */
746 err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset,
747 ds->ds_dir->dd_phys->dd_child_dir_zapobj,
748 rbsa->clonelastname, 8, 1, &val);
749 if (err == 0)
750 return (EEXIST);
751 if (err != ENOENT)
752 return (err);
753
754 return (0);
753 return (0);
754
755}
756
755}
756
757/* ARGSUSED */
757static int
758dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
759{
760 dmu_recv_begin_arg_t *drba = arg;
761 dsl_pool_t *dp = dmu_tx_pool(tx);
762 struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
763 uint64_t fromguid = drrb->drr_fromguid;
764 int flags = drrb->drr_flags;
765 int error;
766 dsl_dataset_t *ds;
767 const char *tofs = drba->drba_cookie->drc_tofs;
768
769 /* already checked */
770 ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
771
772 if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
773 DMU_COMPOUNDSTREAM ||
774 drrb->drr_type >= DMU_OST_NUMTYPES ||
775 ((flags & DRR_FLAG_CLONE) && drba->drba_origin == NULL))
776 return (EINVAL);
777
778 /* Verify pool version supports SA if SA_SPILL feature set */
779 if ((DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
780 DMU_BACKUP_FEATURE_SA_SPILL) &&
781 spa_version(dp->dp_spa) < SPA_VERSION_SA) {
782 return (ENOTSUP);
783 }
784
785 error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
786 if (error == 0) {
787 /* target fs already exists; recv into temp clone */
788
789 /* Can't recv a clone into an existing fs */
790 if (flags & DRR_FLAG_CLONE) {
791 dsl_dataset_rele(ds, FTAG);
792 return (EINVAL);
793 }
794
795 error = recv_begin_check_existing_impl(drba, ds, fromguid);
796 dsl_dataset_rele(ds, FTAG);
797 } else if (error == ENOENT) {
798 /* target fs does not exist; must be a full backup or clone */
799 char buf[MAXNAMELEN];
800
801 /*
802 * If it's a non-clone incremental, we are missing the
803 * target fs, so fail the recv.
804 */
805 if (fromguid != 0 && !(flags & DRR_FLAG_CLONE))
806 return (ENOENT);
807
808 /* Open the parent of tofs */
809 ASSERT3U(strlen(tofs), <, MAXNAMELEN);
810 (void) strlcpy(buf, tofs, strrchr(tofs, '/') - tofs + 1);
811 error = dsl_dataset_hold(dp, buf, FTAG, &ds);
812 if (error != 0)
813 return (error);
814
815 if (drba->drba_origin != NULL) {
816 dsl_dataset_t *origin;
817 error = dsl_dataset_hold(dp, drba->drba_origin,
818 FTAG, &origin);
819 if (error != 0) {
820 dsl_dataset_rele(ds, FTAG);
821 return (error);
822 }
823 if (!dsl_dataset_is_snapshot(origin)) {
824 dsl_dataset_rele(origin, FTAG);
825 dsl_dataset_rele(ds, FTAG);
826 return (EINVAL);
827 }
828 if (origin->ds_phys->ds_guid != fromguid) {
829 dsl_dataset_rele(origin, FTAG);
830 dsl_dataset_rele(ds, FTAG);
831 return (ENODEV);
832 }
833 dsl_dataset_rele(origin, FTAG);
834 }
835 dsl_dataset_rele(ds, FTAG);
836 error = 0;
837 }
838 return (error);
839}
840
758static void
841static void
759recv_existing_sync(void *arg1, void *arg2, dmu_tx_t *tx)
842dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
760{
843{
761 dsl_dataset_t *ohds = arg1;
762 struct recvbeginsyncarg *rbsa = arg2;
763 dsl_pool_t *dp = ohds->ds_dir->dd_pool;
764 dsl_dataset_t *cds;
765 uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags;
844 dmu_recv_begin_arg_t *drba = arg;
845 dsl_pool_t *dp = dmu_tx_pool(tx);
846 struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
847 const char *tofs = drba->drba_cookie->drc_tofs;
848 dsl_dataset_t *ds, *newds;
766 uint64_t dsobj;
849 uint64_t dsobj;
850 int error;
851 uint64_t crflags;
767
852
768 /* create and open the temporary clone */
769 dsobj = dsl_dataset_create_sync(ohds->ds_dir, rbsa->clonelastname,
770 ohds->ds_prev, flags, rbsa->cr, tx);
771 VERIFY(0 == dsl_dataset_own_obj(dp, dsobj, B_TRUE, dmu_recv_tag, &cds));
853 crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ?
854 DS_FLAG_CI_DATASET : 0;
772
855
856 error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
857 if (error == 0) {
858 /* create temporary clone */
859 dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name,
860 ds->ds_prev, crflags, drba->drba_cred, tx);
861 dsl_dataset_rele(ds, FTAG);
862 } else {
863 dsl_dir_t *dd;
864 const char *tail;
865 dsl_dataset_t *origin = NULL;
866
867 VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail));
868
869 if (drba->drba_origin != NULL) {
870 VERIFY0(dsl_dataset_hold(dp, drba->drba_origin,
871 FTAG, &origin));
872 }
873
874 /* Create new dataset. */
875 dsobj = dsl_dataset_create_sync(dd,
876 strrchr(tofs, '/') + 1,
877 origin, crflags, drba->drba_cred, tx);
878 if (origin != NULL)
879 dsl_dataset_rele(origin, FTAG);
880 dsl_dir_rele(dd, FTAG);
881 drba->drba_cookie->drc_newfs = B_TRUE;
882 }
883 VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds));
884
885 dmu_buf_will_dirty(newds->ds_dbuf, tx);
886 newds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
887
773 /*
774 * If we actually created a non-clone, we need to create the
775 * objset in our new dataset.
776 */
888 /*
889 * If we actually created a non-clone, we need to create the
890 * objset in our new dataset.
891 */
777 if (BP_IS_HOLE(dsl_dataset_get_blkptr(cds))) {
892 if (BP_IS_HOLE(dsl_dataset_get_blkptr(newds))) {
778 (void) dmu_objset_create_impl(dp->dp_spa,
893 (void) dmu_objset_create_impl(dp->dp_spa,
779 cds, dsl_dataset_get_blkptr(cds), rbsa->type, tx);
894 newds, dsl_dataset_get_blkptr(newds), drrb->drr_type, tx);
780 }
781
895 }
896
782 rbsa->ds = cds;
897 drba->drba_cookie->drc_ds = newds;
783
898
784 spa_history_log_internal(LOG_DS_REPLAY_INC_SYNC,
785 dp->dp_spa, tx, "dataset = %lld", dsobj);
899 spa_history_log_internal_ds(newds, "receive", tx, "");
786}
787
900}
901
788static boolean_t
789dmu_recv_verify_features(dsl_dataset_t *ds, struct drr_begin *drrb)
790{
791 int featureflags;
792
793 featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
794
795 /* Verify pool version supports SA if SA_SPILL feature set */
796 return ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) &&
797 (spa_version(dsl_dataset_get_spa(ds)) < SPA_VERSION_SA));
798}
799
800/*
801 * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin()
802 * succeeds; otherwise we will leak the holds on the datasets.
803 */
804int
902/*
903 * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin()
904 * succeeds; otherwise we will leak the holds on the datasets.
905 */
906int
805dmu_recv_begin(char *tofs, char *tosnap, char *top_ds, struct drr_begin *drrb,
806 boolean_t force, objset_t *origin, dmu_recv_cookie_t *drc)
907dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb,
908 boolean_t force, char *origin, dmu_recv_cookie_t *drc)
807{
909{
808 int err = 0;
809 boolean_t byteswap;
810 struct recvbeginsyncarg rbsa = { 0 };
811 uint64_t versioninfo;
812 int flags;
813 dsl_dataset_t *ds;
910 dmu_recv_begin_arg_t drba = { 0 };
911 dmu_replay_record_t *drr;
814
912
815 if (drrb->drr_magic == DMU_BACKUP_MAGIC)
816 byteswap = FALSE;
817 else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC))
818 byteswap = TRUE;
819 else
820 return (EINVAL);
821
822 rbsa.tofs = tofs;
823 rbsa.tosnap = tosnap;
824 rbsa.origin = origin ? origin->os_dsl_dataset : NULL;
825 rbsa.fromguid = drrb->drr_fromguid;
826 rbsa.type = drrb->drr_type;
827 rbsa.tag = FTAG;
828 rbsa.dsflags = 0;
829 rbsa.cr = CRED();
830 versioninfo = drrb->drr_versioninfo;
831 flags = drrb->drr_flags;
832
833 if (byteswap) {
834 rbsa.type = BSWAP_32(rbsa.type);
835 rbsa.fromguid = BSWAP_64(rbsa.fromguid);
836 versioninfo = BSWAP_64(versioninfo);
837 flags = BSWAP_32(flags);
838 }
839
840 if (DMU_GET_STREAM_HDRTYPE(versioninfo) == DMU_COMPOUNDSTREAM ||
841 rbsa.type >= DMU_OST_NUMTYPES ||
842 ((flags & DRR_FLAG_CLONE) && origin == NULL))
843 return (EINVAL);
844
845 if (flags & DRR_FLAG_CI_DATA)
846 rbsa.dsflags = DS_FLAG_CI_DATASET;
847
848 bzero(drc, sizeof (dmu_recv_cookie_t));
849 drc->drc_drrb = drrb;
850 drc->drc_tosnap = tosnap;
913 bzero(drc, sizeof (dmu_recv_cookie_t));
914 drc->drc_drrb = drrb;
915 drc->drc_tosnap = tosnap;
851 drc->drc_top_ds = top_ds;
916 drc->drc_tofs = tofs;
852 drc->drc_force = force;
853
917 drc->drc_force = force;
918
854 /*
855 * Process the begin in syncing context.
856 */
919 if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC))
920 drc->drc_byteswap = B_TRUE;
921 else if (drrb->drr_magic != DMU_BACKUP_MAGIC)
922 return (EINVAL);
857
923
858 /* open the dataset we are logically receiving into */
859 err = dsl_dataset_hold(tofs, dmu_recv_tag, &ds);
860 if (err == 0) {
861 if (dmu_recv_verify_features(ds, drrb)) {
862 dsl_dataset_rele(ds, dmu_recv_tag);
863 return (ENOTSUP);
864 }
865 /* target fs already exists; recv into temp clone */
924 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
925 drr->drr_type = DRR_BEGIN;
926 drr->drr_u.drr_begin = *drc->drc_drrb;
927 if (drc->drc_byteswap) {
928 fletcher_4_incremental_byteswap(drr,
929 sizeof (dmu_replay_record_t), &drc->drc_cksum);
930 } else {
931 fletcher_4_incremental_native(drr,
932 sizeof (dmu_replay_record_t), &drc->drc_cksum);
933 }
934 kmem_free(drr, sizeof (dmu_replay_record_t));
866
935
867 /* Can't recv a clone into an existing fs */
868 if (flags & DRR_FLAG_CLONE) {
869 dsl_dataset_rele(ds, dmu_recv_tag);
870 return (EINVAL);
871 }
872
873 /* must not have an incremental recv already in progress */
874 if (!mutex_tryenter(&ds->ds_recvlock)) {
875 dsl_dataset_rele(ds, dmu_recv_tag);
876 return (EBUSY);
877 }
878
879 /* tmp clone name is: tofs/%tosnap" */
880 (void) snprintf(rbsa.clonelastname, sizeof (rbsa.clonelastname),
881 "%%%s", tosnap);
882 rbsa.force = force;
883 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
884 recv_existing_check, recv_existing_sync, ds, &rbsa, 5);
885 if (err) {
886 mutex_exit(&ds->ds_recvlock);
887 dsl_dataset_rele(ds, dmu_recv_tag);
888 return (err);
889 }
890 drc->drc_logical_ds = ds;
891 drc->drc_real_ds = rbsa.ds;
892 } else if (err == ENOENT) {
893 /* target fs does not exist; must be a full backup or clone */
894 char *cp;
895
896 /*
897 * If it's a non-clone incremental, we are missing the
898 * target fs, so fail the recv.
899 */
900 if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE))
901 return (ENOENT);
902
903 /* Open the parent of tofs */
904 cp = strrchr(tofs, '/');
905 *cp = '\0';
906 err = dsl_dataset_hold(tofs, FTAG, &ds);
907 *cp = '/';
908 if (err)
909 return (err);
910
911 if (dmu_recv_verify_features(ds, drrb)) {
912 dsl_dataset_rele(ds, FTAG);
913 return (ENOTSUP);
914 }
915
916 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
917 recv_new_check, recv_new_sync, ds->ds_dir, &rbsa, 5);
918 dsl_dataset_rele(ds, FTAG);
919 if (err)
920 return (err);
921 drc->drc_logical_ds = drc->drc_real_ds = rbsa.ds;
922 drc->drc_newfs = B_TRUE;
936 if (drc->drc_byteswap) {
937 drrb->drr_magic = BSWAP_64(drrb->drr_magic);
938 drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo);
939 drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time);
940 drrb->drr_type = BSWAP_32(drrb->drr_type);
941 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
942 drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid);
923 }
924
943 }
944
925 return (err);
945 drba.drba_origin = origin;
946 drba.drba_cookie = drc;
947 drba.drba_cred = CRED();
948
949 return (dsl_sync_task(tofs, dmu_recv_begin_check, dmu_recv_begin_sync,
950 &drba, 5));
926}
927
928struct restorearg {
929 int err;
951}
952
953struct restorearg {
954 int err;
930 int byteswap;
955 boolean_t byteswap;
931 kthread_t *td;
932 struct file *fp;
933 char *buf;
934 uint64_t voff;
935 int bufsize; /* amount of memory allocated for buf */
936 zio_cksum_t cksum;
937 avl_tree_t *guid_to_ds_map;
938};

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

959static void
960free_guid_map_onexit(void *arg)
961{
962 avl_tree_t *ca = arg;
963 void *cookie = NULL;
964 guid_map_entry_t *gmep;
965
966 while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) {
956 kthread_t *td;
957 struct file *fp;
958 char *buf;
959 uint64_t voff;
960 int bufsize; /* amount of memory allocated for buf */
961 zio_cksum_t cksum;
962 avl_tree_t *guid_to_ds_map;
963};

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

984static void
985free_guid_map_onexit(void *arg)
986{
987 avl_tree_t *ca = arg;
988 void *cookie = NULL;
989 guid_map_entry_t *gmep;
990
991 while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) {
967 dsl_dataset_rele(gmep->gme_ds, ca);
992 dsl_dataset_long_rele(gmep->gme_ds, gmep);
968 kmem_free(gmep, sizeof (guid_map_entry_t));
969 }
970 avl_destroy(ca);
971 kmem_free(ca, sizeof (avl_tree_t));
972}
973
974static int
975restore_bytes(struct restorearg *ra, void *buf, int len, off_t off, ssize_t *resid)

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

1011
1012 ra->err = restore_bytes(ra, (caddr_t)ra->buf + done,
1013 len - done, ra->voff, &resid);
1014
1015 if (resid == len - done)
1016 ra->err = EINVAL;
1017 ra->voff += len - done - resid;
1018 done = len - resid;
993 kmem_free(gmep, sizeof (guid_map_entry_t));
994 }
995 avl_destroy(ca);
996 kmem_free(ca, sizeof (avl_tree_t));
997}
998
999static int
1000restore_bytes(struct restorearg *ra, void *buf, int len, off_t off, ssize_t *resid)

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

1036
1037 ra->err = restore_bytes(ra, (caddr_t)ra->buf + done,
1038 len - done, ra->voff, &resid);
1039
1040 if (resid == len - done)
1041 ra->err = EINVAL;
1042 ra->voff += len - done - resid;
1043 done = len - resid;
1019 if (ra->err)
1044 if (ra->err != 0)
1020 return (NULL);
1021 }
1022
1023 ASSERT3U(done, ==, len);
1024 rv = ra->buf;
1025 if (ra->byteswap)
1026 fletcher_4_incremental_byteswap(rv, len, &ra->cksum);
1027 else

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

1130
1131 err = dmu_object_info(os, drro->drr_object, NULL);
1132
1133 if (err != 0 && err != ENOENT)
1134 return (EINVAL);
1135
1136 if (drro->drr_bonuslen) {
1137 data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8));
1045 return (NULL);
1046 }
1047
1048 ASSERT3U(done, ==, len);
1049 rv = ra->buf;
1050 if (ra->byteswap)
1051 fletcher_4_incremental_byteswap(rv, len, &ra->cksum);
1052 else

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

1155
1156 err = dmu_object_info(os, drro->drr_object, NULL);
1157
1158 if (err != 0 && err != ENOENT)
1159 return (EINVAL);
1160
1161 if (drro->drr_bonuslen) {
1162 data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8));
1138 if (ra->err)
1163 if (ra->err != 0)
1139 return (ra->err);
1140 }
1141
1142 if (err == ENOENT) {
1143 /* currently free, want to be allocated */
1144 tx = dmu_tx_create(os);
1145 dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
1146 err = dmu_tx_assign(tx, TXG_WAIT);
1164 return (ra->err);
1165 }
1166
1167 if (err == ENOENT) {
1168 /* currently free, want to be allocated */
1169 tx = dmu_tx_create(os);
1170 dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
1171 err = dmu_tx_assign(tx, TXG_WAIT);
1147 if (err) {
1172 if (err != 0) {
1148 dmu_tx_abort(tx);
1149 return (err);
1150 }
1151 err = dmu_object_claim(os, drro->drr_object,
1152 drro->drr_type, drro->drr_blksz,
1153 drro->drr_bonustype, drro->drr_bonuslen, tx);
1154 dmu_tx_commit(tx);
1155 } else {
1156 /* currently allocated, want to be allocated */
1157 err = dmu_object_reclaim(os, drro->drr_object,
1158 drro->drr_type, drro->drr_blksz,
1159 drro->drr_bonustype, drro->drr_bonuslen);
1160 }
1173 dmu_tx_abort(tx);
1174 return (err);
1175 }
1176 err = dmu_object_claim(os, drro->drr_object,
1177 drro->drr_type, drro->drr_blksz,
1178 drro->drr_bonustype, drro->drr_bonuslen, tx);
1179 dmu_tx_commit(tx);
1180 } else {
1181 /* currently allocated, want to be allocated */
1182 err = dmu_object_reclaim(os, drro->drr_object,
1183 drro->drr_type, drro->drr_blksz,
1184 drro->drr_bonustype, drro->drr_bonuslen);
1185 }
1161 if (err) {
1186 if (err != 0) {
1162 return (EINVAL);
1163 }
1164
1165 tx = dmu_tx_create(os);
1166 dmu_tx_hold_bonus(tx, drro->drr_object);
1167 err = dmu_tx_assign(tx, TXG_WAIT);
1187 return (EINVAL);
1188 }
1189
1190 tx = dmu_tx_create(os);
1191 dmu_tx_hold_bonus(tx, drro->drr_object);
1192 err = dmu_tx_assign(tx, TXG_WAIT);
1168 if (err) {
1193 if (err != 0) {
1169 dmu_tx_abort(tx);
1170 return (err);
1171 }
1172
1173 dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksumtype,
1174 tx);
1175 dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx);
1176

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

1208 obj < drrfo->drr_firstobj + drrfo->drr_numobjs;
1209 (void) dmu_object_next(os, &obj, FALSE, 0)) {
1210 int err;
1211
1212 if (dmu_object_info(os, obj, NULL) != 0)
1213 continue;
1214
1215 err = dmu_free_object(os, obj);
1194 dmu_tx_abort(tx);
1195 return (err);
1196 }
1197
1198 dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksumtype,
1199 tx);
1200 dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx);
1201

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

1233 obj < drrfo->drr_firstobj + drrfo->drr_numobjs;
1234 (void) dmu_object_next(os, &obj, FALSE, 0)) {
1235 int err;
1236
1237 if (dmu_object_info(os, obj, NULL) != 0)
1238 continue;
1239
1240 err = dmu_free_object(os, obj);
1216 if (err)
1241 if (err != 0)
1217 return (err);
1218 }
1219 return (0);
1220}
1221
1222static int
1223restore_write(struct restorearg *ra, objset_t *os,
1224 struct drr_write *drrw)

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

1238 if (dmu_object_info(os, drrw->drr_object, NULL) != 0)
1239 return (EINVAL);
1240
1241 tx = dmu_tx_create(os);
1242
1243 dmu_tx_hold_write(tx, drrw->drr_object,
1244 drrw->drr_offset, drrw->drr_length);
1245 err = dmu_tx_assign(tx, TXG_WAIT);
1242 return (err);
1243 }
1244 return (0);
1245}
1246
1247static int
1248restore_write(struct restorearg *ra, objset_t *os,
1249 struct drr_write *drrw)

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

1263 if (dmu_object_info(os, drrw->drr_object, NULL) != 0)
1264 return (EINVAL);
1265
1266 tx = dmu_tx_create(os);
1267
1268 dmu_tx_hold_write(tx, drrw->drr_object,
1269 drrw->drr_offset, drrw->drr_length);
1270 err = dmu_tx_assign(tx, TXG_WAIT);
1246 if (err) {
1271 if (err != 0) {
1247 dmu_tx_abort(tx);
1248 return (err);
1249 }
1250 if (ra->byteswap) {
1251 dmu_object_byteswap_t byteswap =
1252 DMU_OT_BYTESWAP(drrw->drr_type);
1253 dmu_ot_byteswap[byteswap].ob_func(data, drrw->drr_length);
1254 }

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

1300 drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH))
1301 return (err);
1302
1303 tx = dmu_tx_create(os);
1304
1305 dmu_tx_hold_write(tx, drrwbr->drr_object,
1306 drrwbr->drr_offset, drrwbr->drr_length);
1307 err = dmu_tx_assign(tx, TXG_WAIT);
1272 dmu_tx_abort(tx);
1273 return (err);
1274 }
1275 if (ra->byteswap) {
1276 dmu_object_byteswap_t byteswap =
1277 DMU_OT_BYTESWAP(drrw->drr_type);
1278 dmu_ot_byteswap[byteswap].ob_func(data, drrw->drr_length);
1279 }

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

1325 drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH))
1326 return (err);
1327
1328 tx = dmu_tx_create(os);
1329
1330 dmu_tx_hold_write(tx, drrwbr->drr_object,
1331 drrwbr->drr_offset, drrwbr->drr_length);
1332 err = dmu_tx_assign(tx, TXG_WAIT);
1308 if (err) {
1333 if (err != 0) {
1309 dmu_tx_abort(tx);
1310 return (err);
1311 }
1312 dmu_write(os, drrwbr->drr_object,
1313 drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx);
1314 dmu_buf_rele(dbp, FTAG);
1315 dmu_tx_commit(tx);
1316 return (0);

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

1341 return (err);
1342 }
1343
1344 tx = dmu_tx_create(os);
1345
1346 dmu_tx_hold_spill(tx, db->db_object);
1347
1348 err = dmu_tx_assign(tx, TXG_WAIT);
1334 dmu_tx_abort(tx);
1335 return (err);
1336 }
1337 dmu_write(os, drrwbr->drr_object,
1338 drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx);
1339 dmu_buf_rele(dbp, FTAG);
1340 dmu_tx_commit(tx);
1341 return (0);

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

1366 return (err);
1367 }
1368
1369 tx = dmu_tx_create(os);
1370
1371 dmu_tx_hold_spill(tx, db->db_object);
1372
1373 err = dmu_tx_assign(tx, TXG_WAIT);
1349 if (err) {
1374 if (err != 0) {
1350 dmu_buf_rele(db, FTAG);
1351 dmu_buf_rele(db_spill, FTAG);
1352 dmu_tx_abort(tx);
1353 return (err);
1354 }
1355 dmu_buf_will_dirty(db_spill, tx);
1356
1357 if (db_spill->db_size < drrs->drr_length)

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

1380 if (dmu_object_info(os, drrf->drr_object, NULL) != 0)
1381 return (EINVAL);
1382
1383 err = dmu_free_long_range(os, drrf->drr_object,
1384 drrf->drr_offset, drrf->drr_length);
1385 return (err);
1386}
1387
1375 dmu_buf_rele(db, FTAG);
1376 dmu_buf_rele(db_spill, FTAG);
1377 dmu_tx_abort(tx);
1378 return (err);
1379 }
1380 dmu_buf_will_dirty(db_spill, tx);
1381
1382 if (db_spill->db_size < drrs->drr_length)

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

1405 if (dmu_object_info(os, drrf->drr_object, NULL) != 0)
1406 return (EINVAL);
1407
1408 err = dmu_free_long_range(os, drrf->drr_object,
1409 drrf->drr_offset, drrf->drr_length);
1410 return (err);
1411}
1412
1413/* used to destroy the drc_ds on error */
1414static void
1415dmu_recv_cleanup_ds(dmu_recv_cookie_t *drc)
1416{
1417 char name[MAXNAMELEN];
1418 dsl_dataset_name(drc->drc_ds, name);
1419 dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
1420 (void) dsl_destroy_head(name);
1421}
1422
1388/*
1389 * NB: callers *must* call dmu_recv_end() if this succeeds.
1390 */
1391int
1392dmu_recv_stream(dmu_recv_cookie_t *drc, struct file *fp, offset_t *voffp,
1393 int cleanup_fd, uint64_t *action_handlep)
1394{
1395 struct restorearg ra = { 0 };
1396 dmu_replay_record_t *drr;
1397 objset_t *os;
1398 zio_cksum_t pcksum;
1399 int featureflags;
1400
1423/*
1424 * NB: callers *must* call dmu_recv_end() if this succeeds.
1425 */
1426int
1427dmu_recv_stream(dmu_recv_cookie_t *drc, struct file *fp, offset_t *voffp,
1428 int cleanup_fd, uint64_t *action_handlep)
1429{
1430 struct restorearg ra = { 0 };
1431 dmu_replay_record_t *drr;
1432 objset_t *os;
1433 zio_cksum_t pcksum;
1434 int featureflags;
1435
1401 if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC))
1402 ra.byteswap = TRUE;
1403
1404 {
1405 /* compute checksum of drr_begin record */
1406 dmu_replay_record_t *drr;
1407 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
1408
1409 drr->drr_type = DRR_BEGIN;
1410 drr->drr_u.drr_begin = *drc->drc_drrb;
1411 if (ra.byteswap) {
1412 fletcher_4_incremental_byteswap(drr,
1413 sizeof (dmu_replay_record_t), &ra.cksum);
1414 } else {
1415 fletcher_4_incremental_native(drr,
1416 sizeof (dmu_replay_record_t), &ra.cksum);
1417 }
1418 kmem_free(drr, sizeof (dmu_replay_record_t));
1419 }
1420
1421 if (ra.byteswap) {
1422 struct drr_begin *drrb = drc->drc_drrb;
1423 drrb->drr_magic = BSWAP_64(drrb->drr_magic);
1424 drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo);
1425 drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time);
1426 drrb->drr_type = BSWAP_32(drrb->drr_type);
1427 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
1428 drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid);
1429 }
1430
1436 ra.byteswap = drc->drc_byteswap;
1437 ra.cksum = drc->drc_cksum;
1431 ra.td = curthread;
1432 ra.fp = fp;
1433 ra.voff = *voffp;
1434 ra.bufsize = 1<<20;
1435 ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP);
1436
1437 /* these were verified in dmu_recv_begin */
1438 ra.td = curthread;
1439 ra.fp = fp;
1440 ra.voff = *voffp;
1441 ra.bufsize = 1<<20;
1442 ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP);
1443
1444 /* these were verified in dmu_recv_begin */
1438 ASSERT(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo) ==
1445 ASSERT3U(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo), ==,
1439 DMU_SUBSTREAM);
1446 DMU_SUBSTREAM);
1440 ASSERT(drc->drc_drrb->drr_type < DMU_OST_NUMTYPES);
1447 ASSERT3U(drc->drc_drrb->drr_type, <, DMU_OST_NUMTYPES);
1441
1442 /*
1443 * Open the objset we are modifying.
1444 */
1448
1449 /*
1450 * Open the objset we are modifying.
1451 */
1445 VERIFY(dmu_objset_from_ds(drc->drc_real_ds, &os) == 0);
1452 VERIFY0(dmu_objset_from_ds(drc->drc_ds, &os));
1446
1453
1447 ASSERT(drc->drc_real_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT);
1454 ASSERT(drc->drc_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT);
1448
1449 featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo);
1450
1451 /* if this stream is dedup'ed, set up the avl tree for guid mapping */
1452 if (featureflags & DMU_BACKUP_FEATURE_DEDUP) {
1453 minor_t minor;
1454
1455 if (cleanup_fd == -1) {
1456 ra.err = EBADF;
1457 goto out;
1458 }
1459 ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor);
1455
1456 featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo);
1457
1458 /* if this stream is dedup'ed, set up the avl tree for guid mapping */
1459 if (featureflags & DMU_BACKUP_FEATURE_DEDUP) {
1460 minor_t minor;
1461
1462 if (cleanup_fd == -1) {
1463 ra.err = EBADF;
1464 goto out;
1465 }
1466 ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor);
1460 if (ra.err) {
1467 if (ra.err != 0) {
1461 cleanup_fd = -1;
1462 goto out;
1463 }
1464
1465 if (*action_handlep == 0) {
1466 ra.guid_to_ds_map =
1467 kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
1468 avl_create(ra.guid_to_ds_map, guid_compare,
1469 sizeof (guid_map_entry_t),
1470 offsetof(guid_map_entry_t, avlnode));
1471 ra.err = zfs_onexit_add_cb(minor,
1472 free_guid_map_onexit, ra.guid_to_ds_map,
1473 action_handlep);
1468 cleanup_fd = -1;
1469 goto out;
1470 }
1471
1472 if (*action_handlep == 0) {
1473 ra.guid_to_ds_map =
1474 kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
1475 avl_create(ra.guid_to_ds_map, guid_compare,
1476 sizeof (guid_map_entry_t),
1477 offsetof(guid_map_entry_t, avlnode));
1478 ra.err = zfs_onexit_add_cb(minor,
1479 free_guid_map_onexit, ra.guid_to_ds_map,
1480 action_handlep);
1474 if (ra.err)
1481 if (ra.err != 0)
1475 goto out;
1476 } else {
1477 ra.err = zfs_onexit_cb_data(minor, *action_handlep,
1478 (void **)&ra.guid_to_ds_map);
1482 goto out;
1483 } else {
1484 ra.err = zfs_onexit_cb_data(minor, *action_handlep,
1485 (void **)&ra.guid_to_ds_map);
1479 if (ra.err)
1486 if (ra.err != 0)
1480 goto out;
1481 }
1482
1483 drc->drc_guid_to_ds_map = ra.guid_to_ds_map;
1484 }
1485
1486 /*
1487 * Read records and process them.

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

1565 if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1))
1566 zfs_onexit_fd_rele(cleanup_fd);
1567
1568 if (ra.err != 0) {
1569 /*
1570 * destroy what we created, so we don't leave it in the
1571 * inconsistent restoring state.
1572 */
1487 goto out;
1488 }
1489
1490 drc->drc_guid_to_ds_map = ra.guid_to_ds_map;
1491 }
1492
1493 /*
1494 * Read records and process them.

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

1572 if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1))
1573 zfs_onexit_fd_rele(cleanup_fd);
1574
1575 if (ra.err != 0) {
1576 /*
1577 * destroy what we created, so we don't leave it in the
1578 * inconsistent restoring state.
1579 */
1573 txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0);
1574
1575 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
1576 B_FALSE);
1577 if (drc->drc_real_ds != drc->drc_logical_ds) {
1578 mutex_exit(&drc->drc_logical_ds->ds_recvlock);
1579 dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag);
1580 }
1580 dmu_recv_cleanup_ds(drc);
1581 }
1582
1583 kmem_free(ra.buf, ra.bufsize);
1584 *voffp = ra.voff;
1585 return (ra.err);
1586}
1587
1581 }
1582
1583 kmem_free(ra.buf, ra.bufsize);
1584 *voffp = ra.voff;
1585 return (ra.err);
1586}
1587
1588struct recvendsyncarg {
1589 char *tosnap;
1590 uint64_t creation_time;
1591 uint64_t toguid;
1592};
1593
1594static int
1588static int
1595recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx)
1589dmu_recv_end_check(void *arg, dmu_tx_t *tx)
1596{
1590{
1597 dsl_dataset_t *ds = arg1;
1598 struct recvendsyncarg *resa = arg2;
1591 dmu_recv_cookie_t *drc = arg;
1592 dsl_pool_t *dp = dmu_tx_pool(tx);
1593 int error;
1599
1594
1600 return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx));
1595 ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag);
1596
1597 if (!drc->drc_newfs) {
1598 dsl_dataset_t *origin_head;
1599
1600 error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head);
1601 if (error != 0)
1602 return (error);
1603 error = dsl_dataset_clone_swap_check_impl(drc->drc_ds,
1604 origin_head, drc->drc_force);
1605 if (error != 0) {
1606 dsl_dataset_rele(origin_head, FTAG);
1607 return (error);
1608 }
1609 error = dsl_dataset_snapshot_check_impl(origin_head,
1610 drc->drc_tosnap, tx);
1611 dsl_dataset_rele(origin_head, FTAG);
1612 if (error != 0)
1613 return (error);
1614
1615 error = dsl_destroy_head_check_impl(drc->drc_ds, 1);
1616 } else {
1617 error = dsl_dataset_snapshot_check_impl(drc->drc_ds,
1618 drc->drc_tosnap, tx);
1619 }
1620 return (error);
1601}
1602
1603static void
1621}
1622
1623static void
1604recv_end_sync(void *arg1, void *arg2, dmu_tx_t *tx)
1624dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
1605{
1625{
1606 dsl_dataset_t *ds = arg1;
1607 struct recvendsyncarg *resa = arg2;
1626 dmu_recv_cookie_t *drc = arg;
1627 dsl_pool_t *dp = dmu_tx_pool(tx);
1608
1628
1609 dsl_dataset_snapshot_sync(ds, resa->tosnap, tx);
1629 spa_history_log_internal_ds(drc->drc_ds, "finish receiving",
1630 tx, "snap=%s", drc->drc_tosnap);
1610
1631
1611 /* set snapshot's creation time and guid */
1612 dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
1613 ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time;
1614 ds->ds_prev->ds_phys->ds_guid = resa->toguid;
1615 ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1632 if (!drc->drc_newfs) {
1633 dsl_dataset_t *origin_head;
1616
1634
1617 dmu_buf_will_dirty(ds->ds_dbuf, tx);
1618 ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1635 VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG,
1636 &origin_head));
1637 dsl_dataset_clone_swap_sync_impl(drc->drc_ds,
1638 origin_head, tx);
1639 dsl_dataset_snapshot_sync_impl(origin_head,
1640 drc->drc_tosnap, tx);
1641
1642 /* set snapshot's creation time and guid */
1643 dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx);
1644 origin_head->ds_prev->ds_phys->ds_creation_time =
1645 drc->drc_drrb->drr_creation_time;
1646 origin_head->ds_prev->ds_phys->ds_guid =
1647 drc->drc_drrb->drr_toguid;
1648 origin_head->ds_prev->ds_phys->ds_flags &=
1649 ~DS_FLAG_INCONSISTENT;
1650
1651 dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
1652 origin_head->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1653
1654 dsl_dataset_rele(origin_head, FTAG);
1655 dsl_destroy_head_sync_impl(drc->drc_ds, tx);
1656 } else {
1657 dsl_dataset_t *ds = drc->drc_ds;
1658
1659 dsl_dataset_snapshot_sync_impl(ds, drc->drc_tosnap, tx);
1660
1661 /* set snapshot's creation time and guid */
1662 dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx);
1663 ds->ds_prev->ds_phys->ds_creation_time =
1664 drc->drc_drrb->drr_creation_time;
1665 ds->ds_prev->ds_phys->ds_guid = drc->drc_drrb->drr_toguid;
1666 ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1667
1668 dmu_buf_will_dirty(ds->ds_dbuf, tx);
1669 ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1670 }
1671 drc->drc_newsnapobj = drc->drc_ds->ds_phys->ds_prev_snap_obj;
1672 /*
1673 * Release the hold from dmu_recv_begin. This must be done before
1674 * we return to open context, so that when we free the dataset's dnode,
1675 * we can evict its bonus buffer.
1676 */
1677 dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
1678 drc->drc_ds = NULL;
1619}
1620
1621static int
1679}
1680
1681static int
1622add_ds_to_guidmap(avl_tree_t *guid_map, dsl_dataset_t *ds)
1682add_ds_to_guidmap(const char *name, avl_tree_t *guid_map, uint64_t snapobj)
1623{
1683{
1624 dsl_pool_t *dp = ds->ds_dir->dd_pool;
1625 uint64_t snapobj = ds->ds_phys->ds_prev_snap_obj;
1684 dsl_pool_t *dp;
1626 dsl_dataset_t *snapds;
1627 guid_map_entry_t *gmep;
1628 int err;
1629
1630 ASSERT(guid_map != NULL);
1631
1685 dsl_dataset_t *snapds;
1686 guid_map_entry_t *gmep;
1687 int err;
1688
1689 ASSERT(guid_map != NULL);
1690
1632 rw_enter(&dp->dp_config_rwlock, RW_READER);
1633 err = dsl_dataset_hold_obj(dp, snapobj, guid_map, &snapds);
1691 err = dsl_pool_hold(name, FTAG, &dp);
1692 if (err != 0)
1693 return (err);
1694 err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &snapds);
1634 if (err == 0) {
1635 gmep = kmem_alloc(sizeof (guid_map_entry_t), KM_SLEEP);
1636 gmep->guid = snapds->ds_phys->ds_guid;
1637 gmep->gme_ds = snapds;
1638 avl_add(guid_map, gmep);
1695 if (err == 0) {
1696 gmep = kmem_alloc(sizeof (guid_map_entry_t), KM_SLEEP);
1697 gmep->guid = snapds->ds_phys->ds_guid;
1698 gmep->gme_ds = snapds;
1699 avl_add(guid_map, gmep);
1700 dsl_dataset_long_hold(snapds, gmep);
1701 dsl_dataset_rele(snapds, FTAG);
1639 }
1640
1702 }
1703
1641 rw_exit(&dp->dp_config_rwlock);
1704 dsl_pool_rele(dp, FTAG);
1642 return (err);
1643}
1644
1705 return (err);
1706}
1707
1708static int dmu_recv_end_modified_blocks = 3;
1709
1645static int
1646dmu_recv_existing_end(dmu_recv_cookie_t *drc)
1647{
1710static int
1711dmu_recv_existing_end(dmu_recv_cookie_t *drc)
1712{
1648 struct recvendsyncarg resa;
1649 dsl_dataset_t *ds = drc->drc_logical_ds;
1650 int err, myerr;
1713 int error;
1714 char name[MAXNAMELEN];
1651
1715
1652 if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) {
1653 err = dsl_dataset_clone_swap(drc->drc_real_ds, ds,
1654 drc->drc_force);
1655 if (err)
1656 goto out;
1657 } else {
1658 mutex_exit(&ds->ds_recvlock);
1659 dsl_dataset_rele(ds, dmu_recv_tag);
1660 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag,
1661 B_FALSE);
1662 return (EBUSY);
1663 }
1716#ifdef _KERNEL
1717 /*
1718 * We will be destroying the ds; make sure its origin is unmounted if
1719 * necessary.
1720 */
1721 dsl_dataset_name(drc->drc_ds, name);
1722 zfs_destroy_unmount_origin(name);
1723#endif
1664
1724
1665 resa.creation_time = drc->drc_drrb->drr_creation_time;
1666 resa.toguid = drc->drc_drrb->drr_toguid;
1667 resa.tosnap = drc->drc_tosnap;
1725 error = dsl_sync_task(drc->drc_tofs,
1726 dmu_recv_end_check, dmu_recv_end_sync, drc,
1727 dmu_recv_end_modified_blocks);
1668
1728
1669 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1670 recv_end_check, recv_end_sync, ds, &resa, 3);
1671 if (err) {
1672 /* swap back */
1673 (void) dsl_dataset_clone_swap(drc->drc_real_ds, ds, B_TRUE);
1674 }
1675
1676out:
1677 mutex_exit(&ds->ds_recvlock);
1678 if (err == 0 && drc->drc_guid_to_ds_map != NULL)
1679 (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
1680 dsl_dataset_disown(ds, dmu_recv_tag);
1681 myerr = dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag, B_FALSE);
1682 ASSERT0(myerr);
1683 return (err);
1729 if (error != 0)
1730 dmu_recv_cleanup_ds(drc);
1731 return (error);
1684}
1685
1686static int
1687dmu_recv_new_end(dmu_recv_cookie_t *drc)
1688{
1732}
1733
1734static int
1735dmu_recv_new_end(dmu_recv_cookie_t *drc)
1736{
1689 struct recvendsyncarg resa;
1690 dsl_dataset_t *ds = drc->drc_logical_ds;
1691 int err;
1737 int error;
1692
1738
1693 /*
1694 * XXX hack; seems the ds is still dirty and dsl_pool_zil_clean()
1695 * expects it to have a ds_user_ptr (and zil), but clone_swap()
1696 * can close it.
1697 */
1698 txg_wait_synced(ds->ds_dir->dd_pool, 0);
1739 error = dsl_sync_task(drc->drc_tofs,
1740 dmu_recv_end_check, dmu_recv_end_sync, drc,
1741 dmu_recv_end_modified_blocks);
1699
1742
1700 resa.creation_time = drc->drc_drrb->drr_creation_time;
1701 resa.toguid = drc->drc_drrb->drr_toguid;
1702 resa.tosnap = drc->drc_tosnap;
1703
1704 err = dsl_sync_task_do(ds->ds_dir->dd_pool,
1705 recv_end_check, recv_end_sync, ds, &resa, 3);
1706 if (err) {
1707 /* clean up the fs we just recv'd into */
1708 (void) dsl_dataset_destroy(ds, dmu_recv_tag, B_FALSE);
1709 } else {
1710 if (drc->drc_guid_to_ds_map != NULL)
1711 (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
1712 /* release the hold from dmu_recv_begin */
1713 dsl_dataset_disown(ds, dmu_recv_tag);
1743 if (error != 0) {
1744 dmu_recv_cleanup_ds(drc);
1745 } else if (drc->drc_guid_to_ds_map != NULL) {
1746 (void) add_ds_to_guidmap(drc->drc_tofs,
1747 drc->drc_guid_to_ds_map,
1748 drc->drc_newsnapobj);
1714 }
1749 }
1715 return (err);
1750 return (error);
1716}
1717
1718int
1719dmu_recv_end(dmu_recv_cookie_t *drc)
1720{
1751}
1752
1753int
1754dmu_recv_end(dmu_recv_cookie_t *drc)
1755{
1721 if (drc->drc_logical_ds != drc->drc_real_ds)
1722 return (dmu_recv_existing_end(drc));
1723 else
1756 if (drc->drc_newfs)
1724 return (dmu_recv_new_end(drc));
1757 return (dmu_recv_new_end(drc));
1758 else
1759 return (dmu_recv_existing_end(drc));
1725}
1760}