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>


1516 {
1517         *refdbytesp = ds->ds_phys->ds_referenced_bytes;
1518         *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE);
1519         if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes)
1520                 *availbytesp += ds->ds_reserved - ds->ds_phys->ds_unique_bytes;
1521         if (ds->ds_quota != 0) {
1522                 /*
1523                  * Adjust available bytes according to refquota
1524                  */
1525                 if (*refdbytesp < ds->ds_quota)
1526                         *availbytesp = MIN(*availbytesp,
1527                             ds->ds_quota - *refdbytesp);
1528                 else
1529                         *availbytesp = 0;
1530         }
1531         *usedobjsp = ds->ds_phys->ds_bp.blk_fill;
1532         *availobjsp = DN_MAX_OBJECT - *usedobjsp;
1533 }
1534 
1535 boolean_t
1536 dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds)
1537 {
1538         dsl_pool_t *dp = ds->ds_dir->dd_pool;
1539 
1540         ASSERT(dsl_pool_config_held(dp));
1541         if (ds->ds_prev == NULL)
1542                 return (B_FALSE);
1543         if (ds->ds_phys->ds_bp.blk_birth >
1544             ds->ds_prev->ds_phys->ds_creation_txg) {
1545                 objset_t *os, *os_prev;
1546                 /*
1547                  * It may be that only the ZIL differs, because it was
1548                  * reset in the head.  Don't count that as being
1549                  * modified.
1550                  */
1551                 if (dmu_objset_from_ds(ds, &os) != 0)
1552                         return (B_TRUE);
1553                 if (dmu_objset_from_ds(ds->ds_prev, &os_prev) != 0)
1554                         return (B_TRUE);
1555                 return (bcmp(&os->os_phys->os_meta_dnode,
1556                     &os_prev->os_phys->os_meta_dnode,
1557                     sizeof (os->os_phys->os_meta_dnode)) != 0);
1558         }
1559         return (B_FALSE);
1560 }
1561 
1562 typedef struct dsl_dataset_rename_snapshot_arg {
1563         const char *ddrsa_fsname;
1564         const char *ddrsa_oldsnapname;
1565         const char *ddrsa_newsnapname;
1566         boolean_t ddrsa_recursive;
1567         dmu_tx_t *ddrsa_tx;
1568 } dsl_dataset_rename_snapshot_arg_t;
1569 
1570 /* ARGSUSED */
1571 static int
1572 dsl_dataset_rename_snapshot_check_impl(dsl_pool_t *dp,
1573     dsl_dataset_t *hds, void *arg)
1574 {
1575         dsl_dataset_rename_snapshot_arg_t *ddrsa = arg;
1576         int error;


2339                 return (error);
2340 
2341         ddpa.ddpa_clonename = name;
2342         ddpa.err_ds = conflsnap;
2343 
2344         return (dsl_sync_task(name, dsl_dataset_promote_check,
2345             dsl_dataset_promote_sync, &ddpa, 2 + numsnaps));
2346 }
2347 
2348 int
2349 dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
2350     dsl_dataset_t *origin_head, boolean_t force, void *owner, dmu_tx_t *tx)
2351 {
2352         int64_t unused_refres_delta;
2353 
2354         /* they should both be heads */
2355         if (dsl_dataset_is_snapshot(clone) ||
2356             dsl_dataset_is_snapshot(origin_head))
2357                 return (SET_ERROR(EINVAL));
2358 
2359         /* the branch point should be just before them */
2360         if (clone->ds_prev != origin_head->ds_prev)
2361                 return (SET_ERROR(EINVAL));
2362 
2363         /* clone should be the clone (unless they are unrelated) */
2364         if (clone->ds_prev != NULL &&
2365             clone->ds_prev != clone->ds_dir->dd_pool->dp_origin_snap &&
2366             origin_head->ds_object !=
2367             clone->ds_prev->ds_phys->ds_next_snap_obj)
2368                 return (SET_ERROR(EINVAL));
2369 
2370         /* the clone should be a child of the origin */
2371         if (clone->ds_dir->dd_parent != origin_head->ds_dir)
2372                 return (SET_ERROR(EINVAL));
2373 
2374         /* origin_head shouldn't be modified unless 'force' */
2375         if (!force && dsl_dataset_modified_since_lastsnap(origin_head))

2376                 return (SET_ERROR(ETXTBSY));
2377 
2378         /* origin_head should have no long holds (e.g. is not mounted) */
2379         if (dsl_dataset_handoff_check(origin_head, owner, tx))
2380                 return (SET_ERROR(EBUSY));
2381 
2382         /* check amount of any unconsumed refreservation */
2383         unused_refres_delta =
2384             (int64_t)MIN(origin_head->ds_reserved,
2385             origin_head->ds_phys->ds_unique_bytes) -
2386             (int64_t)MIN(origin_head->ds_reserved,
2387             clone->ds_phys->ds_unique_bytes);
2388 
2389         if (unused_refres_delta > 0 &&
2390             unused_refres_delta >
2391             dsl_dir_space_available(origin_head->ds_dir, NULL, 0, TRUE))
2392                 return (SET_ERROR(ENOSPC));
2393 
2394         /* clone can't be over the head's refquota */
2395         if (origin_head->ds_quota != 0 &&
2396             clone->ds_phys->ds_referenced_bytes > origin_head->ds_quota)
2397                 return (SET_ERROR(EDQUOT));
2398 
2399         return (0);
2400 }
2401 
2402 void
2403 dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
2404     dsl_dataset_t *origin_head, dmu_tx_t *tx)
2405 {
2406         dsl_pool_t *dp = dmu_tx_pool(tx);
2407         int64_t unused_refres_delta;
2408 
2409         ASSERT(clone->ds_reserved == 0);
2410         ASSERT(origin_head->ds_quota == 0 ||
2411             clone->ds_phys->ds_unique_bytes <= origin_head->ds_quota);

2412 
2413         dmu_buf_will_dirty(clone->ds_dbuf, tx);
2414         dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
2415 
2416         if (clone->ds_objset != NULL) {
2417                 dmu_objset_evict(clone->ds_objset);
2418                 clone->ds_objset = NULL;
2419         }
2420 
2421         if (origin_head->ds_objset != NULL) {
2422                 dmu_objset_evict(origin_head->ds_objset);
2423                 origin_head->ds_objset = NULL;
2424         }
2425 
2426         unused_refres_delta =
2427             (int64_t)MIN(origin_head->ds_reserved,
2428             origin_head->ds_phys->ds_unique_bytes) -
2429             (int64_t)MIN(origin_head->ds_reserved,
2430             clone->ds_phys->ds_unique_bytes);
2431 




1516 {
1517         *refdbytesp = ds->ds_phys->ds_referenced_bytes;
1518         *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE);
1519         if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes)
1520                 *availbytesp += ds->ds_reserved - ds->ds_phys->ds_unique_bytes;
1521         if (ds->ds_quota != 0) {
1522                 /*
1523                  * Adjust available bytes according to refquota
1524                  */
1525                 if (*refdbytesp < ds->ds_quota)
1526                         *availbytesp = MIN(*availbytesp,
1527                             ds->ds_quota - *refdbytesp);
1528                 else
1529                         *availbytesp = 0;
1530         }
1531         *usedobjsp = ds->ds_phys->ds_bp.blk_fill;
1532         *availobjsp = DN_MAX_OBJECT - *usedobjsp;
1533 }
1534 
1535 boolean_t
1536 dsl_dataset_modified_since_snap(dsl_dataset_t *ds, dsl_dataset_t *snap)
1537 {
1538         dsl_pool_t *dp = ds->ds_dir->dd_pool;
1539 
1540         ASSERT(dsl_pool_config_held(dp));
1541         if (snap == NULL)
1542                 return (B_FALSE);
1543         if (ds->ds_phys->ds_bp.blk_birth >
1544             snap->ds_phys->ds_creation_txg) {
1545                 objset_t *os, *os_snap;
1546                 /*
1547                  * It may be that only the ZIL differs, because it was
1548                  * reset in the head.  Don't count that as being
1549                  * modified.
1550                  */
1551                 if (dmu_objset_from_ds(ds, &os) != 0)
1552                         return (B_TRUE);
1553                 if (dmu_objset_from_ds(snap, &os_snap) != 0)
1554                         return (B_TRUE);
1555                 return (bcmp(&os->os_phys->os_meta_dnode,
1556                     &os_snap->os_phys->os_meta_dnode,
1557                     sizeof (os->os_phys->os_meta_dnode)) != 0);
1558         }
1559         return (B_FALSE);
1560 }
1561 
1562 typedef struct dsl_dataset_rename_snapshot_arg {
1563         const char *ddrsa_fsname;
1564         const char *ddrsa_oldsnapname;
1565         const char *ddrsa_newsnapname;
1566         boolean_t ddrsa_recursive;
1567         dmu_tx_t *ddrsa_tx;
1568 } dsl_dataset_rename_snapshot_arg_t;
1569 
1570 /* ARGSUSED */
1571 static int
1572 dsl_dataset_rename_snapshot_check_impl(dsl_pool_t *dp,
1573     dsl_dataset_t *hds, void *arg)
1574 {
1575         dsl_dataset_rename_snapshot_arg_t *ddrsa = arg;
1576         int error;


2339                 return (error);
2340 
2341         ddpa.ddpa_clonename = name;
2342         ddpa.err_ds = conflsnap;
2343 
2344         return (dsl_sync_task(name, dsl_dataset_promote_check,
2345             dsl_dataset_promote_sync, &ddpa, 2 + numsnaps));
2346 }
2347 
2348 int
2349 dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
2350     dsl_dataset_t *origin_head, boolean_t force, void *owner, dmu_tx_t *tx)
2351 {
2352         int64_t unused_refres_delta;
2353 
2354         /* they should both be heads */
2355         if (dsl_dataset_is_snapshot(clone) ||
2356             dsl_dataset_is_snapshot(origin_head))
2357                 return (SET_ERROR(EINVAL));
2358 
2359         /* if we are not forcing, the branch point should be just before them */
2360         if (!force && clone->ds_prev != origin_head->ds_prev)
2361                 return (SET_ERROR(EINVAL));
2362 
2363         /* clone should be the clone (unless they are unrelated) */
2364         if (clone->ds_prev != NULL &&
2365             clone->ds_prev != clone->ds_dir->dd_pool->dp_origin_snap &&
2366             origin_head->ds_dir != clone->ds_prev->ds_dir)

2367                 return (SET_ERROR(EINVAL));
2368 
2369         /* the clone should be a child of the origin */
2370         if (clone->ds_dir->dd_parent != origin_head->ds_dir)
2371                 return (SET_ERROR(EINVAL));
2372 
2373         /* origin_head shouldn't be modified unless 'force' */
2374         if (!force &&
2375             dsl_dataset_modified_since_snap(origin_head, origin_head->ds_prev))
2376                 return (SET_ERROR(ETXTBSY));
2377 
2378         /* origin_head should have no long holds (e.g. is not mounted) */
2379         if (dsl_dataset_handoff_check(origin_head, owner, tx))
2380                 return (SET_ERROR(EBUSY));
2381 
2382         /* check amount of any unconsumed refreservation */
2383         unused_refres_delta =
2384             (int64_t)MIN(origin_head->ds_reserved,
2385             origin_head->ds_phys->ds_unique_bytes) -
2386             (int64_t)MIN(origin_head->ds_reserved,
2387             clone->ds_phys->ds_unique_bytes);
2388 
2389         if (unused_refres_delta > 0 &&
2390             unused_refres_delta >
2391             dsl_dir_space_available(origin_head->ds_dir, NULL, 0, TRUE))
2392                 return (SET_ERROR(ENOSPC));
2393 
2394         /* clone can't be over the head's refquota */
2395         if (origin_head->ds_quota != 0 &&
2396             clone->ds_phys->ds_referenced_bytes > origin_head->ds_quota)
2397                 return (SET_ERROR(EDQUOT));
2398 
2399         return (0);
2400 }
2401 
2402 void
2403 dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
2404     dsl_dataset_t *origin_head, dmu_tx_t *tx)
2405 {
2406         dsl_pool_t *dp = dmu_tx_pool(tx);
2407         int64_t unused_refres_delta;
2408 
2409         ASSERT(clone->ds_reserved == 0);
2410         ASSERT(origin_head->ds_quota == 0 ||
2411             clone->ds_phys->ds_unique_bytes <= origin_head->ds_quota);
2412         ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
2413 
2414         dmu_buf_will_dirty(clone->ds_dbuf, tx);
2415         dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
2416 
2417         if (clone->ds_objset != NULL) {
2418                 dmu_objset_evict(clone->ds_objset);
2419                 clone->ds_objset = NULL;
2420         }
2421 
2422         if (origin_head->ds_objset != NULL) {
2423                 dmu_objset_evict(origin_head->ds_objset);
2424                 origin_head->ds_objset = NULL;
2425         }
2426 
2427         unused_refres_delta =
2428             (int64_t)MIN(origin_head->ds_reserved,
2429             origin_head->ds_phys->ds_unique_bytes) -
2430             (int64_t)MIN(origin_head->ds_reserved,
2431             clone->ds_phys->ds_unique_bytes);
2432