OpenZFS restructuring - zfs_ioctl
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
This commit is contained in:
parent
3768db24ab
commit
7bb0c29468
|
@ -194,8 +194,6 @@ typedef struct zfid_long {
|
||||||
#define SHORT_FID_LEN (sizeof (zfid_short_t) - sizeof (uint16_t))
|
#define SHORT_FID_LEN (sizeof (zfid_short_t) - sizeof (uint16_t))
|
||||||
#define LONG_FID_LEN (sizeof (zfid_long_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_suspend_fs(zfsvfs_t *zfsvfs);
|
||||||
extern int zfs_resume_fs(zfsvfs_t *zfsvfs, struct dsl_dataset *ds);
|
extern int zfs_resume_fs(zfsvfs_t *zfsvfs, struct dsl_dataset *ds);
|
||||||
extern int zfs_end_fs(zfsvfs_t *zfsvfs, struct dsl_dataset *ds);
|
extern int zfs_end_fs(zfsvfs_t *zfsvfs, struct dsl_dataset *ds);
|
||||||
|
|
|
@ -124,6 +124,7 @@ COMMON_H = \
|
||||||
|
|
||||||
KERNEL_H = \
|
KERNEL_H = \
|
||||||
$(top_srcdir)/include/sys/zfs_ioctl.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/zfs_onexit.h \
|
||||||
$(top_srcdir)/include/sys/zvol.h \
|
$(top_srcdir)/include/sys/zvol.h \
|
||||||
$(top_srcdir)/include/sys/zvol_impl.h
|
$(top_srcdir)/include/sys/zvol_impl.h
|
||||||
|
|
|
@ -39,6 +39,8 @@ extern "C" {
|
||||||
#include <sys/zfs_context.h>
|
#include <sys/zfs_context.h>
|
||||||
#include <sys/refcount.h>
|
#include <sys/refcount.h>
|
||||||
|
|
||||||
|
extern uint_t rrw_tsd_key;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A reader-writer lock implementation that allows re-entrant reads, but
|
* A reader-writer lock implementation that allows re-entrant reads, but
|
||||||
* still gives writers priority on "new" reads.
|
* still gives writers priority on "new" reads.
|
||||||
|
|
|
@ -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 int zfsdev_getminor(struct file *filp, minor_t *minorp);
|
||||||
extern minor_t zfsdev_minor_alloc(void);
|
extern minor_t zfsdev_minor_alloc(void);
|
||||||
|
|
||||||
|
extern uint_t zfs_fsyncer_key;
|
||||||
|
extern uint_t zfs_allow_log_key;
|
||||||
|
|
||||||
#endif /* _KERNEL */
|
#endif /* _KERNEL */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -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
|
|
@ -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_ctldir.o
|
||||||
$(MODULE)-objs += ../os/linux/zfs/zfs_debug.o
|
$(MODULE)-objs += ../os/linux/zfs/zfs_debug.o
|
||||||
$(MODULE)-objs += ../os/linux/zfs/zfs_dir.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_sysfs.o
|
||||||
$(MODULE)-objs += ../os/linux/zfs/zfs_vfsops.o
|
$(MODULE)-objs += ../os/linux/zfs/zfs_vfsops.o
|
||||||
$(MODULE)-objs += ../os/linux/zfs/zfs_vnops.o
|
$(MODULE)-objs += ../os/linux/zfs/zfs_vnops.o
|
||||||
|
|
|
@ -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
|
|
@ -192,6 +192,7 @@
|
||||||
#include <sys/dsl_scan.h>
|
#include <sys/dsl_scan.h>
|
||||||
#include <sys/fm/util.h>
|
#include <sys/fm/util.h>
|
||||||
#include <sys/dsl_crypt.h>
|
#include <sys/dsl_crypt.h>
|
||||||
|
#include <sys/rrwlock.h>
|
||||||
|
|
||||||
#include <sys/dmu_recv.h>
|
#include <sys/dmu_recv.h>
|
||||||
#include <sys/dmu_send.h>
|
#include <sys/dmu_send.h>
|
||||||
|
@ -203,14 +204,10 @@
|
||||||
#include <sys/zcp.h>
|
#include <sys/zcp.h>
|
||||||
#include <sys/zio_checksum.h>
|
#include <sys/zio_checksum.h>
|
||||||
#include <sys/vdev_removal.h>
|
#include <sys/vdev_removal.h>
|
||||||
#include <sys/zfs_sysfs.h>
|
|
||||||
#include <sys/vdev_impl.h>
|
#include <sys/vdev_impl.h>
|
||||||
#include <sys/vdev_initialize.h>
|
#include <sys/vdev_initialize.h>
|
||||||
#include <sys/vdev_trim.h>
|
#include <sys/vdev_trim.h>
|
||||||
|
|
||||||
#include <linux/miscdevice.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
|
|
||||||
#include "zfs_namecheck.h"
|
#include "zfs_namecheck.h"
|
||||||
#include "zfs_prop.h"
|
#include "zfs_prop.h"
|
||||||
#include "zfs_deleg.h"
|
#include "zfs_deleg.h"
|
||||||
|
@ -218,12 +215,7 @@
|
||||||
|
|
||||||
#include <sys/lua/lua.h>
|
#include <sys/lua/lua.h>
|
||||||
#include <sys/lua/lauxlib.h>
|
#include <sys/lua/lauxlib.h>
|
||||||
|
#include <sys/zfs_ioctl_impl.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
|
|
||||||
|
|
||||||
kmutex_t zfsdev_state_lock;
|
kmutex_t zfsdev_state_lock;
|
||||||
zfsdev_state_t *zfsdev_state_list;
|
zfsdev_state_t *zfsdev_state_list;
|
||||||
|
@ -231,58 +223,18 @@ zfsdev_state_t *zfsdev_state_list;
|
||||||
extern void zfs_init(void);
|
extern void zfs_init(void);
|
||||||
extern void zfs_fini(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.
|
* Limit maximum nvlist size. We don't want users passing in insane values
|
||||||
* See zfs_keys_recv_new for an example declaration. Any key name that is not
|
* for zc->zc_nvlist_src_size, since we will need to allocate that much memory.
|
||||||
* 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 {
|
#define MAX_NVLIST_SRC_SIZE KMALLOC_MAX_SIZE
|
||||||
ZK_OPTIONAL = 1 << 0, /* pair is optional */
|
|
||||||
ZK_WILDCARDLIST = 1 << 1, /* one or more unspecified key names */
|
uint_t zfs_fsyncer_key;
|
||||||
} ioc_key_flag_t;
|
uint_t zfs_allow_log_key;
|
||||||
|
|
||||||
/* DATA_TYPE_ANY is used when zkey_type can vary. */
|
/* DATA_TYPE_ANY is used when zkey_type can vary. */
|
||||||
#define DATA_TYPE_ANY DATA_TYPE_UNKNOWN
|
#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 {
|
typedef struct zfs_ioc_vec {
|
||||||
zfs_ioc_legacy_func_t *zvec_legacy_func;
|
zfs_ioc_legacy_func_t *zvec_legacy_func;
|
||||||
zfs_ioc_func_t *zvec_func;
|
zfs_ioc_func_t *zvec_func;
|
||||||
|
@ -490,7 +442,8 @@ zfs_dozonecheck(const char *dataset, cred_t *cr)
|
||||||
{
|
{
|
||||||
uint64_t zoned;
|
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 (SET_ERROR(ENOENT));
|
||||||
|
|
||||||
return (zfs_dozonecheck_impl(dataset, zoned, cr));
|
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;
|
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 (SET_ERROR(ENOENT));
|
||||||
|
|
||||||
return (zfs_dozonecheck_impl(dataset, zoned, cr));
|
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)
|
* limit on things *under* (ie. contained by)
|
||||||
* the thing they own.
|
* the thing they own.
|
||||||
*/
|
*/
|
||||||
if (dsl_prop_get_integer(dsname, "zoned", &zoned,
|
if (dsl_prop_get_integer(dsname,
|
||||||
setpoint))
|
zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, setpoint))
|
||||||
return (SET_ERROR(EPERM));
|
return (SET_ERROR(EPERM));
|
||||||
if (!zoned || strlen(dsname) <= strlen(setpoint))
|
if (!zoned || strlen(dsname) <= strlen(setpoint))
|
||||||
return (SET_ERROR(EPERM));
|
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.
|
* SYS_CONFIG privilege, which is not available in a local zone.
|
||||||
*/
|
*/
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
static int
|
int
|
||||||
zfs_secpolicy_config(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
|
zfs_secpolicy_config(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
|
||||||
{
|
{
|
||||||
if (secpolicy_sys_config(cr, B_FALSE) != 0)
|
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);
|
mutex_enter(&os->os_user_ptr_lock);
|
||||||
*zfvp = dmu_objset_get_user(os);
|
*zfvp = dmu_objset_get_user(os);
|
||||||
/* bump s_active only when non-zero to prevent umount race */
|
/* bump s_active only when non-zero to prevent umount race */
|
||||||
if (*zfvp == NULL || (*zfvp)->z_sb == NULL ||
|
error = zfs_vfs_ref(zfvp);
|
||||||
!atomic_inc_not_zero(&((*zfvp)->z_sb->s_active))) {
|
|
||||||
error = SET_ERROR(ESRCH);
|
|
||||||
}
|
|
||||||
mutex_exit(&os->os_user_ptr_lock);
|
mutex_exit(&os->os_user_ptr_lock);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
@ -3629,16 +3579,33 @@ static const zfs_ioc_key_t zfs_keys_destroy_snaps[] = {
|
||||||
static int
|
static int
|
||||||
zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
|
zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||||
{
|
{
|
||||||
|
int poollen;
|
||||||
nvlist_t *snaps;
|
nvlist_t *snaps;
|
||||||
nvpair_t *pair;
|
nvpair_t *pair;
|
||||||
boolean_t defer;
|
boolean_t defer;
|
||||||
|
spa_t *spa;
|
||||||
|
|
||||||
snaps = fnvlist_lookup_nvlist(innvl, "snaps");
|
snaps = fnvlist_lookup_nvlist(innvl, "snaps");
|
||||||
defer = nvlist_exists(innvl, "defer");
|
defer = nvlist_exists(innvl, "defer");
|
||||||
|
|
||||||
|
poollen = strlen(poolname);
|
||||||
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
|
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
|
||||||
pair = nvlist_next_nvpair(snaps, pair)) {
|
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));
|
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));
|
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);
|
nvarg = fnvlist_lookup_nvpair(innvl, ZCP_ARG_ARGLIST);
|
||||||
|
|
||||||
if (instrlimit == 0 || instrlimit > zfs_lua_max_instrlimit)
|
if (instrlimit == 0 || instrlimit > zfs_lua_max_instrlimit)
|
||||||
return (EINVAL);
|
return (SET_ERROR(EINVAL));
|
||||||
if (memlimit == 0 || memlimit > zfs_lua_max_memlimit)
|
if (memlimit == 0 || memlimit > zfs_lua_max_memlimit)
|
||||||
return (EINVAL);
|
return (SET_ERROR(EINVAL));
|
||||||
|
|
||||||
return (zcp_eval(poolname, program, sync_flag, instrlimit, memlimit,
|
return (zcp_eval(poolname, program, sync_flag, instrlimit, memlimit,
|
||||||
nvarg, outnvl));
|
nvarg, outnvl));
|
||||||
|
@ -4715,6 +4682,15 @@ extract_delay_props(nvlist_t *props)
|
||||||
return (delayprops);
|
return (delayprops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
zfs_allow_log_destroy(void *arg)
|
||||||
|
{
|
||||||
|
char *poolname = arg;
|
||||||
|
|
||||||
|
if (poolname != NULL)
|
||||||
|
strfree(poolname);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static boolean_t zfs_ioc_recv_inject_err;
|
static boolean_t zfs_ioc_recv_inject_err;
|
||||||
#endif
|
#endif
|
||||||
|
@ -5602,7 +5578,7 @@ zfs_ioc_clear(zfs_cmd_t *zc)
|
||||||
* outnvl is unused
|
* outnvl is unused
|
||||||
*/
|
*/
|
||||||
static const zfs_ioc_key_t zfs_keys_pool_reopen[] = {
|
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 */
|
/* ARGSUSED */
|
||||||
|
@ -5611,11 +5587,13 @@ zfs_ioc_pool_reopen(const char *pool, nvlist_t *innvl, nvlist_t *outnvl)
|
||||||
{
|
{
|
||||||
spa_t *spa;
|
spa_t *spa;
|
||||||
int error;
|
int error;
|
||||||
boolean_t scrub_restart = B_TRUE;
|
boolean_t rc, scrub_restart = B_TRUE;
|
||||||
|
|
||||||
if (innvl) {
|
if (innvl) {
|
||||||
scrub_restart = fnvlist_lookup_boolean_value(innvl,
|
error = nvlist_lookup_boolean_value(innvl,
|
||||||
"scrub_restart");
|
"scrub_restart", &rc);
|
||||||
|
if (error == 0)
|
||||||
|
scrub_restart = rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = spa_open(pool, &spa, FTAG);
|
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) {
|
if (nvlist_lookup_int32(args, "cleanup_fd", &cleanup_fd) == 0) {
|
||||||
error = zfs_onexit_fd_hold(cleanup_fd, &minor);
|
error = zfs_onexit_fd_hold(cleanup_fd, &minor);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (SET_ERROR(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
error = dsl_dataset_user_hold(holds, minor, errlist);
|
error = dsl_dataset_user_hold(holds, minor, errlist);
|
||||||
if (minor != 0)
|
if (minor != 0)
|
||||||
zfs_onexit_fd_rele(cleanup_fd);
|
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
|
* See the block comment at the beginning of this file for details on
|
||||||
* each argument to this function.
|
* each argument to this function.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
zfs_ioctl_register(const char *name, zfs_ioc_t ioc, zfs_ioc_func_t *func,
|
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_secpolicy_func_t *secpolicy, zfs_ioc_namecheck_t namecheck,
|
||||||
zfs_ioc_poolcheck_t pool_check, boolean_t smush_outnvlist,
|
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);
|
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_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)
|
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);
|
DATASET_NAME, B_TRUE, POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
zfs_ioctl_init(void)
|
zfs_ioctl_init(void)
|
||||||
{
|
{
|
||||||
zfs_ioctl_register("snapshot", ZFS_IOC_SNAPSHOT,
|
zfs_ioctl_register("snapshot", ZFS_IOC_SNAPSHOT,
|
||||||
|
@ -7080,15 +7058,14 @@ zfs_ioctl_init(void)
|
||||||
zfs_ioc_tmp_snapshot, zfs_secpolicy_tmp_snapshot,
|
zfs_ioc_tmp_snapshot, zfs_secpolicy_tmp_snapshot,
|
||||||
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
|
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
|
||||||
|
|
||||||
/*
|
|
||||||
* ZoL functions
|
|
||||||
*/
|
|
||||||
zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_NEXT, zfs_ioc_events_next,
|
zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_NEXT, zfs_ioc_events_next,
|
||||||
zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
|
zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
|
||||||
zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_CLEAR, zfs_ioc_events_clear,
|
zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_CLEAR, zfs_ioc_events_clear,
|
||||||
zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
|
zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
|
||||||
zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_SEEK, zfs_ioc_events_seek,
|
zfs_ioctl_register_legacy(ZFS_IOC_EVENTS_SEEK, zfs_ioc_events_seek,
|
||||||
zfs_secpolicy_config, NO_NAME, B_FALSE, POOL_CHECK_NONE);
|
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);
|
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
|
* 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.
|
* be short since it is only a list of currently open file handles.
|
||||||
|
@ -7276,109 +7222,17 @@ zfsdev_minor_alloc(void)
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
long
|
||||||
zfsdev_state_init(struct file *filp)
|
zfsdev_ioctl_common(uint_t vecnum, unsigned long arg)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
zfs_cmd_t *zc;
|
zfs_cmd_t *zc;
|
||||||
uint_t vecnum;
|
int error, cmd, rc, flag = 0;
|
||||||
int error, rc, flag = 0;
|
|
||||||
const zfs_ioc_vec_t *vec;
|
const zfs_ioc_vec_t *vec;
|
||||||
char *saved_poolname = NULL;
|
char *saved_poolname = NULL;
|
||||||
nvlist_t *innvl = NULL;
|
nvlist_t *innvl = NULL;
|
||||||
fstrans_cookie_t cookie;
|
fstrans_cookie_t cookie;
|
||||||
|
|
||||||
vecnum = cmd - ZFS_IOC_FIRST;
|
cmd = vecnum;
|
||||||
if (vecnum >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
|
if (vecnum >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
|
||||||
return (-SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL));
|
return (-SET_ERROR(ZFS_ERR_IOC_CMD_UNAVAIL));
|
||||||
vec = &zfs_ioc_vec[vecnum];
|
vec = &zfs_ioc_vec[vecnum];
|
||||||
|
@ -7577,97 +7431,8 @@ out:
|
||||||
return (-error);
|
return (-error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_COMPAT
|
int
|
||||||
static long
|
zfs_kmod_init(void)
|
||||||
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");
|
|
||||||
|
|
||||||
static int
|
|
||||||
zfs_attach(void)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
zfs_detach(void)
|
|
||||||
{
|
|
||||||
zfsdev_state_t *zs, *zsprev = NULL;
|
|
||||||
|
|
||||||
misc_deregister(&zfs_misc);
|
|
||||||
mutex_destroy(&zfsdev_state_lock);
|
|
||||||
|
|
||||||
for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
|
|
||||||
if (zsprev)
|
|
||||||
kmem_free(zsprev, sizeof (zfsdev_state_t));
|
|
||||||
zsprev = zs;
|
|
||||||
}
|
|
||||||
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;
|
int error;
|
||||||
|
|
||||||
|
@ -7678,42 +7443,44 @@ _init(void)
|
||||||
zfs_init();
|
zfs_init();
|
||||||
|
|
||||||
zfs_ioctl_init();
|
zfs_ioctl_init();
|
||||||
zfs_sysfs_init();
|
|
||||||
|
|
||||||
if ((error = zfs_attach()) != 0)
|
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;
|
||||||
|
|
||||||
|
if ((error = zfsdev_attach()) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
tsd_create(&zfs_fsyncer_key, NULL);
|
tsd_create(&zfs_fsyncer_key, NULL);
|
||||||
tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
|
tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
|
||||||
tsd_create(&zfs_allow_log_key, zfs_allow_log_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);
|
return (0);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
zfs_sysfs_fini();
|
|
||||||
zfs_fini();
|
zfs_fini();
|
||||||
spa_fini();
|
spa_fini();
|
||||||
(void) zvol_fini();
|
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);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit
|
void
|
||||||
_fini(void)
|
zfs_kmod_fini(void)
|
||||||
{
|
{
|
||||||
zfs_detach();
|
zfsdev_state_t *zs, *zsprev = NULL;
|
||||||
zfs_sysfs_fini();
|
|
||||||
|
zfsdev_detach();
|
||||||
|
|
||||||
|
mutex_destroy(&zfsdev_state_lock);
|
||||||
|
|
||||||
|
for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
|
||||||
|
if (zsprev)
|
||||||
|
kmem_free(zsprev, sizeof (zfsdev_state_t));
|
||||||
|
zsprev = zs;
|
||||||
|
}
|
||||||
|
if (zsprev)
|
||||||
|
kmem_free(zsprev, sizeof (zfsdev_state_t));
|
||||||
|
|
||||||
zfs_fini();
|
zfs_fini();
|
||||||
spa_fini();
|
spa_fini();
|
||||||
zvol_fini();
|
zvol_fini();
|
||||||
|
@ -7721,17 +7488,4 @@ _fini(void)
|
||||||
tsd_destroy(&zfs_fsyncer_key);
|
tsd_destroy(&zfs_fsyncer_key);
|
||||||
tsd_destroy(&rrw_tsd_key);
|
tsd_destroy(&rrw_tsd_key);
|
||||||
tsd_destroy(&zfs_allow_log_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
|
|
||||||
|
|
|
@ -272,13 +272,13 @@ test_pool_sync(const char *pool)
|
||||||
static void
|
static void
|
||||||
test_pool_reopen(const char *pool)
|
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
|
static void
|
||||||
|
|
Loading…
Reference in New Issue