]>
Commit | Line | Data |
---|---|---|
9f0a21e6 MM |
1 | /* |
2 | * Copyright (c) 2020 iXsystems, Inc. | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * | |
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND | |
15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE | |
18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
24 | * SUCH DAMAGE. | |
25 | * | |
26 | */ | |
27 | ||
28 | #include <sys/cdefs.h> | |
29 | __FBSDID("$FreeBSD$"); | |
30 | ||
9f0a21e6 | 31 | #include <sys/param.h> |
82b81a2a RM |
32 | #include <sys/buf.h> |
33 | #include <sys/cmn_err.h> | |
9f0a21e6 | 34 | #include <sys/conf.h> |
82b81a2a RM |
35 | #include <sys/dmu.h> |
36 | #include <sys/dmu_impl.h> | |
37 | #include <sys/dmu_objset.h> | |
38 | #include <sys/dmu_send.h> | |
39 | #include <sys/dmu_tx.h> | |
40 | #include <sys/dsl_bookmark.h> | |
41 | #include <sys/dsl_crypt.h> | |
42 | #include <sys/dsl_dataset.h> | |
43 | #include <sys/dsl_deleg.h> | |
44 | #include <sys/dsl_destroy.h> | |
45 | #include <sys/dsl_dir.h> | |
46 | #include <sys/dsl_prop.h> | |
47 | #include <sys/dsl_scan.h> | |
48 | #include <sys/dsl_userhold.h> | |
49 | #include <sys/errno.h> | |
9f0a21e6 | 50 | #include <sys/eventhandler.h> |
82b81a2a RM |
51 | #include <sys/file.h> |
52 | #include <sys/fm/util.h> | |
53 | #include <sys/fs/zfs.h> | |
9f0a21e6 | 54 | #include <sys/kernel.h> |
82b81a2a | 55 | #include <sys/kmem.h> |
9f0a21e6 MM |
56 | #include <sys/lock.h> |
57 | #include <sys/malloc.h> | |
82b81a2a | 58 | #include <sys/mount.h> |
9f0a21e6 | 59 | #include <sys/mutex.h> |
82b81a2a RM |
60 | #include <sys/nvpair.h> |
61 | #include <sys/policy.h> | |
9f0a21e6 | 62 | #include <sys/proc.h> |
82b81a2a | 63 | #include <sys/sdt.h> |
9f0a21e6 MM |
64 | #include <sys/spa.h> |
65 | #include <sys/spa_impl.h> | |
82b81a2a | 66 | #include <sys/stat.h> |
9f0a21e6 | 67 | #include <sys/sunddi.h> |
dc45a00e | 68 | #include <sys/sysctl.h> |
82b81a2a | 69 | #include <sys/systm.h> |
9f0a21e6 | 70 | #include <sys/taskqueue.h> |
82b81a2a RM |
71 | #include <sys/uio.h> |
72 | #include <sys/vdev.h> | |
9f0a21e6 | 73 | #include <sys/vdev_removal.h> |
82b81a2a RM |
74 | #include <sys/zap.h> |
75 | #include <sys/zcp.h> | |
76 | #include <sys/zfeature.h> | |
c0bd2e0f | 77 | #include <sys/zfs_context.h> |
82b81a2a RM |
78 | #include <sys/zfs_ctldir.h> |
79 | #include <sys/zfs_dir.h> | |
80 | #include <sys/zfs_ioctl.h> | |
9f0a21e6 MM |
81 | #include <sys/zfs_ioctl_compat.h> |
82 | #include <sys/zfs_ioctl_impl.h> | |
82b81a2a RM |
83 | #include <sys/zfs_onexit.h> |
84 | #include <sys/zfs_vfsops.h> | |
85 | #include <sys/zfs_znode.h> | |
86 | #include <sys/zio_checksum.h> | |
87 | #include <sys/zone.h> | |
88 | #include <sys/zvol.h> | |
9f0a21e6 | 89 | |
82b81a2a RM |
90 | #include "zfs_comutil.h" |
91 | #include "zfs_deleg.h" | |
9f0a21e6 MM |
92 | #include "zfs_namecheck.h" |
93 | #include "zfs_prop.h" | |
9f0a21e6 MM |
94 | |
95 | SYSCTL_DECL(_vfs_zfs); | |
96 | SYSCTL_DECL(_vfs_zfs_vdev); | |
97 | ||
c0bd2e0f | 98 | extern uint_t rrw_tsd_key; |
23c87167 | 99 | static int zfs_version_ioctl = ZFS_IOCVER_OZFS; |
9f0a21e6 MM |
100 | SYSCTL_DECL(_vfs_zfs_version); |
101 | SYSCTL_INT(_vfs_zfs_version, OID_AUTO, ioctl, CTLFLAG_RD, &zfs_version_ioctl, | |
102 | 0, "ZFS_IOCTL_VERSION"); | |
103 | ||
104 | static struct cdev *zfsdev; | |
105 | ||
9f0a21e6 MM |
106 | static struct root_hold_token *zfs_root_token; |
107 | ||
108 | extern uint_t rrw_tsd_key; | |
109 | extern uint_t zfs_allow_log_key; | |
110 | extern uint_t zfs_geom_probe_vdev_key; | |
111 | ||
112 | static int zfs__init(void); | |
113 | static int zfs__fini(void); | |
114 | static void zfs_shutdown(void *, int); | |
115 | ||
116 | static eventhandler_tag zfs_shutdown_event_tag; | |
9f0a21e6 MM |
117 | |
118 | #define ZFS_MIN_KSTACK_PAGES 4 | |
119 | ||
9f0a21e6 MM |
120 | static int |
121 | zfsdev_ioctl(struct cdev *dev, ulong_t zcmd, caddr_t arg, int flag, | |
122 | struct thread *td) | |
123 | { | |
23c87167 MM |
124 | uint_t len; |
125 | int vecnum; | |
9f0a21e6 MM |
126 | zfs_iocparm_t *zp; |
127 | zfs_cmd_t *zc; | |
20b867f5 | 128 | #ifdef ZFS_LEGACY_SUPPORT |
9f0a21e6 | 129 | zfs_cmd_legacy_t *zcl; |
20b867f5 | 130 | #endif |
9f0a21e6 MM |
131 | int rc, error; |
132 | void *uaddr; | |
133 | ||
134 | len = IOCPARM_LEN(zcmd); | |
135 | vecnum = zcmd & 0xff; | |
136 | zp = (void *)arg; | |
9f0a21e6 | 137 | error = 0; |
20b867f5 | 138 | #ifdef ZFS_LEGACY_SUPPORT |
9f0a21e6 | 139 | zcl = NULL; |
20b867f5 | 140 | #endif |
9f0a21e6 | 141 | |
24502bd3 | 142 | if (len != sizeof (zfs_iocparm_t)) |
9f0a21e6 | 143 | return (EINVAL); |
9f0a21e6 | 144 | |
008baa09 | 145 | uaddr = (void *)(uintptr_t)zp->zfs_cmd; |
13312e2f | 146 | zc = vmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); |
20b867f5 | 147 | #ifdef ZFS_LEGACY_SUPPORT |
9f0a21e6 MM |
148 | /* |
149 | * Remap ioctl code for legacy user binaries | |
150 | */ | |
23c87167 MM |
151 | if (zp->zfs_ioctl_version == ZFS_IOCVER_LEGACY) { |
152 | vecnum = zfs_ioctl_legacy_to_ozfs(vecnum); | |
153 | if (vecnum < 0) { | |
13312e2f | 154 | vmem_free(zc, sizeof (zfs_cmd_t)); |
9f0a21e6 MM |
155 | return (ENOTSUP); |
156 | } | |
13312e2f | 157 | zcl = vmem_zalloc(sizeof (zfs_cmd_legacy_t), KM_SLEEP); |
9f0a21e6 MM |
158 | if (copyin(uaddr, zcl, sizeof (zfs_cmd_legacy_t))) { |
159 | error = SET_ERROR(EFAULT); | |
160 | goto out; | |
161 | } | |
23c87167 | 162 | zfs_cmd_legacy_to_ozfs(zcl, zc); |
20b867f5 BD |
163 | } else |
164 | #endif | |
165 | if (copyin(uaddr, zc, sizeof (zfs_cmd_t))) { | |
9f0a21e6 MM |
166 | error = SET_ERROR(EFAULT); |
167 | goto out; | |
168 | } | |
529246df | 169 | error = zfsdev_ioctl_common(vecnum, zc, 0); |
20b867f5 | 170 | #ifdef ZFS_LEGACY_SUPPORT |
9f0a21e6 | 171 | if (zcl) { |
23c87167 | 172 | zfs_cmd_ozfs_to_legacy(zc, zcl); |
9f0a21e6 | 173 | rc = copyout(zcl, uaddr, sizeof (*zcl)); |
20b867f5 BD |
174 | } else |
175 | #endif | |
176 | { | |
9f0a21e6 MM |
177 | rc = copyout(zc, uaddr, sizeof (*zc)); |
178 | } | |
179 | if (error == 0 && rc != 0) | |
180 | error = SET_ERROR(EFAULT); | |
181 | out: | |
20b867f5 | 182 | #ifdef ZFS_LEGACY_SUPPORT |
9f0a21e6 | 183 | if (zcl) |
13312e2f | 184 | vmem_free(zcl, sizeof (zfs_cmd_legacy_t)); |
20b867f5 | 185 | #endif |
13312e2f | 186 | vmem_free(zc, sizeof (zfs_cmd_t)); |
c0bd2e0f | 187 | MPASS(tsd_get(rrw_tsd_key) == NULL); |
9f0a21e6 MM |
188 | return (error); |
189 | } | |
190 | ||
191 | static void | |
192 | zfsdev_close(void *data) | |
193 | { | |
a631283b | 194 | zfsdev_state_destroy(data); |
9f0a21e6 MM |
195 | } |
196 | ||
a631283b RM |
197 | void |
198 | zfsdev_private_set_state(void *priv __unused, zfsdev_state_t *zs) | |
9f0a21e6 | 199 | { |
9f0a21e6 | 200 | devfs_set_cdevpriv(zs, zfsdev_close); |
a631283b | 201 | } |
9f0a21e6 | 202 | |
a631283b RM |
203 | zfsdev_state_t * |
204 | zfsdev_private_get_state(void *priv) | |
205 | { | |
206 | return (priv); | |
9f0a21e6 MM |
207 | } |
208 | ||
209 | static int | |
a631283b RM |
210 | zfsdev_open(struct cdev *devp __unused, int flag __unused, int mode __unused, |
211 | struct thread *td __unused) | |
9f0a21e6 MM |
212 | { |
213 | int error; | |
214 | ||
215 | mutex_enter(&zfsdev_state_lock); | |
a631283b | 216 | error = zfsdev_state_init(NULL); |
9f0a21e6 MM |
217 | mutex_exit(&zfsdev_state_lock); |
218 | ||
219 | return (error); | |
220 | } | |
221 | ||
222 | static struct cdevsw zfs_cdevsw = { | |
223 | .d_version = D_VERSION, | |
224 | .d_open = zfsdev_open, | |
225 | .d_ioctl = zfsdev_ioctl, | |
226 | .d_name = ZFS_DRIVER | |
227 | }; | |
228 | ||
229 | int | |
230 | zfsdev_attach(void) | |
231 | { | |
60d99572 RM |
232 | struct make_dev_args args; |
233 | ||
234 | make_dev_args_init(&args); | |
235 | args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK; | |
236 | args.mda_devsw = &zfs_cdevsw; | |
237 | args.mda_cr = NULL; | |
238 | args.mda_uid = UID_ROOT; | |
239 | args.mda_gid = GID_OPERATOR; | |
240 | args.mda_mode = 0666; | |
241 | return (make_dev_s(&args, &zfsdev, ZFS_DRIVER)); | |
9f0a21e6 MM |
242 | } |
243 | ||
244 | void | |
245 | zfsdev_detach(void) | |
246 | { | |
247 | if (zfsdev != NULL) | |
248 | destroy_dev(zfsdev); | |
249 | } | |
250 | ||
251 | int | |
252 | zfs__init(void) | |
253 | { | |
254 | int error; | |
255 | ||
256 | #if KSTACK_PAGES < ZFS_MIN_KSTACK_PAGES | |
257 | printf("ZFS NOTICE: KSTACK_PAGES is %d which could result in stack " | |
258 | "overflow panic!\nPlease consider adding " | |
259 | "'options KSTACK_PAGES=%d' to your kernel config\n", KSTACK_PAGES, | |
260 | ZFS_MIN_KSTACK_PAGES); | |
261 | #endif | |
262 | zfs_root_token = root_mount_hold("ZFS"); | |
263 | if ((error = zfs_kmod_init()) != 0) { | |
264 | printf("ZFS: Failed to Load ZFS Filesystem" | |
265 | ", rc = %d\n", error); | |
266 | root_mount_rel(zfs_root_token); | |
267 | return (error); | |
268 | } | |
269 | ||
270 | ||
271 | tsd_create(&zfs_geom_probe_vdev_key, NULL); | |
272 | ||
273 | printf("ZFS storage pool version: features support (" | |
274 | SPA_VERSION_STRING ")\n"); | |
275 | root_mount_rel(zfs_root_token); | |
276 | ddi_sysevent_init(); | |
277 | return (0); | |
278 | } | |
279 | ||
280 | int | |
281 | zfs__fini(void) | |
282 | { | |
283 | if (zfs_busy() || zvol_busy() || | |
284 | zio_injection_enabled) { | |
285 | return (EBUSY); | |
286 | } | |
287 | zfs_kmod_fini(); | |
288 | tsd_destroy(&zfs_geom_probe_vdev_key); | |
289 | return (0); | |
290 | } | |
291 | ||
292 | static void | |
293 | zfs_shutdown(void *arg __unused, int howto __unused) | |
294 | { | |
295 | ||
296 | /* | |
297 | * ZFS fini routines can not properly work in a panic-ed system. | |
298 | */ | |
299 | if (panicstr == NULL) | |
300 | zfs__fini(); | |
301 | } | |
302 | ||
9f0a21e6 MM |
303 | static int |
304 | zfs_modevent(module_t mod, int type, void *unused __unused) | |
305 | { | |
306 | int err; | |
307 | ||
308 | switch (type) { | |
309 | case MOD_LOAD: | |
310 | err = zfs__init(); | |
311 | if (err == 0) | |
312 | zfs_shutdown_event_tag = EVENTHANDLER_REGISTER( | |
313 | shutdown_post_sync, zfs_shutdown, NULL, | |
314 | SHUTDOWN_PRI_FIRST); | |
315 | return (err); | |
316 | case MOD_UNLOAD: | |
317 | err = zfs__fini(); | |
318 | if (err == 0 && zfs_shutdown_event_tag != NULL) | |
319 | EVENTHANDLER_DEREGISTER(shutdown_post_sync, | |
320 | zfs_shutdown_event_tag); | |
321 | return (err); | |
322 | case MOD_SHUTDOWN: | |
323 | return (0); | |
324 | default: | |
325 | break; | |
326 | } | |
327 | return (EOPNOTSUPP); | |
328 | } | |
329 | ||
330 | static moduledata_t zfs_mod = { | |
331 | "zfsctrl", | |
332 | zfs_modevent, | |
333 | 0 | |
334 | }; | |
335 | ||
336 | #ifdef _KERNEL | |
337 | EVENTHANDLER_DEFINE(mountroot, spa_boot_init, NULL, 0); | |
338 | #endif | |
339 | ||
dc45a00e GT |
340 | FEATURE(zfs, "OpenZFS support"); |
341 | ||
9f0a21e6 MM |
342 | DECLARE_MODULE(zfsctrl, zfs_mod, SI_SUB_CLOCKS, SI_ORDER_ANY); |
343 | MODULE_VERSION(zfsctrl, 1); | |
86a0f494 RM |
344 | #if __FreeBSD_version > 1300092 |
345 | MODULE_DEPEND(zfsctrl, xdr, 1, 1, 1); | |
346 | #else | |
9f0a21e6 | 347 | MODULE_DEPEND(zfsctrl, krpc, 1, 1, 1); |
86a0f494 | 348 | #endif |
9f0a21e6 MM |
349 | MODULE_DEPEND(zfsctrl, acl_nfs4, 1, 1, 1); |
350 | MODULE_DEPEND(zfsctrl, crypto, 1, 1, 1); | |
41bee403 | 351 | MODULE_DEPEND(zfsctrl, zlib, 1, 1, 1); |