Print this page
2882 implement libzfs_core
2883 changing "canmount" property to "on" should not always remount dataset
2900 "zfs snapshot" should be able to create multiple, arbitrary snapshots at once
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Chris Siden <christopher.siden@delphix.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Bill Pijewski <wdp@joyent.com>
Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com>
*** 912,922 ****
/*
* The snapshots must all be in the same pool.
*/
int
! dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, char *failed)
{
int err;
dsl_sync_task_t *dst;
spa_t *spa;
nvpair_t *pair;
--- 912,923 ----
/*
* The snapshots must all be in the same pool.
*/
int
! dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer,
! nvlist_t *errlist)
{
int err;
dsl_sync_task_t *dst;
spa_t *spa;
nvpair_t *pair;
*** 947,957 ****
dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
dsl_dataset_destroy_sync, dsda, dstg, 0);
} else if (err == ENOENT) {
err = 0;
} else {
! (void) strcpy(failed, nvpair_name(pair));
break;
}
}
if (err == 0)
--- 948,958 ----
dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
dsl_dataset_destroy_sync, dsda, dstg, 0);
} else if (err == ENOENT) {
err = 0;
} else {
! fnvlist_add_int32(errlist, nvpair_name(pair), err);
break;
}
}
if (err == 0)
*** 961,974 ****
dst = list_next(&dstg->dstg_tasks, dst)) {
struct dsl_ds_destroyarg *dsda = dst->dst_arg1;
dsl_dataset_t *ds = dsda->ds;
/*
! * Return the file system name that triggered the error
*/
! if (dst->dst_err) {
! dsl_dataset_name(ds, failed);
}
ASSERT3P(dsda->rm_origin, ==, NULL);
dsl_dataset_disown(ds, dstg);
kmem_free(dsda, sizeof (struct dsl_ds_destroyarg));
}
--- 962,977 ----
dst = list_next(&dstg->dstg_tasks, dst)) {
struct dsl_ds_destroyarg *dsda = dst->dst_arg1;
dsl_dataset_t *ds = dsda->ds;
/*
! * Return the snapshots that triggered the error.
*/
! if (dst->dst_err != 0) {
! char name[ZFS_MAXNAMELEN];
! dsl_dataset_name(ds, name);
! fnvlist_add_int32(errlist, name, dst->dst_err);
}
ASSERT3P(dsda->rm_origin, ==, NULL);
dsl_dataset_disown(ds, dstg);
kmem_free(dsda, sizeof (struct dsl_ds_destroyarg));
}
*** 1043,1053 ****
dsl_sync_task_group_t *dstg;
objset_t *os;
dsl_dir_t *dd;
uint64_t obj;
struct dsl_ds_destroyarg dsda = { 0 };
- dsl_dataset_t dummy_ds = { 0 };
dsda.ds = ds;
if (dsl_dataset_is_snapshot(ds)) {
/* Destroying a snapshot is simpler */
--- 1046,1055 ----
*** 1063,1074 ****
err = EINVAL;
goto out;
}
dd = ds->ds_dir;
- dummy_ds.ds_dir = dd;
- dummy_ds.ds_object = ds->ds_object;
/*
* Check for errors and mark this ds as inconsistent, in
* case we crash while freeing the objects.
*/
--- 1065,1074 ----
*** 1151,1161 ****
dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool);
dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
dsl_dataset_destroy_sync, &dsda, tag, 0);
dsl_sync_task_create(dstg, dsl_dir_destroy_check,
! dsl_dir_destroy_sync, &dummy_ds, FTAG, 0);
err = dsl_sync_task_group_wait(dstg);
dsl_sync_task_group_destroy(dstg);
/*
* We could be racing against 'zfs release' or 'zfs destroy -d'
--- 1151,1161 ----
dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool);
dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
dsl_dataset_destroy_sync, &dsda, tag, 0);
dsl_sync_task_create(dstg, dsl_dir_destroy_check,
! dsl_dir_destroy_sync, dd, FTAG, 0);
err = dsl_sync_task_group_wait(dstg);
dsl_sync_task_group_destroy(dstg);
/*
* We could be racing against 'zfs release' or 'zfs destroy -d'
*** 1326,1343 ****
/* ARGSUSED */
static void
dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, dmu_tx_t *tx)
{
dsl_dataset_t *ds = arg1;
- dsl_pool_t *dp = ds->ds_dir->dd_pool;
/* Mark it as inconsistent on-disk, in case we crash */
dmu_buf_will_dirty(ds->ds_dbuf, tx);
ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
! spa_history_log_internal(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx,
! "dataset = %llu", ds->ds_object);
}
static int
dsl_dataset_origin_check(struct dsl_ds_destroyarg *dsda, void *tag,
dmu_tx_t *tx)
--- 1326,1341 ----
/* ARGSUSED */
static void
dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, dmu_tx_t *tx)
{
dsl_dataset_t *ds = arg1;
/* Mark it as inconsistent on-disk, in case we crash */
dmu_buf_will_dirty(ds->ds_dbuf, tx);
ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
! spa_history_log_internal_ds(ds, "destroy begin", tx, "");
}
static int
dsl_dataset_origin_check(struct dsl_ds_destroyarg *dsda, void *tag,
dmu_tx_t *tx)
*** 1658,1670 ****
--- 1656,1672 ----
if (wont_destroy) {
ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS);
dmu_buf_will_dirty(ds->ds_dbuf, tx);
ds->ds_phys->ds_flags |= DS_FLAG_DEFER_DESTROY;
+ spa_history_log_internal_ds(ds, "defer_destroy", tx, "");
return;
}
+ /* We need to log before removing it from the namespace. */
+ spa_history_log_internal_ds(ds, "destroy", tx, "");
+
/* signal any waiters that this dataset is going away */
mutex_enter(&ds->ds_lock);
ds->ds_owner = dsl_reaper;
cv_broadcast(&ds->ds_exclusive_cv);
mutex_exit(&ds->ds_lock);
*** 1955,1966 ****
if (ds_prev && ds->ds_prev != ds_prev)
dsl_dataset_rele(ds_prev, FTAG);
spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx);
- spa_history_log_internal(LOG_DS_DESTROY, dp->dp_spa, tx,
- "dataset = %llu", ds->ds_object);
if (ds->ds_phys->ds_next_clones_obj != 0) {
uint64_t count;
ASSERT(0 == zap_count(mos,
ds->ds_phys->ds_next_clones_obj, &count) && count == 0);
--- 1957,1966 ----
*** 2004,2027 ****
asize = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved);
if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE))
return (ENOSPC);
/*
! * Propogate any reserved space for this snapshot to other
* snapshot checks in this sync group.
*/
if (asize > 0)
dsl_dir_willuse_space(ds->ds_dir, asize, tx);
return (0);
}
int
! dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx)
{
- dsl_dataset_t *ds = arg1;
- const char *snapname = arg2;
int err;
uint64_t value;
/*
* We don't allow multiple snapshots of the same txg. If there
--- 2004,2026 ----
asize = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved);
if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE))
return (ENOSPC);
/*
! * Propagate any reserved space for this snapshot to other
* snapshot checks in this sync group.
*/
if (asize > 0)
dsl_dir_willuse_space(ds->ds_dir, asize, tx);
return (0);
}
int
! dsl_dataset_snapshot_check(dsl_dataset_t *ds, const char *snapname,
! dmu_tx_t *tx)
{
int err;
uint64_t value;
/*
* We don't allow multiple snapshots of the same txg. If there
*** 2029,2039 ****
*/
if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg)
return (EAGAIN);
/*
! * Check for conflicting name snapshot name.
*/
err = dsl_dataset_snap_lookup(ds, snapname, &value);
if (err == 0)
return (EEXIST);
if (err != ENOENT)
--- 2028,2038 ----
*/
if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg)
return (EAGAIN);
/*
! * Check for conflicting snapshot name.
*/
err = dsl_dataset_snap_lookup(ds, snapname, &value);
if (err == 0)
return (EEXIST);
if (err != ENOENT)
*** 2053,2066 ****
ds->ds_trysnap_txg = tx->tx_txg;
return (0);
}
void
! dsl_dataset_snapshot_sync(void *arg1, void *arg2, dmu_tx_t *tx)
{
- dsl_dataset_t *ds = arg1;
- const char *snapname = arg2;
dsl_pool_t *dp = ds->ds_dir->dd_pool;
dmu_buf_t *dbuf;
dsl_dataset_phys_t *dsphys;
uint64_t dsobj, crtxg;
objset_t *mos = dp->dp_meta_objset;
--- 2052,2064 ----
ds->ds_trysnap_txg = tx->tx_txg;
return (0);
}
void
! dsl_dataset_snapshot_sync(dsl_dataset_t *ds, const char *snapname,
! dmu_tx_t *tx)
{
dsl_pool_t *dp = ds->ds_dir->dd_pool;
dmu_buf_t *dbuf;
dsl_dataset_phys_t *dsphys;
uint64_t dsobj, crtxg;
objset_t *mos = dp->dp_meta_objset;
*** 2162,2173 ****
dsl_scan_ds_snapshotted(ds, tx);
dsl_dir_snap_cmtime_update(ds->ds_dir);
! spa_history_log_internal(LOG_DS_SNAPSHOT, dp->dp_spa, tx,
! "dataset = %llu", dsobj);
}
void
dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
{
--- 2160,2170 ----
dsl_scan_ds_snapshotted(ds, tx);
dsl_dir_snap_cmtime_update(ds->ds_dir);
! spa_history_log_internal_ds(ds->ds_prev, "snapshot", tx, "");
}
void
dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
{
*** 2250,2260 ****
--- 2247,2270 ----
void
dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
{
uint64_t refd, avail, uobjs, aobjs, ratio;
+ ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 :
+ (ds->ds_phys->ds_uncompressed_bytes * 100 /
+ ds->ds_phys->ds_compressed_bytes);
+
+ dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio);
+
+ if (dsl_dataset_is_snapshot(ds)) {
+ dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio);
+ dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
+ ds->ds_phys->ds_unique_bytes);
+ get_clones_stat(ds, nv);
+ } else {
dsl_dir_stats(ds->ds_dir, nv);
+ }
dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs);
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail);
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd);
*** 2295,2349 ****
written);
}
}
}
- ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 :
- (ds->ds_phys->ds_uncompressed_bytes * 100 /
- ds->ds_phys->ds_compressed_bytes);
- dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio);
-
- if (ds->ds_phys->ds_next_snap_obj) {
- /*
- * This is a snapshot; override the dd's space used with
- * our unique space and compression ratio.
- */
- dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
- ds->ds_phys->ds_unique_bytes);
- dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio);
-
- get_clones_stat(ds, nv);
- }
}
void
dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat)
{
stat->dds_creation_txg = ds->ds_phys->ds_creation_txg;
stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT;
stat->dds_guid = ds->ds_phys->ds_guid;
! if (ds->ds_phys->ds_next_snap_obj) {
stat->dds_is_snapshot = B_TRUE;
stat->dds_num_clones = ds->ds_phys->ds_num_children - 1;
} else {
stat->dds_is_snapshot = B_FALSE;
stat->dds_num_clones = 0;
- }
- /* clone origin is really a dsl_dir thing... */
rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
if (dsl_dir_is_clone(ds->ds_dir)) {
dsl_dataset_t *ods;
VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool,
ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods));
dsl_dataset_name(ods, stat->dds_origin);
dsl_dataset_drop_ref(ods, FTAG);
- } else {
- stat->dds_origin[0] = '\0';
}
rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
}
uint64_t
dsl_dataset_fsid_guid(dsl_dataset_t *ds)
{
--- 2305,2341 ----
written);
}
}
}
}
void
dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat)
{
stat->dds_creation_txg = ds->ds_phys->ds_creation_txg;
stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT;
stat->dds_guid = ds->ds_phys->ds_guid;
! stat->dds_origin[0] = '\0';
! if (dsl_dataset_is_snapshot(ds)) {
stat->dds_is_snapshot = B_TRUE;
stat->dds_num_clones = ds->ds_phys->ds_num_children - 1;
} else {
stat->dds_is_snapshot = B_FALSE;
stat->dds_num_clones = 0;
rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
if (dsl_dir_is_clone(ds->ds_dir)) {
dsl_dataset_t *ods;
VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool,
ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods));
dsl_dataset_name(ods, stat->dds_origin);
dsl_dataset_drop_ref(ods, FTAG);
}
rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
+ }
}
uint64_t
dsl_dataset_fsid_guid(dsl_dataset_t *ds)
{
*** 2456,2467 ****
mutex_exit(&ds->ds_lock);
err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj,
ds->ds_snapname, 8, 1, &ds->ds_object, tx);
ASSERT3U(err, ==, 0);
! spa_history_log_internal(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx,
! "dataset = %llu", ds->ds_object);
dsl_dataset_rele(hds, FTAG);
}
struct renamesnaparg {
dsl_sync_task_group_t *dstg;
--- 2448,2459 ----
mutex_exit(&ds->ds_lock);
err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj,
ds->ds_snapname, 8, 1, &ds->ds_object, tx);
ASSERT3U(err, ==, 0);
! spa_history_log_internal_ds(ds, "rename", tx,
! "-> @%s", newsnapname);
dsl_dataset_rele(hds, FTAG);
}
struct renamesnaparg {
dsl_sync_task_group_t *dstg;
*** 2937,2948 ****
-pa->used - delta, -pa->comp, -pa->uncomp, tx);
origin_ds->ds_phys->ds_unique_bytes = pa->unique;
/* log history record */
! spa_history_log_internal(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx,
! "dataset = %llu", hds->ds_object);
dsl_dir_close(odd, FTAG);
}
static char *snaplist_tag = "snaplist";
--- 2929,2939 ----
-pa->used - delta, -pa->comp, -pa->uncomp, tx);
origin_ds->ds_phys->ds_unique_bytes = pa->unique;
/* log history record */
! spa_history_log_internal_ds(hds, "promote", tx, "");
dsl_dir_close(odd, FTAG);
}
static char *snaplist_tag = "snaplist";
*** 3296,3305 ****
--- 3287,3299 ----
csa->cds->ds_phys->ds_deadlist_obj);
dsl_deadlist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset,
csa->ohds->ds_phys->ds_deadlist_obj);
dsl_scan_ds_clone_swapped(csa->ohds, csa->cds, tx);
+
+ spa_history_log_internal_ds(csa->cds, "clone swap", tx,
+ "parent=%s", csa->ohds->ds_dir->dd_myname);
}
/*
* Swap 'clone' with its origin head datasets. Used at the end of "zfs
* recv" into an existing fs to swizzle the file system to the new
*** 3452,3464 ****
if (ds->ds_quota != effective_value) {
dmu_buf_will_dirty(ds->ds_dbuf, tx);
ds->ds_quota = effective_value;
! spa_history_log_internal(LOG_DS_REFQUOTA,
! ds->ds_dir->dd_pool->dp_spa, tx, "%lld dataset = %llu ",
! (longlong_t)ds->ds_quota, ds->ds_object);
}
}
int
dsl_dataset_set_quota(const char *dsname, zprop_source_t source, uint64_t quota)
--- 3446,3457 ----
if (ds->ds_quota != effective_value) {
dmu_buf_will_dirty(ds->ds_dbuf, tx);
ds->ds_quota = effective_value;
! spa_history_log_internal_ds(ds, "set refquota", tx,
! "refquota=%lld", (longlong_t)ds->ds_quota);
}
}
int
dsl_dataset_set_quota(const char *dsname, zprop_source_t source, uint64_t quota)
*** 3559,3571 ****
mutex_exit(&ds->ds_lock);
dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx);
mutex_exit(&ds->ds_dir->dd_lock);
! spa_history_log_internal(LOG_DS_REFRESERV,
! ds->ds_dir->dd_pool->dp_spa, tx, "%lld dataset = %llu",
! (longlong_t)effective_value, ds->ds_object);
}
int
dsl_dataset_set_reservation(const char *dsname, zprop_source_t source,
uint64_t reservation)
--- 3552,3563 ----
mutex_exit(&ds->ds_lock);
dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx);
mutex_exit(&ds->ds_dir->dd_lock);
! spa_history_log_internal_ds(ds, "set refreservation", tx,
! "refreservation=%lld", (longlong_t)effective_value);
}
int
dsl_dataset_set_reservation(const char *dsname, zprop_source_t source,
uint64_t reservation)
*** 3627,3637 ****
static int
dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx)
{
dsl_dataset_t *ds = arg1;
struct dsl_ds_holdarg *ha = arg2;
! char *htag = ha->htag;
objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
int error = 0;
if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS)
return (ENOTSUP);
--- 3619,3629 ----
static int
dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx)
{
dsl_dataset_t *ds = arg1;
struct dsl_ds_holdarg *ha = arg2;
! const char *htag = ha->htag;
objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
int error = 0;
if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS)
return (ENOTSUP);
*** 3661,3671 ****
void
dsl_dataset_user_hold_sync(void *arg1, void *arg2, dmu_tx_t *tx)
{
dsl_dataset_t *ds = arg1;
struct dsl_ds_holdarg *ha = arg2;
! char *htag = ha->htag;
dsl_pool_t *dp = ds->ds_dir->dd_pool;
objset_t *mos = dp->dp_meta_objset;
uint64_t now = gethrestime_sec();
uint64_t zapobj;
--- 3653,3663 ----
void
dsl_dataset_user_hold_sync(void *arg1, void *arg2, dmu_tx_t *tx)
{
dsl_dataset_t *ds = arg1;
struct dsl_ds_holdarg *ha = arg2;
! const char *htag = ha->htag;
dsl_pool_t *dp = ds->ds_dir->dd_pool;
objset_t *mos = dp->dp_meta_objset;
uint64_t now = gethrestime_sec();
uint64_t zapobj;
*** 3689,3701 ****
if (ha->temphold) {
VERIFY(0 == dsl_pool_user_hold(dp, ds->ds_object,
htag, &now, tx));
}
! spa_history_log_internal(LOG_DS_USER_HOLD,
! dp->dp_spa, tx, "<%s> temp = %d dataset = %llu", htag,
! (int)ha->temphold, ds->ds_object);
}
static int
dsl_dataset_user_hold_one(const char *dsname, void *arg)
{
--- 3681,3693 ----
if (ha->temphold) {
VERIFY(0 == dsl_pool_user_hold(dp, ds->ds_object,
htag, &now, tx));
}
! spa_history_log_internal_ds(ds, "hold", tx,
! "tag = %s temp = %d holds now = %llu",
! htag, (int)ha->temphold, ds->ds_userrefs);
}
static int
dsl_dataset_user_hold_one(const char *dsname, void *arg)
{
*** 3898,3908 ****
struct dsl_ds_releasearg *ra = arg1;
dsl_dataset_t *ds = ra->ds;
dsl_pool_t *dp = ds->ds_dir->dd_pool;
objset_t *mos = dp->dp_meta_objset;
uint64_t zapobj;
- uint64_t dsobj = ds->ds_object;
uint64_t refs;
int error;
mutex_enter(&ds->ds_lock);
ds->ds_userrefs--;
--- 3890,3899 ----
*** 3921,3933 ****
dsda.releasing = B_TRUE;
/* We already did the destroy_check */
dsl_dataset_destroy_sync(&dsda, tag, tx);
}
! spa_history_log_internal(LOG_DS_USER_RELEASE,
! dp->dp_spa, tx, "<%s> %lld dataset = %llu",
! ra->htag, (longlong_t)refs, dsobj);
}
static int
dsl_dataset_user_release_one(const char *dsname, void *arg)
{
--- 3912,3923 ----
dsda.releasing = B_TRUE;
/* We already did the destroy_check */
dsl_dataset_destroy_sync(&dsda, tag, tx);
}
! spa_history_log_internal_ds(ds, "release", tx,
! "tag = %s refs now = %lld", ra->htag, (longlong_t)refs);
}
static int
dsl_dataset_user_release_one(const char *dsname, void *arg)
{