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