Example #1
0
static int
dsl_bookmark_create_check_impl(dsl_dataset_t *snapds, const char *bookmark_name,
    dmu_tx_t *tx)
{
	dsl_pool_t *dp = dmu_tx_pool(tx);
	dsl_dataset_t *bmark_fs;
	char *shortname;
	int error;
	zfs_bookmark_phys_t bmark_phys;

	if (!snapds->ds_is_snapshot)
		return (SET_ERROR(EINVAL));

	error = dsl_bookmark_hold_ds(dp, bookmark_name,
	    &bmark_fs, FTAG, &shortname);
	if (error != 0)
		return (error);

	if (!dsl_dataset_is_before(bmark_fs, snapds, 0)) {
		dsl_dataset_rele(bmark_fs, FTAG);
		return (SET_ERROR(EINVAL));
	}

	error = dsl_dataset_bmark_lookup(bmark_fs, shortname,
	    &bmark_phys);
	dsl_dataset_rele(bmark_fs, FTAG);
	if (error == 0)
		return (SET_ERROR(EEXIST));
	if (error == ESRCH)
		return (0);
	return (error);
}
Example #2
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);
	}
}
Example #3
0
static int
dsl_bookmark_destroy_check(void *arg, dmu_tx_t *tx)
{
	dsl_bookmark_destroy_arg_t *dbda = arg;
	dsl_pool_t *dp = dmu_tx_pool(tx);
	int rv = 0;
	nvpair_t *pair;

	if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_BOOKMARKS))
		return (0);

	for (pair = nvlist_next_nvpair(dbda->dbda_bmarks, NULL);
	    pair != NULL; pair = nvlist_next_nvpair(dbda->dbda_bmarks, pair)) {
		const char *fullname = nvpair_name(pair);
		dsl_dataset_t *ds;
		zfs_bookmark_phys_t bm;
		int error;
		char *shortname;

		error = dsl_bookmark_hold_ds(dp, fullname, &ds,
		    FTAG, &shortname);
		if (error == ENOENT) {
			/* ignore it; the bookmark is "already destroyed" */
			continue;
		}
		if (error == 0) {
			error = dsl_dataset_bmark_lookup(ds, shortname, &bm);
			dsl_dataset_rele(ds, FTAG);
			if (error == ESRCH) {
				/*
				 * ignore it; the bookmark is
				 * "already destroyed"
				 */
				continue;
			}
		}
		if (error == 0) {
			fnvlist_add_boolean(dbda->dbda_success, fullname);
		} else {
			fnvlist_add_int32(dbda->dbda_errors, fullname, error);
			rv = error;
		}
	}
	return (rv);
}
Example #4
0
/*
 * If later_ds is non-NULL, this will return EXDEV if the the specified bookmark
 * does not represents an earlier point in later_ds's timeline.
 *
 * Returns ENOENT if the dataset containing the bookmark does not exist.
 * Returns ESRCH if the dataset exists but the bookmark was not found in it.
 */
int
dsl_bookmark_lookup(dsl_pool_t *dp, const char *fullname,
    dsl_dataset_t *later_ds, zfs_bookmark_phys_t *bmp)
{
	char *shortname;
	dsl_dataset_t *ds;
	int error;

	error = dsl_bookmark_hold_ds(dp, fullname, &ds, FTAG, &shortname);
	if (error != 0)
		return (error);

	error = dsl_dataset_bmark_lookup(ds, shortname, bmp);
	if (error == 0 && later_ds != NULL) {
		if (!dsl_dataset_is_before(later_ds, ds, bmp->zbm_creation_txg))
			error = SET_ERROR(EXDEV);
	}
	dsl_dataset_rele(ds, FTAG);
	return (error);
}
Example #5
0
static void
dsl_bookmark_destroy_sync(void *arg, dmu_tx_t *tx)
{
	dsl_bookmark_destroy_arg_t *dbda = arg;
	dsl_pool_t *dp = dmu_tx_pool(tx);
	objset_t *mos = dp->dp_meta_objset;
	nvpair_t *pair;

	for (pair = nvlist_next_nvpair(dbda->dbda_success, NULL);
	    pair != NULL; pair = nvlist_next_nvpair(dbda->dbda_success, pair)) {
		dsl_dataset_t *ds;
		char *shortname;
		uint64_t zap_cnt;

		VERIFY0(dsl_bookmark_hold_ds(dp, nvpair_name(pair),
		    &ds, FTAG, &shortname));
		VERIFY0(dsl_dataset_bookmark_remove(ds, shortname, tx));

		/*
		 * If all of this dataset's bookmarks have been destroyed,
		 * free the zap object and decrement the feature's use count.
		 */
		VERIFY0(zap_count(mos, ds->ds_bookmarks,
		    &zap_cnt));
		if (zap_cnt == 0) {
			dmu_buf_will_dirty(ds->ds_dbuf, tx);
			VERIFY0(zap_destroy(mos, ds->ds_bookmarks, tx));
			ds->ds_bookmarks = 0;
			spa_feature_decr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx);
			VERIFY0(zap_remove(mos, ds->ds_object,
			    DS_FIELD_BOOKMARK_NAMES, tx));
		}

		spa_history_log_internal_ds(ds, "remove bookmark", tx,
		    "name=%s", shortname);

		dsl_dataset_rele(ds, FTAG);
	}
}
Example #6
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);
	}
}