zfs_ioctl.c revision b693757a2e07699c354cbc85e1ab83b588553262
/*
* 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
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/zfs_ioctl.h>
#include <sys/zfs_znode.h>
#include <sys/spa_impl.h>
#include <sys/vdev_impl.h>
#include <sys/dsl_dataset.h>
#include <sys/dsl_prop.h>
#include <sys/dsl_deleg.h>
#include <sys/dmu_objset.h>
#include <sys/pathname.h>
#include <sys/zfs_ctldir.h>
#include <sys/dmu_objset.h>
#include "zfs_namecheck.h"
#include "zfs_prop.h"
#include "zfs_deleg.h"
extern struct modlfs zfs_modlfs;
extern void zfs_init(void);
extern void zfs_fini(void);
typedef int zfs_ioc_func_t(zfs_cmd_t *);
typedef enum {
typedef struct zfs_ioc_vec {
/* This array is indexed by zfs_userquota_prop_t */
static const char *userquota_perms[] = {
};
boolean_t *);
int zfs_set_prop_nvlist(const char *, nvlist_t *);
/* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */
void
{
const char *newfile;
char buf[256];
/*
* Get rid of annoying "../common/" prefix to filename.
*/
} else {
}
/*
* To get this data, use the zfs-dprintf probe as so:
* dtrace -q -n 'zfs-dprintf \
* /stringof(arg0) == "dbuf.c"/ \
* {printf("%s: %s", stringof(arg1), stringof(arg3))}'
* arg0 = file name
* arg1 = function name
* arg2 = line number
* arg3 = message
*/
}
static void
history_str_free(char *buf)
{
}
static char *
{
char *buf;
return (NULL);
return (NULL);
}
return (buf);
}
/*
* Check to see if the named dataset is currently defined as bootable
*/
static boolean_t
zfs_is_bootfs(const char *name)
{
return (ret);
}
return (B_FALSE);
}
/*
* zfs_earlier_version
*
* Return non-zero if the spa version is less than requested version.
*/
static int
{
return (1);
}
}
return (0);
}
/*
* zpl_earlier_version
*
* Return TRUE if the ZPL version is less than requested version.
*/
static boolean_t
{
return (B_TRUE);
}
/* XXX reading from non-owned objset */
}
return (rc);
}
static void
{
char *buf;
return;
}
}
/*
* Policy for top-level read operations (list pools). Requires no privileges,
* and can be used in the local zone, as there is no associated dataset.
*/
/* ARGSUSED */
static int
{
return (0);
}
/*
* Policy for dataset read operations (list children, get statistics). Requires
* no privileges, but must be visible in the local zone.
*/
/* ARGSUSED */
static int
{
if (INGLOBALZONE(curproc) ||
return (0);
return (ENOENT);
}
static int
{
int writable = 1;
/*
* The dataset must be visible by this zone -- check this first
* so they don't see EPERM on something they shouldn't know about.
*/
if (!INGLOBALZONE(curproc) &&
return (ENOENT);
return (ENOENT);
if (INGLOBALZONE(curproc)) {
/*
* If the fs is zoned, only root can access it from the
* global zone.
*/
return (EPERM);
} else {
/*
* If we are in a local zone, the 'zoned' property must be set.
*/
if (!zoned)
return (EPERM);
/* must be writable by this zone */
if (!writable)
return (EPERM);
}
return (0);
}
int
{
int error;
if (error == 0) {
if (error)
}
return (error);
}
static int
{
/*
* 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;
case ZFS_PROP_QUOTA:
if (!INGLOBALZONE(curproc)) {
char setpoint[MAXNAMELEN];
/*
* Unprivileged users are allowed to modify the
* quota on things *under* (ie. contained by)
* the thing they own.
*/
setpoint))
return (EPERM);
return (EPERM);
}
break;
}
}
int
{
int error;
if (error)
return (error);
/*
* permission to set permissions will be evaluated later in
* dsl_deleg_can_allow()
*/
return (0);
}
int
{
}
int
{
}
static int
{
int error;
return (error);
/* Now make sure mntpnt and dataset are ZFS */
return (EPERM);
}
}
int
{
if (!INGLOBALZONE(curproc))
return (EPERM);
if (secpolicy_nfs(cr) == 0) {
return (0);
} else {
}
}
int
{
if (!INGLOBALZONE(curproc))
return (EPERM);
if (secpolicy_smb(cr) == 0) {
return (0);
} else {
}
}
static int
{
char *cp;
/*
* Remove the @bla or /bla from the end of the name to get the parent.
*/
cp[0] = '\0';
} else {
return (ENOENT);
cp[0] = '\0';
}
return (0);
}
int
{
int error;
ZFS_DELEG_PERM_MOUNT, cr)) != 0)
return (error);
}
static int
{
}
/*
* Must have sys_config privilege to check the iscsi permission
*/
/* ARGSUSED */
static int
{
return (secpolicy_zfs(cr));
}
int
{
char parentname[MAXNAMELEN];
int error;
ZFS_DELEG_PERM_RENAME, cr)) != 0)
return (error);
ZFS_DELEG_PERM_MOUNT, cr)) != 0)
return (error);
sizeof (parentname))) != 0)
return (error);
ZFS_DELEG_PERM_CREATE, cr)) != 0)
return (error);
ZFS_DELEG_PERM_MOUNT, cr)) != 0)
return (error);
return (error);
}
static int
{
}
static int
{
char parentname[MAXNAMELEN];
int error;
if (error)
return (error);
if (error == 0) {
if (error) {
return (error);
}
if (error == 0)
}
return (error);
}
static int
{
int error;
ZFS_DELEG_PERM_RECEIVE, cr)) != 0)
return (error);
ZFS_DELEG_PERM_MOUNT, cr)) != 0)
return (error);
}
int
{
return (zfs_secpolicy_write_perms(name,
}
static int
{
}
static int
{
char parentname[MAXNAMELEN];
int error;
sizeof (parentname))) != 0)
return (error);
ZFS_DELEG_PERM_CLONE, cr)) != 0)
return (error);
}
ZFS_DELEG_PERM_CREATE, cr)) != 0)
return (error);
return (error);
}
static int
{
int error;
if (error) {
}
return (error);
}
/*
* SYS_CONFIG privilege, which is not available in a local zone.
*/
/* ARGSUSED */
static int
{
return (EPERM);
return (0);
}
/*
* Policy for fault injection. Requires all privileges.
*/
/* ARGSUSED */
static int
{
return (secpolicy_zinject(cr));
}
static int
{
if (prop == ZPROP_INVAL) {
return (EINVAL);
} else {
if (!zfs_prop_inheritable(prop))
return (EINVAL);
}
}
static int
{
if (err)
return (err);
return (EINVAL);
/*
* themself, allow it.
*/
return (0);
} else {
return (0);
}
}
}
static int
{
if (err)
return (err);
return (EINVAL);
}
static int
{
}
static int
{
}
static int
{
}
/*
* Returns the nvlist as specified by the user in the zfs_cmd_t.
*/
static int
{
char *packed;
int error;
/*
* Read in and unpack the user-supplied nvlist.
*/
if (size == 0)
return (EINVAL);
iflag)) != 0) {
return (error);
}
return (error);
}
return (0);
}
static int
{
int error;
} else {
KM_SLEEP) == 0);
}
return (error);
}
static int
{
int error;
if (error)
return (error);
return (EINVAL);
}
if (*zvp) {
} else {
}
return (error);
}
/*
* Find a zfsvfs_t for a mounted filesystem, or create our own, in which
* case its z_vfs will be NULL, and it will be opened as the owner.
*/
static int
{
int error = 0;
if (error == 0) {
if ((*zvp)->z_unmounted) {
/*
* XXX we could probably try again, since the unmounting
* thread should be just about to disassociate the
* objset from the zfsvfs.
*/
return (EBUSY);
}
}
return (error);
}
static void
{
} else {
}
}
static int
{
int error;
char *buf;
return (error);
return (error);
}
if (props) {
(void) nvlist_lookup_uint64(props,
goto pool_props_bad;
}
if (nvl) {
if (error != 0) {
return (error);
}
}
if (error)
goto pool_props_bad;
}
/*
* Set the remaining root properties
*/
if (!error &&
return (error);
}
static int
{
int error;
if (error == 0)
return (error);
}
static int
{
int error;
return (error);
return (error);
}
props);
else
if (props)
return (error);
}
static int
{
int error;
if (error == 0)
return (error);
}
static int
{
int error;
return (EEXIST);
return (error);
}
static int
{
int error;
int ret = 0;
/*
* The config may be present even if 'error' is non-zero.
* In this case we return success, and preserve the real errno
* in 'zc_cookie'.
*/
} else {
}
return (ret);
}
/*
* Try to import the given pool, returning pool stats as appropriate so that
* user land knows which devices are available and overall pool health.
*/
static int
{
int error;
return (error);
return (EINVAL);
return (error);
}
static int
{
int error;
return (error);
return (error);
}
static int
{
int error;
if (error == 0) {
}
return (error);
}
static int
{
int error;
return (error);
return (EINVAL);
}
return (error);
}
static int
{
char *hist_buf;
int error;
return (EINVAL);
return (error);
return (ENOTSUP);
}
}
return (error);
}
static int
{
int error;
return (error);
return (0);
}
/*
* inputs:
* zc_name name of filesystem
* zc_obj object to find
*
* outputs:
* zc_value name of object
*/
static int
{
int error;
/* XXX reading from objset not owned */
return (error);
return (EINVAL);
}
return (error);
}
static int
{
int error;
if (error != 0)
return (error);
/*
* A root pool with concatenated devices is not supported.
* Thus, can not add a device to a root pool.
*
* Intent log device can not be added to a rootpool because
* during mountroot, zil is replayed, a seperated log device
* can not be accessed during the mountroot time.
*
* l2cache and spare devices are ok to be added to a rootpool.
*/
return (EDOM);
}
if (error == 0) {
}
return (error);
}
static int
{
int error;
if (error != 0)
return (error);
return (error);
}
static int
{
int error;
return (error);
if (nslock)
case VDEV_STATE_ONLINE:
break;
case VDEV_STATE_OFFLINE:
break;
case VDEV_STATE_FAULTED:
break;
case VDEV_STATE_DEGRADED:
break;
default:
}
if (nslock)
return (error);
}
static int
{
int error;
return (error);
}
return (error);
}
static int
{
int error;
return (error);
return (error);
}
static int
{
int error;
if (error != 0)
return (error);
return (error);
}
static int
{
int error;
if (error != 0)
return (error);
return (error);
}
/*
* inputs:
* zc_name name of filesystem
* zc_nvlist_dst_size size of buffer for property nvlist
*
* outputs:
* zc_objset_stats stats
* zc_nvlist_dst property nvlist
* zc_nvlist_dst_size size of property nvlist
*/
static int
{
int error;
return (error);
if (zc->zc_nvlist_dst != 0 &&
/*
* NB: zvol_get_stats() will read the objset contents,
* which we aren't supposed to do with a
* DS_MODE_USER hold, because it could be
* inconsistent. So this is a bit of a workaround...
* XXX reading with out owning
*/
}
}
return (error);
}
static int
{
int error;
/*
* zfs_get_zplprop() will either find a value or give us
* the default value (if there is one).
*/
return (error);
return (0);
}
/*
* inputs:
* zc_name name of filesystem
* zc_nvlist_dst_size size of buffer for zpl property nvlist
*
* outputs:
* zc_nvlist_dst zpl property nvlist
* zc_nvlist_dst_size size of zpl property nvlist
*/
static int
{
int err;
/* XXX reading without owning */
return (err);
/*
* NB: nvl_add_zplprop() will read the objset contents,
* which we aren't supposed to do with a DS_MODE_USER
* hold, because it could be inconsistent.
*/
} else {
}
return (err);
}
static boolean_t
dataset_name_hidden(const char *name)
{
/*
* Skip over datasets that are not visible in this zone,
* internal datasets (which have a $ in their name), and
* temporary datasets (which have a % in their name).
*/
return (B_TRUE);
return (B_TRUE);
return (B_TRUE);
return (B_FALSE);
}
/*
* inputs:
* zc_name name of filesystem
* zc_cookie zap cursor
* zc_nvlist_dst_size size of buffer for property nvlist
*
* outputs:
* zc_name name of next filesystem
* zc_cookie zap cursor
* zc_objset_stats stats
* zc_nvlist_dst property nvlist
* zc_nvlist_dst_size size of property nvlist
*/
static int
{
int error;
char *p;
return (error);
}
/*
* Pre-fetch the datasets. dmu_objset_prefetch() always returns 0
* but is not declared void because its called by dmu_objset_find().
*/
(void) dmu_objset_prefetch(p, NULL);
}
do {
/*
* If it's an internal dataset (ie. with a '$' in its name),
* don't try to get stats for it, otherwise we'll return ENOENT.
*/
return (error);
}
/*
* inputs:
* zc_name name of filesystem
* zc_cookie zap cursor
* zc_nvlist_dst_size size of buffer for property nvlist
*
* outputs:
* zc_name name of next snapshot
* zc_objset_stats stats
* zc_nvlist_dst property nvlist
* zc_nvlist_dst_size size of property nvlist
*/
static int
{
int error;
if (error)
/*
* A dataset name of maximum length cannot have any snapshots,
* so exit immediately.
*/
return (ESRCH);
}
if (error == 0)
/* if we failed, undo the @ that we tacked on to zc_name */
if (error)
return (error);
}
int
{
int error = 0;
char *strval;
/*
* First validate permission to set all of the properties
*/
if (prop == ZPROP_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) &&
return (error);
continue;
}
const char *perm;
const char *up = zfs_userquota_prop_prefixes
else
return (error);
continue;
}
return (EINVAL);
}
if (issnap)
return (EINVAL);
return (error);
/*
* Check that this value is valid for this pool version
*/
switch (prop) {
case ZFS_PROP_COMPRESSION:
/*
* If the user specified gzip compression, make sure
* the SPA supports it. We ignore any errors here since
* we'll catch them later.
*/
if (intval >= ZIO_COMPRESS_GZIP_1 &&
intval <= ZIO_COMPRESS_GZIP_9 &&
return (ENOTSUP);
/*
* If this is a bootable dataset then
* verify that the compression algorithm
* is supported for booting. We must return
* something other than ENOTSUP since it
* implies a downrev pool version.
*/
if (zfs_is_bootfs(name) &&
return (ERANGE);
}
break;
case ZFS_PROP_COPIES:
return (ENOTSUP);
break;
case ZFS_PROP_SHARESMB:
return (ENOTSUP);
break;
case ZFS_PROP_ACLINHERIT:
if (intval == ZFS_ACL_PASSTHROUGH_X &&
return (ENOTSUP);
}
}
if (prop == ZPROP_INVAL) {
if (zfs_prop_userquota(propname)) {
unsigned int vallen;
const char *domain;
if (error == 0) {
}
if (error == 0)
continue;
else
goto out;
} else if (zfs_prop_user(propname)) {
if (error == 0)
continue;
else
goto out;
}
}
switch (prop) {
case ZFS_PROP_QUOTA:
goto out;
break;
case ZFS_PROP_REFQUOTA:
goto out;
break;
case ZFS_PROP_RESERVATION:
intval)) != 0)
goto out;
break;
case ZFS_PROP_REFRESERVATION:
intval)) != 0)
goto out;
break;
case ZFS_PROP_VOLSIZE:
goto out;
break;
case ZFS_PROP_VERSION:
{
goto out;
goto out;
(void) zfs_ioc_userspace_upgrade(&zc);
}
if (error)
goto out;
break;
}
default:
if (zfs_prop_get_type(prop) !=
goto out;
}
const char *unused;
switch (zfs_prop_get_type(prop)) {
case PROP_TYPE_NUMBER:
break;
case PROP_TYPE_STRING:
goto out;
case PROP_TYPE_INDEX:
goto out;
}
break;
default:
"unknown property type");
break;
}
} else {
goto out;
}
goto out;
}
}
}
out:
return (error);
}
/*
* Check that all the properties are valid user properties.
*/
static int
{
int error = 0;
char *valstr;
if (!zfs_prop_user(propname) ||
return (EINVAL);
return (error);
return (ENAMETOOLONG);
return (E2BIG);
}
return (0);
}
/*
* inputs:
* zc_name name of filesystem
* zc_value name of property to set
* zc_nvlist_src{_size} nvlist of properties to apply
* zc_cookie clear existing local props?
*
* outputs: none
*/
static int
{
int error;
return (error);
}
}
}
return (error);
}
/*
* inputs:
* zc_name name of filesystem
* zc_value name of property to inherit
*
* outputs: none
*/
static int
{
/* the property name has been validated by zfs_secpolicy_inherit() */
}
static int
{
int error;
return (error);
/*
* If the only property is the configfile, then just do a spa_lookup()
* to handle the faulted case.
*/
zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 &&
}
return (0);
}
}
return (error);
}
return (error);
}
static int
{
int error;
/*
* If the pool is faulted, there may be properties we can still
* get (such as altroot and cachefile), so attempt to get them
* anyway.
*/
} else {
}
else
return (error);
}
static int
{
int error;
return (error);
}
ZFS_DELEG_PERM_UID, &uid)) != 0) {
return (EPERM);
}
ZFS_DELEG_PERM_GID, &gid)) != 0) {
return (EPERM);
}
return (EPERM);
}
return (EPERM);
}
return (error);
}
/*
* inputs:
* zc_name name of filesystem
* zc_nvlist_src{_size} nvlist of delegated permissions
*
* outputs: none
*/
static int
{
int error;
return (error);
/*
* Verify nvlist is constructed correctly
*/
return (EINVAL);
}
/*
* If we don't have PRIV_SYS_MOUNT, then validate
* that user is allowed to hand out each permission in
* the nvlist(s)
*/
if (error) {
} else {
}
}
if (error == 0)
return (error);
}
/*
* inputs:
* zc_name name of filesystem
*
* outputs:
* zc_nvlist_src{_size} nvlist of delegated permissions
*/
static int
{
int error;
}
return (error);
}
/*
* Search the vfs list for a specified resource. Returns a pointer to it
* or NULL if no suitable entry is found. The caller of this routine
* is responsible for releasing the returned vfs pointer.
*/
static vfs_t *
zfs_get_vfs(const char *resource)
{
do {
break;
}
return (vfs_found);
}
/* ARGSUSED */
static void
{
}
/*
* inputs:
* createprops list of properties requested by creator
* default_zplver zpl version to use if unspecified in createprops
* fuids_ok fuids allowed in this version of the spa?
* os parent objset pointer (NULL if root fs)
*
* outputs:
* zplprops values for the zplprops we attach to the master node object
* is_ci true if requested file system will be purely case-insensitive
*
* Determine the settings for utf8only, normalization and
* casesensitivity. Specific values may have been requested by the
* the file system is of too early a vintage, a creator can not
* request settings for these properties, even if the requested
* setting is the default value. We don't actually want to create dsl
* properties for these, so remove them from the source nvlist after
* processing.
*/
static int
{
/*
* Pull out creator prop choices, if any.
*/
if (createprops) {
(void) nvlist_lookup_uint64(createprops,
(void) nvlist_lookup_uint64(createprops,
(void) nvlist_remove_all(createprops,
(void) nvlist_lookup_uint64(createprops,
(void) nvlist_remove_all(createprops,
(void) nvlist_lookup_uint64(createprops,
(void) nvlist_remove_all(createprops,
}
/*
* If the zpl version requested is whacky or the file system
* or pool is version is too "young" to support normalization
* and the creator tried to set a value for one of the props,
* error out.
*/
sense != ZFS_PROP_UNDEFINED)))
return (ENOTSUP);
/*
* Put the version in the zplprops
*/
if (norm == ZFS_PROP_UNDEFINED)
/*
* If we're normalizing, names must always be valid UTF-8 strings.
*/
if (norm)
u8 = 1;
if (u8 == ZFS_PROP_UNDEFINED)
if (sense == ZFS_PROP_UNDEFINED)
if (is_ci)
return (0);
}
static int
{
char parentname[MAXNAMELEN];
char *cp;
int error;
cp[0] = '\0';
}
/*
* Open parent object set so we can inherit zplprop values.
*/
return (error);
return (error);
}
static int
{
int error;
if (spa_vers < SPA_VERSION_FUID) {
}
return (error);
}
/*
* inputs:
* zc_objset_type type of objset to create (fs vs zvol)
* zc_name name of new objset
* zc_value name of snapshot to clone from (may be empty)
* zc_nvlist_src{_size} nvlist of properties to apply
*
* outputs: none
*/
static int
{
int error = 0;
switch (type) {
case DMU_OST_ZFS:
break;
case DMU_OST_ZVOL:
break;
default:
break;
}
return (EINVAL);
return (error);
/*
* We're creating a clone of an existing snapshot.
*/
return (EINVAL);
}
if (error) {
return (error);
}
if (error) {
return (error);
}
} else {
return (EINVAL);
}
if (type == DMU_OST_ZVOL) {
&volsize) != 0) {
return (EINVAL);
}
return (EINVAL);
}
if (error != 0)
if ((error = zvol_check_volblocksize(
volblocksize)) != 0 ||
volblocksize)) != 0) {
return (error);
}
} else if (type == DMU_OST_ZFS) {
int error;
/*
* We have to have normalization and
* case-folding flags correct when we do the
* file system creation, so go figure them out
* now.
*/
NV_UNIQUE_NAME, KM_SLEEP) == 0);
if (error != 0) {
return (error);
}
}
}
/*
* It would be nice to do this atomically.
*/
if (error == 0) {
}
return (error);
}
/*
* inputs:
* zc_name name of filesystem
* zc_value short name of snapshot
* zc_cookie recursive flag
* zc_nvlist_src[_size] property list
*
* outputs:
* zc_value short snapname (i.e. part after the '@')
*/
static int
{
int error;
return (EINVAL);
return (error);
if (error)
goto out;
goto out;
}
out:
return (error);
}
int
{
if (arg) {
}
if (vfsp) {
/*
* Always force the unmount for snapshots.
*/
int err;
return (err);
}
return (err);
}
return (0);
}
/*
* inputs:
* zc_name name of filesystem
* zc_value short name of snapshot
* zc_defer_destroy mark for deferred destroy
*
* outputs: none
*/
static int
{
int err;
return (EINVAL);
if (err)
return (err);
zc->zc_defer_destroy));
}
/*
* inputs:
* zc_name name of dataset to destroy
* zc_objset_type type of objset
* zc_defer_destroy mark for deferred destroy
*
* outputs: none
*/
static int
{
int err;
if (err)
return (err);
}
return (err);
}
/*
* inputs:
* zc_name name of dataset to rollback (to most recent snapshot)
*
* outputs: none
*/
static int
{
int error;
char *clone_name;
if (error)
return (error);
/* must not be a snapshot */
if (dsl_dataset_is_snapshot(ds)) {
return (EINVAL);
}
/* must have a most recent snapshot */
return (EINVAL);
}
/*
* Create clone of most recent snapshot.
*/
if (error)
goto out;
if (error)
goto out;
/*
* Do clone swap.
*/
if (error == 0) {
int resume_err;
B_TRUE);
} else {
}
}
} else {
} else {
}
}
/*
* Destroy clone (which also closes it).
*/
out:
if (ds)
return (error);
}
/*
* inputs:
* zc_name old name of dataset
* zc_value new name of dataset
* zc_cookie recursive flag (only valid for snapshots)
*
* outputs: none
*/
static int
{
return (EINVAL);
/*
* Unmount snapshot unless we're doing a recursive rename,
* in which case the dataset code figures out which snapshots
* to unmount.
*/
if (err)
return (err);
}
}
static void
{
return;
continue;
(void) zfs_ioc_inherit_prop(zc);
}
}
/*
* inputs:
* zc_name name of containing filesystem
* zc_nvlist_src{_size} nvlist of properties to apply
* zc_value name of snapshot to create
* zc_string name of clone origin (if DRR_FLAG_CLONE)
* zc_cookie file descriptor to recv from
* zc_begin_record the BEGIN record of the stream (not byteswapped)
* zc_guid force flag
*
* outputs:
* zc_cookie number of bytes read
*/
static int
{
char *tosnap;
char tofs[ZFS_MAXNAMELEN];
return (EINVAL);
*tosnap = '\0';
tosnap++;
return (error);
return (EBADF);
}
/*
* If new properties are supplied, they are to completely
* replace the existing ones, so stash away the existing ones.
*/
}
if (error)
goto out;
}
if (origin)
if (error)
goto out;
/*
* Reset properties. We do this before we receive the stream
* so that the properties are applied to the new data.
*/
if (props) {
/*
* XXX - Note, this is all-or-nothing; should be best-effort.
*/
}
if (error == 0) {
/* online recv */
int end_err;
/*
* If the suspend fails, then the recv_end will
* likely also fail, and clean up after itself.
*/
if (error == 0) {
int resume_err =
}
} else {
}
}
/*
* On error, restore the original props.
*/
}
out:
return (error);
}
/*
* inputs:
* zc_name name of snapshot to send
* zc_value short name of incremental fromsnap (may be empty)
* zc_cookie file descriptor to send stream to
* zc_obj fromorigin flag (mutually exclusive with zc_value)
*
* outputs: none
*/
static int
{
int error;
if (error)
return (error);
char *buf;
char *cp;
if (cp)
*(cp+1) = 0;
if (error) {
return (error);
}
}
if (fromsnap)
return (EBADF);
}
if (fromsnap)
return (error);
}
static int
{
&zc->zc_inject_record);
if (error == 0)
return (error);
}
static int
{
}
static int
{
int error;
&zc->zc_inject_record);
return (error);
}
static int
{
int error;
return (error);
&count);
if (error == 0)
else
return (error);
}
static int
{
int error;
/*
* On zpool clear we also fix up missing slogs
*/
return (EIO);
}
}
return (error);
} else {
return (ENODEV);
}
}
/*
*/
if (zio_resume(spa) != 0)
return (error);
}
/*
* inputs:
* zc_name name of filesystem
* zc_value name of origin snapshot
*
* outputs:
* zc_string name of conflicting snapshot, if there is one
*/
static int
{
char *cp;
/*
* We don't need to unmount *all* the origin fs's snapshots, but
* it's easier.
*/
if (cp)
*cp = '\0';
}
/*
* Retrieve a single {user|group}{used|quota}@... property.
*
* inputs:
* zc_name name of filesystem
* zc_objset_type zfs_userquota_prop_t
* zc_value domain name (eg. "S-1-234-567-89")
*
* outputs:
* zc_cookie property value
*/
static int
{
int error;
return (EINVAL);
if (error)
return (error);
return (error);
}
/*
* inputs:
* zc_name name of filesystem
* zc_cookie zap cursor
* zc_objset_type zfs_userquota_prop_t
* zc_nvlist_dst[_size] buffer to fill (not really an nvlist)
*
* outputs:
* zc_nvlist_dst[_size] data buffer (array of zfs_useracct_t)
* zc_cookie zap cursor
*/
static int
{
int error;
if (error)
return (error);
if (error == 0) {
}
return (error);
}
/*
* inputs:
* zc_name name of filesystem
*
* outputs:
* none
*/
static int
{
int error;
/*
* If userused is not enabled, it may be because the
* objset needs to be closed & reopened (to grow the
*/
if (error == 0)
}
if (error == 0)
} else {
/* XXX kind of reading contents without owning */
if (error)
return (error);
}
return (error);
}
/*
* We don't want to have a hard dependency
* against some special symbols in sharefs
* nfs, and smbsrv. Determine them if needed when
* the first file system is shared.
* Neither sharefs, nfs or smbsrv are unloadable modules.
*/
int (*znfsexport_fs)(void *arg);
int zfs_nfsshare_inited;
int zfs_smbshare_inited;
static int
{
int error;
/* Both NFS and SMB shares also require sharetab support. */
ddi_modopen("fs/sharefs",
return (ENOSYS);
}
return (ENOSYS);
}
return (0);
}
static int
{
int error;
int opcode;
case ZFS_SHARE_NFS:
case ZFS_UNSHARE_NFS:
if (zfs_nfsshare_inited == 0) {
return (ENOSYS);
}
if (znfsexport_fs == NULL &&
((znfsexport_fs = (int (*)(void *))
return (ENOSYS);
}
error = zfs_init_sharefs();
if (error) {
return (ENOSYS);
}
zfs_nfsshare_inited = 1;
}
break;
case ZFS_SHARE_SMB:
case ZFS_UNSHARE_SMB:
if (zfs_smbshare_inited == 0) {
ddi_modopen("drv/smbsrv",
return (ENOSYS);
}
return (ENOSYS);
}
error = zfs_init_sharefs();
if (error) {
return (ENOSYS);
}
zfs_smbshare_inited = 1;
}
break;
default:
return (EINVAL);
}
case ZFS_SHARE_NFS:
case ZFS_UNSHARE_NFS:
if (error =
znfsexport_fs((void *)
return (error);
break;
case ZFS_SHARE_SMB:
case ZFS_UNSHARE_SMB:
if (error = zsmbexport_fs((void *)
return (error);
}
break;
}
/*
* Add or remove share from sharetab
*/
return (error);
}
ace_t full_access[] = {
};
/*
* Remove all ACL files in shares dir
*/
static int
{
int error;
zap_cursor_advance(&zc)) {
NULL, 0)) != 0)
break;
}
return (error);
}
static int
{
int error = 0;
return (error);
/* Now make sure mntpnt and dataset are ZFS */
return (EINVAL);
}
/*
* Create share dir if its missing.
*/
if (zfsvfs->z_shares_dir == 0) {
if (error) {
} else {
}
if (error) {
return (error);
}
}
return (error);
}
case ZFS_SMB_ACL_ADD:
if (resourcevp)
break;
case ZFS_SMB_ACL_REMOVE:
NULL, 0);
break;
case ZFS_SMB_ACL_RENAME:
return (error);
}
&target)) {
return (error);
}
break;
case ZFS_SMB_ACL_PURGE:
break;
default:
break;
}
return (error);
}
/*
* inputs:
* zc_name name of filesystem
* zc_value short name of snap
* zc_string user-supplied tag for this reference
* zc_cookie recursive flag
* zc_temphold set if hold is temporary
*
* outputs: none
*/
static int
{
return (EINVAL);
}
/*
* inputs:
* zc_name name of dataset from which we're releasing a user reference
* zc_value short name of snap
* zc_string user-supplied tag for this reference
* zc_cookie recursive flag
*
* outputs: none
*/
static int
{
return (EINVAL);
}
/*
* inputs:
* zc_name name of filesystem
*
* outputs:
* zc_nvlist_src{_size} nvlist of snapshot holds
*/
static int
{
int error;
}
return (error);
}
/*
* pool create, destroy, and export don't log the history as part of
* zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export
* do the logging of those commands.
*/
static zfs_ioc_vec_t zfs_ioc_vec[] = {
B_FALSE },
B_FALSE },
B_FALSE },
B_FALSE },
B_FALSE },
B_FALSE },
B_FALSE },
B_TRUE },
B_FALSE },
B_TRUE },
B_FALSE },
B_TRUE },
B_TRUE },
B_FALSE },
B_TRUE },
B_TRUE },
B_TRUE },
B_TRUE },
B_FALSE },
B_FALSE },
B_FALSE },
B_FALSE },
B_TRUE},
B_TRUE },
B_FALSE },
B_FALSE },
B_FALSE },
B_FALSE },
B_TRUE },
B_TRUE },
B_TRUE },
B_FALSE },
B_TRUE },
B_TRUE },
B_FALSE },
B_TRUE },
B_FALSE },
B_FALSE },
B_TRUE },
B_FALSE },
B_TRUE },
B_TRUE }
};
int
{
int error;
if (error == 0) {
if (spa_suspended(spa))
}
return (error);
}
static int
{
return (EINVAL);
/*
* the lower layers.
*/
if (error == 0) {
case POOL_NAME:
break;
case DATASET_NAME:
break;
case NO_NAME:
break;
}
}
if (error == 0)
if (error == 0) {
}
return (error);
}
static int
{
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
DDI_PSEUDO, 0) == DDI_FAILURE)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
static int
{
return (DDI_FAILURE);
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
{
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
return (DDI_SUCCESS);
case DDI_INFO_DEVT2INSTANCE:
*result = (void *)0;
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
/*
* OK, so this is a little weird.
*
*
* so most of the standard driver entry points are in zvol.c.
*/
static struct cb_ops zfs_cb_ops = {
zvol_open, /* open */
zvol_close, /* close */
zvol_strategy, /* strategy */
nodev, /* print */
zvol_dump, /* dump */
zvol_read, /* read */
zvol_write, /* write */
zfsdev_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* prop_op */
NULL, /* streamtab */
CB_REV, /* version */
nodev, /* async read */
nodev, /* async write */
};
static struct dev_ops zfs_dev_ops = {
DEVO_REV, /* version */
0, /* refcnt */
zfs_info, /* info */
nulldev, /* identify */
nulldev, /* probe */
zfs_attach, /* attach */
zfs_detach, /* detach */
nodev, /* reset */
&zfs_cb_ops, /* driver operations */
NULL, /* no bus operations */
NULL, /* power */
ddi_quiesce_not_needed, /* quiesce */
};
static struct modldrv zfs_modldrv = {
"ZFS storage pool",
};
static struct modlinkage modlinkage = {
(void *)&zfs_modlfs,
(void *)&zfs_modldrv,
};
extern uint_t rrw_tsd_key;
int
_init(void)
{
int error;
zfs_init();
zvol_init();
zvol_fini();
zfs_fini();
spa_fini();
return (error);
}
return (0);
}
int
_fini(void)
{
int error;
return (EBUSY);
return (error);
zvol_fini();
zfs_fini();
spa_fini();
if (zfs_nfsshare_inited)
(void) ddi_modclose(nfs_mod);
if (zfs_smbshare_inited)
(void) ddi_modclose(smbsrv_mod);
(void) ddi_modclose(sharefs_mod);
return (error);
}
int
{
}