spa_t *spa;
int err;
- (void) strcpy(sn.failed, fsname);
+ sn = kmem_alloc(sizeof (struct snaparg), KM_SLEEP);
+ (void) strcpy(sn->failed, fsname);
err = spa_open(fsname, &spa, FTAG);
- if (err)
+ if (err) {
+ kmem_free(sn, sizeof (struct snaparg));
return (err);
+ }
- sn.dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
- sn.snapname = snapname;
- sn.props = props;
- sn.recursive = recursive;
+ sn->dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
+ sn->snapname = snapname;
+ sn->props = props;
++ sn->recursive = recursive;
if (recursive) {
- sn->checkperms = B_TRUE;
err = dmu_objset_find(fsname,
- dmu_objset_snapshot_one, &sn, DS_FIND_CHILDREN);
+ dmu_objset_snapshot_one, sn, DS_FIND_CHILDREN);
} else {
- sn->checkperms = B_FALSE;
- err = dmu_objset_snapshot_one(fsname, &sn);
+ err = dmu_objset_snapshot_one(fsname, sn);
}
if (err == 0)
- err = dsl_sync_task_group_wait(sn.dstg);
+ err = dsl_sync_task_group_wait(sn->dstg);
- for (dst = list_head(&sn.dstg->dstg_tasks); dst;
- dst = list_next(&sn.dstg->dstg_tasks, dst)) {
+ for (dst = list_head(&sn->dstg->dstg_tasks); dst;
+ dst = list_next(&sn->dstg->dstg_tasks, dst)) {
objset_t *os = dst->dst_arg1;
- dsl_dataset_t *ds = os->os->os_dsl_dataset;
+ dsl_dataset_t *ds = os->os_dsl_dataset;
if (dst->dst_err)
- dsl_dataset_name(ds, sn.failed);
+ dsl_dataset_name(ds, sn->failed);
zil_resume(dmu_objset_zil(os));
- dmu_objset_close(os);
+ dmu_objset_rele(os, &sn);
}
if (err)
return (0);
}
+ /*
+ * Handle a DRR_WRITE_BYREF record. This record is used in dedup'ed
+ * streams to refer to a copy of the data that is already on the
+ * system because it came in earlier in the stream. This function
+ * finds the earlier copy of the data, and uses that copy instead of
+ * data from the stream to fulfill this write.
+ */
+ static int
+ restore_write_byref(struct restorearg *ra, objset_t *os,
+ struct drr_write_byref *drrwbr)
+ {
+ dmu_tx_t *tx;
+ int err;
+ guid_map_entry_t gmesrch;
+ guid_map_entry_t *gmep;
+ avl_index_t where;
+ objset_t *ref_os = NULL;
+ dmu_buf_t *dbp;
+
+ if (drrwbr->drr_offset + drrwbr->drr_length < drrwbr->drr_offset)
+ return (EINVAL);
+
+ /*
+ * If the GUID of the referenced dataset is different from the
+ * GUID of the target dataset, find the referenced dataset.
+ */
+ if (drrwbr->drr_toguid != drrwbr->drr_refguid) {
+ gmesrch.guid = drrwbr->drr_refguid;
+ if ((gmep = avl_find(&ra->guid_to_ds_map, &gmesrch,
+ &where)) == NULL) {
+ return (EINVAL);
+ }
+ if (dmu_objset_from_ds(gmep->gme_ds, &ref_os))
+ return (EINVAL);
+ } else {
+ ref_os = os;
+ }
+
+ if (err = dmu_buf_hold(ref_os, drrwbr->drr_refobject,
+ drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH))
+ return (err);
+
+ tx = dmu_tx_create(os);
+
+ dmu_tx_hold_write(tx, drrwbr->drr_object,
+ drrwbr->drr_offset, drrwbr->drr_length);
+ err = dmu_tx_assign(tx, TXG_WAIT);
+ if (err) {
+ dmu_tx_abort(tx);
+ return (err);
+ }
+ dmu_write(os, drrwbr->drr_object,
+ drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx);
+ dmu_buf_rele(dbp, FTAG);
+ dmu_tx_commit(tx);
+ return (0);
+ }
+
+ static int
+ restore_spill(struct restorearg *ra, objset_t *os, struct drr_spill *drrs)
+ {
+ dmu_tx_t *tx;
+ void *data;
+ dmu_buf_t *db, *db_spill;
+ int err;
+
+ if (drrs->drr_length < SPA_MINBLOCKSIZE ||
+ drrs->drr_length > SPA_MAXBLOCKSIZE)
+ return (EINVAL);
+
+ data = restore_read(ra, drrs->drr_length);
+ if (data == NULL)
+ return (ra->err);
+
+ if (dmu_object_info(os, drrs->drr_object, NULL) != 0)
+ return (EINVAL);
+
+ VERIFY(0 == dmu_bonus_hold(os, drrs->drr_object, FTAG, &db));
+ if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) {
+ dmu_buf_rele(db, FTAG);
+ return (err);
+ }
+
+ tx = dmu_tx_create(os);
+
+ dmu_tx_hold_spill(tx, db->db_object);
+
+ err = dmu_tx_assign(tx, TXG_WAIT);
+ if (err) {
+ dmu_buf_rele(db, FTAG);
+ dmu_buf_rele(db_spill, FTAG);
+ dmu_tx_abort(tx);
+ return (err);
+ }
+ dmu_buf_will_dirty(db_spill, tx);
+
+ if (db_spill->db_size < drrs->drr_length)
+ VERIFY(0 == dbuf_spill_set_blksz(db_spill,
+ drrs->drr_length, tx));
+ bcopy(data, db_spill->db_data, drrs->drr_length);
+
+ dmu_buf_rele(db, FTAG);
+ dmu_buf_rele(db_spill, FTAG);
+
+ dmu_tx_commit(tx);
+ return (0);
+ }
+
/* ARGSUSED */
-static int
+noinline static int
restore_free(struct restorearg *ra, objset_t *os,
struct drr_free *drrf)
{