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>
*** 385,397 ****
ASSERT(err == 0 || err == EINTR);
return (err);
}
int
! dmu_send(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
! int outfd, vnode_t *vp, offset_t *off)
{
dsl_dataset_t *ds = tosnap->os_dsl_dataset;
dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL;
dmu_replay_record_t *drr;
dmu_sendarg_t *dsp;
--- 385,436 ----
ASSERT(err == 0 || err == EINTR);
return (err);
}
+ /*
+ * Return TRUE if 'earlier' is an earlier snapshot in 'later's timeline.
+ * For example, they could both be snapshots of the same filesystem, and
+ * 'earlier' is before 'later'. Or 'earlier' could be the origin of
+ * 'later's filesystem. Or 'earlier' could be an older snapshot in the origin's
+ * filesystem. Or 'earlier' could be the origin's origin.
+ */
+ static boolean_t
+ is_before(dsl_dataset_t *later, dsl_dataset_t *earlier)
+ {
+ dsl_pool_t *dp = later->ds_dir->dd_pool;
+ int error;
+ boolean_t ret;
+ dsl_dataset_t *origin;
+
+ if (earlier->ds_phys->ds_creation_txg >=
+ later->ds_phys->ds_creation_txg)
+ return (B_FALSE);
+
+ if (later->ds_dir == earlier->ds_dir)
+ return (B_TRUE);
+ if (!dsl_dir_is_clone(later->ds_dir))
+ return (B_FALSE);
+
+ rw_enter(&dp->dp_config_rwlock, RW_READER);
+ if (later->ds_dir->dd_phys->dd_origin_obj == earlier->ds_object) {
+ rw_exit(&dp->dp_config_rwlock);
+ return (B_TRUE);
+ }
+ error = dsl_dataset_hold_obj(dp,
+ later->ds_dir->dd_phys->dd_origin_obj, FTAG, &origin);
+ rw_exit(&dp->dp_config_rwlock);
+ if (error != 0)
+ return (B_FALSE);
+ ret = is_before(origin, earlier);
+ dsl_dataset_rele(origin, FTAG);
+ return (ret);
+ }
+
int
! dmu_send(objset_t *tosnap, objset_t *fromsnap, int outfd, vnode_t *vp,
! offset_t *off)
{
dsl_dataset_t *ds = tosnap->os_dsl_dataset;
dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL;
dmu_replay_record_t *drr;
dmu_sendarg_t *dsp;
*** 400,433 ****
/* tosnap must be a snapshot */
if (ds->ds_phys->ds_next_snap_obj == 0)
return (EINVAL);
! /* fromsnap must be an earlier snapshot from the same fs as tosnap */
! if (fromds && (ds->ds_dir != fromds->ds_dir ||
! fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg))
return (EXDEV);
- if (fromorigin) {
- dsl_pool_t *dp = ds->ds_dir->dd_pool;
-
- if (fromsnap)
- return (EINVAL);
-
- if (dsl_dir_is_clone(ds->ds_dir)) {
- rw_enter(&dp->dp_config_rwlock, RW_READER);
- err = dsl_dataset_hold_obj(dp,
- ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds);
- rw_exit(&dp->dp_config_rwlock);
- if (err)
- return (err);
- } else {
- fromorigin = B_FALSE;
- }
- }
-
-
drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
drr->drr_type = DRR_BEGIN;
drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo,
DMU_SUBSTREAM);
--- 439,455 ----
/* tosnap must be a snapshot */
if (ds->ds_phys->ds_next_snap_obj == 0)
return (EINVAL);
! /*
! * fromsnap must be an earlier snapshot from the same fs as tosnap,
! * or the origin's fs.
! */
! if (fromds != NULL && !is_before(ds, fromds))
return (EXDEV);
drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
drr->drr_type = DRR_BEGIN;
drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo,
DMU_SUBSTREAM);
*** 448,458 ****
#endif
drr->drr_u.drr_begin.drr_creation_time =
ds->ds_phys->ds_creation_time;
drr->drr_u.drr_begin.drr_type = tosnap->os_phys->os_type;
! if (fromorigin)
drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE;
drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid;
if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA;
--- 470,480 ----
#endif
drr->drr_u.drr_begin.drr_creation_time =
ds->ds_phys->ds_creation_time;
drr->drr_u.drr_begin.drr_type = tosnap->os_phys->os_type;
! if (fromds != NULL && ds->ds_dir != fromds->ds_dir)
drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE;
drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid;
if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA;
*** 460,471 ****
drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid;
dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname);
if (fromds)
fromtxg = fromds->ds_phys->ds_creation_txg;
- if (fromorigin)
- dsl_dataset_rele(fromds, FTAG);
dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP);
dsp->dsa_drr = drr;
dsp->dsa_vp = vp;
--- 482,491 ----
*** 519,530 ****
return (err);
}
int
! dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
! uint64_t *sizep)
{
dsl_dataset_t *ds = tosnap->os_dsl_dataset;
dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL;
dsl_pool_t *dp = ds->ds_dir->dd_pool;
int err;
--- 539,549 ----
return (err);
}
int
! dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, uint64_t *sizep)
{
dsl_dataset_t *ds = tosnap->os_dsl_dataset;
dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL;
dsl_pool_t *dp = ds->ds_dir->dd_pool;
int err;
*** 532,571 ****
/* tosnap must be a snapshot */
if (ds->ds_phys->ds_next_snap_obj == 0)
return (EINVAL);
! /* fromsnap must be an earlier snapshot from the same fs as tosnap */
! if (fromds && (ds->ds_dir != fromds->ds_dir ||
! fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg))
return (EXDEV);
- if (fromorigin) {
- if (fromsnap)
- return (EINVAL);
-
- if (dsl_dir_is_clone(ds->ds_dir)) {
- rw_enter(&dp->dp_config_rwlock, RW_READER);
- err = dsl_dataset_hold_obj(dp,
- ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds);
- rw_exit(&dp->dp_config_rwlock);
- if (err)
- return (err);
- } else {
- fromorigin = B_FALSE;
- }
- }
-
/* Get uncompressed size estimate of changed data. */
if (fromds == NULL) {
size = ds->ds_phys->ds_uncompressed_bytes;
} else {
uint64_t used, comp;
err = dsl_dataset_space_written(fromds, ds,
&used, &comp, &size);
- if (fromorigin)
- dsl_dataset_rele(fromds, FTAG);
if (err)
return (err);
}
/*
--- 551,574 ----
/* tosnap must be a snapshot */
if (ds->ds_phys->ds_next_snap_obj == 0)
return (EINVAL);
! /*
! * fromsnap must be an earlier snapshot from the same fs as tosnap,
! * or the origin's fs.
! */
! if (fromds != NULL && !is_before(ds, fromds))
return (EXDEV);
/* Get uncompressed size estimate of changed data. */
if (fromds == NULL) {
size = ds->ds_phys->ds_uncompressed_bytes;
} else {
uint64_t used, comp;
err = dsl_dataset_space_written(fromds, ds,
&used, &comp, &size);
if (err)
return (err);
}
/*
*** 660,671 ****
if (rbsa->origin == NULL) {
(void) dmu_objset_create_impl(dd->dd_pool->dp_spa,
rbsa->ds, &rbsa->ds->ds_phys->ds_bp, rbsa->type, tx);
}
! spa_history_log_internal(LOG_DS_REPLAY_FULL_SYNC,
! dd->dd_pool->dp_spa, tx, "dataset = %lld", dsobj);
}
/* ARGSUSED */
static int
recv_existing_check(void *arg1, void *arg2, dmu_tx_t *tx)
--- 663,673 ----
if (rbsa->origin == NULL) {
(void) dmu_objset_create_impl(dd->dd_pool->dp_spa,
rbsa->ds, &rbsa->ds->ds_phys->ds_bp, rbsa->type, tx);
}
! spa_history_log_internal_ds(rbsa->ds, "receive new", tx, "");
}
/* ARGSUSED */
static int
recv_existing_check(void *arg1, void *arg2, dmu_tx_t *tx)
*** 762,773 ****
cds, dsl_dataset_get_blkptr(cds), rbsa->type, tx);
}
rbsa->ds = cds;
! spa_history_log_internal(LOG_DS_REPLAY_INC_SYNC,
! dp->dp_spa, tx, "dataset = %lld", dsobj);
}
static boolean_t
dmu_recv_verify_features(dsl_dataset_t *ds, struct drr_begin *drrb)
{
--- 764,774 ----
cds, dsl_dataset_get_blkptr(cds), rbsa->type, tx);
}
rbsa->ds = cds;
! spa_history_log_internal_ds(cds, "receive over existing", tx, "");
}
static boolean_t
dmu_recv_verify_features(dsl_dataset_t *ds, struct drr_begin *drrb)
{
*** 1571,1580 ****
--- 1572,1582 ----
ds->ds_prev->ds_phys->ds_guid = resa->toguid;
ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
dmu_buf_will_dirty(ds->ds_dbuf, tx);
ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
+ spa_history_log_internal_ds(ds, "finished receiving", tx, "");
}
static int
add_ds_to_guidmap(avl_tree_t *guid_map, dsl_dataset_t *ds)
{