1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Portions Copyright 2011 Martin Matuska
25 * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
26 * Portions Copyright 2012 Pawel Jakub Dawidek <pawel@dawidek.net>
27 * Copyright (c) 2014, 2016 Joyent, Inc. All rights reserved.
28 * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
29 * Copyright (c) 2014, Joyent, Inc. All rights reserved.
30 * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
31 * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
32 * Copyright (c) 2013 Steven Hartland. All rights reserved.
33 * Copyright (c) 2014 Integros [integros.com]
34 * Copyright 2016 Toomas Soome <tsoome@me.com>
35 * Copyright (c) 2016 Actifio, Inc. All rights reserved.
36 * Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
37 * Copyright 2017 RackTop Systems.
38 * Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
39 * Copyright (c) 2019 Datto Inc.
40 */
41
42#include <sys/types.h>
43#include <sys/param.h>
44#include <sys/errno.h>
45#include <sys/uio.h>
46#include <sys/file.h>
47#include <sys/kmem.h>
48#include <sys/stat.h>
49#include <sys/zfs_ioctl.h>
50#include <sys/zfs_vfsops.h>
51#include <sys/zap.h>
52#include <sys/spa.h>
53#include <sys/nvpair.h>
54#include <sys/fs/zfs.h>
55#include <sys/zfs_ctldir.h>
56#include <sys/zfs_dir.h>
57#include <sys/zfs_onexit.h>
58#include <sys/zvol.h>
59#include <sys/fm/util.h>
60#include <sys/dsl_crypt.h>
61
62#include <sys/zfs_ioctl_impl.h>
63
64#include <sys/zfs_sysfs.h>
65#include <linux/miscdevice.h>
66#include <linux/slab.h>
67
68boolean_t
69zfs_vfs_held(zfsvfs_t *zfsvfs)
70{
71	return (zfsvfs->z_sb != NULL);
72}
73
74int
75zfs_vfs_ref(zfsvfs_t **zfvp)
76{
77	if (*zfvp == NULL || (*zfvp)->z_sb == NULL ||
78	    !atomic_inc_not_zero(&((*zfvp)->z_sb->s_active))) {
79		return (SET_ERROR(ESRCH));
80	}
81	return (0);
82}
83
84void
85zfs_vfs_rele(zfsvfs_t *zfsvfs)
86{
87	deactivate_super(zfsvfs->z_sb);
88}
89
90static int
91zfsdev_state_init(struct file *filp)
92{
93	zfsdev_state_t *zs, *zsprev = NULL;
94	minor_t minor;
95	boolean_t newzs = B_FALSE;
96
97	ASSERT(MUTEX_HELD(&zfsdev_state_lock));
98
99	minor = zfsdev_minor_alloc();
100	if (minor == 0)
101		return (SET_ERROR(ENXIO));
102
103	for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
104		if (zs->zs_minor == -1)
105			break;
106		zsprev = zs;
107	}
108
109	if (!zs) {
110		zs = kmem_zalloc(sizeof (zfsdev_state_t), KM_SLEEP);
111		newzs = B_TRUE;
112	}
113
114	filp->private_data = zs;
115
116	zfs_onexit_init((zfs_onexit_t **)&zs->zs_onexit);
117	zfs_zevent_init((zfs_zevent_t **)&zs->zs_zevent);
118
119	/*
120	 * In order to provide for lock-free concurrent read access
121	 * to the minor list in zfsdev_get_state_impl(), new entries
122	 * must be completely written before linking them into the
123	 * list whereas existing entries are already linked; the last
124	 * operation must be updating zs_minor (from -1 to the new
125	 * value).
126	 */
127	if (newzs) {
128		zs->zs_minor = minor;
129		smp_wmb();
130		zsprev->zs_next = zs;
131	} else {
132		smp_wmb();
133		zs->zs_minor = minor;
134	}
135
136	return (0);
137}
138
139static int
140zfsdev_state_destroy(struct file *filp)
141{
142	zfsdev_state_t *zs;
143
144	ASSERT(MUTEX_HELD(&zfsdev_state_lock));
145	ASSERT(filp->private_data != NULL);
146
147	zs = filp->private_data;
148	zs->zs_minor = -1;
149	zfs_onexit_destroy(zs->zs_onexit);
150	zfs_zevent_destroy(zs->zs_zevent);
151	zs->zs_onexit = NULL;
152	zs->zs_zevent = NULL;
153
154	return (0);
155}
156
157static int
158zfsdev_open(struct inode *ino, struct file *filp)
159{
160	int error;
161
162	mutex_enter(&zfsdev_state_lock);
163	error = zfsdev_state_init(filp);
164	mutex_exit(&zfsdev_state_lock);
165
166	return (-error);
167}
168
169static int
170zfsdev_release(struct inode *ino, struct file *filp)
171{
172	int error;
173
174	mutex_enter(&zfsdev_state_lock);
175	error = zfsdev_state_destroy(filp);
176	mutex_exit(&zfsdev_state_lock);
177
178	return (-error);
179}
180
181static long
182zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
183{
184	uint_t vecnum;
185	zfs_cmd_t *zc;
186	int error, rc;
187
188	vecnum = cmd - ZFS_IOC_FIRST;
189
190	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
191
192	if (ddi_copyin((void *)(uintptr_t)arg, zc, sizeof (zfs_cmd_t), 0)) {
193		error = -SET_ERROR(EFAULT);
194		goto out;
195	}
196	error = -zfsdev_ioctl_common(vecnum, zc, 0);
197	rc = ddi_copyout(zc, (void *)(uintptr_t)arg, sizeof (zfs_cmd_t), 0);
198	if (error == 0 && rc != 0)
199		error = -SET_ERROR(EFAULT);
200out:
201	kmem_free(zc, sizeof (zfs_cmd_t));
202	return (error);
203
204}
205
206uint64_t
207zfs_max_nvlist_src_size_os(void)
208{
209	if (zfs_max_nvlist_src_size != 0)
210		return (zfs_max_nvlist_src_size);
211
212	return (MIN(ptob(zfs_totalram_pages) / 4, 128 * 1024 * 1024));
213}
214
215/* Update the VFS's cache of mountpoint properties */
216void
217zfs_ioctl_update_mount_cache(const char *dsname)
218{
219}
220
221void
222zfs_ioctl_init_os(void)
223{
224}
225
226#ifdef CONFIG_COMPAT
227static long
228zfsdev_compat_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
229{
230	return (zfsdev_ioctl(filp, cmd, arg));
231}
232#else
233#define	zfsdev_compat_ioctl	NULL
234#endif
235
236static const struct file_operations zfsdev_fops = {
237	.open		= zfsdev_open,
238	.release	= zfsdev_release,
239	.unlocked_ioctl	= zfsdev_ioctl,
240	.compat_ioctl	= zfsdev_compat_ioctl,
241	.owner		= THIS_MODULE,
242};
243
244static struct miscdevice zfs_misc = {
245	.minor		= ZFS_DEVICE_MINOR,
246	.name		= ZFS_DRIVER,
247	.fops		= &zfsdev_fops,
248};
249
250MODULE_ALIAS_MISCDEV(ZFS_DEVICE_MINOR);
251MODULE_ALIAS("devname:zfs");
252
253int
254zfsdev_attach(void)
255{
256	int error;
257
258	error = misc_register(&zfs_misc);
259	if (error == -EBUSY) {
260		/*
261		 * Fallback to dynamic minor allocation in the event of a
262		 * collision with a reserved minor in linux/miscdevice.h.
263		 * In this case the kernel modules must be manually loaded.
264		 */
265		printk(KERN_INFO "ZFS: misc_register() with static minor %d "
266		    "failed %d, retrying with MISC_DYNAMIC_MINOR\n",
267		    ZFS_DEVICE_MINOR, error);
268
269		zfs_misc.minor = MISC_DYNAMIC_MINOR;
270		error = misc_register(&zfs_misc);
271	}
272
273	if (error)
274		printk(KERN_INFO "ZFS: misc_register() failed %d\n", error);
275
276	return (error);
277}
278
279void
280zfsdev_detach(void)
281{
282	misc_deregister(&zfs_misc);
283}
284
285#ifdef ZFS_DEBUG
286#define	ZFS_DEBUG_STR	" (DEBUG mode)"
287#else
288#define	ZFS_DEBUG_STR	""
289#endif
290
291static int __init
292openzfs_init(void)
293{
294	int error;
295
296	if ((error = zfs_kmod_init()) != 0) {
297		printk(KERN_NOTICE "ZFS: Failed to Load ZFS Filesystem v%s-%s%s"
298		    ", rc = %d\n", ZFS_META_VERSION, ZFS_META_RELEASE,
299		    ZFS_DEBUG_STR, error);
300
301		return (-error);
302	}
303
304	zfs_sysfs_init();
305
306	printk(KERN_NOTICE "ZFS: Loaded module v%s-%s%s, "
307	    "ZFS pool version %s, ZFS filesystem version %s\n",
308	    ZFS_META_VERSION, ZFS_META_RELEASE, ZFS_DEBUG_STR,
309	    SPA_VERSION_STRING, ZPL_VERSION_STRING);
310#ifndef CONFIG_FS_POSIX_ACL
311	printk(KERN_NOTICE "ZFS: Posix ACLs disabled by kernel\n");
312#endif /* CONFIG_FS_POSIX_ACL */
313
314	return (0);
315}
316
317static void __exit
318openzfs_fini(void)
319{
320	zfs_sysfs_fini();
321	zfs_kmod_fini();
322
323	printk(KERN_NOTICE "ZFS: Unloaded module v%s-%s%s\n",
324	    ZFS_META_VERSION, ZFS_META_RELEASE, ZFS_DEBUG_STR);
325}
326
327#if defined(_KERNEL)
328module_init(openzfs_init);
329module_exit(openzfs_fini);
330#endif
331
332ZFS_MODULE_DESCRIPTION("ZFS");
333ZFS_MODULE_AUTHOR(ZFS_META_AUTHOR);
334ZFS_MODULE_LICENSE(ZFS_META_LICENSE);
335ZFS_MODULE_VERSION(ZFS_META_VERSION "-" ZFS_META_RELEASE);
336