zfs_ioctl.c revision fa9e4066f08beec538e775443c5be79dd423fcab
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/zfs_ioctl.h>
#include <sys/dsl_dataset.h>
#include <sys/dsl_prop.h>
#include <sys/pathname.h>
#include <sys/zfs_ctldir.h>
#include "zfs_namecheck.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 int zfs_secpolicy_func_t(const char *, const char *, cred_t *);
typedef struct zfs_ioc_vec {
enum {
/* _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
*/
}
/*
* 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);
}
/*
* Policy for dataset write operations (create children, set properties, etc).
* Requires SYS_MOUNT privilege, and must be writable in the local zone.
*/
/* ARGSUSED */
int
{
int error;
return (error);
return (secpolicy_zfs(cr));
}
/*
* Policy for operations that want to write a dataset's parent:
* create, destroy, snapshot, clone, restore.
*/
static int
{
char parentname[MAXNAMELEN];
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';
}
}
/*
* Policy for dataset write operations (create children, set properties, etc).
* Requires SYS_MOUNT privilege, and must be writable in the local zone.
*/
static int
{
int error;
return (error);
/*
* 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
{
int error;
return (error);
if (!INGLOBALZONE(curproc)) {
char setpoint[MAXNAMELEN];
int dslen;
/*
* Unprivileged users are allowed to modify the quota
* on things *under* (ie. contained by) the thing they
* own.
*/
return (EPERM);
if (!zoned) /* this shouldn't happen */
return (EPERM);
return (EPERM);
}
return (secpolicy_zfs(cr));
}
/*
* SYS_CONFIG privilege, which is not available in a local zone.
*/
/* ARGSUSED */
static int
{
return (EPERM);
return (0);
}
/*
* 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. 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.
*/
return (EINVAL);
size)) != 0) {
return (error);
}
return (error);
}
return (0);
}
static int
{
int error;
return (error);
return (error);
}
static int
{
}
static int
{
int error;
return (error);
else
return (error);
}
static int
{
}
static int
{
int error;
return (EEXIST);
else
size);
return (error);
}
static int
{
int error;
if (error == 0) {
}
return (error);
}
static int
{
int error;
NV_ENCODE_NATIVE, 0) == 0);
size))
} else {
}
return (error);
}
/*
* 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);
else
size);
return (error);
}
static int
{
int error;
if (error == 0) {
}
return (error);
}
static int
{
int error;
if (error == 0) {
}
return (error);
}
static int
{
int error;
if (error != 0)
return (error);
}
return (error);
}
/* ARGSUSED */
static int
{
return (ENOTSUP);
}
static int
{
int error;
if (error != 0)
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);
}
static int
{
int error;
if (error != 0)
return (error);
return (error);
}
static int
{
int error;
return (error);
return (0);
}
static int
{
int error;
if (error != 0) {
/*
* This is ugly: dmu_objset_open() can return EBUSY if
* the objset is held exclusively. Fortunately this hold is
* only for a short while, so we retry here.
* This avoids user code having to handle EBUSY,
* for example for a "zfs list".
*/
delay(1);
goto retry;
}
return (error);
}
case DMU_OST_ZFS:
break;
case DMU_OST_ZVOL:
break;
}
return (error);
}
static int
{
int error;
char *p;
return (ESRCH);
return (ESRCH);
}
do {
if (error != 0) {
*p = '\0';
return (error);
}
} while (!INGLOBALZONE(curproc) &&
/*
* If it's a hidden dataset, don't try to get stats for it.
* User land will skip over it.
*/
return (0);
return (error);
}
static int
{
int error;
if (error) {
/*
* This is ugly: dsl_dataset_open() can return EBUSY if
* the objset is held exclusively. Fortunately this hold is
* only for a short while, so we retry here.
* This avoids user code having to handle EBUSY,
* for example for a "zfs list -s".
*/
delay(1);
goto retry;
}
return (ESRCH);
return (error);
}
/*
* If ds_snapnames_zapobj is 0, someone is trying to iterate over
* snapshots of a snapshot. In this case, pretend that it has no
* snapshots; otherwise zap_cursor_retrieve() will blow up.
*/
goto out;
}
if (error != 0)
goto out;
goto out;
}
out:
return (error);
}
static int
{
}
static int
{
}
static int
{
}
static int
{
return (zvol_set_volsize(zc));
}
static int
{
return (zvol_set_volblocksize(zc));
}
static int
{
return (zvol_create_minor(zc));
}
static int
{
return (zvol_remove_minor(zc));
}
/*
* 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);
}
static void
{
}
static int
{
int error = 0;
switch (type) {
case DMU_OST_ZFS:
break;
case DMU_OST_ZVOL:
break;
default:
return (EINVAL);
}
/*
* We're creating a clone of an existing snapshot.
*/
return (EINVAL);
if (error)
return (error);
/*
* We're taking a snapshot of an existing dataset.
*/
} else {
/*
* We're creating a new dataset.
*/
if (type == DMU_OST_ZVOL) {
return (error);
return (error);
}
}
return (error);
}
static int
{
int err;
/*
* Snapshots under .zfs control must be unmounted
* before they can be destroyed.
*/
/*
* Always force the unmount for snapshots.
*/
return (err);
}
return (err);
}
}
}
static int
{
}
static int
{
return (EINVAL);
int err;
/*
* Snapshots under .zfs control must be unmounted
* before they can be renamed.
*/
/*
* Always force the unmount for snapshots.
*/
return (err);
}
return (err);
}
}
}
static int
{
return (EBADF);
return (error);
}
static int
{
int error;
if (error)
return (error);
if (error) {
return (error);
}
}
if (fromsnap)
return (EBADF);
}
if (fromsnap)
return (error);
}
static zfs_ioc_vec_t zfs_ioc_vec[] = {
};
static int
{
int error;
return (EINVAL);
if (error == 0) {
}
/*
* the lower layers.
*/
if (error == 0) {
case pool_name:
break;
case dataset_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:
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 */
nodev, /* 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 */
zvol_aread, /* async read */
zvol_awrite, /* 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 */
};
static struct modldrv zfs_modldrv = {
};
static struct modlinkage modlinkage = {
(void *)&zfs_modlfs,
(void *)&zfs_modldrv,
};
int
_init(void)
{
int error;
return (error);
zfs_init();
zvol_init();
return (0);
}
int
_fini(void)
{
int error;
return (EBUSY);
return (error);
zvol_fini();
zfs_fini();
spa_fini();
return (error);
}
int
{
}