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>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/dmu_send.c
          +++ new/usr/src/uts/common/fs/zfs/dmu_send.c
↓ open down ↓ 646 lines elided ↑ open up ↑
 647  647  
 648  648          *sizep = size;
 649  649  
 650  650          return (0);
 651  651  }
 652  652  
 653  653  typedef struct dmu_recv_begin_arg {
 654  654          const char *drba_origin;
 655  655          dmu_recv_cookie_t *drba_cookie;
 656  656          cred_t *drba_cred;
      657 +        uint64_t drba_snapobj;
 657  658  } dmu_recv_begin_arg_t;
 658  659  
 659  660  static int
 660  661  recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
 661  662      uint64_t fromguid)
 662  663  {
 663  664          uint64_t val;
 664  665          int error;
 665  666          dsl_pool_t *dp = ds->ds_dir->dd_pool;
 666  667  
 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  668          /* temporary clone name must not exist */
 673  669          error = zap_lookup(dp->dp_meta_objset,
 674  670              ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name,
 675  671              8, 1, &val);
 676  672          if (error != ENOENT)
 677  673                  return (error == 0 ? EBUSY : error);
 678  674  
 679  675          /* new snapshot name must not exist */
 680  676          error = zap_lookup(dp->dp_meta_objset,
 681  677              ds->ds_phys->ds_snapnames_zapobj, drba->drba_cookie->drc_tosnap,
 682  678              8, 1, &val);
 683  679          if (error != ENOENT)
 684  680                  return (error == 0 ? EEXIST : error);
 685  681  
 686  682          if (fromguid != 0) {
 687      -                /* if incremental, most recent snapshot must match fromguid */
 688      -                if (ds->ds_prev == NULL)
      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)
 689  702                          return (SET_ERROR(ENODEV));
 690  703  
 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;
      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)) {
 713  712                                  dsl_dataset_rele(snap, FTAG);
      713 +                                return (SET_ERROR(ETXTBSY));
 714  714                          }
 715      -                        if (obj == 0)
 716      -                                return (SET_ERROR(ENODEV));
      715 +                        drba->drba_snapobj = ds->ds_prev->ds_object;
 717  716                  }
      717 +
      718 +                dsl_dataset_rele(snap, FTAG);
 718  719          } else {
 719  720                  /* if full, most recent snapshot must be $ORIGIN */
 720  721                  if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL)
 721  722                          return (SET_ERROR(ENODEV));
      723 +                drba->drba_snapobj = ds->ds_phys->ds_prev_snap_obj;
 722  724          }
 723  725  
 724  726          return (0);
 725  727  
 726  728  }
 727  729  
 728  730  static int
 729  731  dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
 730  732  {
 731  733          dmu_recv_begin_arg_t *drba = arg;
↓ open down ↓ 88 lines elided ↑ open up ↑
 820  822          uint64_t dsobj;
 821  823          int error;
 822  824          uint64_t crflags;
 823  825  
 824  826          crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ?
 825  827              DS_FLAG_CI_DATASET : 0;
 826  828  
 827  829          error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
 828  830          if (error == 0) {
 829  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 +                }
 830  837                  dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name,
 831      -                    ds->ds_prev, crflags, drba->drba_cred, tx);
      838 +                    snap, crflags, drba->drba_cred, tx);
      839 +                dsl_dataset_rele(snap, FTAG);
 832  840                  dsl_dataset_rele(ds, FTAG);
 833  841          } else {
 834  842                  dsl_dir_t *dd;
 835  843                  const char *tail;
 836  844                  dsl_dataset_t *origin = NULL;
 837  845  
 838  846                  VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail));
 839  847  
 840  848                  if (drba->drba_origin != NULL) {
 841  849                          VERIFY0(dsl_dataset_hold(dp, drba->drba_origin,
↓ open down ↓ 697 lines elided ↑ open up ↑
1539 1547          int error;
1540 1548  
1541 1549          ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag);
1542 1550  
1543 1551          if (!drc->drc_newfs) {
1544 1552                  dsl_dataset_t *origin_head;
1545 1553  
1546 1554                  error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head);
1547 1555                  if (error != 0)
1548 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 +                }
1549 1583                  error = dsl_dataset_clone_swap_check_impl(drc->drc_ds,
1550 1584                      origin_head, drc->drc_force, drc->drc_owner, tx);
1551 1585                  if (error != 0) {
1552 1586                          dsl_dataset_rele(origin_head, FTAG);
1553 1587                          return (error);
1554 1588                  }
1555 1589                  error = dsl_dataset_snapshot_check_impl(origin_head,
1556 1590                      drc->drc_tosnap, tx, B_TRUE);
1557 1591                  dsl_dataset_rele(origin_head, FTAG);
1558 1592                  if (error != 0)
↓ open down ↓ 14 lines elided ↑ open up ↑
1573 1607          dsl_pool_t *dp = dmu_tx_pool(tx);
1574 1608  
1575 1609          spa_history_log_internal_ds(drc->drc_ds, "finish receiving",
1576 1610              tx, "snap=%s", drc->drc_tosnap);
1577 1611  
1578 1612          if (!drc->drc_newfs) {
1579 1613                  dsl_dataset_t *origin_head;
1580 1614  
1581 1615                  VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG,
1582 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 +
1583 1638                  dsl_dataset_clone_swap_sync_impl(drc->drc_ds,
1584 1639                      origin_head, tx);
1585 1640                  dsl_dataset_snapshot_sync_impl(origin_head,
1586 1641                      drc->drc_tosnap, tx);
1587 1642  
1588 1643                  /* set snapshot's creation time and guid */
1589 1644                  dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx);
1590 1645                  origin_head->ds_prev->ds_phys->ds_creation_time =
1591 1646                      drc->drc_drrb->drr_creation_time;
1592 1647                  origin_head->ds_prev->ds_phys->ds_guid =
↓ open down ↓ 120 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX