zfs_ioctl.c revision 6a0f006613b1cd364266eadbfd955d769a018891
/*
* 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 2008 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 struct zfs_ioc_vec {
enum {
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)
{
if (spa->spa_bootfs) {
}
}
}
return (ret);
}
/*
* 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 (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 error;
if (error == 0)
return (error);
}
int
{
}
int
{
if (!INGLOBALZONE(curproc))
return (EPERM);
if (secpolicy_nfs(cr) == 0) {
return (0);
} else {
int error;
return (error);
/* Now make sure mntpnt and dataset are ZFS */
return (EPERM);
}
}
}
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
{
int error;
ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0)
return (error);
return (error);
}
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);
}
/*
* Just like zfs_secpolicy_config, except that we will check for
* the minor nodes.
*/
static int
{
}
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);
}
}
/*
* 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);
return (error);
}
return (error);
}
return (0);
}
static int
{
int error;
} else {
KM_SLEEP) == 0);
size);
}
return (error);
}
static int
{
int error;
char *buf;
&config))
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;
return (error);
}
static int
{
int error;
&config)) != 0)
return (error);
return (error);
}
props);
else
if (props)
return (error);
}
static int
{
int error;
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;
&tryconfig)) != 0)
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);
}
zc->zc_history_len);
}
return (error);
}
static int
{
int error;
return (error);
return (0);
}
static int
{
int error;
return (error);
return (error);
}
static int
{
int error;
if (error != 0)
return (error);
&config);
/*
* 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);
case VDEV_STATE_ONLINE:
break;
case VDEV_STATE_OFFLINE:
break;
case VDEV_STATE_FAULTED:
break;
case VDEV_STATE_DEGRADED:
break;
default:
}
return (error);
}
static int
{
int error;
return (error);
&config)) == 0) {
}
return (error);
}
static int
{
int error;
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...
*/
}
}
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;
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);
}
/*
* 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_objset_stats stats
* zc_nvlist_dst property nvlist
* zc_nvlist_dst_size size of property nvlist
*/
static int
{
int error;
char *p;
return (error);
}
do {
/*
* If it's a hidden dataset (ie. with a '$' in its name), don't
* try to get stats for it. Userland will skip over it.
*/
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;
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 (EINVAL);
return (error);
continue;
}
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:
if (zfs_earlier_version(name,
return (ENOTSUP);
break;
case ZFS_PROP_SHARESMB:
return (ENOTSUP);
break;
}
}
if (prop == ZPROP_INVAL) {
if (error == 0)
continue;
else
return (error);
}
switch (prop) {
case ZFS_PROP_QUOTA:
return (error);
break;
case ZFS_PROP_REFQUOTA:
return (error);
break;
case ZFS_PROP_RESERVATION:
intval)) != 0)
return (error);
break;
case ZFS_PROP_REFRESERVATION:
intval)) != 0)
return (error);
break;
case ZFS_PROP_VOLSIZE:
return (error);
break;
case ZFS_PROP_VOLBLOCKSIZE:
return (error);
break;
case ZFS_PROP_VERSION:
return (error);
break;
default:
if (zfs_prop_get_type(prop) !=
return (EINVAL);
strval)) != 0)
return (error);
const char *unused;
switch (zfs_prop_get_type(prop)) {
case PROP_TYPE_NUMBER:
break;
case PROP_TYPE_STRING:
return (EINVAL);
case PROP_TYPE_INDEX:
return (EINVAL);
break;
default:
"unknown property type");
break;
}
return (error);
} else {
return (EINVAL);
}
break;
}
}
return (0);
}
/*
* inputs:
* zc_name name of filesystem
* zc_value name of property to inherit
* zc_nvlist_src{_size} nvlist of properties to apply
* zc_cookie clear existing local props?
*
* outputs: none
*/
static int
{
int error;
&nvl)) != 0)
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;
&props)))
return (error);
return (error);
}
return (error);
}
static int
{
int error;
return (error);
else
if (nvp)
return (error);
}
static int
{
int error;
&nvp)) != 0) {
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;
&fsaclnv)) != 0)
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);
}
/*
* inputs:
* zc_name name of volume
*
* outputs: none
*/
static int
{
}
/*
* inputs:
* zc_name name of volume
*
* outputs: none
*/
static int
{
}
/*
* 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);
&nvprops)) != 0)
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);
}
struct snap_prop_arg {
const char *snapname;
};
static int
{
int err;
if (err)
(void) dmu_objset_destroy(buf);
return (err);
}
/*
* inputs:
* zc_name name of filesystem
* zc_value short name of snapshot
* zc_cookie recursive flag
*
* outputs: none
*/
static int
{
int error;
return (EINVAL);
&nvprops)) != 0)
return (error);
/*
* It would be nice to do this atomically.
*/
if (error == 0) {
struct snap_prop_arg snpa;
if (recursive) {
if (error) {
}
} else {
}
}
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
*
* outputs: none
*/
static int
{
int err;
return (EINVAL);
if (err)
return (err);
}
/*
* inputs:
* zc_name name of dataset to destroy
* zc_objset_type type of objset
*
* outputs: none
*/
static int
{
if (err)
return (err);
}
}
/*
* inputs:
* zc_name name of dataset to rollback (to most recent snapshot)
*
* outputs: none
*/
static int
{
int error;
/*
* Get the zfsvfs for the receiving objset. There
* won't be one if we're operating on a zvol, if the
* objset doesn't exist yet, or is not mounted.
*/
if (error)
return (error);
}
char *osname;
int mode;
if (error == 0) {
int resume_err;
} else {
}
} else {
}
/* Note, the dmu_objset_rollback() releases the objset for us. */
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;
(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++;
&props)) != 0)
return (error);
return (EBADF);
}
/*
* Try to get the zfsvfs for the receiving objset.
* There won't be one if we're operating on a zvol,
* if the objset doesn't exist yet, or is not mounted.
*/
goto out;
}
}
/*
* If new properties are supplied, they are to completely
* replace the existing ones, so stash away the existing ones.
*/
if (props)
}
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.
*/
}
char *osname;
int mode;
/* online recv */
if (error == 0) {
int resume_err;
} else {
}
} else if (error == 0) {
}
/*
* On error, restore the original props.
*/
}
out:
if (zfsvfs) {
}
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);
}
}
/*
*/
return (0);
}
/*
* inputs:
* zc_name name of filesystem
* zc_value name of origin snapshot
*
* outputs: none
*/
static int
{
char *cp;
/*
* We don't need to unmount *all* the origin fs's snapshots, but
* it's easier.
*/
if (cp)
*cp = '\0';
}
/*
* 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);
}
/*
* 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[] = {
DATASET_NAME, B_FALSE },
DATASET_NAME, B_FALSE },
DATASET_NAME, B_FALSE },
};
static int
{
return (EINVAL);
if (error == 0)
/*
* 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
{
}