]> granicus.if.org Git - zfs/commitdiff
OpenZFS restructuring - zfs_ioctl
authorMatthew Macy <mmacy@mattmacy.io>
Fri, 27 Sep 2019 17:46:28 +0000 (10:46 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 27 Sep 2019 17:46:28 +0000 (10:46 -0700)
Refactor the zfs ioctls in to platform dependent and independent bits.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Sean Eric Fagan <sef@ixsystems.com>
Signed-off-by: Matthew Macy <mmacy@FreeBSD.org>
Signed-off-by: Ryan Moeller <ryan@ixsystems.com>
Closes #9301

include/os/linux/zfs/sys/zfs_vfsops.h
include/sys/Makefile.am
include/sys/rrwlock.h
include/sys/zfs_ioctl.h
include/sys/zfs_ioctl_impl.h [new file with mode: 0644]
module/os/linux/zfs/Makefile.in
module/os/linux/zfs/zfs_ioctl_os.c [new file with mode: 0644]
module/zfs/zfs_ioctl.c
tests/zfs-tests/cmd/libzfs_input_check/libzfs_input_check.c

index 415e46645ab41f42cd28f74be353f9882e1935ab..34d957bcbb041d1028fc563bb080b5906f1bb168 100644 (file)
@@ -194,8 +194,6 @@ typedef struct zfid_long {
 #define        SHORT_FID_LEN   (sizeof (zfid_short_t) - sizeof (uint16_t))
 #define        LONG_FID_LEN    (sizeof (zfid_long_t) - sizeof (uint16_t))
 
-extern uint_t zfs_fsyncer_key;
-
 extern int zfs_suspend_fs(zfsvfs_t *zfsvfs);
 extern int zfs_resume_fs(zfsvfs_t *zfsvfs, struct dsl_dataset *ds);
 extern int zfs_end_fs(zfsvfs_t *zfsvfs, struct dsl_dataset *ds);
index 2ac6a2b8d104a87b47210bdefef5dbe5e17974cf..734d5c161d206032e6e7bed3587ab6e368397b11 100644 (file)
@@ -124,6 +124,7 @@ COMMON_H = \
 
 KERNEL_H = \
        $(top_srcdir)/include/sys/zfs_ioctl.h \
+       $(top_srcdir)/include/sys/zfs_ioctl_impl.h \
        $(top_srcdir)/include/sys/zfs_onexit.h \
        $(top_srcdir)/include/sys/zvol.h \
        $(top_srcdir)/include/sys/zvol_impl.h
index e1c1756cf29abdee8d84a89fc28b7dc9fa4423ea..935a7ee9401963f2aa9fe292233b7b53a5405e8a 100644 (file)
@@ -39,6 +39,8 @@ extern "C" {
 #include <sys/zfs_context.h>
 #include <sys/refcount.h>
 
+extern uint_t rrw_tsd_key;
+
 /*
  * A reader-writer lock implementation that allows re-entrant reads, but
  * still gives writers priority on "new" reads.
index 3f9fdf4df542ff80b5b8a6b6bc8ecaee5adce745..daa1560f3413b3033a820a4a25e59960773dc0b5 100644 (file)
@@ -549,6 +549,9 @@ extern void *zfsdev_get_state(minor_t minor, enum zfsdev_state_type which);
 extern int zfsdev_getminor(struct file *filp, minor_t *minorp);
 extern minor_t zfsdev_minor_alloc(void);
 
+extern uint_t zfs_fsyncer_key;
+extern uint_t zfs_allow_log_key;
+
 #endif /* _KERNEL */
 
 #ifdef __cplusplus
diff --git a/include/sys/zfs_ioctl_impl.h b/include/sys/zfs_ioctl_impl.h
new file mode 100644 (file)
index 0000000..0c59441
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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
+ */
+
+
+#ifndef _ZFS_IOCTL_IMPL_H_
+#define        _ZFS_IOCTL_IMPL_H_
+
+extern kmutex_t zfsdev_state_lock;
+extern zfsdev_state_t *zfsdev_state_list;
+
+typedef int zfs_ioc_legacy_func_t(zfs_cmd_t *);
+typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *);
+typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *);
+
+typedef enum {
+       POOL_CHECK_NONE         = 1 << 0,
+       POOL_CHECK_SUSPENDED    = 1 << 1,
+       POOL_CHECK_READONLY     = 1 << 2,
+} zfs_ioc_poolcheck_t;
+
+typedef enum {
+       NO_NAME,
+       POOL_NAME,
+       DATASET_NAME,
+       ENTITY_NAME
+} zfs_ioc_namecheck_t;
+
+/*
+ * IOC Keys are used to document and validate user->kernel interface inputs.
+ * See zfs_keys_recv_new for an example declaration. Any key name that is not
+ * listed will be rejected as input.
+ *
+ * The keyname 'optional' is always allowed, and must be an nvlist if present.
+ * Arguments which older kernels can safely ignore can be placed under the
+ * "optional" key.
+ *
+ * When adding new keys to an existing ioc for new functionality, consider:
+ *     - adding an entry into zfs_sysfs.c zfs_features[] list
+ *     - updating the libzfs_input_check.c test utility
+ *
+ * Note: in the ZK_WILDCARDLIST case, the name serves as documentation
+ * for the expected name (bookmark, snapshot, property, etc) but there
+ * is no validation in the preflight zfs_check_input_nvpairs() check.
+ */
+typedef enum {
+       ZK_OPTIONAL = 1 << 0,           /* pair is optional */
+       ZK_WILDCARDLIST = 1 << 1,       /* one or more unspecified key names */
+} ioc_key_flag_t;
+
+typedef struct zfs_ioc_key {
+       const char      *zkey_name;
+       data_type_t     zkey_type;
+       ioc_key_flag_t  zkey_flags;
+} zfs_ioc_key_t;
+
+int zfs_secpolicy_config(zfs_cmd_t *, nvlist_t *, cred_t *);
+
+void zfs_ioctl_register_dataset_nolog(zfs_ioc_t, zfs_ioc_legacy_func_t *,
+    zfs_secpolicy_func_t *, zfs_ioc_poolcheck_t);
+
+void zfs_ioctl_register(const char *, zfs_ioc_t, zfs_ioc_func_t *,
+    zfs_secpolicy_func_t *, zfs_ioc_namecheck_t, zfs_ioc_poolcheck_t,
+    boolean_t, boolean_t, const zfs_ioc_key_t *, size_t);
+
+void zfs_ioctl_init_os(void);
+
+int zfs_vfs_ref(zfsvfs_t **);
+
+long zfsdev_ioctl_common(uint_t, unsigned long);
+int zfsdev_attach(void);
+void zfsdev_detach(void);
+int zfs_kmod_init(void);
+void zfs_kmod_fini(void);
+
+#endif
index a4f198907856ba0c4ab8b41f4ed14da42e7f7729..1a7ea0d69bc15ed484668ab546dc43a0432735c3 100644 (file)
@@ -22,6 +22,7 @@ $(MODULE)-objs += ../os/linux/zfs/zfs_acl.o
 $(MODULE)-objs += ../os/linux/zfs/zfs_ctldir.o
 $(MODULE)-objs += ../os/linux/zfs/zfs_debug.o
 $(MODULE)-objs += ../os/linux/zfs/zfs_dir.o
+$(MODULE)-objs += ../os/linux/zfs/zfs_ioctl_os.o
 $(MODULE)-objs += ../os/linux/zfs/zfs_sysfs.o
 $(MODULE)-objs += ../os/linux/zfs/zfs_vfsops.o
 $(MODULE)-objs += ../os/linux/zfs/zfs_vnops.o
diff --git a/module/os/linux/zfs/zfs_ioctl_os.c b/module/os/linux/zfs/zfs_ioctl_os.c
new file mode 100644 (file)
index 0000000..9b562ca
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Portions Copyright 2011 Martin Matuska
+ * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
+ * Portions Copyright 2012 Pawel Jakub Dawidek <pawel@dawidek.net>
+ * Copyright (c) 2014, 2016 Joyent, Inc. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2016 Toomas Soome <tsoome@me.com>
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
+ * Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
+ * Copyright 2017 RackTop Systems.
+ * Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
+ * Copyright (c) 2019 Datto Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/kmem.h>
+#include <sys/stat.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zfs_vfsops.h>
+#include <sys/zap.h>
+#include <sys/spa.h>
+#include <sys/nvpair.h>
+#include <sys/fs/zfs.h>
+#include <sys/zfs_ctldir.h>
+#include <sys/zfs_dir.h>
+#include <sys/zfs_onexit.h>
+#include <sys/zvol.h>
+#include <sys/fm/util.h>
+#include <sys/dsl_crypt.h>
+
+#include <sys/zfs_ioctl_impl.h>
+
+#include <sys/zfs_sysfs.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+
+int
+zfs_vfs_ref(zfsvfs_t **zfvp)
+{
+       if (*zfvp == NULL || (*zfvp)->z_sb == NULL ||
+           !atomic_inc_not_zero(&((*zfvp)->z_sb->s_active))) {
+               return (SET_ERROR(ESRCH));
+       }
+       return (0);
+}
+
+static int
+zfsdev_state_init(struct file *filp)
+{
+       zfsdev_state_t *zs, *zsprev = NULL;
+       minor_t minor;
+       boolean_t newzs = B_FALSE;
+
+       ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+
+       minor = zfsdev_minor_alloc();
+       if (minor == 0)
+               return (SET_ERROR(ENXIO));
+
+       for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
+               if (zs->zs_minor == -1)
+                       break;
+               zsprev = zs;
+       }
+
+       if (!zs) {
+               zs = kmem_zalloc(sizeof (zfsdev_state_t), KM_SLEEP);
+               newzs = B_TRUE;
+       }
+
+       zs->zs_file = filp;
+       filp->private_data = zs;
+
+       zfs_onexit_init((zfs_onexit_t **)&zs->zs_onexit);
+       zfs_zevent_init((zfs_zevent_t **)&zs->zs_zevent);
+
+       /*
+        * In order to provide for lock-free concurrent read access
+        * to the minor list in zfsdev_get_state_impl(), new entries
+        * must be completely written before linking them into the
+        * list whereas existing entries are already linked; the last
+        * operation must be updating zs_minor (from -1 to the new
+        * value).
+        */
+       if (newzs) {
+               zs->zs_minor = minor;
+               smp_wmb();
+               zsprev->zs_next = zs;
+       } else {
+               smp_wmb();
+               zs->zs_minor = minor;
+       }
+
+       return (0);
+}
+
+static int
+zfsdev_state_destroy(struct file *filp)
+{
+       zfsdev_state_t *zs;
+
+       ASSERT(MUTEX_HELD(&zfsdev_state_lock));
+       ASSERT(filp->private_data != NULL);
+
+       zs = filp->private_data;
+       zs->zs_minor = -1;
+       zfs_onexit_destroy(zs->zs_onexit);
+       zfs_zevent_destroy(zs->zs_zevent);
+
+       return (0);
+}
+
+static int
+zfsdev_open(struct inode *ino, struct file *filp)
+{
+       int error;
+
+       mutex_enter(&zfsdev_state_lock);
+       error = zfsdev_state_init(filp);
+       mutex_exit(&zfsdev_state_lock);
+
+       return (-error);
+}
+
+static int
+zfsdev_release(struct inode *ino, struct file *filp)
+{
+       int error;
+
+       mutex_enter(&zfsdev_state_lock);
+       error = zfsdev_state_destroy(filp);
+       mutex_exit(&zfsdev_state_lock);
+
+       return (-error);
+}
+
+static long
+zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
+{
+       uint_t vecnum;
+
+       vecnum = cmd - ZFS_IOC_FIRST;
+       return (zfsdev_ioctl_common(vecnum, arg));
+}
+
+int
+zfsdev_getminor(struct file *filp, minor_t *minorp)
+{
+       zfsdev_state_t *zs, *fpd;
+
+       ASSERT(filp != NULL);
+       ASSERT(!MUTEX_HELD(&zfsdev_state_lock));
+
+       fpd = filp->private_data;
+       if (fpd == NULL)
+               return (SET_ERROR(EBADF));
+
+       mutex_enter(&zfsdev_state_lock);
+
+       for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
+
+               if (zs->zs_minor == -1)
+                       continue;
+
+               if (fpd == zs) {
+                       *minorp = fpd->zs_minor;
+                       mutex_exit(&zfsdev_state_lock);
+                       return (0);
+               }
+       }
+
+       mutex_exit(&zfsdev_state_lock);
+
+       return (SET_ERROR(EBADF));
+}
+
+void
+zfs_ioctl_init_os(void)
+{
+}
+
+#ifdef CONFIG_COMPAT
+static long
+zfsdev_compat_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
+{
+       return (zfsdev_ioctl(filp, cmd, arg));
+}
+#else
+#define        zfsdev_compat_ioctl     NULL
+#endif
+
+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,
+};
+
+static struct miscdevice zfs_misc = {
+       .minor          = ZFS_DEVICE_MINOR,
+       .name           = ZFS_DRIVER,
+       .fops           = &zfsdev_fops,
+};
+
+MODULE_ALIAS_MISCDEV(ZFS_DEVICE_MINOR);
+MODULE_ALIAS("devname:zfs");
+
+int
+zfsdev_attach(void)
+{
+       int error;
+
+       error = misc_register(&zfs_misc);
+       if (error == -EBUSY) {
+               /*
+                * Fallback to dynamic minor allocation in the event of a
+                * collision with a reserved minor in linux/miscdevice.h.
+                * In this case the kernel modules must be manually loaded.
+                */
+               printk(KERN_INFO "ZFS: misc_register() with static minor %d "
+                   "failed %d, retrying with MISC_DYNAMIC_MINOR\n",
+                   ZFS_DEVICE_MINOR, error);
+
+               zfs_misc.minor = MISC_DYNAMIC_MINOR;
+               error = misc_register(&zfs_misc);
+       }
+
+       if (error)
+               printk(KERN_INFO "ZFS: misc_register() failed %d\n", error);
+
+       return (error);
+}
+
+void
+zfsdev_detach(void)
+{
+       misc_deregister(&zfs_misc);
+}
+
+#ifdef DEBUG
+#define        ZFS_DEBUG_STR   " (DEBUG mode)"
+#else
+#define        ZFS_DEBUG_STR   ""
+#endif
+
+static int __init
+_init(void)
+{
+       int error;
+
+       if ((error = zfs_kmod_init()) != 0) {
+               printk(KERN_NOTICE "ZFS: Failed to Load ZFS Filesystem v%s-%s%s"
+                   ", rc = %d\n", ZFS_META_VERSION, ZFS_META_RELEASE,
+                   ZFS_DEBUG_STR, error);
+
+               return (-error);
+       }
+
+       zfs_sysfs_init();
+
+       printk(KERN_NOTICE "ZFS: Loaded module v%s-%s%s, "
+           "ZFS pool version %s, ZFS filesystem version %s\n",
+           ZFS_META_VERSION, ZFS_META_RELEASE, ZFS_DEBUG_STR,
+           SPA_VERSION_STRING, ZPL_VERSION_STRING);
+#ifndef CONFIG_FS_POSIX_ACL
+       printk(KERN_NOTICE "ZFS: Posix ACLs disabled by kernel\n");
+#endif /* CONFIG_FS_POSIX_ACL */
+
+       return (0);
+}
+
+static void __exit
+_fini(void)
+{
+       zfs_sysfs_fini();
+       zfs_kmod_fini();
+
+       printk(KERN_NOTICE "ZFS: Unloaded module v%s-%s%s\n",
+           ZFS_META_VERSION, ZFS_META_RELEASE, ZFS_DEBUG_STR);
+}
+
+#if defined(_KERNEL)
+module_init(_init);
+module_exit(_fini);
+
+MODULE_DESCRIPTION("ZFS");
+MODULE_AUTHOR(ZFS_META_AUTHOR);
+MODULE_LICENSE(ZFS_META_LICENSE);
+MODULE_VERSION(ZFS_META_VERSION "-" ZFS_META_RELEASE);
+#endif
index 39718a9a8677cebdac4a1e76c9a86567ca54988d..dfd0b693e9b03acb4b0a3f4799a7e731e2fbcd66 100644 (file)
 #include <sys/dsl_scan.h>
 #include <sys/fm/util.h>
 #include <sys/dsl_crypt.h>
+#include <sys/rrwlock.h>
 
 #include <sys/dmu_recv.h>
 #include <sys/dmu_send.h>
 #include <sys/zcp.h>
 #include <sys/zio_checksum.h>
 #include <sys/vdev_removal.h>
-#include <sys/zfs_sysfs.h>
 #include <sys/vdev_impl.h>
 #include <sys/vdev_initialize.h>
 #include <sys/vdev_trim.h>
 
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-
 #include "zfs_namecheck.h"
 #include "zfs_prop.h"
 #include "zfs_deleg.h"
 
 #include <sys/lua/lua.h>
 #include <sys/lua/lauxlib.h>
-
-/*
- * Limit maximum nvlist size.  We don't want users passing in insane values
- * for zc->zc_nvlist_src_size, since we will need to allocate that much memory.
- */
-#define        MAX_NVLIST_SRC_SIZE     KMALLOC_MAX_SIZE
+#include <sys/zfs_ioctl_impl.h>
 
 kmutex_t zfsdev_state_lock;
 zfsdev_state_t *zfsdev_state_list;
@@ -231,58 +223,18 @@ zfsdev_state_t *zfsdev_state_list;
 extern void zfs_init(void);
 extern void zfs_fini(void);
 
-uint_t zfs_fsyncer_key;
-extern uint_t rrw_tsd_key;
-static uint_t zfs_allow_log_key;
-
-typedef int zfs_ioc_legacy_func_t(zfs_cmd_t *);
-typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *);
-typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *);
-
 /*
- * IOC Keys are used to document and validate user->kernel interface inputs.
- * See zfs_keys_recv_new for an example declaration. Any key name that is not
- * listed will be rejected as input.
- *
- * The keyname 'optional' is always allowed, and must be an nvlist if present.
- * Arguments which older kernels can safely ignore can be placed under the
- * "optional" key.
- *
- * When adding new keys to an existing ioc for new functionality, consider:
- *     - adding an entry into zfs_sysfs.c zfs_features[] list
- *     - updating the libzfs_input_check.c test utility
- *
- * Note: in the ZK_WILDCARDLIST case, the name serves as documentation
- * for the expected name (bookmark, snapshot, property, etc) but there
- * is no validation in the preflight zfs_check_input_nvpairs() check.
+ * Limit maximum nvlist size.  We don't want users passing in insane values
+ * for zc->zc_nvlist_src_size, since we will need to allocate that much memory.
  */
-typedef enum {
-       ZK_OPTIONAL = 1 << 0,           /* pair is optional */
-       ZK_WILDCARDLIST = 1 << 1,       /* one or more unspecified key names */
-} ioc_key_flag_t;
+#define        MAX_NVLIST_SRC_SIZE     KMALLOC_MAX_SIZE
+
+uint_t zfs_fsyncer_key;
+uint_t zfs_allow_log_key;
 
 /* DATA_TYPE_ANY is used when zkey_type can vary. */
 #define        DATA_TYPE_ANY   DATA_TYPE_UNKNOWN
 
-typedef struct zfs_ioc_key {
-       const char      *zkey_name;
-       data_type_t     zkey_type;
-       ioc_key_flag_t  zkey_flags;
-} zfs_ioc_key_t;
-
-typedef enum {
-       NO_NAME,
-       POOL_NAME,
-       DATASET_NAME,
-       ENTITY_NAME
-} zfs_ioc_namecheck_t;
-
-typedef enum {
-       POOL_CHECK_NONE         = 1 << 0,
-       POOL_CHECK_SUSPENDED    = 1 << 1,
-       POOL_CHECK_READONLY     = 1 << 2,
-} zfs_ioc_poolcheck_t;
-
 typedef struct zfs_ioc_vec {
        zfs_ioc_legacy_func_t   *zvec_legacy_func;
        zfs_ioc_func_t          *zvec_func;
@@ -490,7 +442,8 @@ zfs_dozonecheck(const char *dataset, cred_t *cr)
 {
        uint64_t zoned;
 
-       if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL))
+       if (dsl_prop_get_integer(dataset, zfs_prop_to_name(ZFS_PROP_ZONED),
+           &zoned, NULL))
                return (SET_ERROR(ENOENT));
 
        return (zfs_dozonecheck_impl(dataset, zoned, cr));
@@ -501,7 +454,7 @@ zfs_dozonecheck_ds(const char *dataset, dsl_dataset_t *ds, cred_t *cr)
 {
        uint64_t zoned;
 
-       if (dsl_prop_get_int_ds(ds, "zoned", &zoned))
+       if (dsl_prop_get_int_ds(ds, zfs_prop_to_name(ZFS_PROP_ZONED), &zoned))
                return (SET_ERROR(ENOENT));
 
        return (zfs_dozonecheck_impl(dataset, zoned, cr));
@@ -686,8 +639,8 @@ zfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval,
                         * limit on things *under* (ie. contained by)
                         * the thing they own.
                         */
-                       if (dsl_prop_get_integer(dsname, "zoned", &zoned,
-                           setpoint))
+                       if (dsl_prop_get_integer(dsname,
+                           zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, setpoint))
                                return (SET_ERROR(EPERM));
                        if (!zoned || strlen(dsname) <= strlen(setpoint))
                                return (SET_ERROR(EPERM));
@@ -1128,7 +1081,7 @@ zfs_secpolicy_create_clone(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
  * SYS_CONFIG privilege, which is not available in a local zone.
  */
 /* ARGSUSED */
-static int
+int
 zfs_secpolicy_config(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
 {
        if (secpolicy_sys_config(cr, B_FALSE) != 0)
@@ -1435,10 +1388,7 @@ getzfsvfs_impl(objset_t *os, zfsvfs_t **zfvp)
        mutex_enter(&os->os_user_ptr_lock);
        *zfvp = dmu_objset_get_user(os);
        /* bump s_active only when non-zero to prevent umount race */
-       if (*zfvp == NULL || (*zfvp)->z_sb == NULL ||
-           !atomic_inc_not_zero(&((*zfvp)->z_sb->s_active))) {
-               error = SET_ERROR(ESRCH);
-       }
+       error = zfs_vfs_ref(zfvp);
        mutex_exit(&os->os_user_ptr_lock);
        return (error);
 }
@@ -3622,23 +3572,40 @@ zfs_destroy_unmount_origin(const char *fsname)
  */
 static const zfs_ioc_key_t zfs_keys_destroy_snaps[] = {
        {"snaps",       DATA_TYPE_NVLIST,       0},
-       {"defer",       DATA_TYPE_BOOLEAN,      ZK_OPTIONAL},
+       {"defer",       DATA_TYPE_BOOLEAN,      ZK_OPTIONAL},
 };
 
 /* ARGSUSED */
 static int
 zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
 {
+       int poollen;
        nvlist_t *snaps;
        nvpair_t *pair;
        boolean_t defer;
+       spa_t *spa;
 
        snaps = fnvlist_lookup_nvlist(innvl, "snaps");
        defer = nvlist_exists(innvl, "defer");
 
+       poollen = strlen(poolname);
        for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
            pair = nvlist_next_nvpair(snaps, pair)) {
+               const char *name = nvpair_name(pair);
+
+               /*
+                * The snap must be in the specified pool to prevent the
+                * invalid removal of zvol minors below.
+                */
+               if (strncmp(name, poolname, poollen) != 0 ||
+                   (name[poollen] != '/' && name[poollen] != '@'))
+                       return (SET_ERROR(EXDEV));
+
                zfs_unmount_snap(nvpair_name(pair));
+               if (spa_open(name, &spa, FTAG) == 0) {
+                       zvol_remove_minors(spa, name, B_TRUE);
+                       spa_close(spa, FTAG);
+               }
        }
 
        return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
@@ -3811,9 +3778,9 @@ zfs_ioc_channel_program(const char *poolname, nvlist_t *innvl,
        nvarg = fnvlist_lookup_nvpair(innvl, ZCP_ARG_ARGLIST);
 
        if (instrlimit == 0 || instrlimit > zfs_lua_max_instrlimit)
-               return (EINVAL);
+               return (SET_ERROR(EINVAL));
        if (memlimit == 0 || memlimit > zfs_lua_max_memlimit)
-               return (EINVAL);
+               return (SET_ERROR(EINVAL));
 
        return (zcp_eval(poolname, program, sync_flag, instrlimit, memlimit,
            nvarg, outnvl));
@@ -4715,6 +4682,15 @@ extract_delay_props(nvlist_t *props)
        return (delayprops);
 }
 
+static void
+zfs_allow_log_destroy(void *arg)
+{
+       char *poolname = arg;
+
+       if (poolname != NULL)
+               strfree(poolname);
+}
+
 #ifdef DEBUG
 static boolean_t zfs_ioc_recv_inject_err;
 #endif
@@ -5602,7 +5578,7 @@ zfs_ioc_clear(zfs_cmd_t *zc)
  * outnvl is unused
  */
 static const zfs_ioc_key_t zfs_keys_pool_reopen[] = {
-       {"scrub_restart",       DATA_TYPE_BOOLEAN_VALUE,        0},
+       {"scrub_restart",       DATA_TYPE_BOOLEAN_VALUE,        ZK_OPTIONAL},
 };
 
 /* ARGSUSED */
@@ -5611,11 +5587,13 @@ zfs_ioc_pool_reopen(const char *pool, nvlist_t *innvl, nvlist_t *outnvl)
 {
        spa_t *spa;
        int error;
-       boolean_t scrub_restart = B_TRUE;
+       boolean_t rc, scrub_restart = B_TRUE;
 
        if (innvl) {
-               scrub_restart = fnvlist_lookup_boolean_value(innvl,
-                   "scrub_restart");
+               error = nvlist_lookup_boolean_value(innvl,
+                   "scrub_restart", &rc);
+               if (error == 0)
+                       scrub_restart = rc;
        }
 
        error = spa_open(pool, &spa, FTAG);
@@ -6016,13 +5994,13 @@ zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist)
        if (nvlist_lookup_int32(args, "cleanup_fd", &cleanup_fd) == 0) {
                error = zfs_onexit_fd_hold(cleanup_fd, &minor);
                if (error != 0)
-                       return (error);
+                       return (SET_ERROR(error));
        }
 
        error = dsl_dataset_user_hold(holds, minor, errlist);
        if (minor != 0)
                zfs_onexit_fd_rele(cleanup_fd);
-       return (error);
+       return (SET_ERROR(error));
 }
 
 /*
@@ -6714,7 +6692,7 @@ zfs_ioctl_register_legacy(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
  * See the block comment at the beginning of this file for details on
  * each argument to this function.
  */
-static void
+void
 zfs_ioctl_register(const char *name, zfs_ioc_t ioc, zfs_ioc_func_t *func,
     zfs_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck,
     zfs_ioc_poolcheck_t pool_check, boolean_t smush_outnvlist,
@@ -6750,7 +6728,7 @@ zfs_ioctl_register_pool(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
            POOL_NAME, log_history, pool_check);
 }
 
-static void
+void
 zfs_ioctl_register_dataset_nolog(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
     zfs_secpolicy_func_t *secpolicy, zfs_ioc_poolcheck_t pool_check)
 {
@@ -6796,7 +6774,7 @@ zfs_ioctl_register_dataset_modify(zfs_ioc_t ioc, zfs_ioc_legacy_func_t *func,
            DATASET_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
 }
 
-static void
+void
 zfs_ioctl_init(void)
 {
        zfs_ioctl_register("snapshot", ZFS_IOC_SNAPSHOT,
@@ -7080,15 +7058,14 @@ zfs_ioctl_init(void)
            zfs_ioc_tmp_snapshot, zfs_secpolicy_tmp_snapshot,
            POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
 
-       /*
-        * ZoL functions
-        */
        zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_NEXT, zfs_ioc_events_next,
            zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
        zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_CLEAR, zfs_ioc_events_clear,
            zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
        zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_SEEK, zfs_ioc_events_seek,
            zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
+
+       zfs_ioctl_init_os();
 }
 
 /*
@@ -7221,37 +7198,6 @@ zfsdev_get_state(minor_t minor, enum zfsdev_state_type which)
        return (ptr);
 }
 
-int
-zfsdev_getminor(struct file *filp, minor_t *minorp)
-{
-       zfsdev_state_t *zs, *fpd;
-
-       ASSERT(filp != NULL);
-       ASSERT(!MUTEX_HELD(&zfsdev_state_lock));
-
-       fpd = filp->private_data;
-       if (fpd == NULL)
-               return (SET_ERROR(EBADF));
-
-       mutex_enter(&zfsdev_state_lock);
-
-       for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
-
-               if (zs->zs_minor == -1)
-                       continue;
-
-               if (fpd == zs) {
-                       *minorp = fpd->zs_minor;
-                       mutex_exit(&zfsdev_state_lock);
-                       return (0);
-               }
-       }
-
-       mutex_exit(&zfsdev_state_lock);
-
-       return (SET_ERROR(EBADF));
-}
-
 /*
  * 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.
@@ -7276,109 +7222,17 @@ zfsdev_minor_alloc(void)
        return (0);
 }
 
-static int
-zfsdev_state_init(struct file *filp)
-{
-       zfsdev_state_t *zs, *zsprev = NULL;
-       minor_t minor;
-       boolean_t newzs = B_FALSE;
-
-       ASSERT(MUTEX_HELD(&zfsdev_state_lock));
-
-       minor = zfsdev_minor_alloc();
-       if (minor == 0)
-               return (SET_ERROR(ENXIO));
-
-       for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
-               if (zs->zs_minor == -1)
-                       break;
-               zsprev = zs;
-       }
-
-       if (!zs) {
-               zs = kmem_zalloc(sizeof (zfsdev_state_t), KM_SLEEP);
-               newzs = B_TRUE;
-       }
-
-       zs->zs_file = filp;
-       filp->private_data = zs;
-
-       zfs_onexit_init((zfs_onexit_t **)&zs->zs_onexit);
-       zfs_zevent_init((zfs_zevent_t **)&zs->zs_zevent);
-
-
-       /*
-        * In order to provide for lock-free concurrent read access
-        * to the minor list in zfsdev_get_state_impl(), new entries
-        * must be completely written before linking them into the
-        * list whereas existing entries are already linked; the last
-        * operation must be updating zs_minor (from -1 to the new
-        * value).
-        */
-       if (newzs) {
-               zs->zs_minor = minor;
-               smp_wmb();
-               zsprev->zs_next = zs;
-       } else {
-               smp_wmb();
-               zs->zs_minor = minor;
-       }
-
-       return (0);
-}
-
-static int
-zfsdev_state_destroy(struct file *filp)
-{
-       zfsdev_state_t *zs;
-
-       ASSERT(MUTEX_HELD(&zfsdev_state_lock));
-       ASSERT(filp->private_data != NULL);
-
-       zs = filp->private_data;
-       zs->zs_minor = -1;
-       zfs_onexit_destroy(zs->zs_onexit);
-       zfs_zevent_destroy(zs->zs_zevent);
-
-       return (0);
-}
-
-static int
-zfsdev_open(struct inode *ino, struct file *filp)
-{
-       int error;
-
-       mutex_enter(&zfsdev_state_lock);
-       error = zfsdev_state_init(filp);
-       mutex_exit(&zfsdev_state_lock);
-
-       return (-error);
-}
-
-static int
-zfsdev_release(struct inode *ino, struct file *filp)
-{
-       int error;
-
-       mutex_enter(&zfsdev_state_lock);
-       error = zfsdev_state_destroy(filp);
-       mutex_exit(&zfsdev_state_lock);
-
-       return (-error);
-}
-
-static long
-zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
+long
+zfsdev_ioctl_common(uint_t vecnum, unsigned long arg)
 {
        zfs_cmd_t *zc;
-       uint_t vecnum;
-       int error, rc, flag = 0;
+       int error, cmd, rc, flag = 0;
        const zfs_ioc_vec_t *vec;
        char *saved_poolname = NULL;
        nvlist_t *innvl = NULL;
        fstrans_cookie_t cookie;
 
-       vecnum = cmd - ZFS_IOC_FIRST;
+       cmd = vecnum;
        if (vecnum >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
                return (-SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL));
        vec = &zfs_ioc_vec[vecnum];
@@ -7577,69 +7431,46 @@ out:
        return (-error);
 }
 
-#ifdef CONFIG_COMPAT
-static long
-zfsdev_compat_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
+int
+zfs_kmod_init(void)
 {
-       return (zfsdev_ioctl(filp, cmd, arg));
-}
-#else
-#define        zfsdev_compat_ioctl     NULL
-#endif
-
-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,
-};
+       int error;
 
-static struct miscdevice zfs_misc = {
-       .minor          = ZFS_DEVICE_MINOR,
-       .name           = ZFS_DRIVER,
-       .fops           = &zfsdev_fops,
-};
+       if ((error = zvol_init()) != 0)
+               return (error);
 
-MODULE_ALIAS_MISCDEV(ZFS_DEVICE_MINOR);
-MODULE_ALIAS("devname:zfs");
+       spa_init(FREAD | FWRITE);
+       zfs_init();
 
-static int
-zfs_attach(void)
-{
-       int error;
+       zfs_ioctl_init();
 
        mutex_init(&zfsdev_state_lock, NULL, MUTEX_DEFAULT, NULL);
        zfsdev_state_list = kmem_zalloc(sizeof (zfsdev_state_t), KM_SLEEP);
        zfsdev_state_list->zs_minor = -1;
 
-       error = misc_register(&zfs_misc);
-       if (error == -EBUSY) {
-               /*
-                * Fallback to dynamic minor allocation in the event of a
-                * collision with a reserved minor in linux/miscdevice.h.
-                * In this case the kernel modules must be manually loaded.
-                */
-               printk(KERN_INFO "ZFS: misc_register() with static minor %d "
-                   "failed %d, retrying with MISC_DYNAMIC_MINOR\n",
-                   ZFS_DEVICE_MINOR, error);
+       if ((error = zfsdev_attach()) != 0)
+               goto out;
 
-               zfs_misc.minor = MISC_DYNAMIC_MINOR;
-               error = misc_register(&zfs_misc);
-       }
+       tsd_create(&zfs_fsyncer_key, NULL);
+       tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
+       tsd_create(&zfs_allow_log_key, zfs_allow_log_destroy);
 
-       if (error)
-               printk(KERN_INFO "ZFS: misc_register() failed %d\n", error);
+       return (0);
+out:
+       zfs_fini();
+       spa_fini();
+       zvol_fini();
 
        return (error);
 }
 
-static void
-zfs_detach(void)
+void
+zfs_kmod_fini(void)
 {
        zfsdev_state_t *zs, *zsprev = NULL;
 
-       misc_deregister(&zfs_misc);
+       zfsdev_detach();
+
        mutex_destroy(&zfsdev_state_lock);
 
        for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
@@ -7649,71 +7480,7 @@ zfs_detach(void)
        }
        if (zsprev)
                kmem_free(zsprev, sizeof (zfsdev_state_t));
-}
-
-static void
-zfs_allow_log_destroy(void *arg)
-{
-       char *poolname = arg;
-
-       if (poolname != NULL)
-               strfree(poolname);
-}
 
-#ifdef DEBUG
-#define        ZFS_DEBUG_STR   " (DEBUG mode)"
-#else
-#define        ZFS_DEBUG_STR   ""
-#endif
-
-static int __init
-_init(void)
-{
-       int error;
-
-       if ((error = zvol_init()) != 0)
-               return (error);
-
-       spa_init(FREAD | FWRITE);
-       zfs_init();
-
-       zfs_ioctl_init();
-       zfs_sysfs_init();
-
-       if ((error = zfs_attach()) != 0)
-               goto out;
-
-       tsd_create(&zfs_fsyncer_key, NULL);
-       tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
-       tsd_create(&zfs_allow_log_key, zfs_allow_log_destroy);
-
-       printk(KERN_NOTICE "ZFS: Loaded module v%s-%s%s, "
-           "ZFS pool version %s, ZFS filesystem version %s\n",
-           ZFS_META_VERSION, ZFS_META_RELEASE, ZFS_DEBUG_STR,
-           SPA_VERSION_STRING, ZPL_VERSION_STRING);
-#ifndef CONFIG_FS_POSIX_ACL
-       printk(KERN_NOTICE "ZFS: Posix ACLs disabled by kernel\n");
-#endif /* CONFIG_FS_POSIX_ACL */
-
-       return (0);
-
-out:
-       zfs_sysfs_fini();
-       zfs_fini();
-       spa_fini();
-       (void) zvol_fini();
-       printk(KERN_NOTICE "ZFS: Failed to Load ZFS Filesystem v%s-%s%s"
-           ", rc = %d\n", ZFS_META_VERSION, ZFS_META_RELEASE,
-           ZFS_DEBUG_STR, error);
-
-       return (error);
-}
-
-static void __exit
-_fini(void)
-{
-       zfs_detach();
-       zfs_sysfs_fini();
        zfs_fini();
        spa_fini();
        zvol_fini();
@@ -7721,17 +7488,4 @@ _fini(void)
        tsd_destroy(&zfs_fsyncer_key);
        tsd_destroy(&rrw_tsd_key);
        tsd_destroy(&zfs_allow_log_key);
-
-       printk(KERN_NOTICE "ZFS: Unloaded module v%s-%s%s\n",
-           ZFS_META_VERSION, ZFS_META_RELEASE, ZFS_DEBUG_STR);
 }
-
-#if defined(_KERNEL)
-module_init(_init);
-module_exit(_fini);
-
-MODULE_DESCRIPTION("ZFS");
-MODULE_AUTHOR(ZFS_META_AUTHOR);
-MODULE_LICENSE(ZFS_META_LICENSE);
-MODULE_VERSION(ZFS_META_VERSION "-" ZFS_META_RELEASE);
-#endif
index d47954e2bc0ffee0d05860842743a790229cf99f..f3392dc17f58c12d9321f164e70b417519bb8dba 100644 (file)
@@ -272,13 +272,13 @@ test_pool_sync(const char *pool)
 static void
 test_pool_reopen(const char *pool)
 {
-       nvlist_t *required = fnvlist_alloc();
+       nvlist_t *optional = fnvlist_alloc();
 
-       fnvlist_add_boolean_value(required, "scrub_restart", B_FALSE);
+       fnvlist_add_boolean_value(optional, "scrub_restart", B_FALSE);
 
-       IOC_INPUT_TEST(ZFS_IOC_POOL_REOPEN, pool, required, NULL, 0);
+       IOC_INPUT_TEST(ZFS_IOC_POOL_REOPEN, pool, NULL, optional, 0);
 
-       nvlist_free(required);
+       nvlist_free(optional);
 }
 
 static void