From: Brian Behlendorf Date: Fri, 28 May 2010 20:54:08 +0000 (-0700) Subject: Merge commit 'refs/top-bases/fix-stack' into fix-stack X-Git-Tag: zfs-0.5.0~38^2^2~1^2^2~34^2^2^2~6^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=89089d1e4bfb768415cf35a58ed3f87a1586df45;p=zfs Merge commit 'refs/top-bases/fix-stack' into fix-stack Conflicts: module/zfs/dmu_objset.c module/zfs/spa_history.c --- 89089d1e4bfb768415cf35a58ed3f87a1586df45 diff --cc lib/libzpool/include/sys/zfs_context.h index 9c66c6cc1,9a6d712e5..8c16ec1ef --- a/lib/libzpool/include/sys/zfs_context.h +++ b/lib/libzpool/include/sys/zfs_context.h @@@ -75,13 -75,8 +75,14 @@@ extern "C" #include #include #include + #include +/* + * Stack + */ + +#define noinline __attribute__((noinline)) + /* * Debugging */ diff --cc module/zfs/dmu_objset.c index cff74b11b,690e6ecde..32bb614c8 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@@ -820,39 -882,35 +882,38 @@@ dmu_objset_snapshot(char *fsname, char 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) diff --cc module/zfs/dmu_send.c index 266f35ad9,6b00b73b4..2f837a1e9 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@@ -882,8 -1145,116 +1145,116 @@@ restore_write(struct restorearg *ra, ob 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) {