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) {