Пример #1
0
static int
zcp_clones_iter(lua_State *state)
{
	int err;
	char clonename[ZFS_MAX_DATASET_NAME_LEN];
	uint64_t dsobj = lua_tonumber(state, lua_upvalueindex(1));
	uint64_t cursor = lua_tonumber(state, lua_upvalueindex(2));
	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
	dsl_dataset_t *ds, *clone;
	zap_attribute_t za;
	zap_cursor_t zc;

	err = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds);
	if (err == ENOENT) {
		return (0);
	} else if (err != 0) {
		return (luaL_error(state,
		    "unexpected error %d from dsl_dataset_hold_obj(dsobj)",
		    err));
	}

	if (dsl_dataset_phys(ds)->ds_next_clones_obj == 0) {
		dsl_dataset_rele(ds, FTAG);
		return (0);
	}

	zap_cursor_init_serialized(&zc, dp->dp_meta_objset,
	    dsl_dataset_phys(ds)->ds_next_clones_obj, cursor);
	dsl_dataset_rele(ds, FTAG);

	err = zap_cursor_retrieve(&zc, &za);
	if (err != 0) {
		zap_cursor_fini(&zc);
		if (err != ENOENT) {
			return (luaL_error(state,
			    "unexpected error %d from zap_cursor_retrieve()",
			    err));
		}
		return (0);
	}
	zap_cursor_advance(&zc);
	cursor = zap_cursor_serialize(&zc);
	zap_cursor_fini(&zc);

	err = dsl_dataset_hold_obj(dp, za.za_first_integer, FTAG, &clone);
	if (err != 0) {
		return (luaL_error(state,
		    "unexpected error %d from "
		    "dsl_dataset_hold_obj(za_first_integer)", err));
	}

	dsl_dir_name(clone->ds_dir, clonename);
	dsl_dataset_rele(clone, FTAG);

	lua_pushnumber(state, cursor);
	lua_replace(state, lua_upvalueindex(2));

	(void) lua_pushstring(state, clonename);
	return (1);
}
Пример #2
0
int
dsl_dataset_get_holds(const char *dsname, nvlist_t *nvl)
{
	dsl_pool_t *dp;
	dsl_dataset_t *ds;
	int err;

	err = dsl_pool_hold(dsname, FTAG, &dp);
	if (err != 0)
		return (err);
	err = dsl_dataset_hold(dp, dsname, FTAG, &ds);
	if (err != 0) {
		dsl_pool_rele(dp, FTAG);
		return (err);
	}

	if (dsl_dataset_phys(ds)->ds_userrefs_obj != 0) {
		zap_attribute_t *za;
		zap_cursor_t zc;

		za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
		for (zap_cursor_init(&zc, ds->ds_dir->dd_pool->dp_meta_objset,
		    dsl_dataset_phys(ds)->ds_userrefs_obj);
		    zap_cursor_retrieve(&zc, za) == 0;
		    zap_cursor_advance(&zc)) {
			fnvlist_add_uint64(nvl, za->za_name,
			    za->za_first_integer);
		}
		zap_cursor_fini(&zc);
		kmem_free(za, sizeof (zap_attribute_t));
	}
	dsl_dataset_rele(ds, FTAG);
	dsl_pool_rele(dp, FTAG);
	return (0);
}
Пример #3
0
/*
 * If you add new checks here, you may need to add additional checks to the
 * "temporary" case in snapshot_check() in dmu_objset.c.
 */
int
dsl_dataset_user_hold_check_one(dsl_dataset_t *ds, const char *htag,
    boolean_t temphold, dmu_tx_t *tx)
{
	dsl_pool_t *dp = dmu_tx_pool(tx);
	objset_t *mos = dp->dp_meta_objset;
	int error = 0;

	ASSERT(dsl_pool_config_held(dp));

	if (strlen(htag) > MAXNAMELEN)
		return (SET_ERROR(E2BIG));
	/* Tempholds have a more restricted length */
	if (temphold && strlen(htag) + MAX_TAG_PREFIX_LEN >= MAXNAMELEN)
		return (SET_ERROR(E2BIG));

	/* tags must be unique (if ds already exists) */
	if (ds != NULL && dsl_dataset_phys(ds)->ds_userrefs_obj != 0) {
		uint64_t value;

		error = zap_lookup(mos, dsl_dataset_phys(ds)->ds_userrefs_obj,
		    htag, 8, 1, &value);
		if (error == 0)
			error = SET_ERROR(EEXIST);
		else if (error == ENOENT)
			error = 0;
	}

	return (error);
}
Пример #4
0
static void
dsl_bookmark_create_sync(void *arg, dmu_tx_t *tx)
{
	dsl_bookmark_create_arg_t *dbca = arg;
	dsl_pool_t *dp = dmu_tx_pool(tx);
	objset_t *mos = dp->dp_meta_objset;
	nvpair_t *pair;

	ASSERT(spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_BOOKMARKS));

	for (pair = nvlist_next_nvpair(dbca->dbca_bmarks, NULL);
	    pair != NULL; pair = nvlist_next_nvpair(dbca->dbca_bmarks, pair)) {
		dsl_dataset_t *snapds, *bmark_fs;
		zfs_bookmark_phys_t bmark_phys;
		char *shortname;

		VERIFY0(dsl_dataset_hold(dp, fnvpair_value_string(pair),
		    FTAG, &snapds));
		VERIFY0(dsl_bookmark_hold_ds(dp, nvpair_name(pair),
		    &bmark_fs, FTAG, &shortname));
		if (bmark_fs->ds_bookmarks == 0) {
			bmark_fs->ds_bookmarks =
			    zap_create_norm(mos, U8_TEXTPREP_TOUPPER,
			    DMU_OTN_ZAP_METADATA, DMU_OT_NONE, 0, tx);
			spa_feature_incr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx);

			dsl_dataset_zapify(bmark_fs, tx);
			VERIFY0(zap_add(mos, bmark_fs->ds_object,
			    DS_FIELD_BOOKMARK_NAMES,
			    sizeof (bmark_fs->ds_bookmarks), 1,
			    &bmark_fs->ds_bookmarks, tx));
		}

		bmark_phys.zbm_guid = dsl_dataset_phys(snapds)->ds_guid;
		bmark_phys.zbm_creation_txg =
		    dsl_dataset_phys(snapds)->ds_creation_txg;
		bmark_phys.zbm_creation_time =
		    dsl_dataset_phys(snapds)->ds_creation_time;

		VERIFY0(zap_add(mos, bmark_fs->ds_bookmarks,
		    shortname, sizeof (uint64_t),
		    sizeof (zfs_bookmark_phys_t) / sizeof (uint64_t),
		    &bmark_phys, tx));

		spa_history_log_internal_ds(bmark_fs, "bookmark", tx,
		    "name=%s creation_txg=%llu target_snap=%llu",
		    shortname,
		    (longlong_t)bmark_phys.zbm_creation_txg,
		    (longlong_t)snapds->ds_object);

		dsl_dataset_rele(bmark_fs, FTAG);
		dsl_dataset_rele(snapds, FTAG);
	}
}
Пример #5
0
static void
dsl_dataset_user_hold_sync_one_impl(nvlist_t *tmpholds, dsl_dataset_t *ds,
    const char *htag, minor_t minor, uint64_t now, dmu_tx_t *tx)
{
	dsl_pool_t *dp = ds->ds_dir->dd_pool;
	objset_t *mos = dp->dp_meta_objset;
	uint64_t zapobj;

	ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));

	if (dsl_dataset_phys(ds)->ds_userrefs_obj == 0) {
		/*
		 * This is the first user hold for this dataset.  Create
		 * the userrefs zap object.
		 */
		dmu_buf_will_dirty(ds->ds_dbuf, tx);
		zapobj = dsl_dataset_phys(ds)->ds_userrefs_obj =
		    zap_create(mos, DMU_OT_USERREFS, DMU_OT_NONE, 0, tx);
	} else {
		zapobj = dsl_dataset_phys(ds)->ds_userrefs_obj;
	}
	ds->ds_userrefs++;

	VERIFY0(zap_add(mos, zapobj, htag, 8, 1, &now, tx));

	if (minor != 0) {
		char name[MAXNAMELEN];
		nvlist_t *tags;

		VERIFY0(dsl_pool_user_hold(dp, ds->ds_object,
		    htag, now, tx));
		(void) snprintf(name, sizeof (name), "%llx",
		    (u_longlong_t)ds->ds_object);

		if (nvlist_lookup_nvlist(tmpholds, name, &tags) != 0) {
			tags = fnvlist_alloc();
			fnvlist_add_boolean(tags, htag);
			fnvlist_add_nvlist(tmpholds, name, tags);
			fnvlist_free(tags);
		} else {
			fnvlist_add_boolean(tags, htag);
		}
	}

	spa_history_log_internal_ds(ds, "hold", tx,
	    "tag=%s temp=%d refs=%llu",
	    htag, minor != 0, ds->ds_userrefs);
}
Пример #6
0
static void
dsl_dataset_user_release_sync_one(dsl_dataset_t *ds, nvlist_t *holds,
    dmu_tx_t *tx)
{
	dsl_pool_t *dp = ds->ds_dir->dd_pool;
	objset_t *mos = dp->dp_meta_objset;
	nvpair_t *pair;

	for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
	    pair = nvlist_next_nvpair(holds, pair)) {
		int error;
		const char *holdname = nvpair_name(pair);

		/* Remove temporary hold if one exists. */
		error = dsl_pool_user_release(dp, ds->ds_object, holdname, tx);
		VERIFY(error == 0 || error == ENOENT);

		VERIFY0(zap_remove(mos, dsl_dataset_phys(ds)->ds_userrefs_obj,
		    holdname, tx));
		ds->ds_userrefs--;

		spa_history_log_internal_ds(ds, "release", tx,
		    "tag=%s refs=%lld", holdname, (longlong_t)ds->ds_userrefs);
	}
}
Пример #7
0
static void
dsl_destroy_snapshot_handle_remaps(dsl_dataset_t *ds, dsl_dataset_t *ds_next,
    dmu_tx_t *tx)
{
	dsl_pool_t *dp = ds->ds_dir->dd_pool;

	/* Move blocks to be obsoleted to pool's obsolete list. */
	if (dsl_dataset_remap_deadlist_exists(ds_next)) {
		if (!bpobj_is_open(&dp->dp_obsolete_bpobj))
			dsl_pool_create_obsolete_bpobj(dp, tx);

		dsl_deadlist_move_bpobj(&ds_next->ds_remap_deadlist,
		    &dp->dp_obsolete_bpobj,
		    dsl_dataset_phys(ds)->ds_prev_snap_txg, tx);
	}

	/* Merge our deadlist into next's and free it. */
	if (dsl_dataset_remap_deadlist_exists(ds)) {
		uint64_t remap_deadlist_object =
		    dsl_dataset_get_remap_deadlist_object(ds);
		ASSERT(remap_deadlist_object != 0);

		mutex_enter(&ds_next->ds_remap_deadlist_lock);
		if (!dsl_dataset_remap_deadlist_exists(ds_next))
			dsl_dataset_create_remap_deadlist(ds_next, tx);
		mutex_exit(&ds_next->ds_remap_deadlist_lock);

		dsl_deadlist_merge(&ds_next->ds_remap_deadlist,
		    remap_deadlist_object, tx);
		dsl_dataset_destroy_remap_deadlist(ds, tx);
	}
}
Пример #8
0
int
dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer)
{
	if (!ds->ds_is_snapshot)
		return (SET_ERROR(EINVAL));

	if (dsl_dataset_long_held(ds))
		return (SET_ERROR(EBUSY));

	/*
	 * Only allow deferred destroy on pools that support it.
	 * NOTE: deferred destroy is only supported on snapshots.
	 */
	if (defer) {
		if (spa_version(ds->ds_dir->dd_pool->dp_spa) <
		    SPA_VERSION_USERREFS)
			return (SET_ERROR(ENOTSUP));
		return (0);
	}

	/*
	 * If this snapshot has an elevated user reference count,
	 * we can't destroy it yet.
	 */
	if (ds->ds_userrefs > 0)
		return (SET_ERROR(EBUSY));

	/*
	 * Can't delete a branch point.
	 */
	if (dsl_dataset_phys(ds)->ds_num_children > 1)
		return (SET_ERROR(EEXIST));

	return (0);
}
Пример #9
0
static void
dsl_dataset_user_release_sync(void *arg, dmu_tx_t *tx)
{
	dsl_dataset_user_release_arg_t *ddura = arg;
	dsl_holdfunc_t *holdfunc = ddura->ddura_holdfunc;
	dsl_pool_t *dp = dmu_tx_pool(tx);

	ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));

	for (nvpair_t *pair = nvlist_next_nvpair(ddura->ddura_chkholds, NULL);
	    pair != NULL; pair = nvlist_next_nvpair(ddura->ddura_chkholds,
	    pair)) {
		dsl_dataset_t *ds;
		const char *name = nvpair_name(pair);

		VERIFY0(holdfunc(dp, name, FTAG, &ds));

		dsl_dataset_user_release_sync_one(ds,
		    fnvpair_value_nvlist(pair), tx);
		if (nvlist_exists(ddura->ddura_todelete, name)) {
			ASSERT(ds->ds_userrefs == 0 &&
			    dsl_dataset_phys(ds)->ds_num_children == 1 &&
			    DS_IS_DEFER_DESTROY(ds));
			dsl_destroy_snapshot_sync_impl(ds, B_FALSE, tx);
		}
		dsl_dataset_rele(ds, FTAG);
	}
}
Пример #10
0
/*
 * Returns ESRCH if bookmark is not found.
 */
static int
dsl_dataset_bmark_lookup(dsl_dataset_t *ds, const char *shortname,
    zfs_bookmark_phys_t *bmark_phys)
{
	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
	uint64_t bmark_zapobj = ds->ds_bookmarks;
	matchtype_t mt = 0;
	int err;

	if (bmark_zapobj == 0)
		return (SET_ERROR(ESRCH));

	if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
		mt = MT_NORMALIZE;

	/*
	 * Zero out the bookmark in case the one stored on disk
	 * is in an older, shorter format.
	 */
	bzero(bmark_phys, sizeof (*bmark_phys));

	err = zap_lookup_norm(mos, bmark_zapobj, shortname, sizeof (uint64_t),
	    sizeof (*bmark_phys) / sizeof (uint64_t), bmark_phys, mt,
	    NULL, 0, NULL);

	return (err == ENOENT ? ESRCH : err);
}
Пример #11
0
int
dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
    int intsz, int numints, void *buf, char *setpoint)
{
	zfs_prop_t prop = zfs_name_to_prop(propname);
	boolean_t inheritable;
	uint64_t zapobj;

	ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
	inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
	zapobj = dsl_dataset_phys(ds)->ds_props_obj;

	if (zapobj != 0) {
		objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
		int err;

		ASSERT(ds->ds_is_snapshot);

		/* Check for a local value. */
		err = zap_lookup(mos, zapobj, propname, intsz, numints, buf);
		if (err != ENOENT) {
			if (setpoint != NULL && err == 0)
				dsl_dataset_name(ds, setpoint);
			return (err);
		}

		/*
		 * Skip the check for a received value if there is an explicit
		 * inheritance entry.
		 */
		if (inheritable) {
			char *inheritstr = kmem_asprintf("%s%s", propname,
			    ZPROP_INHERIT_SUFFIX);
			err = zap_contains(mos, zapobj, inheritstr);
			strfree(inheritstr);
			if (err != 0 && err != ENOENT)
				return (err);
		}

		if (err == ENOENT) {
			/* Check for a received value. */
			char *recvdstr = kmem_asprintf("%s%s", propname,
			    ZPROP_RECVD_SUFFIX);
			err = zap_lookup(mos, zapobj, recvdstr,
			    intsz, numints, buf);
			strfree(recvdstr);
			if (err != ENOENT) {
				if (setpoint != NULL && err == 0)
					(void) strcpy(setpoint,
					    ZPROP_SOURCE_VAL_RECVD);
				return (err);
			}
		}
	}

	return (dsl_prop_get_dd(ds->ds_dir, propname,
	    intsz, numints, buf, setpoint, ds->ds_is_snapshot));
}
Пример #12
0
static int
dsl_dataset_bookmark_remove(dsl_dataset_t *ds, const char *name, dmu_tx_t *tx)
{
	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
	uint64_t bmark_zapobj = ds->ds_bookmarks;
	matchtype_t mt;

	if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
		mt = MT_FIRST;
	else
		mt = MT_EXACT;

	return (zap_remove_norm(mos, bmark_zapobj, name, mt, tx));
}
Пример #13
0
static int
process_old_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
{
	struct process_old_arg *poa = arg;
	dsl_pool_t *dp = poa->ds->ds_dir->dd_pool;

	ASSERT(!BP_IS_HOLE(bp));

	if (bp->blk_birth <= dsl_dataset_phys(poa->ds)->ds_prev_snap_txg) {
		dsl_deadlist_insert(&poa->ds->ds_deadlist, bp, tx);
		if (poa->ds_prev && !poa->after_branch_point &&
		    bp->blk_birth >
		    dsl_dataset_phys(poa->ds_prev)->ds_prev_snap_txg) {
			dsl_dataset_phys(poa->ds_prev)->ds_unique_bytes +=
			    bp_get_dsize_sync(dp->dp_spa, bp);
		}
	} else {
		poa->used += bp_get_dsize_sync(dp->dp_spa, bp);
		poa->comp += BP_GET_PSIZE(bp);
		poa->uncomp += BP_GET_UCSIZE(bp);
		dsl_free_sync(poa->pio, dp, tx->tx_txg, bp);
	}
	return (0);
}
Пример #14
0
static void
dsl_keychain_clone_phys(dsl_dataset_t *src, dsl_dir_t *dd,
                        dmu_tx_t *tx, zcrypt_key_t *dwkey)
{
    objset_t *mos = dd->dd_pool->dp_meta_objset;
    uint64_t keychain = dsl_dir_phys(dd)->dd_keychain_obj;
    caddr_t wrappedkey = NULL;
    size_t wkeylen = 0;
    zcrypt_keystore_node_t *kn;
    zcrypt_keychain_node_t *n;
    uint64_t newest_txg = dsl_dataset_phys(src)->ds_creation_txg;

    kn = zcrypt_keystore_find_node(dsl_dataset_get_spa(src),
                                   src->ds_object, B_FALSE);
    if (kn == NULL) {
        kn = zcrypt_keystore_find_node(dsl_dataset_get_spa(src),
                                       dsl_dir_phys(src->ds_dir)->dd_head_dataset_obj, B_FALSE);
    }
    ASSERT(kn != NULL);
    ASSERT(dwkey != NULL);

    /*
     * Walk the in memory AVL tree representation of the keychain
     * creating new keychain entries using our wrappingkey, stopping
     * when we reach keychain entries created after the snapshot we
     * are cloning from.
     */
    mutex_enter(&kn->skn_lock);
    for (n = avl_first(&kn->skn_keychain);
            n != NULL && n->dkn_txg <= newest_txg;
            n = AVL_NEXT(&kn->skn_keychain, n)) {
        VERIFY(zcrypt_wrap_key(dwkey, n->dkn_key, &wrappedkey,
                               &wkeylen, zio_crypt_select_wrap(dwkey->zk_crypt)) == 0);
        VERIFY(zap_update_uint64(mos, keychain, &n->dkn_txg,
                                 1, 1, wkeylen, wrappedkey, tx) == 0);
        kmem_free(wrappedkey, wkeylen);
    }
    mutex_exit(&kn->skn_lock);
}
Пример #15
0
/*
 * Returns ESRCH if bookmark is not found.
 */
static int
dsl_dataset_bmark_lookup(dsl_dataset_t *ds, const char *shortname,
    zfs_bookmark_phys_t *bmark_phys)
{
	objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
	uint64_t bmark_zapobj = ds->ds_bookmarks;
	matchtype_t mt;
	int err;

	if (bmark_zapobj == 0)
		return (SET_ERROR(ESRCH));

	if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
		mt = MT_FIRST;
	else
		mt = MT_EXACT;

	err = zap_lookup_norm(mos, bmark_zapobj, shortname, sizeof (uint64_t),
	    sizeof (*bmark_phys) / sizeof (uint64_t), bmark_phys, mt,
	    NULL, 0, NULL);

	return (err == ENOENT ? ESRCH : err);
}
Пример #16
0
static void
process_old_deadlist(dsl_dataset_t *ds, dsl_dataset_t *ds_prev,
    dsl_dataset_t *ds_next, boolean_t after_branch_point, dmu_tx_t *tx)
{
	struct process_old_arg poa = { 0 };
	dsl_pool_t *dp = ds->ds_dir->dd_pool;
	objset_t *mos = dp->dp_meta_objset;
	uint64_t deadlist_obj;

	ASSERT(ds->ds_deadlist.dl_oldfmt);
	ASSERT(ds_next->ds_deadlist.dl_oldfmt);

	poa.ds = ds;
	poa.ds_prev = ds_prev;
	poa.after_branch_point = after_branch_point;
	poa.pio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED);
	VERIFY0(bpobj_iterate(&ds_next->ds_deadlist.dl_bpobj,
	    process_old_cb, &poa, tx));
	VERIFY0(zio_wait(poa.pio));
	ASSERT3U(poa.used, ==, dsl_dataset_phys(ds)->ds_unique_bytes);

	/* change snapused */
	dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP,
	    -poa.used, -poa.comp, -poa.uncomp, tx);

	/* swap next's deadlist to our deadlist */
	dsl_deadlist_close(&ds->ds_deadlist);
	dsl_deadlist_close(&ds_next->ds_deadlist);
	deadlist_obj = dsl_dataset_phys(ds)->ds_deadlist_obj;
	dsl_dataset_phys(ds)->ds_deadlist_obj =
	    dsl_dataset_phys(ds_next)->ds_deadlist_obj;
	dsl_dataset_phys(ds_next)->ds_deadlist_obj = deadlist_obj;
	dsl_deadlist_open(&ds->ds_deadlist, mos,
	    dsl_dataset_phys(ds)->ds_deadlist_obj);
	dsl_deadlist_open(&ds_next->ds_deadlist, mos,
	    dsl_dataset_phys(ds_next)->ds_deadlist_obj);
}
Пример #17
0
void
dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
{
#ifdef ZFS_DEBUG
	int err;
#endif
	spa_feature_t f;
	int after_branch_point = FALSE;
	dsl_pool_t *dp = ds->ds_dir->dd_pool;
	objset_t *mos = dp->dp_meta_objset;
	dsl_dataset_t *ds_prev = NULL;
	uint64_t obj, old_unique, used = 0, comp = 0, uncomp = 0;
	dsl_dataset_t *ds_next, *ds_head, *hds;


	ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
	ASSERT3U(dsl_dataset_phys(ds)->ds_bp.blk_birth, <=, tx->tx_txg);
	ASSERT(refcount_is_zero(&ds->ds_longholds));

	if (defer &&
	    (ds->ds_userrefs > 0 ||
	    dsl_dataset_phys(ds)->ds_num_children > 1)) {
		ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS);
		dmu_buf_will_dirty(ds->ds_dbuf, tx);
		dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_DEFER_DESTROY;
		spa_history_log_internal_ds(ds, "defer_destroy", tx, "");
		return;
	}

	ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1);

	/* We need to log before removing it from the namespace. */
	spa_history_log_internal_ds(ds, "destroy", tx, "");

	dsl_scan_ds_destroyed(ds, tx);

	obj = ds->ds_object;

	for (f = 0; f < SPA_FEATURES; f++) {
		if (ds->ds_feature_inuse[f]) {
			dsl_dataset_deactivate_feature(obj, f, tx);
			ds->ds_feature_inuse[f] = B_FALSE;
		}
	}
	if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
		ASSERT3P(ds->ds_prev, ==, NULL);
		VERIFY0(dsl_dataset_hold_obj(dp,
		    dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &ds_prev));
		after_branch_point =
		    (dsl_dataset_phys(ds_prev)->ds_next_snap_obj != obj);

		dmu_buf_will_dirty(ds_prev->ds_dbuf, tx);
		if (after_branch_point &&
		    dsl_dataset_phys(ds_prev)->ds_next_clones_obj != 0) {
			dsl_dataset_remove_from_next_clones(ds_prev, obj, tx);
			if (dsl_dataset_phys(ds)->ds_next_snap_obj != 0) {
				VERIFY0(zap_add_int(mos,
				    dsl_dataset_phys(ds_prev)->
				    ds_next_clones_obj,
				    dsl_dataset_phys(ds)->ds_next_snap_obj,
				    tx));
			}
		}
		if (!after_branch_point) {
			dsl_dataset_phys(ds_prev)->ds_next_snap_obj =
			    dsl_dataset_phys(ds)->ds_next_snap_obj;
		}
	}
Пример #18
0
			if (dsl_dataset_phys(ds)->ds_next_snap_obj != 0) {
				VERIFY0(zap_add_int(mos,
				    dsl_dataset_phys(ds_prev)->
				    ds_next_clones_obj,
				    dsl_dataset_phys(ds)->ds_next_snap_obj,
				    tx));
			}
		}
		if (!after_branch_point) {
			dsl_dataset_phys(ds_prev)->ds_next_snap_obj =
			    dsl_dataset_phys(ds)->ds_next_snap_obj;
		}
	}

	VERIFY0(dsl_dataset_hold_obj(dp,
	    dsl_dataset_phys(ds)->ds_next_snap_obj, FTAG, &ds_next));
	ASSERT3U(dsl_dataset_phys(ds_next)->ds_prev_snap_obj, ==, obj);

	old_unique = dsl_dataset_phys(ds_next)->ds_unique_bytes;

	dmu_buf_will_dirty(ds_next->ds_dbuf, tx);
	dsl_dataset_phys(ds_next)->ds_prev_snap_obj =
	    dsl_dataset_phys(ds)->ds_prev_snap_obj;
	dsl_dataset_phys(ds_next)->ds_prev_snap_txg =
	    dsl_dataset_phys(ds)->ds_prev_snap_txg;
	ASSERT3U(dsl_dataset_phys(ds)->ds_prev_snap_txg, ==,
	    ds_prev ? dsl_dataset_phys(ds_prev)->ds_creation_txg : 0);

	if (ds_next->ds_deadlist.dl_oldfmt) {
		process_old_deadlist(ds, ds_prev, ds_next,
		    after_branch_point, tx);
Пример #19
0
void
dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
{
	int err;
	int after_branch_point = FALSE;
	dsl_pool_t *dp = ds->ds_dir->dd_pool;
	objset_t *mos = dp->dp_meta_objset;
	dsl_dataset_t *ds_prev = NULL;
	uint64_t obj;

	ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
	ASSERT3U(dsl_dataset_phys(ds)->ds_bp.blk_birth, <=, tx->tx_txg);
	ASSERT(refcount_is_zero(&ds->ds_longholds));

	if (defer &&
	    (ds->ds_userrefs > 0 ||
	    dsl_dataset_phys(ds)->ds_num_children > 1)) {
		ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS);
		dmu_buf_will_dirty(ds->ds_dbuf, tx);
		dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_DEFER_DESTROY;
		spa_history_log_internal_ds(ds, "defer_destroy", tx, "");
		return;
	}

	ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1);

	/* We need to log before removing it from the namespace. */
	spa_history_log_internal_ds(ds, "destroy", tx, "");

	dsl_scan_ds_destroyed(ds, tx);

	obj = ds->ds_object;

	if (ds->ds_large_blocks) {
		ASSERT0(zap_contains(mos, obj, DS_FIELD_LARGE_BLOCKS));
		spa_feature_decr(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS, tx);
	}
	if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
		ASSERT3P(ds->ds_prev, ==, NULL);
		VERIFY0(dsl_dataset_hold_obj(dp,
		    dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &ds_prev));
		after_branch_point =
		    (dsl_dataset_phys(ds_prev)->ds_next_snap_obj != obj);

		dmu_buf_will_dirty(ds_prev->ds_dbuf, tx);
		if (after_branch_point &&
		    dsl_dataset_phys(ds_prev)->ds_next_clones_obj != 0) {
			dsl_dataset_remove_from_next_clones(ds_prev, obj, tx);
			if (dsl_dataset_phys(ds)->ds_next_snap_obj != 0) {
				VERIFY0(zap_add_int(mos,
				    dsl_dataset_phys(ds_prev)->
				    ds_next_clones_obj,
				    dsl_dataset_phys(ds)->ds_next_snap_obj,
				    tx));
			}
		}
		if (!after_branch_point) {
			dsl_dataset_phys(ds_prev)->ds_next_snap_obj =
			    dsl_dataset_phys(ds)->ds_next_snap_obj;
		}
	}
Пример #20
0
int
dsl_pool_open(dsl_pool_t *dp)
{
	int err;
	dsl_dir_t *dd;
	dsl_dataset_t *ds;
	uint64_t obj;

	rrw_enter(&dp->dp_config_rwlock, RW_WRITER, FTAG);
	err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
	    DMU_POOL_ROOT_DATASET, sizeof (uint64_t), 1,
	    &dp->dp_root_dir_obj);
	if (err)
		goto out;

	err = dsl_dir_hold_obj(dp, dp->dp_root_dir_obj,
	    NULL, dp, &dp->dp_root_dir);
	if (err)
		goto out;

	err = dsl_pool_open_special_dir(dp, MOS_DIR_NAME, &dp->dp_mos_dir);
	if (err)
		goto out;

	if (spa_version(dp->dp_spa) >= SPA_VERSION_ORIGIN) {
		err = dsl_pool_open_special_dir(dp, ORIGIN_DIR_NAME, &dd);
		if (err)
			goto out;
		err = dsl_dataset_hold_obj(dp,
		    dsl_dir_phys(dd)->dd_head_dataset_obj, FTAG, &ds);
		if (err == 0) {
			err = dsl_dataset_hold_obj(dp,
			    dsl_dataset_phys(ds)->ds_prev_snap_obj, dp,
			    &dp->dp_origin_snap);
			dsl_dataset_rele(ds, FTAG);
		}
		dsl_dir_rele(dd, dp);
		if (err)
			goto out;
	}

	if (spa_version(dp->dp_spa) >= SPA_VERSION_DEADLISTS) {
		err = dsl_pool_open_special_dir(dp, FREE_DIR_NAME,
		    &dp->dp_free_dir);
		if (err)
			goto out;

		err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
		    DMU_POOL_FREE_BPOBJ, sizeof (uint64_t), 1, &obj);
		if (err)
			goto out;
		VERIFY0(bpobj_open(&dp->dp_free_bpobj,
		    dp->dp_meta_objset, obj));
	}

	if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_OBSOLETE_COUNTS)) {
		err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
		    DMU_POOL_OBSOLETE_BPOBJ, sizeof (uint64_t), 1, &obj);
		if (err == 0) {
			VERIFY0(bpobj_open(&dp->dp_obsolete_bpobj,
			    dp->dp_meta_objset, obj));
		} else if (err == ENOENT) {
			/*
			 * We might not have created the remap bpobj yet.
			 */
			err = 0;
		} else {
			goto out;
		}
	}

	/*
	 * Note: errors ignored, because the these special dirs, used for
	 * space accounting, are only created on demand.
	 */
	(void) dsl_pool_open_special_dir(dp, LEAK_DIR_NAME,
	    &dp->dp_leak_dir);

	if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY)) {
		err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
		    DMU_POOL_BPTREE_OBJ, sizeof (uint64_t), 1,
		    &dp->dp_bptree_obj);
		if (err != 0)
			goto out;
	}

	if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_EMPTY_BPOBJ)) {
		err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
		    DMU_POOL_EMPTY_BPOBJ, sizeof (uint64_t), 1,
		    &dp->dp_empty_bpobj);
		if (err != 0)
			goto out;
	}

	err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
	    DMU_POOL_TMP_USERREFS, sizeof (uint64_t), 1,
	    &dp->dp_tmp_userrefs_obj);
	if (err == ENOENT)
		err = 0;
	if (err)
		goto out;

	err = dsl_scan_init(dp, dp->dp_tx.tx_open_txg);

out:
	rrw_exit(&dp->dp_config_rwlock, FTAG);
	return (err);
}
Пример #21
0
static int
dsl_dataset_user_release_check_one(dsl_dataset_user_release_arg_t *ddura,
    dsl_dataset_t *ds, nvlist_t *holds, const char *snapname)
{
	uint64_t zapobj;
	nvlist_t *holds_found;
	objset_t *mos;
	int numholds;

	if (!dsl_dataset_is_snapshot(ds))
		return (SET_ERROR(EINVAL));

	if (nvlist_empty(holds))
		return (0);

	numholds = 0;
	mos = ds->ds_dir->dd_pool->dp_meta_objset;
	zapobj = dsl_dataset_phys(ds)->ds_userrefs_obj;
	holds_found = fnvlist_alloc();

	for (nvpair_t *pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
	    pair = nvlist_next_nvpair(holds, pair)) {
		uint64_t tmp;
		int error;
		const char *holdname = nvpair_name(pair);

		if (zapobj != 0)
			error = zap_lookup(mos, zapobj, holdname, 8, 1, &tmp);
		else
			error = SET_ERROR(ENOENT);

		/*
		 * Non-existent holds are put on the errlist, but don't
		 * cause an overall failure.
		 */
		if (error == ENOENT) {
			if (ddura->ddura_errlist != NULL) {
				char *errtag = kmem_asprintf("%s#%s",
				    snapname, holdname);
				fnvlist_add_int32(ddura->ddura_errlist, errtag,
				    ENOENT);
				strfree(errtag);
			}
			continue;
		}

		if (error != 0) {
			fnvlist_free(holds_found);
			return (error);
		}

		fnvlist_add_boolean(holds_found, holdname);
		numholds++;
	}

	if (DS_IS_DEFER_DESTROY(ds) &&
	    dsl_dataset_phys(ds)->ds_num_children == 1 &&
	    ds->ds_userrefs == numholds) {
		/* we need to destroy the snapshot as well */
		if (dsl_dataset_long_held(ds)) {
			fnvlist_free(holds_found);
			return (SET_ERROR(EBUSY));
		}
		fnvlist_add_boolean(ddura->ddura_todelete, snapname);
	}

	if (numholds != 0) {
		fnvlist_add_nvlist(ddura->ddura_chkholds, snapname,
		    holds_found);
	}
	fnvlist_free(holds_found);

	return (0);
}
Пример #22
0
static void
dsl_bookmark_create_sync(void *arg, dmu_tx_t *tx)
{
	dsl_bookmark_create_arg_t *dbca = arg;
	dsl_pool_t *dp = dmu_tx_pool(tx);
	objset_t *mos = dp->dp_meta_objset;
	nvpair_t *pair;

	ASSERT(spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_BOOKMARKS));

	for (pair = nvlist_next_nvpair(dbca->dbca_bmarks, NULL);
	    pair != NULL; pair = nvlist_next_nvpair(dbca->dbca_bmarks, pair)) {
		dsl_dataset_t *snapds, *bmark_fs;
		zfs_bookmark_phys_t bmark_phys = { 0 };
		char *shortname;
		uint32_t bmark_len = BOOKMARK_PHYS_SIZE_V1;

		VERIFY0(dsl_dataset_hold(dp, fnvpair_value_string(pair),
		    FTAG, &snapds));
		VERIFY0(dsl_bookmark_hold_ds(dp, nvpair_name(pair),
		    &bmark_fs, FTAG, &shortname));
		if (bmark_fs->ds_bookmarks == 0) {
			bmark_fs->ds_bookmarks =
			    zap_create_norm(mos, U8_TEXTPREP_TOUPPER,
			    DMU_OTN_ZAP_METADATA, DMU_OT_NONE, 0, tx);
			spa_feature_incr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx);

			dsl_dataset_zapify(bmark_fs, tx);
			VERIFY0(zap_add(mos, bmark_fs->ds_object,
			    DS_FIELD_BOOKMARK_NAMES,
			    sizeof (bmark_fs->ds_bookmarks), 1,
			    &bmark_fs->ds_bookmarks, tx));
		}

		bmark_phys.zbm_guid = dsl_dataset_phys(snapds)->ds_guid;
		bmark_phys.zbm_creation_txg =
		    dsl_dataset_phys(snapds)->ds_creation_txg;
		bmark_phys.zbm_creation_time =
		    dsl_dataset_phys(snapds)->ds_creation_time;

		/*
		 * If the dataset is encrypted create a larger bookmark to
		 * accommodate the IVset guid. The IVset guid was added
		 * after the encryption feature to prevent a problem with
		 * raw sends. If we encounter an encrypted dataset without
		 * an IVset guid we fall back to a normal bookmark.
		 */
		if (snapds->ds_dir->dd_crypto_obj != 0 &&
		    spa_feature_is_enabled(dp->dp_spa,
		    SPA_FEATURE_BOOKMARK_V2)) {
			int err = zap_lookup(mos, snapds->ds_object,
			    DS_FIELD_IVSET_GUID, sizeof (uint64_t), 1,
			    &bmark_phys.zbm_ivset_guid);
			if (err == 0) {
				bmark_len = BOOKMARK_PHYS_SIZE_V2;
				spa_feature_incr(dp->dp_spa,
				    SPA_FEATURE_BOOKMARK_V2, tx);
			}
		}

		VERIFY0(zap_add(mos, bmark_fs->ds_bookmarks,
		    shortname, sizeof (uint64_t),
		    bmark_len / sizeof (uint64_t), &bmark_phys, tx));

		spa_history_log_internal_ds(bmark_fs, "bookmark", tx,
		    "name=%s creation_txg=%llu target_snap=%llu",
		    shortname,
		    (longlong_t)bmark_phys.zbm_creation_txg,
		    (longlong_t)snapds->ds_object);

		dsl_dataset_rele(bmark_fs, FTAG);
		dsl_dataset_rele(snapds, FTAG);
	}
}