637 * block, which we observe in practice.
638 */
639 uint64_t recordsize;
640 err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize);
641 if (err != 0)
642 return (err);
643 size -= size / recordsize * sizeof (blkptr_t);
644
645 /* Add in the space for the record associated with each block. */
646 size += size / recordsize * sizeof (dmu_replay_record_t);
647
648 *sizep = size;
649
650 return (0);
651 }
652
653 typedef struct dmu_recv_begin_arg {
654 const char *drba_origin;
655 dmu_recv_cookie_t *drba_cookie;
656 cred_t *drba_cred;
657 } dmu_recv_begin_arg_t;
658
659 static int
660 recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
661 uint64_t fromguid)
662 {
663 uint64_t val;
664 int error;
665 dsl_pool_t *dp = ds->ds_dir->dd_pool;
666
667 /* must not have any changes since most recent snapshot */
668 if (!drba->drba_cookie->drc_force &&
669 dsl_dataset_modified_since_lastsnap(ds))
670 return (SET_ERROR(ETXTBSY));
671
672 /* temporary clone name must not exist */
673 error = zap_lookup(dp->dp_meta_objset,
674 ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name,
675 8, 1, &val);
676 if (error != ENOENT)
677 return (error == 0 ? EBUSY : error);
678
679 /* new snapshot name must not exist */
680 error = zap_lookup(dp->dp_meta_objset,
681 ds->ds_phys->ds_snapnames_zapobj, drba->drba_cookie->drc_tosnap,
682 8, 1, &val);
683 if (error != ENOENT)
684 return (error == 0 ? EEXIST : error);
685
686 if (fromguid != 0) {
687 /* if incremental, most recent snapshot must match fromguid */
688 if (ds->ds_prev == NULL)
689 return (SET_ERROR(ENODEV));
690
691 /*
692 * most recent snapshot must match fromguid, or there are no
693 * changes since the fromguid one
694 */
695 if (ds->ds_prev->ds_phys->ds_guid != fromguid) {
696 uint64_t birth = ds->ds_prev->ds_phys->ds_bp.blk_birth;
697 uint64_t obj = ds->ds_prev->ds_phys->ds_prev_snap_obj;
698 while (obj != 0) {
699 dsl_dataset_t *snap;
700 error = dsl_dataset_hold_obj(dp, obj, FTAG,
701 &snap);
702 if (error != 0)
703 return (SET_ERROR(ENODEV));
704 if (snap->ds_phys->ds_creation_txg < birth) {
705 dsl_dataset_rele(snap, FTAG);
706 return (SET_ERROR(ENODEV));
707 }
708 if (snap->ds_phys->ds_guid == fromguid) {
709 dsl_dataset_rele(snap, FTAG);
710 break; /* it's ok */
711 }
712 obj = snap->ds_phys->ds_prev_snap_obj;
713 dsl_dataset_rele(snap, FTAG);
714 }
715 if (obj == 0)
716 return (SET_ERROR(ENODEV));
717 }
718 } else {
719 /* if full, most recent snapshot must be $ORIGIN */
720 if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL)
721 return (SET_ERROR(ENODEV));
722 }
723
724 return (0);
725
726 }
727
728 static int
729 dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
730 {
731 dmu_recv_begin_arg_t *drba = arg;
732 dsl_pool_t *dp = dmu_tx_pool(tx);
733 struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
734 uint64_t fromguid = drrb->drr_fromguid;
735 int flags = drrb->drr_flags;
736 int error;
737 dsl_dataset_t *ds;
738 const char *tofs = drba->drba_cookie->drc_tofs;
739
740 /* already checked */
741 ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
810 }
811
812 static void
813 dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
814 {
815 dmu_recv_begin_arg_t *drba = arg;
816 dsl_pool_t *dp = dmu_tx_pool(tx);
817 struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
818 const char *tofs = drba->drba_cookie->drc_tofs;
819 dsl_dataset_t *ds, *newds;
820 uint64_t dsobj;
821 int error;
822 uint64_t crflags;
823
824 crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ?
825 DS_FLAG_CI_DATASET : 0;
826
827 error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
828 if (error == 0) {
829 /* create temporary clone */
830 dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name,
831 ds->ds_prev, crflags, drba->drba_cred, tx);
832 dsl_dataset_rele(ds, FTAG);
833 } else {
834 dsl_dir_t *dd;
835 const char *tail;
836 dsl_dataset_t *origin = NULL;
837
838 VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail));
839
840 if (drba->drba_origin != NULL) {
841 VERIFY0(dsl_dataset_hold(dp, drba->drba_origin,
842 FTAG, &origin));
843 }
844
845 /* Create new dataset. */
846 dsobj = dsl_dataset_create_sync(dd,
847 strrchr(tofs, '/') + 1,
848 origin, crflags, drba->drba_cred, tx);
849 if (origin != NULL)
850 dsl_dataset_rele(origin, FTAG);
851 dsl_dir_rele(dd, FTAG);
1529 kmem_free(ra.buf, ra.bufsize);
1530 *voffp = ra.voff;
1531 return (ra.err);
1532 }
1533
1534 static int
1535 dmu_recv_end_check(void *arg, dmu_tx_t *tx)
1536 {
1537 dmu_recv_cookie_t *drc = arg;
1538 dsl_pool_t *dp = dmu_tx_pool(tx);
1539 int error;
1540
1541 ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag);
1542
1543 if (!drc->drc_newfs) {
1544 dsl_dataset_t *origin_head;
1545
1546 error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head);
1547 if (error != 0)
1548 return (error);
1549 error = dsl_dataset_clone_swap_check_impl(drc->drc_ds,
1550 origin_head, drc->drc_force, drc->drc_owner, tx);
1551 if (error != 0) {
1552 dsl_dataset_rele(origin_head, FTAG);
1553 return (error);
1554 }
1555 error = dsl_dataset_snapshot_check_impl(origin_head,
1556 drc->drc_tosnap, tx, B_TRUE);
1557 dsl_dataset_rele(origin_head, FTAG);
1558 if (error != 0)
1559 return (error);
1560
1561 error = dsl_destroy_head_check_impl(drc->drc_ds, 1);
1562 } else {
1563 error = dsl_dataset_snapshot_check_impl(drc->drc_ds,
1564 drc->drc_tosnap, tx, B_TRUE);
1565 }
1566 return (error);
1567 }
1568
1569 static void
1570 dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
1571 {
1572 dmu_recv_cookie_t *drc = arg;
1573 dsl_pool_t *dp = dmu_tx_pool(tx);
1574
1575 spa_history_log_internal_ds(drc->drc_ds, "finish receiving",
1576 tx, "snap=%s", drc->drc_tosnap);
1577
1578 if (!drc->drc_newfs) {
1579 dsl_dataset_t *origin_head;
1580
1581 VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG,
1582 &origin_head));
1583 dsl_dataset_clone_swap_sync_impl(drc->drc_ds,
1584 origin_head, tx);
1585 dsl_dataset_snapshot_sync_impl(origin_head,
1586 drc->drc_tosnap, tx);
1587
1588 /* set snapshot's creation time and guid */
1589 dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx);
1590 origin_head->ds_prev->ds_phys->ds_creation_time =
1591 drc->drc_drrb->drr_creation_time;
1592 origin_head->ds_prev->ds_phys->ds_guid =
1593 drc->drc_drrb->drr_toguid;
1594 origin_head->ds_prev->ds_phys->ds_flags &=
1595 ~DS_FLAG_INCONSISTENT;
1596
1597 dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
1598 origin_head->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1599
1600 dsl_dataset_rele(origin_head, FTAG);
1601 dsl_destroy_head_sync_impl(drc->drc_ds, tx);
1602
|
637 * block, which we observe in practice.
638 */
639 uint64_t recordsize;
640 err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize);
641 if (err != 0)
642 return (err);
643 size -= size / recordsize * sizeof (blkptr_t);
644
645 /* Add in the space for the record associated with each block. */
646 size += size / recordsize * sizeof (dmu_replay_record_t);
647
648 *sizep = size;
649
650 return (0);
651 }
652
653 typedef struct dmu_recv_begin_arg {
654 const char *drba_origin;
655 dmu_recv_cookie_t *drba_cookie;
656 cred_t *drba_cred;
657 uint64_t drba_snapobj;
658 } dmu_recv_begin_arg_t;
659
660 static int
661 recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
662 uint64_t fromguid)
663 {
664 uint64_t val;
665 int error;
666 dsl_pool_t *dp = ds->ds_dir->dd_pool;
667
668 /* temporary clone name must not exist */
669 error = zap_lookup(dp->dp_meta_objset,
670 ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name,
671 8, 1, &val);
672 if (error != ENOENT)
673 return (error == 0 ? EBUSY : error);
674
675 /* new snapshot name must not exist */
676 error = zap_lookup(dp->dp_meta_objset,
677 ds->ds_phys->ds_snapnames_zapobj, drba->drba_cookie->drc_tosnap,
678 8, 1, &val);
679 if (error != ENOENT)
680 return (error == 0 ? EEXIST : error);
681
682 if (fromguid != 0) {
683 dsl_dataset_t *snap;
684 uint64_t obj = ds->ds_phys->ds_prev_snap_obj;
685
686 /* Find snapshot in this dir that matches fromguid. */
687 while (obj != 0) {
688 error = dsl_dataset_hold_obj(dp, obj, FTAG,
689 &snap);
690 if (error != 0)
691 return (SET_ERROR(ENODEV));
692 if (snap->ds_dir != ds->ds_dir) {
693 dsl_dataset_rele(snap, FTAG);
694 return (SET_ERROR(ENODEV));
695 }
696 if (snap->ds_phys->ds_guid == fromguid)
697 break;
698 obj = snap->ds_phys->ds_prev_snap_obj;
699 dsl_dataset_rele(snap, FTAG);
700 }
701 if (obj == 0)
702 return (SET_ERROR(ENODEV));
703
704 if (drba->drba_cookie->drc_force) {
705 drba->drba_snapobj = obj;
706 } else {
707 /*
708 * If we are not forcing, there must be no
709 * changes since fromsnap.
710 */
711 if (dsl_dataset_modified_since_snap(ds, snap)) {
712 dsl_dataset_rele(snap, FTAG);
713 return (SET_ERROR(ETXTBSY));
714 }
715 drba->drba_snapobj = ds->ds_prev->ds_object;
716 }
717
718 dsl_dataset_rele(snap, FTAG);
719 } else {
720 /* if full, most recent snapshot must be $ORIGIN */
721 if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL)
722 return (SET_ERROR(ENODEV));
723 drba->drba_snapobj = ds->ds_phys->ds_prev_snap_obj;
724 }
725
726 return (0);
727
728 }
729
730 static int
731 dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
732 {
733 dmu_recv_begin_arg_t *drba = arg;
734 dsl_pool_t *dp = dmu_tx_pool(tx);
735 struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
736 uint64_t fromguid = drrb->drr_fromguid;
737 int flags = drrb->drr_flags;
738 int error;
739 dsl_dataset_t *ds;
740 const char *tofs = drba->drba_cookie->drc_tofs;
741
742 /* already checked */
743 ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
812 }
813
814 static void
815 dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
816 {
817 dmu_recv_begin_arg_t *drba = arg;
818 dsl_pool_t *dp = dmu_tx_pool(tx);
819 struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
820 const char *tofs = drba->drba_cookie->drc_tofs;
821 dsl_dataset_t *ds, *newds;
822 uint64_t dsobj;
823 int error;
824 uint64_t crflags;
825
826 crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ?
827 DS_FLAG_CI_DATASET : 0;
828
829 error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
830 if (error == 0) {
831 /* create temporary clone */
832 dsl_dataset_t *snap = NULL;
833 if (drba->drba_snapobj != 0) {
834 VERIFY0(dsl_dataset_hold_obj(dp,
835 drba->drba_snapobj, FTAG, &snap));
836 }
837 dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name,
838 snap, crflags, drba->drba_cred, tx);
839 dsl_dataset_rele(snap, FTAG);
840 dsl_dataset_rele(ds, FTAG);
841 } else {
842 dsl_dir_t *dd;
843 const char *tail;
844 dsl_dataset_t *origin = NULL;
845
846 VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail));
847
848 if (drba->drba_origin != NULL) {
849 VERIFY0(dsl_dataset_hold(dp, drba->drba_origin,
850 FTAG, &origin));
851 }
852
853 /* Create new dataset. */
854 dsobj = dsl_dataset_create_sync(dd,
855 strrchr(tofs, '/') + 1,
856 origin, crflags, drba->drba_cred, tx);
857 if (origin != NULL)
858 dsl_dataset_rele(origin, FTAG);
859 dsl_dir_rele(dd, FTAG);
1537 kmem_free(ra.buf, ra.bufsize);
1538 *voffp = ra.voff;
1539 return (ra.err);
1540 }
1541
1542 static int
1543 dmu_recv_end_check(void *arg, dmu_tx_t *tx)
1544 {
1545 dmu_recv_cookie_t *drc = arg;
1546 dsl_pool_t *dp = dmu_tx_pool(tx);
1547 int error;
1548
1549 ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag);
1550
1551 if (!drc->drc_newfs) {
1552 dsl_dataset_t *origin_head;
1553
1554 error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head);
1555 if (error != 0)
1556 return (error);
1557 if (drc->drc_force) {
1558 /*
1559 * We will destroy any snapshots in tofs (i.e. before
1560 * origin_head) that are after the origin (which is
1561 * the snap before drc_ds, because drc_ds can not
1562 * have any snaps of its own).
1563 */
1564 uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj;
1565 while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) {
1566 dsl_dataset_t *snap;
1567 error = dsl_dataset_hold_obj(dp, obj, FTAG,
1568 &snap);
1569 if (error != 0)
1570 return (error);
1571 if (snap->ds_dir != origin_head->ds_dir)
1572 error = SET_ERROR(EINVAL);
1573 if (error == 0) {
1574 error = dsl_destroy_snapshot_check_impl(
1575 snap, B_FALSE);
1576 }
1577 obj = snap->ds_phys->ds_prev_snap_obj;
1578 dsl_dataset_rele(snap, FTAG);
1579 if (error != 0)
1580 return (error);
1581 }
1582 }
1583 error = dsl_dataset_clone_swap_check_impl(drc->drc_ds,
1584 origin_head, drc->drc_force, drc->drc_owner, tx);
1585 if (error != 0) {
1586 dsl_dataset_rele(origin_head, FTAG);
1587 return (error);
1588 }
1589 error = dsl_dataset_snapshot_check_impl(origin_head,
1590 drc->drc_tosnap, tx, B_TRUE);
1591 dsl_dataset_rele(origin_head, FTAG);
1592 if (error != 0)
1593 return (error);
1594
1595 error = dsl_destroy_head_check_impl(drc->drc_ds, 1);
1596 } else {
1597 error = dsl_dataset_snapshot_check_impl(drc->drc_ds,
1598 drc->drc_tosnap, tx, B_TRUE);
1599 }
1600 return (error);
1601 }
1602
1603 static void
1604 dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
1605 {
1606 dmu_recv_cookie_t *drc = arg;
1607 dsl_pool_t *dp = dmu_tx_pool(tx);
1608
1609 spa_history_log_internal_ds(drc->drc_ds, "finish receiving",
1610 tx, "snap=%s", drc->drc_tosnap);
1611
1612 if (!drc->drc_newfs) {
1613 dsl_dataset_t *origin_head;
1614
1615 VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG,
1616 &origin_head));
1617
1618 if (drc->drc_force) {
1619 /*
1620 * Destroy any snapshots of drc_tofs (origin_head)
1621 * after the origin (the snap before drc_ds).
1622 */
1623 uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj;
1624 while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) {
1625 dsl_dataset_t *snap;
1626 VERIFY0(dsl_dataset_hold_obj(dp, obj, FTAG,
1627 &snap));
1628 ASSERT3P(snap->ds_dir, ==, origin_head->ds_dir);
1629 obj = snap->ds_phys->ds_prev_snap_obj;
1630 dsl_destroy_snapshot_sync_impl(snap,
1631 B_FALSE, tx);
1632 dsl_dataset_rele(snap, FTAG);
1633 }
1634 }
1635 VERIFY3P(drc->drc_ds->ds_prev, ==,
1636 origin_head->ds_prev);
1637
1638 dsl_dataset_clone_swap_sync_impl(drc->drc_ds,
1639 origin_head, tx);
1640 dsl_dataset_snapshot_sync_impl(origin_head,
1641 drc->drc_tosnap, tx);
1642
1643 /* set snapshot's creation time and guid */
1644 dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx);
1645 origin_head->ds_prev->ds_phys->ds_creation_time =
1646 drc->drc_drrb->drr_creation_time;
1647 origin_head->ds_prev->ds_phys->ds_guid =
1648 drc->drc_drrb->drr_toguid;
1649 origin_head->ds_prev->ds_phys->ds_flags &=
1650 ~DS_FLAG_INCONSISTENT;
1651
1652 dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
1653 origin_head->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
1654
1655 dsl_dataset_rele(origin_head, FTAG);
1656 dsl_destroy_head_sync_impl(drc->drc_ds, tx);
1657
|