summaryrefslogtreecommitdiffstats
path: root/module/zfs/zfs_ioctl.c
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2010-08-26 11:44:39 -0700
committerBrian Behlendorf <[email protected]>2010-08-31 13:41:50 -0700
commit325f023544bbec6a478882c442e15304ee379759 (patch)
treee41ddbab7f373fc7fd43390c4ba05ea722729e68 /module/zfs/zfs_ioctl.c
parent47d0ed1e6f8a8ee67492ec63173a27df8e4ca059 (diff)
Add linux kernel device support
This branch contains the majority of the changes required to cleanly intergrate with Linux style special devices (/dev/zfs). Mainly this means dropping all the Solaris style callbacks and replacing them with the Linux equivilants. This patch also adds the onexit infrastructure needed to track some minimal state between ioctls. Under Linux it would be easy to do this simply using the file->private_data. But under Solaris they apparent need to pass the file descriptor as part of the ioctl data and then perform a lookup in the kernel. Once again to keep code change to a minimum I've implemented the Solaris solution. Signed-off-by: Brian Behlendorf <[email protected]>
Diffstat (limited to 'module/zfs/zfs_ioctl.c')
-rw-r--r--module/zfs/zfs_ioctl.c430
1 files changed, 238 insertions, 192 deletions
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c
index 2302c0f3c..99287e443 100644
--- a/module/zfs/zfs_ioctl.c
+++ b/module/zfs/zfs_ioctl.c
@@ -65,20 +65,21 @@
#include <sys/dsl_scan.h>
#include <sharefs/share.h>
#include <sys/dmu_objset.h>
+#include <sys/fm/util.h>
+
+#include <linux/miscdevice.h>
#include "zfs_namecheck.h"
#include "zfs_prop.h"
#include "zfs_deleg.h"
#include "zfs_comutil.h"
-extern struct modlfs zfs_modlfs;
+kmutex_t zfsdev_state_lock;
+list_t zfsdev_state_list;
extern void zfs_init(void);
extern void zfs_fini(void);
-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(zfs_cmd_t *, cred_t *);
@@ -591,6 +592,7 @@ zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr)
return (error);
}
+#ifdef HAVE_ZPL
static int
zfs_secpolicy_deleg_share(zfs_cmd_t *zc, cred_t *cr)
{
@@ -614,10 +616,12 @@ zfs_secpolicy_deleg_share(zfs_cmd_t *zc, cred_t *cr)
return (dsl_deleg_access(zc->zc_name,
ZFS_DELEG_PERM_SHARE, cr));
}
+#endif /* HAVE_ZPL */
int
zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr)
{
+#ifdef HAVE_ZPL
if (!INGLOBALZONE(curproc))
return (EPERM);
@@ -626,11 +630,15 @@ zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr)
} else {
return (zfs_secpolicy_deleg_share(zc, cr));
}
+#else
+ return (ENOTSUP);
+#endif /* HAVE_ZPL */
}
int
zfs_secpolicy_smb_acl(zfs_cmd_t *zc, cred_t *cr)
{
+#ifdef HAVE_ZPL
if (!INGLOBALZONE(curproc))
return (EPERM);
@@ -639,6 +647,9 @@ zfs_secpolicy_smb_acl(zfs_cmd_t *zc, cred_t *cr)
} else {
return (zfs_secpolicy_deleg_share(zc, cr));
}
+#else
+ return (ENOTSUP);
+#endif /* HAVE_ZPL */
}
static int
@@ -839,6 +850,7 @@ zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr)
return (error);
}
+#ifdef HAVE_ZPL
static int
zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr)
{
@@ -850,6 +862,7 @@ zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr)
}
return (error);
}
+#endif /* HAVE_ZPL */
/*
* Policy for pool operations - create/destroy pools, add vdevs, etc. Requires
@@ -1093,6 +1106,7 @@ put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
return (error);
}
+#ifdef HAVE_ZPL
static int
getzfsvfs(const char *dsname, zfsvfs_t **zfvp)
{
@@ -1118,6 +1132,7 @@ getzfsvfs(const char *dsname, zfsvfs_t **zfvp)
dmu_objset_rele(os, FTAG);
return (error);
}
+#endif
/*
* Find a zfsvfs_t for a mounted filesystem, or create our own, in which
@@ -1126,6 +1141,7 @@ getzfsvfs(const char *dsname, zfsvfs_t **zfvp)
static int
zfsvfs_hold(const char *name, void *tag, zfsvfs_t **zfvp, boolean_t writer)
{
+#ifdef HAVE_ZPL
int error = 0;
if (getzfsvfs(name, zfvp) != 0)
@@ -1144,11 +1160,15 @@ zfsvfs_hold(const char *name, void *tag, zfsvfs_t **zfvp, boolean_t writer)
}
}
return (error);
+#else
+ return ENOTSUP;
+#endif
}
static void
zfsvfs_rele(zfsvfs_t *zfsvfs, void *tag)
{
+#ifdef HAVE_ZPL
rrw_exit(&zfsvfs->z_teardown_lock, tag);
if (zfsvfs->z_vfs) {
@@ -1157,6 +1177,7 @@ zfsvfs_rele(zfsvfs_t *zfsvfs, void *tag)
dmu_objset_disown(zfsvfs->z_os, zfsvfs);
zfsvfs_free(zfsvfs);
}
+#endif
}
static int
@@ -2063,6 +2084,7 @@ top:
static int
zfs_prop_set_userquota(const char *dsname, nvpair_t *pair)
{
+#ifdef HAVE_ZPL
const char *propname = nvpair_name(pair);
uint64_t *valary;
unsigned int vallen;
@@ -2103,6 +2125,9 @@ zfs_prop_set_userquota(const char *dsname, nvpair_t *pair)
}
return (err);
+#else
+ return ENOTSUP;
+#endif
}
/*
@@ -2164,7 +2189,9 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
if ((err = zfsvfs_hold(dsname, FTAG, &zfsvfs, B_TRUE)) != 0)
break;
+#ifdef HAVE_ZPL
err = zfs_set_version(zfsvfs, intval);
+#endif
zfsvfs_rele(zfsvfs, FTAG);
if (err == 0 && intval >= ZPL_VERSION_USERSPACE) {
@@ -2696,6 +2723,7 @@ zfs_ioc_get_fsacl(zfs_cmd_t *zc)
return (error);
}
+#ifdef HAVE_ZPL
/*
* 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
@@ -2720,6 +2748,7 @@ zfs_get_vfs(const char *resource)
vfs_list_unlock();
return (vfs_found);
}
+#endif /* HAVE_ZPL */
/* ARGSUSED */
static void
@@ -3074,6 +3103,7 @@ out:
int
zfs_unmount_snap(const char *name, void *arg)
{
+#ifdef HAVE_ZPL
vfs_t *vfsp = NULL;
if (arg) {
@@ -3100,6 +3130,7 @@ zfs_unmount_snap(const char *name, void *arg)
if ((err = dounmount(vfsp, flag, kcred)) != 0)
return (err);
}
+#endif /* HAVE_ZPL */
return (0);
}
@@ -3159,6 +3190,7 @@ zfs_ioc_destroy(zfs_cmd_t *zc)
static int
zfs_ioc_rollback(zfs_cmd_t *zc)
{
+#ifdef HAVE_ZPL
dsl_dataset_t *ds, *clone;
int error;
zfsvfs_t *zfsvfs;
@@ -3232,6 +3264,9 @@ out:
if (ds)
dsl_dataset_rele(ds, FTAG);
return (error);
+#else
+ return (ENOTSUP);
+#endif /* HAVE_ZPL */
}
/*
@@ -3675,6 +3710,7 @@ zfs_ioc_recv(zfs_cmd_t *zc)
&zc->zc_action_handle);
if (error == 0) {
+#ifdef HAVE_ZPL
zfsvfs_t *zfsvfs = NULL;
if (getzfsvfs(tofs, &zfsvfs) == 0) {
@@ -3694,6 +3730,9 @@ zfs_ioc_recv(zfs_cmd_t *zc)
} else {
error = dmu_recv_end(&drc);
}
+#else
+ error = dmu_recv_end(&drc);
+#endif /* HAVE_ZPL */
}
zc->zc_cookie = off - fp->f_offset;
@@ -4017,6 +4056,7 @@ zfs_ioc_promote(zfs_cmd_t *zc)
static int
zfs_ioc_userspace_one(zfs_cmd_t *zc)
{
+#ifdef HAVE_ZPL
zfsvfs_t *zfsvfs;
int error;
@@ -4032,6 +4072,9 @@ zfs_ioc_userspace_one(zfs_cmd_t *zc)
zfsvfs_rele(zfsvfs, FTAG);
return (error);
+#else
+ return (ENOTSUP);
+#endif /* HAVE_ZPL */
}
/*
@@ -4048,6 +4091,7 @@ zfs_ioc_userspace_one(zfs_cmd_t *zc)
static int
zfs_ioc_userspace_many(zfs_cmd_t *zc)
{
+#ifdef HAVE_ZPL
zfsvfs_t *zfsvfs;
int bufsize = zc->zc_nvlist_dst_size;
@@ -4072,6 +4116,9 @@ zfs_ioc_userspace_many(zfs_cmd_t *zc)
zfsvfs_rele(zfsvfs, FTAG);
return (error);
+#else
+ return (ENOTSUP);
+#endif /* HAVE_ZPL */
}
/*
@@ -4084,6 +4131,7 @@ zfs_ioc_userspace_many(zfs_cmd_t *zc)
static int
zfs_ioc_userspace_upgrade(zfs_cmd_t *zc)
{
+#ifdef HAVE_ZPL
objset_t *os;
int error = 0;
zfsvfs_t *zfsvfs;
@@ -4113,6 +4161,9 @@ zfs_ioc_userspace_upgrade(zfs_cmd_t *zc)
}
return (error);
+#else
+ return (ENOTSUP);
+#endif /* HAVE_ZPL */
}
/*
@@ -4122,6 +4173,7 @@ zfs_ioc_userspace_upgrade(zfs_cmd_t *zc)
* the first file system is shared.
* Neither sharefs, nfs or smbsrv are unloadable modules.
*/
+#ifdef HAVE_ZPL
int (*znfsexport_fs)(void *arg);
int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t);
int (*zsmbexport_fs)(void *arg, boolean_t add_share);
@@ -4153,10 +4205,12 @@ zfs_init_sharefs()
}
return (0);
}
+#endif /* HAVE_ZPL */
static int
zfs_ioc_share(zfs_cmd_t *zc)
{
+#ifdef HAVE_ZPL
int error;
int opcode;
@@ -4246,7 +4300,9 @@ zfs_ioc_share(zfs_cmd_t *zc)
zc->zc_share.z_sharemax);
return (error);
-
+#else
+ return (ENOTSUP);
+#endif /* HAVE_ZPL */
}
ace_t full_access[] = {
@@ -4363,6 +4419,7 @@ zfs_ioc_diff(zfs_cmd_t *zc)
/*
* Remove all ACL files in shares dir
*/
+#ifdef HAVE_ZPL
static int
zfs_smb_acl_purge(znode_t *dzp)
{
@@ -4381,10 +4438,12 @@ zfs_smb_acl_purge(znode_t *dzp)
zap_cursor_fini(&zc);
return (error);
}
+#endif /* HAVE ZPL */
static int
zfs_ioc_smb_acl(zfs_cmd_t *zc)
{
+#ifdef HAVE_ZPL
vnode_t *vp;
znode_t *dzp;
vnode_t *resourcevp = NULL;
@@ -4507,6 +4566,9 @@ zfs_ioc_smb_acl(zfs_cmd_t *zc)
ZFS_EXIT(zfsvfs);
return (error);
+#else
+ return (ENOTSUP);
+#endif /* HAVE_ZPL */
}
/*
@@ -4842,13 +4904,56 @@ pool_status_check(const char *name, zfs_ioc_namecheck_t type,
return (error);
}
+static void *
+zfsdev_get_state_impl(minor_t minor, enum zfsdev_state_type which)
+{
+ zfsdev_state_t *zs;
+
+ ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+
+ for (zs = list_head(&zfsdev_state_list); zs != NULL;
+ zs = list_next(&zfsdev_state_list, zs)) {
+ if (zs->zs_minor == minor) {
+ switch (which) {
+ case ZST_ONEXIT: return (zs->zs_onexit);
+ case ZST_ZEVENT: return (zs->zs_zevent);
+ case ZST_ALL: return (zs);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void *
+zfsdev_get_state(minor_t minor, enum zfsdev_state_type which)
+{
+ void *ptr;
+
+ mutex_enter(&zfsdev_state_lock);
+ ptr = zfsdev_get_state_impl(minor, which);
+ mutex_exit(&zfsdev_state_lock);
+
+ return ptr;
+}
+
+minor_t
+zfsdev_getminor(struct file *filp)
+{
+ ASSERT(filp != NULL);
+ ASSERT(filp->private_data != NULL);
+
+ return (((zfsdev_state_t *)filp->private_data)->zs_minor);
+}
+
/*
- * Find a free minor number.
+ * Find a free minor number. The zfsdev_state_list is expected to
+ * be short since it is only a list of currently open file handles.
*/
minor_t
zfsdev_minor_alloc(void)
{
- static minor_t last_minor;
+ static minor_t last_minor = 0;
minor_t m;
ASSERT(MUTEX_HELD(&zfsdev_state_lock));
@@ -4856,7 +4961,7 @@ zfsdev_minor_alloc(void)
for (m = last_minor + 1; m != last_minor; m++) {
if (m > ZFSDEV_MAX_MINOR)
m = 1;
- if (ddi_get_soft_state(zfsdev_state, m) == NULL) {
+ if (zfsdev_get_state_impl(m, ZST_ALL) == NULL) {
last_minor = m;
return (m);
}
@@ -4866,107 +4971,85 @@ zfsdev_minor_alloc(void)
}
static int
-zfs_ctldev_init(dev_t *devp)
+zfsdev_state_init(struct file *filp)
{
+ zfsdev_state_t *zs;
minor_t minor;
- zfs_soft_state_t *zs;
ASSERT(MUTEX_HELD(&zfsdev_state_lock));
- ASSERT(getminor(*devp) == 0);
- minor = zfsdev_minor_alloc();
- if (minor == 0)
- return (ENXIO);
+ minor = zfsdev_minor_alloc();
+ if (minor == 0)
+ return (ENXIO);
+
+ zs = kmem_zalloc( sizeof(zfsdev_state_t), KM_SLEEP);
+ if (zs == NULL)
+ return (ENOMEM);
- if (ddi_soft_state_zalloc(zfsdev_state, minor) != DDI_SUCCESS)
- return (EAGAIN);
+ zs->zs_file = filp;
+ zs->zs_minor = minor;
+ filp->private_data = zs;
- *devp = makedevice(getemajor(*devp), minor);
+ zfs_onexit_init((zfs_onexit_t **)&zs->zs_onexit);
+ zfs_zevent_init((zfs_zevent_t **)&zs->zs_zevent);
- zs = ddi_get_soft_state(zfsdev_state, minor);
- zs->zss_type = ZSST_CTLDEV;
- zfs_onexit_init((zfs_onexit_t **)&zs->zss_data);
+ list_insert_tail(&zfsdev_state_list, zs);
return (0);
}
-static void
-zfs_ctldev_destroy(zfs_onexit_t *zo, minor_t minor)
+static int
+zfsdev_state_destroy(struct file *filp)
{
- ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+ zfsdev_state_t *zs;
- zfs_onexit_destroy(zo);
- ddi_soft_state_free(zfsdev_state, minor);
-}
+ ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+ ASSERT(filp->private_data != NULL);
-void *
-zfsdev_get_soft_state(minor_t minor, enum zfs_soft_state_type which)
-{
- zfs_soft_state_t *zp;
+ zs = filp->private_data;
+ zfs_onexit_destroy(zs->zs_onexit);
+ zfs_zevent_destroy(zs->zs_zevent);
- zp = ddi_get_soft_state(zfsdev_state, minor);
- if (zp == NULL || zp->zss_type != which)
- return (NULL);
+ list_remove(&zfsdev_state_list, zs);
+ kmem_free(zs, sizeof(zfsdev_state_t));
- return (zp->zss_data);
+ return 0;
}
static int
-zfsdev_open(dev_t *devp, int flag, int otyp, cred_t *cr)
+zfsdev_open(struct inode *ino, struct file *filp)
{
- int error = 0;
-
- if (getminor(*devp) != 0)
- return (zvol_open(devp, flag, otyp, cr));
+ int error;
- /* This is the control device. Allocate a new minor if requested. */
- if (flag & FEXCL) {
- mutex_enter(&zfsdev_state_lock);
- error = zfs_ctldev_init(devp);
- mutex_exit(&zfsdev_state_lock);
- }
+ mutex_enter(&zfsdev_state_lock);
+ error = zfsdev_state_init(filp);
+ mutex_exit(&zfsdev_state_lock);
- return (error);
+ return (-error);
}
static int
-zfsdev_close(dev_t dev, int flag, int otyp, cred_t *cr)
+zfsdev_release(struct inode *ino, struct file *filp)
{
- zfs_onexit_t *zo;
- minor_t minor = getminor(dev);
-
- if (minor == 0)
- return (0);
+ int error;
mutex_enter(&zfsdev_state_lock);
- zo = zfsdev_get_soft_state(minor, ZSST_CTLDEV);
- if (zo == NULL) {
- mutex_exit(&zfsdev_state_lock);
- return (zvol_close(dev, flag, otyp, cr));
- }
- zfs_ctldev_destroy(zo, minor);
+ error = zfsdev_state_destroy(filp);
mutex_exit(&zfsdev_state_lock);
- return (0);
+ return (-error);
}
-static int
-zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
+static long
+zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
{
zfs_cmd_t *zc;
uint_t vec;
- int error, rc;
- minor_t minor = getminor(dev);
-
- if (minor != 0 &&
- zfsdev_get_soft_state(minor, ZSST_CTLDEV) == NULL)
- return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp));
+ int error, rc, flag = 0;
vec = cmd - ZFS_IOC;
- ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip));
-
if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
- return (EINVAL);
+ return (-EINVAL);
zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
@@ -4975,7 +5058,7 @@ zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
error = EFAULT;
if ((error == 0) && !(flag & FKIOCTL))
- error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr);
+ error = zfs_ioc_vec[vec].zvec_secpolicy(zc, NULL);
/*
* Ensure that all pool/dataset names are valid before we pass down to
@@ -5018,121 +5101,74 @@ zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
}
kmem_free(zc, sizeof (zfs_cmd_t));
- return (error);
+ return (-error);
}
-static int
-zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+#ifdef CONFIG_COMPAT
+static long
+zfsdev_compat_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
{
- if (cmd != DDI_ATTACH)
- return (DDI_FAILURE);
-
- if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0,
- DDI_PSEUDO, 0) == DDI_FAILURE)
- return (DDI_FAILURE);
-
- zfs_dip = dip;
+ return zfsdev_ioctl(filp, cmd, arg);
+}
+#else
+#define zfs_compat_ioctl NULL
+#endif
- ddi_report_dev(dip);
+static const struct file_operations zfsdev_fops = {
+ .open = zfsdev_open,
+ .release = zfsdev_release,
+ .unlocked_ioctl = zfsdev_ioctl,
+ .compat_ioctl = zfsdev_compat_ioctl,
+ .owner = THIS_MODULE,
+};
- return (DDI_SUCCESS);
-}
+static struct miscdevice zfs_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = ZFS_DRIVER,
+ .fops = &zfsdev_fops,
+};
static int
-zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+zfs_attach(void)
{
- if (spa_busy() || zfs_busy() || zvol_busy())
- return (DDI_FAILURE);
-
- if (cmd != DDI_DETACH)
- return (DDI_FAILURE);
+ int error;
- zfs_dip = NULL;
+ mutex_init(&zfsdev_state_lock, NULL, MUTEX_DEFAULT, NULL);
+ list_create(&zfsdev_state_list, sizeof (zfsdev_state_t),
+ offsetof(zfsdev_state_t, zs_next));
- ddi_prop_remove_all(dip);
- ddi_remove_minor_node(dip, NULL);
+ error = misc_register(&zfs_misc);
+ if (error) {
+ printk(KERN_INFO "ZFS: misc_register() failed %d\n", error);
+ return (error);
+ }
- return (DDI_SUCCESS);
+ return (0);
}
-/*ARGSUSED*/
-static int
-zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
+static void
+zfs_detach(void)
{
- switch (infocmd) {
- case DDI_INFO_DEVT2DEVINFO:
- *result = zfs_dip;
- return (DDI_SUCCESS);
+ int error;
- case DDI_INFO_DEVT2INSTANCE:
- *result = (void *)0;
- return (DDI_SUCCESS);
- }
+ error = misc_deregister(&zfs_misc);
+ if (error)
+ printk(KERN_INFO "ZFS: misc_deregister() failed %d\n", error);
- return (DDI_FAILURE);
+ mutex_destroy(&zfsdev_state_lock);
+ list_destroy(&zfsdev_state_list);
}
-/*
- * OK, so this is a little weird.
- *
- * /dev/zfs is the control node, i.e. minor 0.
- * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0.
- *
- * /dev/zfs has basically nothing to do except serve up ioctls,
- * so most of the standard driver entry points are in zvol.c.
- */
-static struct cb_ops zfs_cb_ops = {
- zfsdev_open, /* open */
- zfsdev_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 */
- D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */
- 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 = {
- &mod_driverops,
- "ZFS storage pool",
- &zfs_dev_ops
-};
-
-static struct modlinkage modlinkage = {
- MODREV_1,
- (void *)&zfs_modlfs,
- (void *)&zfs_modldrv,
- NULL
-};
-
-
+#ifdef HAVE_ZPL
uint_t zfs_fsyncer_key;
extern uint_t rrw_tsd_key;
+#endif
+
+#ifdef DEBUG
+#define ZFS_DEBUG_STR " (DEBUG mode)"
+#else
+#define ZFS_DEBUG_STR ""
+#endif
int
_init(void)
@@ -5141,39 +5177,44 @@ _init(void)
spa_init(FREAD | FWRITE);
zfs_init();
- zvol_init();
- if ((error = mod_install(&modlinkage)) != 0) {
- zvol_fini();
- zfs_fini();
- spa_fini();
- return (error);
- }
+ if ((error = zvol_init()) != 0)
+ goto out1;
+
+ if ((error = zfs_attach()) != 0)
+ goto out2;
+#ifdef HAVE_ZPL
tsd_create(&zfs_fsyncer_key, NULL);
tsd_create(&rrw_tsd_key, NULL);
- error = ldi_ident_from_mod(&modlinkage, &zfs_li);
- ASSERT(error == 0);
mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL);
+#endif /* HAVE_ZPL */
+
+ printk(KERN_NOTICE "ZFS: Loaded ZFS Filesystem v%s%s\n",
+ ZFS_META_VERSION, ZFS_DEBUG_STR);
return (0);
+
+out2:
+ (void) zvol_fini();
+out1:
+ zfs_fini();
+ spa_fini();
+ printk(KERN_NOTICE "ZFS: Failed to Load ZFS Filesystem v%s%s"
+ ", rc = %d\n", ZFS_META_VERSION, ZFS_DEBUG_STR, error);
+
+ return (error);
}
int
_fini(void)
{
- int error;
-
- if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled)
- return (EBUSY);
-
- if ((error = mod_remove(&modlinkage)) != 0)
- return (error);
-
+ zfs_detach();
zvol_fini();
zfs_fini();
spa_fini();
+#ifdef HAVE_ZPL
if (zfs_nfsshare_inited)
(void) ddi_modclose(nfs_mod);
if (zfs_smbshare_inited)
@@ -5181,16 +5222,21 @@ _fini(void)
if (zfs_nfsshare_inited || zfs_smbshare_inited)
(void) ddi_modclose(sharefs_mod);
- tsd_destroy(&zfs_fsyncer_key);
- ldi_ident_release(zfs_li);
- zfs_li = NULL;
mutex_destroy(&zfs_share_lock);
+ tsd_destroy(&zfs_fsyncer_key);
+#endif /* HAVE_ZPL */
- return (error);
-}
+ printk(KERN_NOTICE "ZFS: Unloaded ZFS Filesystem v%s%s\n",
+ ZFS_META_VERSION, ZFS_DEBUG_STR);
-int
-_info(struct modinfo *modinfop)
-{
- return (mod_info(&modlinkage, modinfop));
+ return (0);
}
+
+#ifdef HAVE_SPL
+spl_module_init(_init);
+spl_module_exit(_fini);
+
+MODULE_DESCRIPTION("ZFS");
+MODULE_AUTHOR(ZFS_META_AUTHOR);
+MODULE_LICENSE(ZFS_META_LICENSE);
+#endif /* HAVE_SPL */