summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/zfs/zfs_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/fs/zfs/zfs_ioctl.c')
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c553
1 files changed, 340 insertions, 213 deletions
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 029138ff3a..e51c1587df 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -58,6 +58,7 @@
#include <sys/zfs_ctldir.h>
#include "zfs_namecheck.h"
+#include "zfs_prop.h"
extern struct modlfs zfs_modlfs;
@@ -68,7 +69,7 @@ ldi_ident_t zfs_li = NULL;
dev_info_t *zfs_dip;
typedef int zfs_ioc_func_t(zfs_cmd_t *);
-typedef int zfs_secpolicy_func_t(const char *, const char *, cred_t *);
+typedef int zfs_secpolicy_func_t(const char *, cred_t *);
typedef struct zfs_ioc_vec {
zfs_ioc_func_t *zvec_func;
@@ -122,7 +123,7 @@ __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
*/
/* ARGSUSED */
static int
-zfs_secpolicy_none(const char *unused1, const char *unused2, cred_t *cr)
+zfs_secpolicy_none(const char *unused1, cred_t *cr)
{
return (0);
}
@@ -133,7 +134,7 @@ zfs_secpolicy_none(const char *unused1, const char *unused2, cred_t *cr)
*/
/* ARGSUSED */
static int
-zfs_secpolicy_read(const char *dataset, const char *unused, cred_t *cr)
+zfs_secpolicy_read(const char *dataset, cred_t *cr)
{
if (INGLOBALZONE(curproc) ||
zone_dataset_visible(dataset, NULL))
@@ -184,9 +185,8 @@ zfs_dozonecheck(const char *dataset, cred_t *cr)
* Policy for dataset write operations (create children, set properties, etc).
* Requires SYS_MOUNT privilege, and must be writable in the local zone.
*/
-/* ARGSUSED */
int
-zfs_secpolicy_write(const char *dataset, const char *unused, cred_t *cr)
+zfs_secpolicy_write(const char *dataset, cred_t *cr)
{
int error;
@@ -201,7 +201,7 @@ zfs_secpolicy_write(const char *dataset, const char *unused, cred_t *cr)
* create, destroy, snapshot, clone, restore.
*/
static int
-zfs_secpolicy_parent(const char *dataset, const char *unused, cred_t *cr)
+zfs_secpolicy_parent(const char *dataset, cred_t *cr)
{
char parentname[MAXNAMELEN];
char *cp;
@@ -221,65 +221,7 @@ zfs_secpolicy_parent(const char *dataset, const char *unused, cred_t *cr)
}
- return (zfs_secpolicy_write(parentname, unused, cr));
-}
-
-/*
- * Policy for dataset write operations (create children, set properties, etc).
- * Requires SYS_MOUNT privilege, and must be writable in the local zone.
- */
-static int
-zfs_secpolicy_setprop(const char *dataset, const char *prop, cred_t *cr)
-{
- int error;
-
- if (error = zfs_dozonecheck(dataset, cr))
- return (error);
-
- if (strcmp(prop, "zoned") == 0) {
- /*
- * Disallow setting of 'zoned' from within a local zone.
- */
- if (!INGLOBALZONE(curproc))
- return (EPERM);
- }
-
- return (secpolicy_zfs(cr));
-}
-
-/*
- * Security policy for setting the quota. This is the same as
- * zfs_secpolicy_write, except that the local zone may not change the quota at
- * the zone-property setpoint.
- */
-/* ARGSUSED */
-static int
-zfs_secpolicy_quota(const char *dataset, const char *unused, cred_t *cr)
-{
- int error;
-
- if (error = zfs_dozonecheck(dataset, cr))
- return (error);
-
- if (!INGLOBALZONE(curproc)) {
- uint64_t zoned;
- char setpoint[MAXNAMELEN];
- int dslen;
- /*
- * Unprivileged users are allowed to modify the quota
- * on things *under* (ie. contained by) the thing they
- * own.
- */
- if (dsl_prop_get_integer(dataset, "zoned", &zoned, setpoint))
- return (EPERM);
- if (!zoned) /* this shouldn't happen */
- return (EPERM);
- dslen = strlen(dataset);
- if (dslen <= strlen(setpoint))
- return (EPERM);
- }
-
- return (secpolicy_zfs(cr));
+ return (zfs_secpolicy_write(parentname, cr));
}
/*
@@ -288,7 +230,7 @@ zfs_secpolicy_quota(const char *dataset, const char *unused, cred_t *cr)
*/
/* ARGSUSED */
static int
-zfs_secpolicy_config(const char *unused, const char *unused2, cred_t *cr)
+zfs_secpolicy_config(const char *unused, cred_t *cr)
{
if (secpolicy_sys_config(cr, B_FALSE) != 0)
return (EPERM);
@@ -301,7 +243,7 @@ zfs_secpolicy_config(const char *unused, const char *unused2, cred_t *cr)
*/
/* ARGSUSED */
static int
-zfs_secpolicy_inject(const char *unused, const char *unused2, cred_t *cr)
+zfs_secpolicy_inject(const char *unused, cred_t *cr)
{
return (secpolicy_zinject(cr));
}
@@ -310,7 +252,7 @@ zfs_secpolicy_inject(const char *unused, const char *unused2, cred_t *cr)
* Returns the nvlist as specified by the user in the zfs_cmd_t.
*/
static int
-get_config(zfs_cmd_t *zc, nvlist_t **nvp)
+get_nvlist(zfs_cmd_t *zc, nvlist_t **nvp)
{
char *packed;
size_t size;
@@ -318,16 +260,14 @@ get_config(zfs_cmd_t *zc, nvlist_t **nvp)
nvlist_t *config = NULL;
/*
- * Read in and unpack the user-supplied nvlist. By this point, we know
- * that the user has the SYS_CONFIG privilege, so allocating arbitrary
- * sized regions of memory should not be a problem.
+ * Read in and unpack the user-supplied nvlist.
*/
- if ((size = zc->zc_config_src_size) == 0)
+ if ((size = zc->zc_nvlist_src_size) == 0)
return (EINVAL);
packed = kmem_alloc(size, KM_SLEEP);
- if ((error = xcopyin((void *)(uintptr_t)zc->zc_config_src, packed,
+ if ((error = xcopyin((void *)(uintptr_t)zc->zc_nvlist_src, packed,
size)) != 0) {
kmem_free(packed, size);
return (error);
@@ -345,16 +285,39 @@ get_config(zfs_cmd_t *zc, nvlist_t **nvp)
}
static int
+put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
+{
+ char *packed = NULL;
+ size_t size;
+ int error;
+
+ VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
+
+ if (size > zc->zc_nvlist_dst_size) {
+ error = ENOMEM;
+ } else {
+ VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
+ KM_SLEEP) == 0);
+ error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst,
+ size);
+ kmem_free(packed, size);
+ }
+
+ zc->zc_nvlist_dst_size = size;
+ return (error);
+}
+
+static int
zfs_ioc_pool_create(zfs_cmd_t *zc)
{
int error;
nvlist_t *config;
- if ((error = get_config(zc, &config)) != 0)
+ if ((error = get_nvlist(zc, &config)) != 0)
return (error);
- error = spa_create(zc->zc_name, config, zc->zc_root[0] == '\0' ?
- NULL : zc->zc_root);
+ error = spa_create(zc->zc_name, config, zc->zc_value[0] == '\0' ?
+ NULL : zc->zc_value);
nvlist_free(config);
@@ -374,7 +337,7 @@ zfs_ioc_pool_import(zfs_cmd_t *zc)
nvlist_t *config;
uint64_t guid;
- if ((error = get_config(zc, &config)) != 0)
+ if ((error = get_nvlist(zc, &config)) != 0)
return (error);
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
@@ -382,7 +345,7 @@ zfs_ioc_pool_import(zfs_cmd_t *zc)
error = EINVAL;
else
error = spa_import(zc->zc_name, config,
- zc->zc_root[0] == '\0' ? NULL : zc->zc_root);
+ zc->zc_value[0] == '\0' ? NULL : zc->zc_value);
nvlist_free(config);
@@ -399,25 +362,13 @@ static int
zfs_ioc_pool_configs(zfs_cmd_t *zc)
{
nvlist_t *configs;
- char *packed = NULL;
- size_t size = 0;
int error;
if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
return (EEXIST);
- VERIFY(nvlist_pack(configs, &packed, &size, NV_ENCODE_NATIVE,
- KM_SLEEP) == 0);
+ error = put_nvlist(zc, configs);
- if (size > zc->zc_config_dst_size)
- error = ENOMEM;
- else
- error = xcopyout(packed, (void *)(uintptr_t)zc->zc_config_dst,
- size);
-
- zc->zc_config_dst_size = size;
-
- kmem_free(packed, size);
nvlist_free(configs);
return (error);
@@ -427,27 +378,14 @@ static int
zfs_ioc_pool_stats(zfs_cmd_t *zc)
{
nvlist_t *config;
- char *packed = NULL;
- size_t size = 0;
int error;
int ret = 0;
- error = spa_get_stats(zc->zc_name, &config, zc->zc_root,
- sizeof (zc->zc_root));
+ error = spa_get_stats(zc->zc_name, &config, zc->zc_value,
+ sizeof (zc->zc_value));
if (config != NULL) {
- VERIFY(nvlist_pack(config, &packed, &size,
- NV_ENCODE_NATIVE, KM_SLEEP) == 0);
-
- if (size > zc->zc_config_dst_size)
- ret = ENOMEM;
- else if (xcopyout(packed, (void *)(uintptr_t)zc->zc_config_dst,
- size))
- ret = EFAULT;
-
- zc->zc_config_dst_size = size;
-
- kmem_free(packed, size);
+ ret = put_nvlist(zc, config);
nvlist_free(config);
/*
@@ -471,11 +409,9 @@ static int
zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
{
nvlist_t *tryconfig, *config;
- char *packed = NULL;
- size_t size = 0;
int error;
- if ((error = get_config(zc, &tryconfig)) != 0)
+ if ((error = get_nvlist(zc, &tryconfig)) != 0)
return (error);
config = spa_tryimport(tryconfig);
@@ -485,18 +421,7 @@ zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
if (config == NULL)
return (EINVAL);
- VERIFY(nvlist_pack(config, &packed, &size, NV_ENCODE_NATIVE,
- KM_SLEEP) == 0);
-
- if (size > zc->zc_config_dst_size)
- error = ENOMEM;
- else
- error = xcopyout(packed, (void *)(uintptr_t)zc->zc_config_dst,
- size);
-
- zc->zc_config_dst_size = size;
-
- kmem_free(packed, size);
+ error = put_nvlist(zc, config);
nvlist_free(config);
return (error);
@@ -555,7 +480,7 @@ zfs_ioc_vdev_add(zfs_cmd_t *zc)
if (error != 0)
return (error);
- if ((error = get_config(zc, &config)) == 0) {
+ if ((error = get_nvlist(zc, &config)) == 0) {
error = spa_vdev_add(spa, config);
nvlist_free(config);
}
@@ -619,7 +544,7 @@ zfs_ioc_vdev_attach(zfs_cmd_t *zc)
if (error != 0)
return (error);
- if ((error = get_config(zc, &config)) == 0) {
+ if ((error = get_nvlist(zc, &config)) == 0) {
error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
nvlist_free(config);
}
@@ -648,7 +573,7 @@ static int
zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
{
spa_t *spa;
- char *path = zc->zc_prop_value;
+ char *path = zc->zc_value;
uint64_t guid = zc->zc_guid;
int error;
@@ -668,8 +593,6 @@ zfs_ioc_objset_stats(zfs_cmd_t *zc)
objset_t *os = NULL;
int error;
nvlist_t *nv;
- size_t sz;
- char *buf;
retry:
error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
@@ -691,27 +614,16 @@ retry:
dmu_objset_stats(os, &zc->zc_objset_stats);
- if (zc->zc_config_src != NULL &&
+ if (zc->zc_nvlist_dst != NULL &&
(error = dsl_prop_get_all(os, &nv)) == 0) {
- VERIFY(nvlist_size(nv, &sz, NV_ENCODE_NATIVE) == 0);
- if (sz > zc->zc_config_src_size) {
- zc->zc_config_src_size = sz;
- error = ENOMEM;
- } else {
- buf = kmem_alloc(sz, KM_SLEEP);
- VERIFY(nvlist_pack(nv, &buf, &sz,
- NV_ENCODE_NATIVE, 0) == 0);
- error = xcopyout(buf,
- (void *)(uintptr_t)zc->zc_config_src, sz);
- kmem_free(buf, sz);
- }
+ error = put_nvlist(zc, nv);
nvlist_free(nv);
}
if (!error && zc->zc_objset_stats.dds_type == DMU_OST_ZVOL)
- error = zvol_get_stats(zc, os);
+ error = zvol_get_stats(os, &zc->zc_vol_stats);
- spa_altroot(dmu_objset_spa(os), zc->zc_root, sizeof (zc->zc_root));
+ spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value));
dmu_objset_close(os);
return (error);
@@ -818,46 +730,215 @@ retry:
}
static int
-zfs_ioc_set_prop(zfs_cmd_t *zc)
+zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl)
{
- return (dsl_prop_set(zc->zc_name, zc->zc_prop_name,
- zc->zc_intsz, zc->zc_numints, zc->zc_prop_value));
-}
+ nvpair_t *elem;
+ int error;
+ const char *propname;
+ zfs_prop_t prop;
+ uint64_t intval;
+ char *strval;
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
+ propname = nvpair_name(elem);
+
+ if ((prop = zfs_name_to_prop(propname)) ==
+ ZFS_PROP_INVAL) {
+ /*
+ * If this is a user-defined property, it must be a
+ * string, and there is no further validation to do.
+ */
+ if (!zfs_prop_user(propname) ||
+ nvpair_type(elem) != DATA_TYPE_STRING)
+ return (EINVAL);
+
+ VERIFY(nvpair_value_string(elem, &strval) == 0);
+ error = dsl_prop_set(name, propname, 1,
+ strlen(strval) + 1, strval);
+ if (error == 0)
+ continue;
+ else
+ break;
+ }
-static int
-zfs_ioc_set_quota(zfs_cmd_t *zc)
-{
- return (dsl_dir_set_quota(zc->zc_name, zc->zc_cookie));
-}
+ /*
+ * Check permissions for special properties.
+ */
+ switch (prop) {
+ case ZFS_PROP_ZONED:
+ /*
+ * Disallow setting of 'zoned' from within a local zone.
+ */
+ if (!INGLOBALZONE(curproc))
+ return (EPERM);
+ break;
-static int
-zfs_ioc_set_reservation(zfs_cmd_t *zc)
-{
- return (dsl_dir_set_reservation(zc->zc_name, zc->zc_cookie));
-}
+ case ZFS_PROP_QUOTA:
+ if (error = zfs_dozonecheck(name, cr))
+ return (error);
-static int
-zfs_ioc_set_volsize(zfs_cmd_t *zc)
-{
- return (zvol_set_volsize(zc));
+ if (!INGLOBALZONE(curproc)) {
+ uint64_t zoned;
+ char setpoint[MAXNAMELEN];
+ int dslen;
+ /*
+ * Unprivileged users are allowed to modify the
+ * quota on things *under* (ie. contained by)
+ * the thing they own.
+ */
+ if (dsl_prop_get_integer(name, "zoned", &zoned,
+ setpoint))
+ return (EPERM);
+ if (!zoned) /* this shouldn't happen */
+ return (EPERM);
+ dslen = strlen(name);
+ if (dslen <= strlen(setpoint))
+ return (EPERM);
+ }
+ }
+
+ switch (prop) {
+ case ZFS_PROP_QUOTA:
+ if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
+ (error = dsl_dir_set_quota(name,
+ intval)) != 0)
+ return (error);
+ break;
+
+ case ZFS_PROP_RESERVATION:
+ if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
+ (error = dsl_dir_set_reservation(name,
+ intval)) != 0)
+ return (error);
+ break;
+
+ case ZFS_PROP_VOLSIZE:
+ if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
+ (error = zvol_set_volsize(name, dev,
+ intval)) != 0)
+ return (error);
+ break;
+
+ case ZFS_PROP_VOLBLOCKSIZE:
+ if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
+ (error = zvol_set_volblocksize(name,
+ intval)) != 0)
+ return (error);
+ break;
+
+ default:
+ if (nvpair_type(elem) == DATA_TYPE_STRING) {
+ if (zfs_prop_get_type(prop) !=
+ prop_type_string)
+ return (EINVAL);
+ ASSERT(nvpair_value_string(elem, &strval) == 0);
+ error = dsl_prop_set(name,
+ nvpair_name(elem), 1, strlen(strval) + 1,
+ strval);
+ } else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
+ ASSERT(nvpair_value_uint64(elem, &intval) == 0);
+
+ switch (zfs_prop_get_type(prop)) {
+ case prop_type_number:
+ break;
+ case prop_type_boolean:
+ if (intval > 1)
+ error = EINVAL;
+ break;
+ case prop_type_string:
+ error = EINVAL;
+ break;
+ case prop_type_index:
+ switch (prop) {
+ case ZFS_PROP_CHECKSUM:
+ if (intval >=
+ ZIO_CHECKSUM_FUNCTIONS)
+ error = EINVAL;
+ break;
+ case ZFS_PROP_COMPRESSION:
+ if (intval >=
+ ZIO_COMPRESS_FUNCTIONS)
+ error = EINVAL;
+ break;
+ case ZFS_PROP_SNAPDIR:
+ if (intval >
+ ZFS_SNAPDIR_VISIBLE)
+ error = EINVAL;
+ break;
+ case ZFS_PROP_ACLMODE:
+ if (intval >
+ ZFS_ACL_PASSTHROUGH)
+ error = EINVAL;
+ break;
+ case ZFS_PROP_ACLINHERIT:
+ if (intval > ZFS_ACL_SECURE ||
+ intval == ZFS_ACL_GROUPMASK)
+ error = EINVAL;
+ break;
+ default:
+ cmn_err(CE_PANIC,
+ "unknown index property");
+ }
+ break;
+ default:
+ cmn_err(CE_PANIC, "unknown property "
+ "type");
+ break;
+ }
+
+ error = dsl_prop_set(name, propname, 8, 1,
+ &intval);
+ } else {
+ return (EINVAL);
+ }
+ break;
+ }
+ }
+
+ return (0);
}
static int
-zfs_ioc_set_volblocksize(zfs_cmd_t *zc)
+zfs_ioc_set_prop(zfs_cmd_t *zc)
{
- return (zvol_set_volblocksize(zc));
+ nvlist_t *nvl;
+ int error;
+ zfs_prop_t prop;
+
+ /*
+ * If zc_value is set, then this is an attempt to inherit a value.
+ * Otherwise, zc_nvlist refers to a list of properties to set.
+ */
+ if (zc->zc_value[0] != '\0') {
+ if (!zfs_prop_user(zc->zc_value) &&
+ ((prop = zfs_name_to_prop(zc->zc_value)) ==
+ ZFS_PROP_INVAL ||
+ !zfs_prop_inheritable(prop)))
+ return (EINVAL);
+
+ return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL));
+ }
+
+ if ((error = get_nvlist(zc, &nvl)) != 0)
+ return (error);
+
+ error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev,
+ (cred_t *)(uintptr_t)zc->zc_cred, nvl);
+ nvlist_free(nvl);
+ return (error);
}
static int
zfs_ioc_create_minor(zfs_cmd_t *zc)
{
- return (zvol_create_minor(zc));
+ return (zvol_create_minor(zc->zc_name, zc->zc_dev));
}
static int
zfs_ioc_remove_minor(zfs_cmd_t *zc)
{
- return (zvol_remove_minor(zc));
+ return (zvol_remove_minor(zc->zc_name));
}
/*
@@ -888,7 +969,7 @@ zfs_get_vfs(const char *resource)
static void
zfs_create_cb(objset_t *os, void *arg, dmu_tx_t *tx)
{
- zfs_cmd_t *zc = arg;
+ zfs_create_data_t *zc = arg;
zfs_create_fs(os, (cred_t *)(uintptr_t)zc->zc_cred, tx);
}
@@ -897,6 +978,7 @@ zfs_ioc_create(zfs_cmd_t *zc)
{
objset_t *clone;
int error = 0;
+ zfs_create_data_t cbdata = { 0 };
void (*cbfunc)(objset_t *os, void *arg, dmu_tx_t *tx);
dmu_objset_type_t type = zc->zc_objset_type;
@@ -916,47 +998,93 @@ zfs_ioc_create(zfs_cmd_t *zc)
if (strchr(zc->zc_name, '@'))
return (EINVAL);
- if (zc->zc_filename[0] != '\0') {
+ if (zc->zc_nvlist_src != NULL &&
+ (error = get_nvlist(zc, &cbdata.zc_props)) != 0)
+ return (error);
+
+ cbdata.zc_cred = (cred_t *)(uintptr_t)zc->zc_cred;
+ cbdata.zc_dev = (dev_t)zc->zc_dev;
+
+ if (zc->zc_value[0] != '\0') {
/*
* We're creating a clone of an existing snapshot.
*/
- zc->zc_filename[sizeof (zc->zc_filename) - 1] = '\0';
- if (dataset_namecheck(zc->zc_filename, NULL, NULL) != 0)
+ zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
+ if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) {
+ nvlist_free(cbdata.zc_props);
return (EINVAL);
+ }
- error = dmu_objset_open(zc->zc_filename, type,
+ error = dmu_objset_open(zc->zc_value, type,
DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
- if (error)
+ if (error) {
+ nvlist_free(cbdata.zc_props);
return (error);
+ }
error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL);
dmu_objset_close(clone);
} else {
- if (cbfunc == NULL)
+ if (cbfunc == NULL) {
+ nvlist_free(cbdata.zc_props);
return (EINVAL);
- /*
- * We're creating a new dataset.
- */
- if (type == DMU_OST_ZVOL) {
-
- if ((error = zvol_check_volblocksize(zc)) != 0)
- return (error);
+ }
- if ((error = zvol_check_volsize(zc,
- zc->zc_volblocksize)) != 0)
+ if (type == DMU_OST_ZVOL) {
+ uint64_t volsize, volblocksize;
+
+ if (cbdata.zc_props == NULL ||
+ nvlist_lookup_uint64(cbdata.zc_props,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE),
+ &volsize) != 0) {
+ nvlist_free(cbdata.zc_props);
+ return (EINVAL);
+ }
+
+ if ((error = nvlist_lookup_uint64(cbdata.zc_props,
+ zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+ &volblocksize)) != 0 && error != ENOENT) {
+ nvlist_free(cbdata.zc_props);
+ return (EINVAL);
+ }
+
+ if (error != 0)
+ volblocksize = zfs_prop_default_numeric(
+ ZFS_PROP_VOLBLOCKSIZE);
+
+ if ((error = zvol_check_volblocksize(
+ volblocksize)) != 0 ||
+ (error = zvol_check_volsize(volsize,
+ volblocksize)) != 0) {
+ nvlist_free(cbdata.zc_props);
return (error);
+ }
}
- error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, zc);
+
+ error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc,
+ &cbdata);
}
+
+ /*
+ * It would be nice to do this atomically.
+ */
+ if (error == 0) {
+ if ((error = zfs_set_prop_nvlist(zc->zc_name,
+ zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred,
+ cbdata.zc_props)) != 0)
+ (void) dmu_objset_destroy(zc->zc_name);
+ }
+
+ nvlist_free(cbdata.zc_props);
return (error);
}
static int
zfs_ioc_snapshot(zfs_cmd_t *zc)
{
- if (snapshot_namecheck(zc->zc_prop_value, NULL, NULL) != 0)
+ if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
return (EINVAL);
return (dmu_objset_snapshot(zc->zc_name,
- zc->zc_prop_value, zc->zc_cookie));
+ zc->zc_value, zc->zc_cookie));
}
static int
@@ -1004,13 +1132,13 @@ zfs_ioc_destroy_snaps(zfs_cmd_t *zc)
{
int err;
- if (snapshot_namecheck(zc->zc_prop_value, NULL, NULL) != 0)
+ if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
return (EINVAL);
err = dmu_objset_find(zc->zc_name,
- zfs_unmount_snap, zc->zc_prop_value, DS_FIND_CHILDREN);
+ zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN);
if (err)
return (err);
- return (dmu_snapshots_destroy(zc->zc_name, zc->zc_prop_value));
+ return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value));
}
static int
@@ -1034,8 +1162,8 @@ zfs_ioc_rollback(zfs_cmd_t *zc)
static int
zfs_ioc_rename(zfs_cmd_t *zc)
{
- zc->zc_prop_value[sizeof (zc->zc_prop_value) - 1] = '\0';
- if (dataset_namecheck(zc->zc_prop_value, NULL, NULL) != 0)
+ zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
+ if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0)
return (EINVAL);
if (strchr(zc->zc_name, '@') != NULL &&
@@ -1045,7 +1173,7 @@ zfs_ioc_rename(zfs_cmd_t *zc)
return (err);
}
- return (dmu_objset_rename(zc->zc_name, zc->zc_prop_value));
+ return (dmu_objset_rename(zc->zc_name, zc->zc_value));
}
static int
@@ -1058,8 +1186,8 @@ zfs_ioc_recvbackup(zfs_cmd_t *zc)
fp = getf(fd);
if (fp == NULL)
return (EBADF);
- error = dmu_recvbackup(zc->zc_filename, &zc->zc_begin_record,
- &zc->zc_cookie, (boolean_t)zc->zc_numints, fp->f_vnode,
+ error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record,
+ &zc->zc_cookie, (boolean_t)zc->zc_guid, fp->f_vnode,
fp->f_offset);
releasef(fd);
return (error);
@@ -1078,8 +1206,8 @@ zfs_ioc_sendbackup(zfs_cmd_t *zc)
if (error)
return (error);
- if (zc->zc_prop_value[0] != '\0') {
- error = dmu_objset_open(zc->zc_prop_value, DMU_OST_ANY,
+ if (zc->zc_value[0] != '\0') {
+ error = dmu_objset_open(zc->zc_value, DMU_OST_ANY,
DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap);
if (error) {
dmu_objset_close(tosnap);
@@ -1143,17 +1271,17 @@ zfs_ioc_error_log(zfs_cmd_t *zc)
{
spa_t *spa;
int error;
- size_t count = (size_t)zc->zc_config_dst_size;
+ size_t count = (size_t)zc->zc_nvlist_dst_size;
if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
return (error);
- error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_config_dst,
+ error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst,
&count);
if (error == 0)
- zc->zc_config_dst_size = count;
+ zc->zc_nvlist_dst_size = count;
else
- zc->zc_config_dst_size = spa_get_errlog_size(spa);
+ zc->zc_nvlist_dst_size = spa_get_errlog_size(spa);
spa_close(spa, FTAG);
@@ -1172,9 +1300,9 @@ zfs_ioc_clear(zfs_cmd_t *zc)
spa_config_enter(spa, RW_WRITER, FTAG);
- if (zc->zc_prop_value[0] == '\0')
+ if (zc->zc_guid == 0) {
vd = NULL;
- else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) {
+ } else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) {
spa_config_exit(spa, FTAG);
spa_close(spa, FTAG);
return (ENODEV);
@@ -1194,14 +1322,17 @@ zfs_ioc_bookmark_name(zfs_cmd_t *zc)
{
spa_t *spa;
int error;
+ nvlist_t *nvl;
if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
return (error);
- error = spa_bookmark_name(spa, &zc->zc_bookmark,
- zc->zc_prop_name, sizeof (zc->zc_prop_name), zc->zc_prop_value,
- sizeof (zc->zc_prop_value), zc->zc_filename,
- sizeof (zc->zc_filename));
+ VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+ error = spa_bookmark_name(spa, &zc->zc_bookmark, nvl);
+ if (error == 0)
+ error = put_nvlist(zc, nvl);
+ nvlist_free(nvl);
spa_close(spa, FTAG);
@@ -1217,10 +1348,10 @@ zfs_ioc_promote(zfs_cmd_t *zc)
* We don't need to unmount *all* the origin fs's snapshots, but
* it's easier.
*/
- cp = strchr(zc->zc_prop_value, '@');
+ cp = strchr(zc->zc_value, '@');
if (cp)
*cp = '\0';
- (void) dmu_objset_find(zc->zc_prop_value,
+ (void) dmu_objset_find(zc->zc_value,
zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS);
return (dsl_dataset_promote(zc->zc_name));
}
@@ -1246,11 +1377,7 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = {
{ zfs_ioc_objset_stats, zfs_secpolicy_read, dataset_name },
{ zfs_ioc_dataset_list_next, zfs_secpolicy_read, dataset_name },
{ zfs_ioc_snapshot_list_next, zfs_secpolicy_read, dataset_name },
- { zfs_ioc_set_prop, zfs_secpolicy_setprop, dataset_name },
- { zfs_ioc_set_quota, zfs_secpolicy_quota, dataset_name },
- { zfs_ioc_set_reservation, zfs_secpolicy_write, dataset_name },
- { zfs_ioc_set_volsize, zfs_secpolicy_config, dataset_name },
- { zfs_ioc_set_volblocksize, zfs_secpolicy_config, dataset_name },
+ { zfs_ioc_set_prop, zfs_secpolicy_write, dataset_name },
{ zfs_ioc_create_minor, zfs_secpolicy_config, dataset_name },
{ zfs_ioc_remove_minor, zfs_secpolicy_config, dataset_name },
{ zfs_ioc_create, zfs_secpolicy_parent, dataset_name },
@@ -1292,8 +1419,7 @@ zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
if (error == 0) {
zc->zc_cred = (uintptr_t)cr;
zc->zc_dev = dev;
- error = zfs_ioc_vec[vec].zvec_secpolicy(zc->zc_name,
- zc->zc_prop_name, cr);
+ error = zfs_ioc_vec[vec].zvec_secpolicy(zc->zc_name, cr);
}
/*
@@ -1421,7 +1547,8 @@ static struct dev_ops zfs_dev_ops = {
};
static struct modldrv zfs_modldrv = {
- &mod_driverops, "ZFS storage pool version 1", &zfs_dev_ops
+ &mod_driverops, "ZFS storage pool version " ZFS_VERSION_STRING,
+ &zfs_dev_ops
};
static struct modlinkage modlinkage = {