Example #1
0
/* ARGSUSED */
static int
dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
{
	dsl_dir_t *dd = ds->ds_dir;
	dsl_prop_record_t *pr;
	dsl_prop_cb_record_t *cbr;

	mutex_enter(&dd->dd_lock);
	for (pr = list_head(&dd->dd_props);
	    pr; pr = list_next(&dd->dd_props, pr)) {
		for (cbr = list_head(&pr->pr_cbs); cbr;
		    cbr = list_next(&pr->pr_cbs, cbr)) {
			uint64_t value;

			/*
			 * Callback entries do not have holds on their
			 * datasets so that datasets with registered
			 * callbacks are still eligible for eviction.
			 * Unlike operations to update properties on a
			 * single dataset, we are performing a recursive
			 * descent of related head datasets.  The caller
			 * of this function only has a dataset hold on
			 * the passed in head dataset, not the snapshots
			 * associated with this dataset.  Without a hold,
			 * the dataset pointer within callback records
			 * for snapshots can be invalidated by eviction
			 * at any time.
			 *
			 * Use dsl_dataset_try_add_ref() to verify
			 * that the dataset for a snapshot has not
			 * begun eviction processing and to prevent
			 * eviction from occurring for the duration of
			 * the callback.  If the hold attempt fails,
			 * this object is already being evicted and the
			 * callback can be safely ignored.
			 */
			if (ds != cbr->cbr_ds &&
			    !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
				continue;

			if (dsl_prop_get_ds(cbr->cbr_ds,
			    cbr->cbr_pr->pr_propname, sizeof (value), 1,
			    &value, NULL) == 0)
				cbr->cbr_func(cbr->cbr_arg, value);

			if (ds != cbr->cbr_ds)
				dsl_dataset_rele(cbr->cbr_ds, FTAG);
		}
	}
	mutex_exit(&dd->dd_lock);

	return (0);
}
Example #2
0
int
dsl_prop_get(const char *dsname, const char *propname,
    int intsz, int numints, void *buf, char *setpoint)
{
	objset_t *os;
	int error;

	error = dmu_objset_hold(dsname, FTAG, &os);
	if (error != 0)
		return (error);

	error = dsl_prop_get_ds(dmu_objset_ds(os), propname,
	    intsz, numints, buf, setpoint);

	dmu_objset_rele(os, FTAG);
	return (error);
}
Example #3
0
int
dsl_prop_get(const char *dsname, const char *propname,
    int intsz, int numints, void *buf, char *setpoint)
{
	dsl_dataset_t *ds;
	int err;

	err = dsl_dataset_hold(dsname, FTAG, &ds);
	if (err)
		return (err);

	rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
	err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint);
	rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);

	dsl_dataset_rele(ds, FTAG);
	return (err);
}
Example #4
0
/* ARGSUSED */
static int
dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
{
	dsl_dir_t *dd = ds->ds_dir;
	dsl_prop_cb_record_t *cbr;

	mutex_enter(&dd->dd_lock);
	for (cbr = list_head(&dd->dd_prop_cbs); cbr;
	    cbr = list_next(&dd->dd_prop_cbs, cbr)) {
		uint64_t value;

		if (dsl_prop_get_ds(cbr->cbr_ds, cbr->cbr_propname,
		    sizeof (value), 1, &value, NULL) == 0)
			cbr->cbr_func(cbr->cbr_arg, value);
	}
	mutex_exit(&dd->dd_lock);

	return (0);
}
Example #5
0
/* ARGSUSED */
static int
dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
{
	dsl_dir_t *dd = ds->ds_dir;
	dsl_prop_cb_record_t *cbr;

	mutex_enter(&dd->dd_lock);
	for (cbr = list_head(&dd->dd_prop_cbs); cbr;
	    cbr = list_next(&dd->dd_prop_cbs, cbr)) {
		uint64_t value;

		/*
		 * Callback entries do not have holds on their datasets
		 * so that datasets with registered callbacks are still
		 * eligible for eviction.  Unlike operations on callbacks
		 * for a single dataset, we are performing a recursive
		 * descent of related datasets and the calling context
		 * for this iteration only has a dataset hold on the root.
		 * Without a hold, the callback's pointer to the dataset
		 * could be invalidated by eviction at any time.
		 *
		 * Use dsl_dataset_try_add_ref() to verify that the
		 * dataset has not begun eviction processing and to
		 * prevent eviction from occurring for the duration
		 * of the callback.  If the hold attempt fails, this
		 * object is already being evicted and the callback can
		 * be safely ignored.
		 */
		if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
			continue;

		if (dsl_prop_get_ds(cbr->cbr_ds, cbr->cbr_propname,
		    sizeof (value), 1, &value, NULL) == 0)
			cbr->cbr_func(cbr->cbr_arg, value);

		dsl_dataset_rele(cbr->cbr_ds, FTAG);
	}
	mutex_exit(&dd->dd_lock);

	return (0);
}
/*
 * Register interest in the named property.  We'll call the callback
 * once to notify it of the current property value, and again each time
 * the property changes, until this callback is unregistered.
 *
 * Return 0 on success, errno if the prop is not an integer value.
 */
int
dsl_prop_register(dsl_dataset_t *ds, const char *propname,
    dsl_prop_changed_cb_t *callback, void *cbarg)
{
	dsl_dir_t *dd = ds->ds_dir;
	dsl_pool_t *dp = dd->dd_pool;
	uint64_t value;
	dsl_prop_cb_record_t *cbr;
	int err;
	int need_rwlock;

	need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock);
	if (need_rwlock)
		rw_enter(&dp->dp_config_rwlock, RW_READER);

	err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL);
	if (err != 0) {
		if (need_rwlock)
			rw_exit(&dp->dp_config_rwlock);
		return (err);
	}

	cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
	cbr->cbr_ds = ds;
	cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP);
	(void) strcpy((char *)cbr->cbr_propname, propname);
	cbr->cbr_func = callback;
	cbr->cbr_arg = cbarg;
	mutex_enter(&dd->dd_lock);
	list_insert_head(&dd->dd_prop_cbs, cbr);
	mutex_exit(&dd->dd_lock);

	cbr->cbr_func(cbr->cbr_arg, value);

	VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object,
	    NULL, cbr, &dd));
	if (need_rwlock)
		rw_exit(&dp->dp_config_rwlock);
	/* Leave dir open until this callback is unregistered */
	return (0);
}
Example #7
0
/*
 * Register interest in the named property.  We'll call the callback
 * once to notify it of the current property value, and again each time
 * the property changes, until this callback is unregistered.
 *
 * Return 0 on success, errno if the prop is not an integer value.
 */
int
dsl_prop_register(dsl_dataset_t *ds, const char *propname,
    dsl_prop_changed_cb_t *callback, void *cbarg)
{
	dsl_dir_t *dd = ds->ds_dir;
	dsl_pool_t *dp = dd->dd_pool;
	uint64_t value;
	dsl_prop_cb_record_t *cbr;
	int err;
	int need_rwlock;

	need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock);
	if (need_rwlock)
		rw_enter(&dp->dp_config_rwlock, RW_READER);

	err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL);
	if (err != 0) {
		if (need_rwlock)
			rw_exit(&dp->dp_config_rwlock);
		return (err);
	}

	cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_PUSHPAGE);
	cbr->cbr_ds = ds;
	cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_PUSHPAGE);
	(void) strlcpy((char *)cbr->cbr_propname, propname, MAXNAMELEN);
	cbr->cbr_func = callback;
	cbr->cbr_arg = cbarg;
	mutex_enter(&dd->dd_lock);
	list_insert_head(&dd->dd_prop_cbs, cbr);
	mutex_exit(&dd->dd_lock);

	cbr->cbr_func(cbr->cbr_arg, value);

	if (need_rwlock)
		rw_exit(&dp->dp_config_rwlock);
	return (0);
}
Example #8
0
int
dsl_prop_get_int_ds(dsl_dataset_t *ds, const char *propname,
    uint64_t *valuep)
{
	return (dsl_prop_get_ds(ds, propname, 8, 1, valuep, NULL));
}
Example #9
0
static int
dsl_crypto_key_change_find(const char *dsname, void *arg)
{
    struct wkey_change_arg *ca = arg;
    struct kcnode *kcn;
    dsl_dataset_t *ds;
    objset_t *os;
    uint64_t crypt;
    char caource[MAXNAMELEN];
    char setpoint[MAXNAMELEN];
    int err;
    dsl_pool_t *dp;

    err = dsl_pool_hold(dsname, FTAG, &dp);
    if (err != 0)
        return (err);

    kcn = kmem_alloc(sizeof (struct kcnode), KM_SLEEP);
    if ((err = dsl_dataset_hold(dp, dsname, kcn, &ds)) != 0) {
        kmem_free(kcn, sizeof (struct kcnode));
        dsl_pool_rele(dp, FTAG);
        return (err);
    }

    if ((err = dmu_objset_from_ds(ds, &os)) != 0) {
        dsl_dataset_rele(ds, kcn);
        dsl_pool_rele(dp, FTAG);
        kmem_free(kcn, sizeof (struct kcnode));
        return (err);
    }

    /*
     * Check that this child dataset of ca->parent
     * is actually inheriting keysource from ca->parent and
     * not somewhere else (eg local, or some other dataset).
     */
    rrw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER, FTAG);
    VERIFY(dsl_prop_get_ds(ds, zfs_prop_to_name(ZFS_PROP_ENCRYPTION),
                           8, 1, &crypt, NULL/*, DSL_PROP_GET_EFFECTIVE*/) == 0);
    VERIFY(dsl_prop_get_ds(ds, zfs_prop_to_name(ZFS_PROP_KEYSOURCE), 1,
                           sizeof (caource), &caource, setpoint/*, DSL_PROP_GET_EFFECTIVE*/) == 0);
    rrw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock, FTAG);
    if (crypt == ZIO_CRYPT_OFF ||
            ((strcmp(ca->ca_parent, setpoint) != 0 &&
              strcmp(ca->ca_parent, dsname) != 0))) {
        dsl_dataset_rele(ds, kcn);
        dsl_pool_rele(dp, FTAG);
        kmem_free(kcn, sizeof (struct kcnode));
        return (0);
    }

    //dsl_sync_task_create(ca->ca_dstg, dsl_crypto_key_change_check,
    //  dsl_crypto_key_change_sync, ds, arg, 1);
    ca->ca_ds = ds;
    err = dsl_sync_task(dsname, dsl_crypto_key_change_check,
                        dsl_crypto_key_change_sync, arg,
                        1, ZFS_SPACE_CHECK_NONE);

    kcn->kc_ds = ds;
    list_insert_tail(&ca->ca_nodes, kcn);

    return (0);
}
Example #10
0
int
dsl_crypto_key_load(const char *dsname, zcrypt_key_t *wrappingkey)
{
    dsl_dataset_t *ds;
    uint64_t crypt;
    int error;
    dsl_pool_t *dp;

    error = dsl_pool_hold(dsname, FTAG, &dp);
    if (error != 0)
        return (error);

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

    /*
     * This is key load not key change so if ds->ds_key is already
     * set we fail.
     */
    if (zcrypt_keystore_find_node(dsl_dataset_get_spa(ds),
                                  ds->ds_object, B_FALSE) != NULL) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (EEXIST);
    }

    /*
     * Find out what size of key we expect.
     *
     * For now the wrapping key size (and type) matches the size
     * of the dataset key, this may not always be the case
     * (particularly if we ever support wrapping dataset keys
     * with asymmetric keys (eg RSA)).
     *
     * When alternate wrapping keys are added it maybe done using
     * a index property.
     */
    rrw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER, FTAG);
    error = dsl_prop_get_ds(ds, zfs_prop_to_name(ZFS_PROP_ENCRYPTION),
                            8, 1, &crypt, NULL/*, DSL_PROP_GET_EFFECTIVE*/);
    rrw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock, FTAG);
    if (error != 0) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    if (crypt == ZIO_CRYPT_OFF) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOTSUP);
    }

    ASSERT(crypt != ZIO_CRYPT_INHERIT);

    error = dsl_keychain_load(ds, crypt, wrappingkey);
    dsl_dataset_rele(ds, FTAG);
    dsl_pool_rele(dp, FTAG);
    return (error);
}
Example #11
0
/*
 * dsl_crypto_key_clone
 *
 * Our caller (dmu_objset_create_sync) must have a lock on the dataset.
 */
int
dsl_crypto_key_clone(dsl_dir_t *dd, dsl_dataset_phys_t *dsphys,
                     uint64_t dsobj, dsl_dataset_t *clone_origin,
                     dsl_crypto_ctx_t *ctx, dmu_tx_t *tx)
{
    zcrypt_key_t *txgkey;
    zcrypt_key_t *wrappingkey = NULL;
    dsl_dataset_t *origin;
    uint64_t crypt;
    spa_t *spa = dd->dd_pool->dp_spa;
    int error = 0;

    ASSERT(ctx != NULL);

    if (BP_IS_HOLE(&dsphys->ds_bp)) {
        origin = ctx->dcc_origin_ds;
    } else {
        origin = clone_origin;
    }
    ASSERT(origin != NULL);

    /*
     * Need to look at the value of crypt on the origin snapshot
     * since it is sticky for encryption.
     */
    VERIFY(dsl_prop_get_ds(origin, zfs_prop_to_name(ZFS_PROP_ENCRYPTION),
                           8, 1, &crypt,/* DSL_PROP_GET_EFFECTIVE,*/ NULL) == 0);

    if (crypt == ZIO_CRYPT_OFF) {
        return (0);
    }

    wrappingkey = ctx->dcc_wrap_key;

    dsl_keychain_create_obj(dd, tx);
    dsl_keychain_clone_phys(origin, dd, tx, wrappingkey);

    if (ctx->dcc_salt != 0) {
        objset_t *mos = dd->dd_pool->dp_meta_objset;
        uint64_t props_zapobj = dsl_dir_phys(dd)->dd_props_zapobj;

        error = zap_update(mos, props_zapobj,
                           zfs_prop_to_name(ZFS_PROP_SALT), 8, 1,
                           (void *)&ctx->dcc_salt, tx);
    }

    if (ctx->dcc_clone_newkey) {
        caddr_t wkeybuf;
        size_t wkeylen;
        /*
         * Generate a new key and add it to the keychain
         * to be valid from this txg onwards.
         */
        zcrypt_key_hold(wrappingkey, FTAG);
        txgkey = zcrypt_key_gen(crypt);
        VERIFY(zcrypt_wrap_key(wrappingkey, txgkey,
                               &wkeybuf, &wkeylen, zio_crypt_select_wrap(crypt)) == 0);
        zcrypt_key_release(wrappingkey, FTAG);
        dsl_keychain_set_key(dd, tx, wkeybuf, wkeylen,
                             dsphys->ds_creation_time);
        kmem_free(wkeybuf, wkeylen);
        zcrypt_key_free(txgkey);
        spa_history_log_internal(spa, "key create", tx,
                                 "rekey succeeded dataset = %llu from dataset = %llu",
                                 dsobj, clone_origin->ds_object);
    } else {
        spa_history_log_internal(spa, "key create", tx,
                                 "succeeded dataset = %llu from dataset = %llu",
                                 dsobj, clone_origin->ds_object);
    }

    if (wrappingkey != NULL) {
        error = dsl_keychain_load_dd(dd, dsobj, crypt, wrappingkey);
    }

    return (error);
}