Beispiel #1
0
/*
 * dsl_pool must not be held when this is called.
 * Upon successful return, there will be a longhold on the dataset,
 * and the dsl_pool will not be held.
 */
int
dmu_objset_own(const char *name, dmu_objset_type_t type,
    boolean_t readonly, void *tag, objset_t **osp)
{
	dsl_pool_t *dp;
	dsl_dataset_t *ds;
	int err;

	err = dsl_pool_hold(name, FTAG, &dp);
	if (err != 0)
		return (err);
	err = dsl_dataset_own(dp, name, tag, &ds);
	if (err != 0) {
		dsl_pool_rele(dp, FTAG);
		return (err);
	}

	err = dmu_objset_from_ds(ds, osp);
	dsl_pool_rele(dp, FTAG);
	if (err != 0) {
		dsl_dataset_disown(ds, tag);
	} else if (type != DMU_OST_ANY && type != (*osp)->os_phys->os_type) {
		dsl_dataset_disown(ds, tag);
		return (SET_ERROR(EINVAL));
	} else if (!readonly && dsl_dataset_is_snapshot(ds)) {
		dsl_dataset_disown(ds, tag);
		return (SET_ERROR(EROFS));
	}
	return (err);
}
Beispiel #2
0
static int
zcp_props_list(lua_State *state)
{
	const char *dsname = lua_tostring(state, 1);
	dsl_pool_t *dp = zcp_run_info(state)->zri_pool;
	objset_t *os;
	nvlist_t **props = lua_newuserdata(state, sizeof (nvlist_t *));

	dsl_dataset_t *ds = zcp_dataset_hold(state, dp, dsname, FTAG);
	if (ds == NULL)
		return (1); /* not reached; zcp_dataset_hold() longjmp'd */
	VERIFY0(dmu_objset_from_ds(ds, &os));
	VERIFY0(dsl_prop_get_all(os, props));
	dsl_dataset_rele(ds, FTAG);

	/*
	 * Set the metatable for the properties list to free it on completion.
	 */
	luaL_getmetatable(state, zcp_props_list_info.name);
	(void) lua_setmetatable(state, -2);

	lua_pushlightuserdata(state, NULL);
	lua_pushcclosure(state, &zcp_props_iter, 2);
	return (1);
}
Beispiel #3
0
/* called from dsl for meta-objset */
objset_t *
dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
    dmu_objset_type_t type, dmu_tx_t *tx)
{
	objset_t *os;
	dnode_t *mdn;

	ASSERT(dmu_tx_is_syncing(tx));

	if (ds != NULL)
		VERIFY0(dmu_objset_from_ds(ds, &os));
	else
		VERIFY0(dmu_objset_open_impl(spa, NULL, bp, &os));

	mdn = DMU_META_DNODE(os);

	dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT,
	    DN_MAX_INDBLKSHIFT, DMU_OT_NONE, 0, tx);

	/*
	 * We don't want to have to increase the meta-dnode's nlevels
	 * later, because then we could do it in quescing context while
	 * we are also accessing it in open context.
	 *
	 * This precaution is not necessary for the MOS (ds == NULL),
	 * because the MOS is only updated in syncing context.
	 * This is most fortunate: the MOS is the only objset that
	 * needs to be synced multiple times as spa_sync() iterates
	 * to convergence, so minimizing its dn_nlevels matters.
	 */
	if (ds != NULL) {
		int levels = 1;

		/*
		 * Determine the number of levels necessary for the meta-dnode
		 * to contain DN_MAX_OBJECT dnodes.
		 */
		while ((uint64_t)mdn->dn_nblkptr << (mdn->dn_datablkshift +
		    (levels - 1) * (mdn->dn_indblkshift - SPA_BLKPTRSHIFT)) <
		    DN_MAX_OBJECT * sizeof (dnode_phys_t))
			levels++;

		mdn->dn_next_nlevels[tx->tx_txg & TXG_MASK] =
		    mdn->dn_nlevels = levels;
	}

	ASSERT(type != DMU_OST_NONE);
	ASSERT(type != DMU_OST_ANY);
	ASSERT(type < DMU_OST_NUMTYPES);
	os->os_phys->os_type = type;
	if (dmu_objset_userused_enabled(os)) {
		os->os_phys->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE;
		os->os_flags = os->os_phys->os_flags;
	}

	dsl_dataset_dirty(ds, tx);

	return (os);
}
/* called from zpl */
int
dmu_objset_hold(const char *name, void *tag, objset_t **osp)
{
	dsl_dataset_t *ds;
	int err;

	err = dsl_dataset_hold(name, tag, &ds);
	if (err)
		return (err);

	err = dmu_objset_from_ds(ds, osp);
	if (err)
		dsl_dataset_rele(ds, tag);

	return (err);
}
Beispiel #5
0
static int
zcp_children_iter(lua_State *state)
{
	int err;
	char childname[ZFS_MAX_DATASET_NAME_LEN];
	uint64_t dsobj = lua_tonumber(state, lua_upvalueindex(1));
	uint64_t cursor = lua_tonumber(state, lua_upvalueindex(2));
	zcp_run_info_t *ri = zcp_run_info(state);
	dsl_pool_t *dp = ri->zri_pool;
	dsl_dataset_t *ds;
	objset_t *os;
	char *p;

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

	dsl_dataset_name(ds, childname);
	VERIFY3U(sizeof (childname), >,
	    strlcat(childname, "/", sizeof (childname)));
	p = strchr(childname, '\0');

	VERIFY0(dmu_objset_from_ds(ds, &os));
	do {
		err = dmu_dir_list_next(os,
		    sizeof (childname) - (p - childname), p, NULL, &cursor);
	} while (err == 0 && dataset_name_hidden(childname));
	dsl_dataset_rele(ds, FTAG);

	if (err == ENOENT) {
		return (0);
	} else if (err != 0) {
		return (luaL_error(state,
		    "unexpected error %d from dmu_dir_list_next()",
		    err));
	}

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

	(void) lua_pushstring(state, childname);
	return (1);
}
Beispiel #6
0
static int
dmu_objset_own_impl(dsl_dataset_t *ds, dmu_objset_type_t type,
    boolean_t readonly, void *tag, objset_t **osp)
{
	int err;

	err = dmu_objset_from_ds(ds, osp);
	if (err != 0) {
		dsl_dataset_disown(ds, tag);
	} else if (type != DMU_OST_ANY && type != (*osp)->os_phys->os_type) {
		dsl_dataset_disown(ds, tag);
		return (SET_ERROR(EINVAL));
	} else if (!readonly && dsl_dataset_is_snapshot(ds)) {
		dsl_dataset_disown(ds, tag);
		return (SET_ERROR(EROFS));
	}
	return (err);
}
/* called from zpl */
int
dmu_objset_own(const char *name, dmu_objset_type_t type,
    boolean_t readonly, void *tag, objset_t **osp)
{
	dsl_dataset_t *ds;
	int err;

	err = dsl_dataset_own(name, B_FALSE, tag, &ds);
	if (err)
		return (err);

	err = dmu_objset_from_ds(ds, osp);
	if (err) {
		dsl_dataset_disown(ds, tag);
	} else if (type != DMU_OST_ANY && type != (*osp)->os_phys->os_type) {
		dmu_objset_disown(*osp, tag);
		return (EINVAL);
	} else if (!readonly && dsl_dataset_is_snapshot(ds)) {
		dmu_objset_disown(*osp, tag);
		return (EROFS);
	}
	return (err);
}
Beispiel #8
0
/*
 * Holds the pool while the objset is held.  Therefore only one objset
 * can be held at a time.
 */
int
dmu_objset_hold(const char *name, void *tag, objset_t **osp)
{
	dsl_pool_t *dp;
	dsl_dataset_t *ds;
	int err;

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

	err = dmu_objset_from_ds(ds, osp);
	if (err != 0) {
		dsl_dataset_rele(ds, tag);
		dsl_pool_rele(dp, tag);
	}

	return (err);
}
Beispiel #9
0
static int
get_objset_type(dsl_dataset_t *ds, zfs_type_t *type)
{
	int error;
	objset_t *os;
	error = dmu_objset_from_ds(ds, &os);
	if (error != 0)
		return (error);
	if (ds->ds_is_snapshot) {
		*type = ZFS_TYPE_SNAPSHOT;
	} else {
		switch (os->os_phys->os_type) {
		case DMU_OST_ZFS:
			*type = ZFS_TYPE_FILESYSTEM;
			break;
		case DMU_OST_ZVOL:
			*type = ZFS_TYPE_VOLUME;
			break;
		default:
			return (EINVAL);
		}
	}
	return (0);
}
Beispiel #10
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);
}
Beispiel #11
0
int
dsl_crypto_key_new(const char *dsname)
{
    dsl_dataset_t *ds;
    objset_t *os;
    zcrypt_keystore_node_t *skn;
    spa_t *spa;
    struct knarg arg;
    int error;
    dsl_pool_t *dp;
    void *cookie;

    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);
    }

    if (dsl_dataset_is_snapshot(ds)) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOTSUP);
    }

    if ((error = dmu_objset_from_ds(ds, &os)) != 0) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    if (os->os_crypt == ZIO_CRYPT_OFF) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOTSUP);
    }

    ASSERT(os->os_crypt != ZIO_CRYPT_INHERIT);

    /*
     * Need the keychain and wrapping key to already be available.
     */
    spa = dsl_dataset_get_spa(ds);
    skn = zcrypt_keystore_find_node(spa, ds->ds_object, B_FALSE);
    if (skn == NULL) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOENT);
    }

    ASSERT(ds != NULL);
    ASSERT(ds->ds_objset != NULL);

    //zil_suspend_dmu_sync(dmu_objset_zil(os));
    zil_suspend(dsname, &cookie);

    arg.kn_skn = skn;
    arg.kn_txgkey = zcrypt_key_gen(os->os_crypt);
    arg.kn_ds = ds;
    zcrypt_key_hold(skn->skn_wrapkey, FTAG);
    VERIFY(zcrypt_wrap_key(skn->skn_wrapkey, arg.kn_txgkey,
                           &arg.kn_wkeybuf, &arg.kn_wkeylen,
                           zio_crypt_select_wrap(os->os_crypt)) == 0);

    error = dsl_sync_task(spa->spa_name, dsl_crypto_key_new_check,
                          dsl_crypto_key_new_sync, &arg, 1,
                          ZFS_SPACE_CHECK_NONE);

    kmem_free(arg.kn_wkeybuf, arg.kn_wkeylen);

    zcrypt_key_release(skn->skn_wrapkey, FTAG);

    //zil_resume_dmu_sync(dmu_objset_zil(os));
    zil_resume(os);

    dsl_dataset_rele(ds, FTAG);
    dsl_pool_rele(dp, FTAG);

    if (error)
        zcrypt_key_free(arg.kn_txgkey);
    return (error);
}
Beispiel #12
0
/*
 * dsl_crypto_key_unload
 *
 * Remove the key from the in memory keystore.
 *
 * First we have to remove the minor node for a ZVOL or unmount
 * the filesystem.  This is so that we flush all pending IO for it to disk
 * so we won't need to encrypt anything with this key.  Anything in flight
 * should already have a lock on the keys it needs.
 * We can't assume that userland has already successfully unmounted the
 * dataset though in many cases it will have.
 *
 * If the key can't be removed return the failure back to our caller.
 */
int
dsl_crypto_key_unload(const char *dsname)
{
    dsl_dataset_t *ds;
    objset_t *os;
    int error;
    spa_t *spa;
    dsl_pool_t *dp;
#ifdef _KERNEL
    dmu_objset_type_t os_type;
    //vfs_t *vfsp;
    struct vfsmount *vfsp;
#endif /* _KERNEL */

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

    /* XXX - should we use own_exclusive() here? */
    if ((error = dsl_dataset_hold(dp, dsname, FTAG, &ds)) != 0) {
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    if ((error = dmu_objset_from_ds(ds, &os)) != 0) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

#ifdef _KERNEL
    /*
     * Make sure that the device node has gone for ZVOLs
     * and that filesystems are umounted.
     */
#if 0 // FIXME
    os_type = dmu_objset_type(os);
    if (os_type == DMU_OST_ZVOL) {
        error = zvol_remove_minor(dsname);
        if (error == ENXIO)
            error = 0;
    } else if (os_type == DMU_OST_ZFS) {
        vfsp = zfs_get_vfs(dsname);
        if (vfsp != NULL) {
            error = vn_vfswlock(vfsp->vfs_vnodecovered);
            VFS_RELE(vfsp);
            if (error == 0)
                error = dounmount(vfsp, 0, CRED());
        }
    }
    if (error != 0) {
        dsl_dataset_rele(ds, FTAG);
        return (error);
    }
#endif

#endif /* _KERNEL */

    /*
     * Make sure all dbufs are synced.
     *
     * It is essential for encrypted datasets to ensure that
     * there is no further pending IO before removing the key.
     */
    if (dmu_objset_is_dirty(os, 0)) // FIXME, 0?
        txg_wait_synced(dmu_objset_pool(os), 0);
    dmu_objset_evict_dbufs(os);

    spa = dsl_dataset_get_spa(ds);
    error = zcrypt_keystore_remove(spa, ds->ds_object);

    dsl_dataset_rele(ds, FTAG);
    dsl_pool_rele(dp, FTAG);
    return (error);
}
Beispiel #13
0
/* called from dsl for meta-objset */
objset_t *
dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
                       dmu_objset_type_t type, dsl_crypto_ctx_t *dcc, dmu_tx_t *tx)
{
	objset_t *os;
	dnode_t *mdn;

	ASSERT(dmu_tx_is_syncing(tx));
	if (ds != NULL)
		VERIFY(0 == dmu_objset_from_ds(ds, &os));
	else
		VERIFY(0 == dmu_objset_open_impl(spa, NULL, bp, &os));

	mdn = DMU_META_DNODE(os);

	dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT,
	    DN_MAX_INDBLKSHIFT, DMU_OT_NONE, 0, tx);

	/*
	 * We don't want to have to increase the meta-dnode's nlevels
	 * later, because then we could do it in quescing context while
	 * we are also accessing it in open context.
	 *
	 * This precaution is not necessary for the MOS (ds == NULL),
	 * because the MOS is only updated in syncing context.
	 * This is most fortunate: the MOS is the only objset that
	 * needs to be synced multiple times as spa_sync() iterates
	 * to convergence, so minimizing its dn_nlevels matters.
	 */
	if (ds != NULL) {
		int levels = 1;

		/*
		 * Determine the number of levels necessary for the meta-dnode
		 * to contain DN_MAX_OBJECT dnodes.
		 */
		while ((uint64_t)mdn->dn_nblkptr << (mdn->dn_datablkshift +
		    (levels - 1) * (mdn->dn_indblkshift - SPA_BLKPTRSHIFT)) <
		    DN_MAX_OBJECT * sizeof (dnode_phys_t))
			levels++;

		mdn->dn_next_nlevels[tx->tx_txg & TXG_MASK] =
		    mdn->dn_nlevels = levels;
	}

	ASSERT(type != DMU_OST_NONE);
	ASSERT(type != DMU_OST_ANY);
	ASSERT(type < DMU_OST_NUMTYPES);
    /*
     * Note: although we should not be dirtying the objset outside of
     * sync context, the os_type is used directly from the os_phys
     * in dsl_scan so it may not be save to put os_type in the in-core
     * objset_t and set it in the phys in sync context (as with os_flags)
     */
    dmu_objset_dirty(os);
	os->os_phys->os_type = type;
	if (dmu_objset_userused_enabled(os)) {
		os->os_phys->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE;
        // FIXME - removed in newer.
		// os->os_flags = os->os_phys->os_flags;
	}

    if (dcc != NULL && dcc->dcc_crypt != ZIO_CRYPT_INHERIT) {
        os->os_crypt = zio_crypt_select(dcc->dcc_crypt,
                                        ZIO_CRYPT_ON_VALUE);
    }

	dsl_dataset_dirty(ds, tx);

	return (os);
}