diff options
Diffstat (limited to 'usr/src/uts/common/fs')
-rw-r--r-- | usr/src/uts/common/fs/zfs/dmu.c | 20 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/dsl_prop.c | 38 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/spa.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/zfs_acl.h | 10 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h | 48 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/zvol.h | 71 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_acl.c | 14 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_ctldir.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_ioctl.c | 553 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_vfsops.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zvol.c | 79 |
11 files changed, 530 insertions, 313 deletions
diff --git a/usr/src/uts/common/fs/zfs/dmu.c b/usr/src/uts/common/fs/zfs/dmu.c index 8db58a884d..81536337ed 100644 --- a/usr/src/uts/common/fs/zfs/dmu.c +++ b/usr/src/uts/common/fs/zfs/dmu.c @@ -1796,17 +1796,16 @@ dmu_object_size_from_db(dmu_buf_t *db, uint32_t *blksize, u_longlong_t *nblk512) * human-readable format. */ int -spa_bookmark_name(spa_t *spa, zbookmark_t *zb, char *dsname, size_t dslen, - char *objname, size_t objlen, char *range, size_t rangelen) +spa_bookmark_name(spa_t *spa, zbookmark_t *zb, nvlist_t *nvl) { dsl_pool_t *dp; dsl_dataset_t *ds = NULL; objset_t *os = NULL; dnode_t *dn = NULL; int err, shift; - - if (dslen < MAXNAMELEN || objlen < 32 || rangelen < 64) - return (ENOSPC); + char dsname[MAXNAMELEN]; + char objname[32]; + char range[64]; dp = spa_get_dsl(spa); if (zb->zb_objset != 0) { @@ -1832,9 +1831,9 @@ spa_bookmark_name(spa_t *spa, zbookmark_t *zb, char *dsname, size_t dslen, if (zb->zb_object == DMU_META_DNODE_OBJECT) { - (void) strncpy(objname, "mdn", objlen); + (void) strncpy(objname, "mdn", sizeof (objname)); } else { - (void) snprintf(objname, objlen, "%lld", + (void) snprintf(objname, sizeof (objname), "%lld", (longlong_t)zb->zb_object); } @@ -1844,10 +1843,15 @@ spa_bookmark_name(spa_t *spa, zbookmark_t *zb, char *dsname, size_t dslen, shift = (dn->dn_datablkshift?dn->dn_datablkshift:SPA_MAXBLOCKSHIFT) + zb->zb_level * (dn->dn_indblkshift - SPA_BLKPTRSHIFT); - (void) snprintf(range, rangelen, "%llu-%llu", + (void) snprintf(range, sizeof (range), "%llu-%llu", (u_longlong_t)(zb->zb_blkid << shift), (u_longlong_t)((zb->zb_blkid+1) << shift)); + if ((err = nvlist_add_string(nvl, ZPOOL_ERR_DATASET, dsname)) != 0 || + (err = nvlist_add_string(nvl, ZPOOL_ERR_OBJECT, objname)) != 0 || + (err = nvlist_add_string(nvl, ZPOOL_ERR_RANGE, range)) != 0) + goto out; + out: if (dn) dnode_rele(dn, FTAG); diff --git a/usr/src/uts/common/fs/zfs/dsl_prop.c b/usr/src/uts/common/fs/zfs/dsl_prop.c index 0ad81ed920..5c615dad92 100644 --- a/usr/src/uts/common/fs/zfs/dsl_prop.c +++ b/usr/src/uts/common/fs/zfs/dsl_prop.c @@ -67,10 +67,13 @@ dsl_prop_get_impl(dsl_dir_t *dd, const char *propname, int intsz, int numint, void *buf, char *setpoint) { int err = ENOENT; + zfs_prop_t prop; if (setpoint) setpoint[0] = '\0'; + prop = zfs_name_to_prop(propname); + /* * Note: dd may be NULL, therefore we shouldn't dereference it * ouside this loop. @@ -85,6 +88,13 @@ dsl_prop_get_impl(dsl_dir_t *dd, const char *propname, dsl_dir_name(dd, setpoint); break; } + + /* + * Break out of this loop for non-inheritable properties. + */ + if (prop != ZFS_PROP_INVAL && + !zfs_prop_inheritable(prop)) + break; } if (err == ENOENT) err = dodefault(propname, intsz, numint, buf); @@ -403,7 +413,8 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp) zap_attribute_t za; char setpoint[MAXNAMELEN]; char *tmp; - nvlist_t *prop; + nvlist_t *propval; + zfs_prop_t prop; if (dsl_dataset_is_snapshot(ds)) { VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); @@ -422,10 +433,19 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp) for (zap_cursor_init(&zc, mos, dd->dd_phys->dd_props_zapobj); (err = zap_cursor_retrieve(&zc, &za)) == 0; zap_cursor_advance(&zc)) { - if (nvlist_lookup_nvlist(*nvp, za.za_name, &prop) == 0) + /* + * Skip non-inheritable properties. + */ + if ((prop = zfs_name_to_prop(za.za_name)) != + ZFS_PROP_INVAL && !zfs_prop_inheritable(prop) && + dd != ds->ds_dir) + continue; + + if (nvlist_lookup_nvlist(*nvp, za.za_name, + &propval) == 0) continue; - VERIFY(nvlist_alloc(&prop, NV_UNIQUE_NAME, + VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); if (za.za_integer_length == 1) { /* @@ -440,7 +460,7 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp) kmem_free(tmp, za.za_num_integers); break; } - VERIFY(nvlist_add_string(prop, + VERIFY(nvlist_add_string(propval, ZFS_PROP_VALUE, tmp) == 0); kmem_free(tmp, za.za_num_integers); } else { @@ -448,15 +468,15 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp) * Integer property */ ASSERT(za.za_integer_length == 8); - (void) nvlist_add_uint64(prop, ZFS_PROP_VALUE, - za.za_first_integer); + (void) nvlist_add_uint64(propval, + ZFS_PROP_VALUE, za.za_first_integer); } - VERIFY(nvlist_add_string(prop, + VERIFY(nvlist_add_string(propval, ZFS_PROP_SOURCE, setpoint) == 0); VERIFY(nvlist_add_nvlist(*nvp, za.za_name, - prop) == 0); - nvlist_free(prop); + propval) == 0); + nvlist_free(propval); } zap_cursor_fini(&zc); diff --git a/usr/src/uts/common/fs/zfs/sys/spa.h b/usr/src/uts/common/fs/zfs/sys/spa.h index 829c025af2..4f2eb50d1f 100644 --- a/usr/src/uts/common/fs/zfs/sys/spa.h +++ b/usr/src/uts/common/fs/zfs/sys/spa.h @@ -439,8 +439,8 @@ extern int spa_get_errlog(spa_t *spa, void *uaddr, size_t *count); extern void spa_errlog_rotate(spa_t *spa); extern void spa_errlog_drain(spa_t *spa); extern void spa_errlog_sync(spa_t *spa, uint64_t txg); -extern int spa_bookmark_name(spa_t *spa, struct zbookmark *zb, char *ds, - size_t dsname, char *obj, size_t objname, char *range, size_t rangelen); +extern int spa_bookmark_name(spa_t *spa, struct zbookmark *zb, + nvlist_t *nvl); extern void spa_get_errlists(spa_t *spa, avl_tree_t *last, avl_tree_t *scrub); /* Initialization and termination */ diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_acl.h b/usr/src/uts/common/fs/zfs/sys/zfs_acl.h index 34057e83c9..e3a653c5fa 100644 --- a/usr/src/uts/common/fs/zfs/sys/zfs_acl.h +++ b/usr/src/uts/common/fs/zfs/sys/zfs_acl.h @@ -77,11 +77,11 @@ typedef struct zfs_acl { * whereas acl_inherit has secure instead of groupmask. */ -#define DISCARD 0 -#define NOALLOW 1 -#define GROUPMASK 2 -#define PASSTHROUGH 3 -#define SECURE 4 +#define ZFS_ACL_DISCARD 0 +#define ZFS_ACL_NOALLOW 1 +#define ZFS_ACL_GROUPMASK 2 +#define ZFS_ACL_PASSTHROUGH 3 +#define ZFS_ACL_SECURE 4 struct znode; diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h index a8f1f4ed89..b4f834e186 100644 --- a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h +++ b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h @@ -31,6 +31,7 @@ #include <sys/cred.h> #include <sys/dmu.h> #include <sys/zio.h> +#include <sys/zvol.h> #ifdef __cplusplus extern "C" { @@ -115,29 +116,29 @@ typedef struct zinject_record { typedef struct zfs_cmd { char zc_name[MAXPATHLEN]; - char zc_prop_name[MAXNAMELEN]; - char zc_prop_value[MAXPATHLEN]; - char zc_root[MAXPATHLEN]; - char zc_filename[MAXNAMELEN]; - uint32_t zc_intsz; - uint32_t zc_numints; + char zc_value[MAXPATHLEN]; uint64_t zc_guid; - uint64_t zc_config_src; /* really (char *) */ - uint64_t zc_config_src_size; - uint64_t zc_config_dst; /* really (char *) */ - uint64_t zc_config_dst_size; + uint64_t zc_nvlist_src; /* really (char *) */ + uint64_t zc_nvlist_src_size; + uint64_t zc_nvlist_dst; /* really (char *) */ + uint64_t zc_nvlist_dst_size; uint64_t zc_cookie; uint64_t zc_cred; uint64_t zc_dev; - uint64_t zc_volsize; - uint64_t zc_volblocksize; uint64_t zc_objset_type; dmu_objset_stats_t zc_objset_stats; + zvol_stats_t zc_vol_stats; struct drr_begin zc_begin_record; zinject_record_t zc_inject_record; zbookmark_t zc_bookmark; } zfs_cmd_t; +typedef struct zfs_create_data { + cred_t *zc_cred; + dev_t zc_dev; + nvlist_t *zc_props; +} zfs_create_data_t; + #define ZVOL_MAX_MINOR (1 << 16) #define ZFS_MIN_MINOR (ZVOL_MAX_MINOR + 1) @@ -145,30 +146,9 @@ typedef struct zfs_cmd { extern dev_info_t *zfs_dip; -extern int zfs_secpolicy_write(const char *dataset, const char *, cred_t *cr); +extern int zfs_secpolicy_write(const char *dataset, cred_t *cr); extern int zfs_busy(void); -extern int zvol_check_volsize(zfs_cmd_t *zc, uint64_t blocksize); -extern int zvol_check_volblocksize(zfs_cmd_t *zc); -extern int zvol_get_stats(zfs_cmd_t *zc, objset_t *os); -extern void zvol_create_cb(objset_t *os, void *arg, dmu_tx_t *tx); -extern int zvol_create_minor(zfs_cmd_t *zc); -extern int zvol_remove_minor(zfs_cmd_t *zc); -extern int zvol_set_volsize(zfs_cmd_t *zc); -extern int zvol_set_volblocksize(zfs_cmd_t *zc); -extern int zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr); -extern int zvol_close(dev_t dev, int flag, int otyp, cred_t *cr); -extern int zvol_strategy(buf_t *bp); -extern int zvol_read(dev_t dev, uio_t *uiop, cred_t *cr); -extern int zvol_write(dev_t dev, uio_t *uiop, cred_t *cr); -extern int zvol_aread(dev_t dev, struct aio_req *aio, cred_t *cr); -extern int zvol_awrite(dev_t dev, struct aio_req *aio, cred_t *cr); -extern int zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, - int *rvalp); -extern int zvol_busy(void); -extern void zvol_init(void); -extern void zvol_fini(void); - #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/common/fs/zfs/sys/zvol.h b/usr/src/uts/common/fs/zfs/sys/zvol.h new file mode 100644 index 0000000000..9ddbfc2e21 --- /dev/null +++ b/usr/src/uts/common/fs/zfs/sys/zvol.h @@ -0,0 +1,71 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_ZVOL_H +#define _SYS_ZVOL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/zfs_context.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct zvol_stats { + uint64_t zv_volsize; + uint64_t zv_volblocksize; +} zvol_stats_t; + +#ifdef _KERNEL +extern int zvol_check_volsize(uint64_t volsize, uint64_t blocksize); +extern int zvol_check_volblocksize(uint64_t volblocksize); +extern int zvol_get_stats(objset_t *os, zvol_stats_t *zvs); +extern void zvol_create_cb(objset_t *os, void *arg, dmu_tx_t *tx); +extern int zvol_create_minor(const char *, dev_t); +extern int zvol_remove_minor(const char *); +extern int zvol_set_volsize(const char *, dev_t, uint64_t); +extern int zvol_set_volblocksize(const char *, uint64_t); + +extern int zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr); +extern int zvol_close(dev_t dev, int flag, int otyp, cred_t *cr); +extern int zvol_strategy(buf_t *bp); +extern int zvol_read(dev_t dev, uio_t *uiop, cred_t *cr); +extern int zvol_write(dev_t dev, uio_t *uiop, cred_t *cr); +extern int zvol_aread(dev_t dev, struct aio_req *aio, cred_t *cr); +extern int zvol_awrite(dev_t dev, struct aio_req *aio, cred_t *cr); +extern int zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, + int *rvalp); +extern int zvol_busy(void); +extern void zvol_init(void); +extern void zvol_fini(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_ZVOL_H */ diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c index 310ff9c917..430625b84f 100644 --- a/usr/src/uts/common/fs/zfs/zfs_acl.c +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c @@ -788,7 +788,7 @@ zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp, } - if (zfsvfs->z_acl_mode == DISCARD) { + if (zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) { zfs_ace_remove(aclp, i); continue; } @@ -820,7 +820,7 @@ zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp, * This is only applicable when the acl_mode * property == groupmask. */ - if (zfsvfs->z_acl_mode == GROUPMASK) { + if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK) { reuse_deny = zfs_reuse_deny(acep, i); @@ -902,7 +902,7 @@ zfs_acl_chmod_setattr(znode_t *zp, uint64_t mode, dmu_tx_t *tx) static void zfs_securemode_update(zfsvfs_t *zfsvfs, ace_t *acep) { - if ((zfsvfs->z_acl_inherit == SECURE) && + if ((zfsvfs->z_acl_inherit == ZFS_ACL_SECURE) && (acep->a_type == ALLOW)) acep->a_access_mask &= ~SECURE_CLEAR; } @@ -924,10 +924,10 @@ zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp) i = j = 0; pace_cnt = paclp->z_acl_count; pacep = paclp->z_acl; - if (zfsvfs->z_acl_inherit != DISCARD) { + if (zfsvfs->z_acl_inherit != ZFS_ACL_DISCARD) { for (i = 0; i != pace_cnt; i++) { - if (zfsvfs->z_acl_inherit == NOALLOW && + if (zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW && pacep[i].a_type == ALLOW) continue; @@ -941,12 +941,12 @@ zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp) } aclp = zfs_acl_alloc(ace_cnt + OGE_PAD); - if (ace_cnt && zfsvfs->z_acl_inherit != DISCARD) { + if (ace_cnt && zfsvfs->z_acl_inherit != ZFS_ACL_DISCARD) { acep = aclp->z_acl; pacep = paclp->z_acl; for (i = 0; i != pace_cnt; i++) { - if (zfsvfs->z_acl_inherit == NOALLOW && + if (zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW && pacep[i].a_type == ALLOW) continue; diff --git a/usr/src/uts/common/fs/zfs/zfs_ctldir.c b/usr/src/uts/common/fs/zfs/zfs_ctldir.c index e890530701..cb0807aa56 100644 --- a/usr/src/uts/common/fs/zfs/zfs_ctldir.c +++ b/usr/src/uts/common/fs/zfs/zfs_ctldir.c @@ -513,7 +513,7 @@ zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from); if (err) return (err); - err = zfs_secpolicy_write(from, NULL, cr); + err = zfs_secpolicy_write(from, cr); if (err) return (err); @@ -558,7 +558,7 @@ zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr) err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname); if (err) return (err); - err = zfs_secpolicy_write(snapname, NULL, cr); + err = zfs_secpolicy_write(snapname, cr); if (err) return (err); 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 = { diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c index 5abaaa174f..04ada0c8d0 100644 --- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c @@ -1237,5 +1237,5 @@ static vfsdef_t vfw = { }; struct modlfs zfs_modlfs = { - &mod_fsops, "ZFS filesystem version 1", &vfw + &mod_fsops, "ZFS filesystem version " ZFS_VERSION_STRING, &vfw }; diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c index 66a8327b51..0b83bd7bd0 100644 --- a/usr/src/uts/common/fs/zfs/zvol.c +++ b/usr/src/uts/common/fs/zfs/zvol.c @@ -116,27 +116,27 @@ zvol_size_changed(zvol_state_t *zv, dev_t dev) } int -zvol_check_volsize(zfs_cmd_t *zc, uint64_t blocksize) +zvol_check_volsize(uint64_t volsize, uint64_t blocksize) { - if (zc->zc_volsize == 0) + if (volsize == 0) return (EINVAL); - if (zc->zc_volsize % blocksize != 0) + if (volsize % blocksize != 0) return (EINVAL); #ifdef _ILP32 - if (zc->zc_volsize - 1 > SPEC_MAXOFFSET_T) + if (volsize - 1 > SPEC_MAXOFFSET_T) return (EOVERFLOW); #endif return (0); } int -zvol_check_volblocksize(zfs_cmd_t *zc) +zvol_check_volblocksize(uint64_t volblocksize) { - if (zc->zc_volblocksize < SPA_MINBLOCKSIZE || - zc->zc_volblocksize > SPA_MAXBLOCKSIZE || - !ISP2(zc->zc_volblocksize)) + if (volblocksize < SPA_MINBLOCKSIZE || + volblocksize > SPA_MAXBLOCKSIZE || + !ISP2(volblocksize)) return (EDOM); return (0); @@ -151,12 +151,12 @@ zvol_readonly_changed_cb(void *arg, uint64_t newval) } int -zvol_get_stats(zfs_cmd_t *zc, objset_t *os) +zvol_get_stats(objset_t *os, zvol_stats_t *zvs) { int error; dmu_object_info_t doi; - error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &zc->zc_volsize); + error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &zvs->zv_volsize); if (error) return (error); @@ -164,7 +164,7 @@ zvol_get_stats(zfs_cmd_t *zc, objset_t *os) error = dmu_object_info(os, ZVOL_OBJ, &doi); if (error == 0) - zc->zc_volblocksize = doi.doi_data_block_size; + zvs->zv_volblocksize = doi.doi_data_block_size; return (error); } @@ -187,7 +187,7 @@ zvol_minor_alloc(void) } static zvol_state_t * -zvol_minor_lookup(char *name) +zvol_minor_lookup(const char *name) { minor_t minor; zvol_state_t *zv; @@ -208,10 +208,26 @@ zvol_minor_lookup(char *name) void zvol_create_cb(objset_t *os, void *arg, dmu_tx_t *tx) { - zfs_cmd_t *zc = arg; + zfs_create_data_t *zc = arg; int error; + uint64_t volblocksize, volsize; - error = dmu_object_claim(os, ZVOL_OBJ, DMU_OT_ZVOL, zc->zc_volblocksize, + VERIFY(nvlist_lookup_uint64(zc->zc_props, + zfs_prop_to_name(ZFS_PROP_VOLSIZE), &volsize) == 0); + if (nvlist_lookup_uint64(zc->zc_props, + zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &volblocksize) != 0) + volblocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); + + /* + * These properites must be removed from the list so the generic + * property setting step won't apply to them. + */ + VERIFY(nvlist_remove_all(zc->zc_props, + zfs_prop_to_name(ZFS_PROP_VOLSIZE)) == 0); + (void) nvlist_remove_all(zc->zc_props, + zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE)); + + error = dmu_object_claim(os, ZVOL_OBJ, DMU_OT_ZVOL, volblocksize, DMU_OT_NONE, 0, tx); ASSERT(error == 0); @@ -219,7 +235,7 @@ zvol_create_cb(objset_t *os, void *arg, dmu_tx_t *tx) DMU_OT_NONE, 0, tx); ASSERT(error == 0); - error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, &zc->zc_volsize, tx); + error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize, tx); ASSERT(error == 0); } @@ -284,10 +300,8 @@ zil_replay_func_t *zvol_replay_vector[TX_MAX_TYPE] = { * Create a minor node for the specified volume. */ int -zvol_create_minor(zfs_cmd_t *zc) +zvol_create_minor(const char *name, dev_t dev) { - char *name = zc->zc_name; - dev_t dev = zc->zc_dev; zvol_state_t *zv; objset_t *os; uint64_t volsize; @@ -377,7 +391,8 @@ zvol_create_minor(zfs_cmd_t *zc) return (EAGAIN); } - (void) ddi_prop_update_string(minor, zfs_dip, ZVOL_PROP_NAME, name); + (void) ddi_prop_update_string(minor, zfs_dip, ZVOL_PROP_NAME, + (char *)name); (void) sprintf(chrbuf, "%uc,raw", minor); @@ -431,14 +446,14 @@ zvol_create_minor(zfs_cmd_t *zc) * Remove minor node for the specified volume. */ int -zvol_remove_minor(zfs_cmd_t *zc) +zvol_remove_minor(const char *name) { zvol_state_t *zv; char namebuf[30]; mutex_enter(&zvol_state_lock); - if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) { + if ((zv = zvol_minor_lookup(name)) == NULL) { mutex_exit(&zvol_state_lock); return (ENXIO); } @@ -472,23 +487,23 @@ zvol_remove_minor(zfs_cmd_t *zc) } int -zvol_set_volsize(zfs_cmd_t *zc) +zvol_set_volsize(const char *name, dev_t dev, uint64_t volsize) { zvol_state_t *zv; - dev_t dev = zc->zc_dev; dmu_tx_t *tx; int error; dmu_object_info_t doi; mutex_enter(&zvol_state_lock); - if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) { + if ((zv = zvol_minor_lookup(name)) == NULL) { mutex_exit(&zvol_state_lock); return (ENXIO); } if ((error = dmu_object_info(zv->zv_objset, ZVOL_OBJ, &doi)) != 0 || - (error = zvol_check_volsize(zc, doi.doi_data_block_size)) != 0) { + (error = zvol_check_volsize(volsize, + doi.doi_data_block_size)) != 0) { mutex_exit(&zvol_state_lock); return (error); } @@ -500,7 +515,7 @@ zvol_set_volsize(zfs_cmd_t *zc) tx = dmu_tx_create(zv->zv_objset); dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL); - dmu_tx_hold_free(tx, ZVOL_OBJ, zc->zc_volsize, DMU_OBJECT_END); + dmu_tx_hold_free(tx, ZVOL_OBJ, volsize, DMU_OBJECT_END); error = dmu_tx_assign(tx, TXG_WAIT); if (error) { dmu_tx_abort(tx); @@ -509,16 +524,16 @@ zvol_set_volsize(zfs_cmd_t *zc) } error = zap_update(zv->zv_objset, ZVOL_ZAP_OBJ, "size", 8, 1, - &zc->zc_volsize, tx); + &volsize, tx); if (error == 0) { - error = dmu_free_range(zv->zv_objset, ZVOL_OBJ, zc->zc_volsize, + error = dmu_free_range(zv->zv_objset, ZVOL_OBJ, volsize, DMU_OBJECT_END, tx); } dmu_tx_commit(tx); if (error == 0) { - zv->zv_volsize = zc->zc_volsize; + zv->zv_volsize = volsize; zvol_size_changed(zv, dev); } @@ -528,7 +543,7 @@ zvol_set_volsize(zfs_cmd_t *zc) } int -zvol_set_volblocksize(zfs_cmd_t *zc) +zvol_set_volblocksize(const char *name, uint64_t volblocksize) { zvol_state_t *zv; dmu_tx_t *tx; @@ -536,7 +551,7 @@ zvol_set_volblocksize(zfs_cmd_t *zc) mutex_enter(&zvol_state_lock); - if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) { + if ((zv = zvol_minor_lookup(name)) == NULL) { mutex_exit(&zvol_state_lock); return (ENXIO); } @@ -553,7 +568,7 @@ zvol_set_volblocksize(zfs_cmd_t *zc) dmu_tx_abort(tx); } else { error = dmu_object_set_blocksize(zv->zv_objset, ZVOL_OBJ, - zc->zc_volblocksize, 0, tx); + volblocksize, 0, tx); if (error == ENOTSUP) error = EBUSY; dmu_tx_commit(tx); |