Print this page
3888 zfs recv -F should destroy any snapshots created since the incremental source
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Peng Dai <peng.dai@delphix.com>


 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