Mercurial > illumos > illumos-gate
annotate usr/src/uts/common/fs/zfs/zfs_ioctl.c @ 1133:335d069294d1
6357470 vdev_raidz.c has unused RAIDZ_SINGLE define, code
6360844 zvol has an incorrect efi_version in it's EFI label.
6361271 volsize & reservation not consistent while volume size < 128k
author | eschrock |
---|---|
date | Thu, 15 Dec 2005 18:34:13 -0800 |
parents | ce99098d6a9b |
children | 81359ee1ee63 |
rev | line source |
---|---|
789 | 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, Version 1.0 only | |
6 * (the "License"). You may not use this file except in compliance | |
7 * with the License. | |
8 * | |
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
10 * or http://www.opensolaris.org/os/licensing. | |
11 * See the License for the specific language governing permissions | |
12 * and limitations under the License. | |
13 * | |
14 * When distributing Covered Code, include this CDDL HEADER in each | |
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
16 * If applicable, add the following below this CDDL HEADER, with the | |
17 * fields enclosed by brackets "[]" replaced with your own identifying | |
18 * information: Portions Copyright [yyyy] [name of copyright owner] | |
19 * | |
20 * CDDL HEADER END | |
21 */ | |
22 /* | |
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. | |
24 * Use is subject to license terms. | |
25 */ | |
26 | |
27 #pragma ident "%Z%%M% %I% %E% SMI" | |
28 | |
29 #include <sys/types.h> | |
30 #include <sys/param.h> | |
31 #include <sys/errno.h> | |
32 #include <sys/uio.h> | |
33 #include <sys/buf.h> | |
34 #include <sys/modctl.h> | |
35 #include <sys/open.h> | |
36 #include <sys/file.h> | |
37 #include <sys/kmem.h> | |
38 #include <sys/conf.h> | |
39 #include <sys/cmn_err.h> | |
40 #include <sys/stat.h> | |
41 #include <sys/zfs_ioctl.h> | |
42 #include <sys/zap.h> | |
43 #include <sys/spa.h> | |
44 #include <sys/vdev.h> | |
45 #include <sys/dmu.h> | |
46 #include <sys/dsl_dir.h> | |
47 #include <sys/dsl_dataset.h> | |
48 #include <sys/dsl_prop.h> | |
49 #include <sys/ddi.h> | |
50 #include <sys/sunddi.h> | |
51 #include <sys/sunldi.h> | |
52 #include <sys/policy.h> | |
53 #include <sys/zone.h> | |
54 #include <sys/nvpair.h> | |
55 #include <sys/pathname.h> | |
56 #include <sys/mount.h> | |
57 #include <sys/sdt.h> | |
58 #include <sys/fs/zfs.h> | |
59 #include <sys/zfs_ctldir.h> | |
60 | |
61 #include "zfs_namecheck.h" | |
62 | |
63 extern struct modlfs zfs_modlfs; | |
64 | |
65 extern void zfs_init(void); | |
66 extern void zfs_fini(void); | |
67 | |
68 ldi_ident_t zfs_li = NULL; | |
69 dev_info_t *zfs_dip; | |
70 | |
71 typedef int zfs_ioc_func_t(zfs_cmd_t *); | |
72 typedef int zfs_secpolicy_func_t(const char *, const char *, cred_t *); | |
73 | |
74 typedef struct zfs_ioc_vec { | |
75 zfs_ioc_func_t *zvec_func; | |
76 zfs_secpolicy_func_t *zvec_secpolicy; | |
77 enum { | |
78 no_name, | |
79 pool_name, | |
80 dataset_name | |
81 } zvec_namecheck; | |
82 } zfs_ioc_vec_t; | |
83 | |
84 /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ | |
85 void | |
86 __dprintf(const char *file, const char *func, int line, const char *fmt, ...) | |
87 { | |
88 const char *newfile; | |
89 char buf[256]; | |
90 va_list adx; | |
91 | |
92 /* | |
93 * Get rid of annoying "../common/" prefix to filename. | |
94 */ | |
95 newfile = strrchr(file, '/'); | |
96 if (newfile != NULL) { | |
97 newfile = newfile + 1; /* Get rid of leading / */ | |
98 } else { | |
99 newfile = file; | |
100 } | |
101 | |
102 va_start(adx, fmt); | |
103 (void) vsnprintf(buf, sizeof (buf), fmt, adx); | |
104 va_end(adx); | |
105 | |
106 /* | |
107 * To get this data, use the zfs-dprintf probe as so: | |
108 * dtrace -q -n 'zfs-dprintf \ | |
109 * /stringof(arg0) == "dbuf.c"/ \ | |
110 * {printf("%s: %s", stringof(arg1), stringof(arg3))}' | |
111 * arg0 = file name | |
112 * arg1 = function name | |
113 * arg2 = line number | |
114 * arg3 = message | |
115 */ | |
116 DTRACE_PROBE4(zfs__dprintf, | |
117 char *, newfile, char *, func, int, line, char *, buf); | |
118 } | |
119 | |
120 /* | |
121 * Policy for top-level read operations (list pools). Requires no privileges, | |
122 * and can be used in the local zone, as there is no associated dataset. | |
123 */ | |
124 /* ARGSUSED */ | |
125 static int | |
126 zfs_secpolicy_none(const char *unused1, const char *unused2, cred_t *cr) | |
127 { | |
128 return (0); | |
129 } | |
130 | |
131 /* | |
132 * Policy for dataset read operations (list children, get statistics). Requires | |
133 * no privileges, but must be visible in the local zone. | |
134 */ | |
135 /* ARGSUSED */ | |
136 static int | |
137 zfs_secpolicy_read(const char *dataset, const char *unused, cred_t *cr) | |
138 { | |
139 if (INGLOBALZONE(curproc) || | |
140 zone_dataset_visible(dataset, NULL)) | |
141 return (0); | |
142 | |
143 return (ENOENT); | |
144 } | |
145 | |
146 static int | |
147 zfs_dozonecheck(const char *dataset, cred_t *cr) | |
148 { | |
149 uint64_t zoned; | |
150 int writable = 1; | |
151 | |
152 /* | |
153 * The dataset must be visible by this zone -- check this first | |
154 * so they don't see EPERM on something they shouldn't know about. | |
155 */ | |
156 if (!INGLOBALZONE(curproc) && | |
157 !zone_dataset_visible(dataset, &writable)) | |
158 return (ENOENT); | |
159 | |
160 if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) | |
161 return (ENOENT); | |
162 | |
163 if (INGLOBALZONE(curproc)) { | |
164 /* | |
165 * If the fs is zoned, only root can access it from the | |
166 * global zone. | |
167 */ | |
168 if (secpolicy_zfs(cr) && zoned) | |
169 return (EPERM); | |
170 } else { | |
171 /* | |
172 * If we are in a local zone, the 'zoned' property must be set. | |
173 */ | |
174 if (!zoned) | |
175 return (EPERM); | |
176 | |
177 /* must be writable by this zone */ | |
178 if (!writable) | |
179 return (EPERM); | |
180 } | |
181 return (0); | |
182 } | |
183 | |
184 /* | |
185 * Policy for dataset write operations (create children, set properties, etc). | |
186 * Requires SYS_MOUNT privilege, and must be writable in the local zone. | |
187 */ | |
188 /* ARGSUSED */ | |
189 int | |
190 zfs_secpolicy_write(const char *dataset, const char *unused, cred_t *cr) | |
191 { | |
192 int error; | |
193 | |
194 if (error = zfs_dozonecheck(dataset, cr)) | |
195 return (error); | |
196 | |
197 return (secpolicy_zfs(cr)); | |
198 } | |
199 | |
200 /* | |
201 * Policy for operations that want to write a dataset's parent: | |
202 * create, destroy, snapshot, clone, restore. | |
203 */ | |
204 static int | |
205 zfs_secpolicy_parent(const char *dataset, const char *unused, cred_t *cr) | |
206 { | |
207 char parentname[MAXNAMELEN]; | |
208 char *cp; | |
209 | |
210 /* | |
211 * Remove the @bla or /bla from the end of the name to get the parent. | |
212 */ | |
213 (void) strncpy(parentname, dataset, sizeof (parentname)); | |
214 cp = strrchr(parentname, '@'); | |
215 if (cp != NULL) { | |
216 cp[0] = '\0'; | |
217 } else { | |
218 cp = strrchr(parentname, '/'); | |
219 if (cp == NULL) | |
220 return (ENOENT); | |
221 cp[0] = '\0'; | |
222 | |
223 } | |
224 | |
225 return (zfs_secpolicy_write(parentname, unused, cr)); | |
226 } | |
227 | |
228 /* | |
229 * Policy for dataset write operations (create children, set properties, etc). | |
230 * Requires SYS_MOUNT privilege, and must be writable in the local zone. | |
231 */ | |
232 static int | |
233 zfs_secpolicy_setprop(const char *dataset, const char *prop, cred_t *cr) | |
234 { | |
235 int error; | |
236 | |
237 if (error = zfs_dozonecheck(dataset, cr)) | |
238 return (error); | |
239 | |
240 if (strcmp(prop, "zoned") == 0) { | |
241 /* | |
242 * Disallow setting of 'zoned' from within a local zone. | |
243 */ | |
244 if (!INGLOBALZONE(curproc)) | |
245 return (EPERM); | |
246 } | |
247 | |
248 return (secpolicy_zfs(cr)); | |
249 } | |
250 | |
251 /* | |
252 * Security policy for setting the quota. This is the same as | |
253 * zfs_secpolicy_write, except that the local zone may not change the quota at | |
254 * the zone-property setpoint. | |
255 */ | |
256 /* ARGSUSED */ | |
257 static int | |
258 zfs_secpolicy_quota(const char *dataset, const char *unused, cred_t *cr) | |
259 { | |
260 int error; | |
261 | |
262 if (error = zfs_dozonecheck(dataset, cr)) | |
263 return (error); | |
264 | |
265 if (!INGLOBALZONE(curproc)) { | |
266 uint64_t zoned; | |
267 char setpoint[MAXNAMELEN]; | |
268 int dslen; | |
269 /* | |
270 * Unprivileged users are allowed to modify the quota | |
271 * on things *under* (ie. contained by) the thing they | |
272 * own. | |
273 */ | |
274 if (dsl_prop_get_integer(dataset, "zoned", &zoned, setpoint)) | |
275 return (EPERM); | |
276 if (!zoned) /* this shouldn't happen */ | |
277 return (EPERM); | |
278 dslen = strlen(dataset); | |
279 if (dslen <= strlen(setpoint)) | |
280 return (EPERM); | |
281 } | |
282 | |
283 return (secpolicy_zfs(cr)); | |
284 } | |
285 | |
286 /* | |
287 * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires | |
288 * SYS_CONFIG privilege, which is not available in a local zone. | |
289 */ | |
290 /* ARGSUSED */ | |
291 static int | |
292 zfs_secpolicy_config(const char *unused, const char *unused2, cred_t *cr) | |
293 { | |
294 if (secpolicy_sys_config(cr, B_FALSE) != 0) | |
295 return (EPERM); | |
296 | |
297 return (0); | |
298 } | |
299 | |
300 /* | |
301 * Returns the nvlist as specified by the user in the zfs_cmd_t. | |
302 */ | |
303 static int | |
304 get_config(zfs_cmd_t *zc, nvlist_t **nvp) | |
305 { | |
306 char *packed; | |
307 size_t size; | |
308 int error; | |
309 nvlist_t *config = NULL; | |
310 | |
311 /* | |
312 * Read in and unpack the user-supplied nvlist. By this point, we know | |
313 * that the user has the SYS_CONFIG privilege, so allocating arbitrary | |
314 * sized regions of memory should not be a problem. | |
315 */ | |
316 if ((size = zc->zc_config_src_size) == 0) | |
317 return (EINVAL); | |
318 | |
319 packed = kmem_alloc(size, KM_SLEEP); | |
320 | |
321 if ((error = xcopyin((void *)(uintptr_t)zc->zc_config_src, packed, | |
322 size)) != 0) { | |
323 kmem_free(packed, size); | |
324 return (error); | |
325 } | |
326 | |
327 if ((error = nvlist_unpack(packed, size, &config, 0)) != 0) { | |
328 kmem_free(packed, size); | |
329 return (error); | |
330 } | |
331 | |
332 kmem_free(packed, size); | |
333 | |
334 *nvp = config; | |
335 return (0); | |
336 } | |
337 | |
338 static int | |
339 zfs_ioc_pool_create(zfs_cmd_t *zc) | |
340 { | |
341 int error; | |
342 nvlist_t *config; | |
343 | |
344 if ((error = get_config(zc, &config)) != 0) | |
345 return (error); | |
346 | |
347 error = spa_create(zc->zc_name, config, zc->zc_root[0] == '\0' ? | |
348 NULL : zc->zc_root); | |
349 | |
350 nvlist_free(config); | |
351 | |
352 return (error); | |
353 } | |
354 | |
355 static int | |
356 zfs_ioc_pool_destroy(zfs_cmd_t *zc) | |
357 { | |
358 return (spa_destroy(zc->zc_name)); | |
359 } | |
360 | |
361 static int | |
362 zfs_ioc_pool_import(zfs_cmd_t *zc) | |
363 { | |
364 int error; | |
365 nvlist_t *config; | |
366 uint64_t guid; | |
367 | |
368 if ((error = get_config(zc, &config)) != 0) | |
369 return (error); | |
370 | |
371 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || | |
372 guid != zc->zc_pool_guid) | |
373 error = EINVAL; | |
374 else | |
375 error = spa_import(zc->zc_name, config, | |
376 zc->zc_root[0] == '\0' ? NULL : zc->zc_root); | |
377 | |
378 nvlist_free(config); | |
379 | |
380 return (error); | |
381 } | |
382 | |
383 static int | |
384 zfs_ioc_pool_export(zfs_cmd_t *zc) | |
385 { | |
386 return (spa_export(zc->zc_name)); | |
387 } | |
388 | |
389 static int | |
390 zfs_ioc_pool_configs(zfs_cmd_t *zc) | |
391 { | |
392 nvlist_t *configs; | |
393 char *packed = NULL; | |
394 size_t size = 0; | |
395 int error; | |
396 | |
397 if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) | |
398 return (EEXIST); | |
399 | |
400 VERIFY(nvlist_pack(configs, &packed, &size, NV_ENCODE_NATIVE, 0) == 0); | |
401 | |
402 if (size > zc->zc_config_dst_size) | |
403 error = ENOMEM; | |
404 else | |
405 error = xcopyout(packed, (void *)(uintptr_t)zc->zc_config_dst, | |
406 size); | |
407 | |
408 zc->zc_config_dst_size = size; | |
409 | |
410 kmem_free(packed, size); | |
411 nvlist_free(configs); | |
412 | |
413 return (error); | |
414 } | |
415 | |
416 static int | |
417 zfs_ioc_pool_guid(zfs_cmd_t *zc) | |
418 { | |
419 spa_t *spa; | |
420 int error; | |
421 | |
422 error = spa_open(zc->zc_name, &spa, FTAG); | |
423 if (error == 0) { | |
424 zc->zc_pool_guid = spa_guid(spa); | |
425 spa_close(spa, FTAG); | |
426 } | |
427 return (error); | |
428 } | |
429 | |
430 static int | |
431 zfs_ioc_pool_stats(zfs_cmd_t *zc) | |
432 { | |
433 nvlist_t *config; | |
434 char *packed = NULL; | |
435 size_t size = 0; | |
436 int error; | |
437 | |
438 error = spa_get_stats(zc->zc_name, &config); | |
439 | |
440 if (config != NULL) { | |
441 VERIFY(nvlist_pack(config, &packed, &size, | |
442 NV_ENCODE_NATIVE, 0) == 0); | |
443 | |
444 if (size > zc->zc_config_dst_size) | |
445 error = ENOMEM; | |
446 else if (xcopyout(packed, (void *)(uintptr_t)zc->zc_config_dst, | |
447 size)) | |
448 error = EFAULT; | |
449 | |
450 zc->zc_config_dst_size = size; | |
451 | |
452 kmem_free(packed, size); | |
453 nvlist_free(config); | |
454 } else { | |
455 ASSERT(error != 0); | |
456 } | |
457 | |
458 return (error); | |
459 } | |
460 | |
461 /* | |
462 * Try to import the given pool, returning pool stats as appropriate so that | |
463 * user land knows which devices are available and overall pool health. | |
464 */ | |
465 static int | |
466 zfs_ioc_pool_tryimport(zfs_cmd_t *zc) | |
467 { | |
468 nvlist_t *tryconfig, *config; | |
469 char *packed = NULL; | |
470 size_t size = 0; | |
471 int error; | |
472 | |
473 if ((error = get_config(zc, &tryconfig)) != 0) | |
474 return (error); | |
475 | |
476 config = spa_tryimport(tryconfig); | |
477 | |
478 nvlist_free(tryconfig); | |
479 | |
480 if (config == NULL) | |
481 return (EINVAL); | |
482 | |
483 VERIFY(nvlist_pack(config, &packed, &size, NV_ENCODE_NATIVE, 0) == 0); | |
484 | |
485 if (size > zc->zc_config_dst_size) | |
486 error = ENOMEM; | |
487 else | |
488 error = xcopyout(packed, (void *)(uintptr_t)zc->zc_config_dst, | |
489 size); | |
490 | |
491 zc->zc_config_dst_size = size; | |
492 | |
493 kmem_free(packed, size); | |
494 nvlist_free(config); | |
495 | |
496 return (error); | |
497 } | |
498 | |
499 static int | |
500 zfs_ioc_pool_scrub(zfs_cmd_t *zc) | |
501 { | |
502 spa_t *spa; | |
503 int error; | |
504 | |
505 error = spa_open(zc->zc_name, &spa, FTAG); | |
506 if (error == 0) { | |
507 error = spa_scrub(spa, zc->zc_cookie, B_FALSE); | |
508 spa_close(spa, FTAG); | |
509 } | |
510 return (error); | |
511 } | |
512 | |
513 static int | |
514 zfs_ioc_pool_freeze(zfs_cmd_t *zc) | |
515 { | |
516 spa_t *spa; | |
517 int error; | |
518 | |
519 error = spa_open(zc->zc_name, &spa, FTAG); | |
520 if (error == 0) { | |
521 spa_freeze(spa); | |
522 spa_close(spa, FTAG); | |
523 } | |
524 return (error); | |
525 } | |
526 | |
527 static int | |
528 zfs_ioc_vdev_add(zfs_cmd_t *zc) | |
529 { | |
530 spa_t *spa; | |
531 int error; | |
532 nvlist_t *config; | |
533 | |
534 error = spa_open(zc->zc_name, &spa, FTAG); | |
535 if (error != 0) | |
536 return (error); | |
537 | |
538 if ((error = get_config(zc, &config)) == 0) { | |
539 error = spa_vdev_add(spa, config); | |
540 nvlist_free(config); | |
541 } | |
542 | |
543 spa_close(spa, FTAG); | |
544 return (error); | |
545 } | |
546 | |
547 /* ARGSUSED */ | |
548 static int | |
549 zfs_ioc_vdev_remove(zfs_cmd_t *zc) | |
550 { | |
551 return (ENOTSUP); | |
552 } | |
553 | |
554 static int | |
555 zfs_ioc_vdev_online(zfs_cmd_t *zc) | |
556 { | |
557 spa_t *spa; | |
558 char *path = zc->zc_prop_value; | |
559 int error; | |
560 | |
561 error = spa_open(zc->zc_name, &spa, FTAG); | |
562 if (error != 0) | |
563 return (error); | |
564 error = vdev_online(spa, path); | |
565 spa_close(spa, FTAG); | |
566 return (error); | |
567 } | |
568 | |
569 static int | |
570 zfs_ioc_vdev_offline(zfs_cmd_t *zc) | |
571 { | |
572 spa_t *spa; | |
573 char *path = zc->zc_prop_value; | |
574 int error; | |
575 | |
576 error = spa_open(zc->zc_name, &spa, FTAG); | |
577 if (error != 0) | |
578 return (error); | |
579 error = vdev_offline(spa, path); | |
580 spa_close(spa, FTAG); | |
581 return (error); | |
582 } | |
583 | |
584 static int | |
585 zfs_ioc_vdev_attach(zfs_cmd_t *zc) | |
586 { | |
587 spa_t *spa; | |
588 char *path = zc->zc_prop_value; | |
589 int replacing = zc->zc_cookie; | |
590 nvlist_t *config; | |
591 int error; | |
592 | |
593 error = spa_open(zc->zc_name, &spa, FTAG); | |
594 if (error != 0) | |
595 return (error); | |
596 | |
597 if ((error = get_config(zc, &config)) == 0) { | |
598 error = spa_vdev_attach(spa, path, config, replacing); | |
599 nvlist_free(config); | |
600 } | |
601 | |
602 spa_close(spa, FTAG); | |
603 return (error); | |
604 } | |
605 | |
606 static int | |
607 zfs_ioc_vdev_detach(zfs_cmd_t *zc) | |
608 { | |
609 spa_t *spa; | |
610 char *path = zc->zc_prop_value; | |
611 int error; | |
612 | |
613 error = spa_open(zc->zc_name, &spa, FTAG); | |
614 if (error != 0) | |
615 return (error); | |
616 | |
617 error = spa_vdev_detach(spa, path, 0, B_FALSE); | |
618 | |
619 spa_close(spa, FTAG); | |
620 return (error); | |
621 } | |
622 | |
623 static int | |
624 zfs_get_stats(zfs_cmd_t *zc) | |
625 { | |
626 char *name = zc->zc_name; | |
627 zfs_stats_t *zs = &zc->zc_zfs_stats; | |
628 int error; | |
629 | |
630 bzero(zs, sizeof (zfs_stats_t)); | |
631 | |
632 if ((error = dsl_prop_get_integer(name, "atime", | |
633 &zs->zs_atime, zs->zs_atime_setpoint)) != 0 || | |
634 (error = dsl_prop_get_integer(name, "recordsize", | |
635 &zs->zs_recordsize, zs->zs_recordsize_setpoint)) != 0 || | |
636 (error = dsl_prop_get_integer(name, "readonly", | |
637 &zs->zs_readonly, zs->zs_readonly_setpoint)) != 0 || | |
638 (error = dsl_prop_get_integer(name, "devices", | |
639 &zs->zs_devices, zs->zs_devices_setpoint)) != 0 || | |
640 (error = dsl_prop_get_integer(name, "setuid", | |
641 &zs->zs_setuid, zs->zs_setuid_setpoint)) != 0 || | |
642 (error = dsl_prop_get_integer(name, "exec", | |
643 &zs->zs_exec, zs->zs_exec_setpoint)) != 0 || | |
644 (error = dsl_prop_get_string(name, "mountpoint", zs->zs_mountpoint, | |
645 sizeof (zs->zs_mountpoint), zs->zs_mountpoint_setpoint)) != 0 || | |
646 (error = dsl_prop_get_string(name, "sharenfs", zs->zs_sharenfs, | |
647 sizeof (zs->zs_sharenfs), zs->zs_sharenfs_setpoint)) != 0 || | |
648 (error = dsl_prop_get_integer(name, "aclmode", | |
649 &zs->zs_acl_mode, zs->zs_acl_mode_setpoint)) != 0 || | |
650 (error = dsl_prop_get_integer(name, "snapdir", | |
651 &zs->zs_snapdir, zs->zs_snapdir_setpoint)) != 0 || | |
652 (error = dsl_prop_get_integer(name, "aclinherit", | |
653 &zs->zs_acl_inherit, zs->zs_acl_inherit_setpoint)) != 0) | |
654 return (error); | |
655 | |
656 return (0); | |
657 } | |
658 | |
659 static int | |
660 zfs_ioc_objset_stats(zfs_cmd_t *zc) | |
661 { | |
662 objset_t *os = NULL; | |
663 int error; | |
664 | |
665 retry: | |
666 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, | |
667 DS_MODE_STANDARD | DS_MODE_READONLY, &os); | |
668 if (error != 0) { | |
669 /* | |
670 * This is ugly: dmu_objset_open() can return EBUSY if | |
671 * the objset is held exclusively. Fortunately this hold is | |
672 * only for a short while, so we retry here. | |
673 * This avoids user code having to handle EBUSY, | |
674 * for example for a "zfs list". | |
675 */ | |
676 if (error == EBUSY) { | |
677 delay(1); | |
678 goto retry; | |
679 } | |
680 return (error); | |
681 } | |
682 | |
683 dmu_objset_stats(os, &zc->zc_objset_stats); | |
684 | |
685 switch (zc->zc_objset_stats.dds_type) { | |
686 | |
687 case DMU_OST_ZFS: | |
688 error = zfs_get_stats(zc); | |
689 break; | |
690 | |
691 case DMU_OST_ZVOL: | |
692 error = zvol_get_stats(zc, os); | |
693 break; | |
694 } | |
695 | |
696 dmu_objset_close(os); | |
697 return (error); | |
698 } | |
699 | |
700 static int | |
701 zfs_ioc_dataset_list_next(zfs_cmd_t *zc) | |
702 { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
703 objset_t *os; |
789 | 704 int error; |
705 char *p; | |
706 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
707 retry: |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
708 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
709 DS_MODE_STANDARD | DS_MODE_READONLY, &os); |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
710 if (error != 0) { |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
711 /* |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
712 * This is ugly: dmu_objset_open() can return EBUSY if |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
713 * the objset is held exclusively. Fortunately this hold is |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
714 * only for a short while, so we retry here. |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
715 * This avoids user code having to handle EBUSY, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
716 * for example for a "zfs list". |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
717 */ |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
718 if (error == EBUSY) { |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
719 delay(1); |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
720 goto retry; |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
721 } |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
722 if (error == ENOENT) |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
723 error = ESRCH; |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
724 return (error); |
789 | 725 } |
726 | |
727 p = strrchr(zc->zc_name, '/'); | |
728 if (p == NULL || p[1] != '\0') | |
729 (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); | |
730 p = zc->zc_name + strlen(zc->zc_name); | |
731 | |
732 do { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
733 error = dmu_dir_list_next(os, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
734 sizeof (zc->zc_name) - (p - zc->zc_name), p, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
735 NULL, &zc->zc_cookie); |
789 | 736 if (error == ENOENT) |
737 error = ESRCH; | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
738 } while (error == 0 && !INGLOBALZONE(curproc) && |
789 | 739 !zone_dataset_visible(zc->zc_name, NULL)); |
740 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
741 /* |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
742 * If it's a hidden dataset (ie. with a '$' in its name), don't |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
743 * try to get stats for it. Userland will skip over it. |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
744 */ |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
745 if (error == 0 && strchr(zc->zc_name, '$') == NULL) |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
746 error = zfs_ioc_objset_stats(zc); /* fill in the stats */ |
789 | 747 |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
748 dmu_objset_close(os); |
789 | 749 return (error); |
750 } | |
751 | |
752 static int | |
753 zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) | |
754 { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
755 objset_t *os; |
789 | 756 int error; |
757 | |
758 retry: | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
759 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
760 DS_MODE_STANDARD | DS_MODE_READONLY, &os); |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
761 if (error != 0) { |
789 | 762 /* |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
763 * This is ugly: dmu_objset_open() can return EBUSY if |
789 | 764 * the objset is held exclusively. Fortunately this hold is |
765 * only for a short while, so we retry here. | |
766 * This avoids user code having to handle EBUSY, | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
767 * for example for a "zfs list". |
789 | 768 */ |
769 if (error == EBUSY) { | |
770 delay(1); | |
771 goto retry; | |
772 } | |
773 if (error == ENOENT) | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
774 error = ESRCH; |
789 | 775 return (error); |
776 } | |
777 | |
1003 | 778 /* |
779 * A dataset name of maximum length cannot have any snapshots, | |
780 * so exit immediately. | |
781 */ | |
782 if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
783 dmu_objset_close(os); |
1003 | 784 return (ESRCH); |
789 | 785 } |
786 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
787 error = dmu_snapshot_list_next(os, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
788 sizeof (zc->zc_name) - strlen(zc->zc_name), |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
789 zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie); |
789 | 790 if (error == ENOENT) |
791 error = ESRCH; | |
792 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
793 if (error == 0) |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
794 error = zfs_ioc_objset_stats(zc); /* fill in the stats */ |
789 | 795 |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
796 dmu_objset_close(os); |
789 | 797 return (error); |
798 } | |
799 | |
800 static int | |
801 zfs_ioc_set_prop(zfs_cmd_t *zc) | |
802 { | |
803 return (dsl_prop_set(zc->zc_name, zc->zc_prop_name, | |
804 zc->zc_intsz, zc->zc_numints, zc->zc_prop_value)); | |
805 } | |
806 | |
807 static int | |
808 zfs_ioc_set_quota(zfs_cmd_t *zc) | |
809 { | |
810 return (dsl_dir_set_quota(zc->zc_name, zc->zc_cookie)); | |
811 } | |
812 | |
813 static int | |
814 zfs_ioc_set_reservation(zfs_cmd_t *zc) | |
815 { | |
816 return (dsl_dir_set_reservation(zc->zc_name, zc->zc_cookie)); | |
817 } | |
818 | |
819 static int | |
820 zfs_ioc_set_volsize(zfs_cmd_t *zc) | |
821 { | |
822 return (zvol_set_volsize(zc)); | |
823 } | |
824 | |
825 static int | |
826 zfs_ioc_set_volblocksize(zfs_cmd_t *zc) | |
827 { | |
828 return (zvol_set_volblocksize(zc)); | |
829 } | |
830 | |
831 static int | |
832 zfs_ioc_create_minor(zfs_cmd_t *zc) | |
833 { | |
834 return (zvol_create_minor(zc)); | |
835 } | |
836 | |
837 static int | |
838 zfs_ioc_remove_minor(zfs_cmd_t *zc) | |
839 { | |
840 return (zvol_remove_minor(zc)); | |
841 } | |
842 | |
843 /* | |
844 * Search the vfs list for a specified resource. Returns a pointer to it | |
845 * or NULL if no suitable entry is found. The caller of this routine | |
846 * is responsible for releasing the returned vfs pointer. | |
847 */ | |
848 static vfs_t * | |
849 zfs_get_vfs(const char *resource) | |
850 { | |
851 struct vfs *vfsp; | |
852 struct vfs *vfs_found = NULL; | |
853 | |
854 vfs_list_read_lock(); | |
855 vfsp = rootvfs; | |
856 do { | |
857 if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { | |
858 VFS_HOLD(vfsp); | |
859 vfs_found = vfsp; | |
860 break; | |
861 } | |
862 vfsp = vfsp->vfs_next; | |
863 } while (vfsp != rootvfs); | |
864 vfs_list_unlock(); | |
865 return (vfs_found); | |
866 } | |
867 | |
868 static void | |
869 zfs_create_cb(objset_t *os, void *arg, dmu_tx_t *tx) | |
870 { | |
871 zfs_cmd_t *zc = arg; | |
872 zfs_create_fs(os, (cred_t *)(uintptr_t)zc->zc_cred, tx); | |
873 } | |
874 | |
875 static int | |
876 zfs_ioc_create(zfs_cmd_t *zc) | |
877 { | |
878 objset_t *clone; | |
879 int error = 0; | |
880 void (*cbfunc)(objset_t *os, void *arg, dmu_tx_t *tx); | |
881 dmu_objset_type_t type = zc->zc_objset_type; | |
882 | |
883 switch (type) { | |
884 | |
885 case DMU_OST_ZFS: | |
886 cbfunc = zfs_create_cb; | |
887 break; | |
888 | |
889 case DMU_OST_ZVOL: | |
890 cbfunc = zvol_create_cb; | |
891 break; | |
892 | |
893 default: | |
894 return (EINVAL); | |
895 } | |
896 | |
897 if (zc->zc_filename[0] != '\0') { | |
898 /* | |
899 * We're creating a clone of an existing snapshot. | |
900 */ | |
901 zc->zc_filename[sizeof (zc->zc_filename) - 1] = '\0'; | |
902 if (dataset_namecheck(zc->zc_filename, NULL, NULL) != 0) | |
903 return (EINVAL); | |
904 | |
905 error = dmu_objset_open(zc->zc_filename, type, | |
906 DS_MODE_STANDARD | DS_MODE_READONLY, &clone); | |
907 if (error) | |
908 return (error); | |
909 error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL); | |
910 dmu_objset_close(clone); | |
911 } else if (strchr(zc->zc_name, '@') != 0) { | |
912 /* | |
913 * We're taking a snapshot of an existing dataset. | |
914 */ | |
915 error = dmu_objset_create(zc->zc_name, type, NULL, NULL, NULL); | |
916 } else { | |
917 /* | |
918 * We're creating a new dataset. | |
919 */ | |
920 if (type == DMU_OST_ZVOL) { | |
1133
335d069294d1
6357470 vdev_raidz.c has unused RAIDZ_SINGLE define, code
eschrock
parents:
1003
diff
changeset
|
921 |
335d069294d1
6357470 vdev_raidz.c has unused RAIDZ_SINGLE define, code
eschrock
parents:
1003
diff
changeset
|
922 if ((error = zvol_check_volblocksize(zc)) != 0) |
789 | 923 return (error); |
1133
335d069294d1
6357470 vdev_raidz.c has unused RAIDZ_SINGLE define, code
eschrock
parents:
1003
diff
changeset
|
924 |
335d069294d1
6357470 vdev_raidz.c has unused RAIDZ_SINGLE define, code
eschrock
parents:
1003
diff
changeset
|
925 if ((error = zvol_check_volsize(zc, |
335d069294d1
6357470 vdev_raidz.c has unused RAIDZ_SINGLE define, code
eschrock
parents:
1003
diff
changeset
|
926 zc->zc_volblocksize)) != 0) |
789 | 927 return (error); |
928 } | |
929 error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, zc); | |
930 } | |
931 return (error); | |
932 } | |
933 | |
934 static int | |
935 zfs_ioc_destroy(zfs_cmd_t *zc) | |
936 { | |
937 if (strchr(zc->zc_name, '@') != NULL && | |
938 zc->zc_objset_type == DMU_OST_ZFS) { | |
939 vfs_t *vfsp; | |
940 int err; | |
941 | |
942 /* | |
943 * Snapshots under .zfs control must be unmounted | |
944 * before they can be destroyed. | |
945 */ | |
946 if ((vfsp = zfs_get_vfs(zc->zc_name)) != NULL) { | |
947 /* | |
948 * Always force the unmount for snapshots. | |
949 */ | |
950 int flag = MS_FORCE; | |
951 | |
952 if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { | |
953 VFS_RELE(vfsp); | |
954 return (err); | |
955 } | |
956 VFS_RELE(vfsp); | |
957 if ((err = dounmount(vfsp, flag, kcred)) != 0) | |
958 return (err); | |
959 } | |
960 } | |
961 | |
962 return (dmu_objset_destroy(zc->zc_name)); | |
963 } | |
964 | |
965 static int | |
966 zfs_ioc_rollback(zfs_cmd_t *zc) | |
967 { | |
968 return (dmu_objset_rollback(zc->zc_name)); | |
969 } | |
970 | |
971 static int | |
972 zfs_ioc_rename(zfs_cmd_t *zc) | |
973 { | |
974 zc->zc_prop_value[sizeof (zc->zc_prop_value) - 1] = '\0'; | |
975 if (dataset_namecheck(zc->zc_prop_value, NULL, NULL) != 0) | |
976 return (EINVAL); | |
977 | |
978 if (strchr(zc->zc_name, '@') != NULL && | |
979 zc->zc_objset_type == DMU_OST_ZFS) { | |
980 vfs_t *vfsp; | |
981 int err; | |
982 | |
983 /* | |
984 * Snapshots under .zfs control must be unmounted | |
985 * before they can be renamed. | |
986 */ | |
987 if ((vfsp = zfs_get_vfs(zc->zc_name)) != NULL) { | |
988 /* | |
989 * Always force the unmount for snapshots. | |
990 */ | |
991 int flag = MS_FORCE; | |
992 | |
993 if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { | |
994 VFS_RELE(vfsp); | |
995 return (err); | |
996 } | |
997 VFS_RELE(vfsp); | |
998 if ((err = dounmount(vfsp, flag, kcred)) != 0) | |
999 return (err); | |
1000 } | |
1001 } | |
1002 | |
1003 return (dmu_objset_rename(zc->zc_name, zc->zc_prop_value)); | |
1004 } | |
1005 | |
1006 static int | |
1007 zfs_ioc_recvbackup(zfs_cmd_t *zc) | |
1008 { | |
1009 file_t *fp; | |
1010 int error, fd; | |
1011 | |
1012 fd = zc->zc_cookie; | |
1013 fp = getf(fd); | |
1014 if (fp == NULL) | |
1015 return (EBADF); | |
1016 error = dmu_recvbackup(&zc->zc_begin_record, &zc->zc_cookie, | |
1017 fp->f_vnode, fp->f_offset); | |
1018 releasef(fd); | |
1019 return (error); | |
1020 } | |
1021 | |
1022 static int | |
1023 zfs_ioc_sendbackup(zfs_cmd_t *zc) | |
1024 { | |
1025 objset_t *fromsnap = NULL; | |
1026 objset_t *tosnap; | |
1027 file_t *fp; | |
1028 int error; | |
1029 | |
1030 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, | |
1031 DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap); | |
1032 if (error) | |
1033 return (error); | |
1034 | |
1035 if (zc->zc_prop_value[0] != '\0') { | |
1036 error = dmu_objset_open(zc->zc_prop_value, DMU_OST_ANY, | |
1037 DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap); | |
1038 if (error) { | |
1039 dmu_objset_close(tosnap); | |
1040 return (error); | |
1041 } | |
1042 } | |
1043 | |
1044 fp = getf(zc->zc_cookie); | |
1045 if (fp == NULL) { | |
1046 dmu_objset_close(tosnap); | |
1047 if (fromsnap) | |
1048 dmu_objset_close(fromsnap); | |
1049 return (EBADF); | |
1050 } | |
1051 | |
1052 error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode); | |
1053 | |
1054 releasef(zc->zc_cookie); | |
1055 if (fromsnap) | |
1056 dmu_objset_close(fromsnap); | |
1057 dmu_objset_close(tosnap); | |
1058 return (error); | |
1059 } | |
1060 | |
1061 static zfs_ioc_vec_t zfs_ioc_vec[] = { | |
1062 { zfs_ioc_pool_create, zfs_secpolicy_config, pool_name }, | |
1063 { zfs_ioc_pool_destroy, zfs_secpolicy_config, pool_name }, | |
1064 { zfs_ioc_pool_import, zfs_secpolicy_config, pool_name }, | |
1065 { zfs_ioc_pool_export, zfs_secpolicy_config, pool_name }, | |
1066 { zfs_ioc_pool_configs, zfs_secpolicy_none, no_name }, | |
1067 { zfs_ioc_pool_guid, zfs_secpolicy_read, pool_name }, | |
1068 { zfs_ioc_pool_stats, zfs_secpolicy_read, pool_name }, | |
1069 { zfs_ioc_pool_tryimport, zfs_secpolicy_config, no_name }, | |
1070 { zfs_ioc_pool_scrub, zfs_secpolicy_config, pool_name }, | |
1071 { zfs_ioc_pool_freeze, zfs_secpolicy_config, no_name }, | |
1072 { zfs_ioc_vdev_add, zfs_secpolicy_config, pool_name }, | |
1073 { zfs_ioc_vdev_remove, zfs_secpolicy_config, pool_name }, | |
1074 { zfs_ioc_vdev_online, zfs_secpolicy_config, pool_name }, | |
1075 { zfs_ioc_vdev_offline, zfs_secpolicy_config, pool_name }, | |
1076 { zfs_ioc_vdev_attach, zfs_secpolicy_config, pool_name }, | |
1077 { zfs_ioc_vdev_detach, zfs_secpolicy_config, pool_name }, | |
1078 { zfs_ioc_objset_stats, zfs_secpolicy_read, dataset_name }, | |
1079 { zfs_ioc_dataset_list_next, zfs_secpolicy_read, dataset_name }, | |
1080 { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, dataset_name }, | |
1081 { zfs_ioc_set_prop, zfs_secpolicy_setprop, dataset_name }, | |
1082 { zfs_ioc_set_quota, zfs_secpolicy_quota, dataset_name }, | |
1083 { zfs_ioc_set_reservation, zfs_secpolicy_write, dataset_name }, | |
1084 { zfs_ioc_set_volsize, zfs_secpolicy_config, dataset_name }, | |
1085 { zfs_ioc_set_volblocksize, zfs_secpolicy_config, dataset_name }, | |
1086 { zfs_ioc_create_minor, zfs_secpolicy_config, dataset_name }, | |
1087 { zfs_ioc_remove_minor, zfs_secpolicy_config, dataset_name }, | |
1088 { zfs_ioc_create, zfs_secpolicy_parent, dataset_name }, | |
1089 { zfs_ioc_destroy, zfs_secpolicy_parent, dataset_name }, | |
1090 { zfs_ioc_rollback, zfs_secpolicy_write, dataset_name }, | |
1091 { zfs_ioc_rename, zfs_secpolicy_write, dataset_name }, | |
1092 { zfs_ioc_recvbackup, zfs_secpolicy_write, dataset_name }, | |
1093 { zfs_ioc_sendbackup, zfs_secpolicy_write, dataset_name }, | |
1094 }; | |
1095 | |
1096 static int | |
1097 zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) | |
1098 { | |
1099 zfs_cmd_t *zc; | |
1100 uint_t vec; | |
1101 int error; | |
1102 | |
1103 if (getminor(dev) != 0) | |
1104 return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); | |
1105 | |
1106 vec = cmd - ZFS_IOC; | |
1107 | |
1108 if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) | |
1109 return (EINVAL); | |
1110 | |
1111 zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); | |
1112 | |
1113 error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); | |
1114 | |
1115 if (error == 0) { | |
1116 zc->zc_cred = (uintptr_t)cr; | |
1117 zc->zc_dev = dev; | |
1118 error = zfs_ioc_vec[vec].zvec_secpolicy(zc->zc_name, | |
1119 zc->zc_prop_name, cr); | |
1120 } | |
1121 | |
1122 /* | |
1123 * Ensure that all pool/dataset names are valid before we pass down to | |
1124 * the lower layers. | |
1125 */ | |
1126 if (error == 0) { | |
1127 zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; | |
1128 switch (zfs_ioc_vec[vec].zvec_namecheck) { | |
1129 case pool_name: | |
1130 if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) | |
1131 error = EINVAL; | |
1132 break; | |
1133 | |
1134 case dataset_name: | |
1135 if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) | |
1136 error = EINVAL; | |
1137 break; | |
1138 } | |
1139 } | |
1140 | |
1141 if (error == 0) | |
1142 error = zfs_ioc_vec[vec].zvec_func(zc); | |
1143 | |
1144 if (error == 0 || error == ENOMEM) { | |
1145 int rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); | |
1146 if (error == 0) | |
1147 error = rc; | |
1148 } | |
1149 | |
1150 kmem_free(zc, sizeof (zfs_cmd_t)); | |
1151 return (error); | |
1152 } | |
1153 | |
1154 static int | |
1155 zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) | |
1156 { | |
1157 if (cmd != DDI_ATTACH) | |
1158 return (DDI_FAILURE); | |
1159 | |
1160 if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, | |
1161 DDI_PSEUDO, 0) == DDI_FAILURE) | |
1162 return (DDI_FAILURE); | |
1163 | |
1164 zfs_dip = dip; | |
1165 | |
1166 ddi_report_dev(dip); | |
1167 | |
1168 return (DDI_SUCCESS); | |
1169 } | |
1170 | |
1171 static int | |
1172 zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) | |
1173 { | |
1174 if (spa_busy() || zfs_busy() || zvol_busy()) | |
1175 return (DDI_FAILURE); | |
1176 | |
1177 if (cmd != DDI_DETACH) | |
1178 return (DDI_FAILURE); | |
1179 | |
1180 zfs_dip = NULL; | |
1181 | |
1182 ddi_prop_remove_all(dip); | |
1183 ddi_remove_minor_node(dip, NULL); | |
1184 | |
1185 return (DDI_SUCCESS); | |
1186 } | |
1187 | |
1188 /*ARGSUSED*/ | |
1189 static int | |
1190 zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) | |
1191 { | |
1192 switch (infocmd) { | |
1193 case DDI_INFO_DEVT2DEVINFO: | |
1194 *result = zfs_dip; | |
1195 return (DDI_SUCCESS); | |
1196 | |
1197 case DDI_INFO_DEVT2INSTANCE: | |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1198 *result = (void *)0; |
789 | 1199 return (DDI_SUCCESS); |
1200 } | |
1201 | |
1202 return (DDI_FAILURE); | |
1203 } | |
1204 | |
1205 /* | |
1206 * OK, so this is a little weird. | |
1207 * | |
1208 * /dev/zfs is the control node, i.e. minor 0. | |
1209 * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. | |
1210 * | |
1211 * /dev/zfs has basically nothing to do except serve up ioctls, | |
1212 * so most of the standard driver entry points are in zvol.c. | |
1213 */ | |
1214 static struct cb_ops zfs_cb_ops = { | |
1215 zvol_open, /* open */ | |
1216 zvol_close, /* close */ | |
1217 zvol_strategy, /* strategy */ | |
1218 nodev, /* print */ | |
1219 nodev, /* dump */ | |
1220 zvol_read, /* read */ | |
1221 zvol_write, /* write */ | |
1222 zfsdev_ioctl, /* ioctl */ | |
1223 nodev, /* devmap */ | |
1224 nodev, /* mmap */ | |
1225 nodev, /* segmap */ | |
1226 nochpoll, /* poll */ | |
1227 ddi_prop_op, /* prop_op */ | |
1228 NULL, /* streamtab */ | |
1229 D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ | |
1230 CB_REV, /* version */ | |
1231 zvol_aread, /* async read */ | |
1232 zvol_awrite, /* async write */ | |
1233 }; | |
1234 | |
1235 static struct dev_ops zfs_dev_ops = { | |
1236 DEVO_REV, /* version */ | |
1237 0, /* refcnt */ | |
1238 zfs_info, /* info */ | |
1239 nulldev, /* identify */ | |
1240 nulldev, /* probe */ | |
1241 zfs_attach, /* attach */ | |
1242 zfs_detach, /* detach */ | |
1243 nodev, /* reset */ | |
1244 &zfs_cb_ops, /* driver operations */ | |
1245 NULL /* no bus operations */ | |
1246 }; | |
1247 | |
1248 static struct modldrv zfs_modldrv = { | |
1249 &mod_driverops, "ZFS storage pool version 1", &zfs_dev_ops | |
1250 }; | |
1251 | |
1252 static struct modlinkage modlinkage = { | |
1253 MODREV_1, | |
1254 (void *)&zfs_modlfs, | |
1255 (void *)&zfs_modldrv, | |
1256 NULL | |
1257 }; | |
1258 | |
1259 int | |
1260 _init(void) | |
1261 { | |
1262 int error; | |
1263 | |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1264 spa_init(FREAD | FWRITE); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1265 zfs_init(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1266 zvol_init(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1267 |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1268 if ((error = mod_install(&modlinkage)) != 0) { |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1269 zvol_fini(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1270 zfs_fini(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1271 spa_fini(); |
789 | 1272 return (error); |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1273 } |
789 | 1274 |
1275 error = ldi_ident_from_mod(&modlinkage, &zfs_li); | |
1276 ASSERT(error == 0); | |
1277 | |
1278 return (0); | |
1279 } | |
1280 | |
1281 int | |
1282 _fini(void) | |
1283 { | |
1284 int error; | |
1285 | |
1286 if (spa_busy() || zfs_busy() || zvol_busy()) | |
1287 return (EBUSY); | |
1288 | |
1289 if ((error = mod_remove(&modlinkage)) != 0) | |
1290 return (error); | |
1291 | |
1292 zvol_fini(); | |
1293 zfs_fini(); | |
1294 spa_fini(); | |
1295 | |
1296 ldi_ident_release(zfs_li); | |
1297 zfs_li = NULL; | |
1298 | |
1299 return (error); | |
1300 } | |
1301 | |
1302 int | |
1303 _info(struct modinfo *modinfop) | |
1304 { | |
1305 return (mod_info(&modlinkage, modinfop)); | |
1306 } |