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
|