Mercurial > illumos > illumos-gate
annotate usr/src/uts/common/fs/zfs/zfs_ioctl.c @ 4670:002728040e28
6580745 "zfs inherit" can be executed by ordinary user
author | ahrens |
---|---|
date | Mon, 16 Jul 2007 12:10:21 -0700 |
parents | 0960c3336815 |
children | e8d212dda064 |
rev | line source |
---|---|
789 | 1 /* |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
1485 | 5 * Common Development and Distribution License (the "License"). |
6 * You may not use this file except in compliance with the License. | |
789 | 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 /* | |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. |
789 | 23 * Use is subject to license terms. |
24 */ | |
25 | |
26 #pragma ident "%Z%%M% %I% %E% SMI" | |
27 | |
28 #include <sys/types.h> | |
29 #include <sys/param.h> | |
30 #include <sys/errno.h> | |
31 #include <sys/uio.h> | |
32 #include <sys/buf.h> | |
33 #include <sys/modctl.h> | |
34 #include <sys/open.h> | |
35 #include <sys/file.h> | |
36 #include <sys/kmem.h> | |
37 #include <sys/conf.h> | |
38 #include <sys/cmn_err.h> | |
39 #include <sys/stat.h> | |
40 #include <sys/zfs_ioctl.h> | |
41 #include <sys/zap.h> | |
42 #include <sys/spa.h> | |
3912 | 43 #include <sys/spa_impl.h> |
789 | 44 #include <sys/vdev.h> |
3912 | 45 #include <sys/vdev_impl.h> |
789 | 46 #include <sys/dmu.h> |
47 #include <sys/dsl_dir.h> | |
48 #include <sys/dsl_dataset.h> | |
49 #include <sys/dsl_prop.h> | |
4543 | 50 #include <sys/dsl_deleg.h> |
51 #include <sys/dmu_objset.h> | |
789 | 52 #include <sys/ddi.h> |
53 #include <sys/sunddi.h> | |
54 #include <sys/sunldi.h> | |
55 #include <sys/policy.h> | |
56 #include <sys/zone.h> | |
57 #include <sys/nvpair.h> | |
58 #include <sys/pathname.h> | |
59 #include <sys/mount.h> | |
60 #include <sys/sdt.h> | |
61 #include <sys/fs/zfs.h> | |
62 #include <sys/zfs_ctldir.h> | |
2885 | 63 #include <sys/zvol.h> |
4543 | 64 #include <sharefs/share.h> |
4577 | 65 #include <sys/zfs_znode.h> |
789 | 66 |
67 #include "zfs_namecheck.h" | |
2676 | 68 #include "zfs_prop.h" |
4543 | 69 #include "zfs_deleg.h" |
789 | 70 |
71 extern struct modlfs zfs_modlfs; | |
72 | |
73 extern void zfs_init(void); | |
74 extern void zfs_fini(void); | |
75 | |
76 ldi_ident_t zfs_li = NULL; | |
77 dev_info_t *zfs_dip; | |
78 | |
79 typedef int zfs_ioc_func_t(zfs_cmd_t *); | |
4543 | 80 typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); |
789 | 81 |
82 typedef struct zfs_ioc_vec { | |
83 zfs_ioc_func_t *zvec_func; | |
84 zfs_secpolicy_func_t *zvec_secpolicy; | |
85 enum { | |
4577 | 86 NO_NAME, |
87 POOL_NAME, | |
88 DATASET_NAME | |
4543 | 89 } zvec_namecheck; |
90 boolean_t zvec_his_log; | |
789 | 91 } zfs_ioc_vec_t; |
92 | |
93 /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ | |
94 void | |
95 __dprintf(const char *file, const char *func, int line, const char *fmt, ...) | |
96 { | |
97 const char *newfile; | |
98 char buf[256]; | |
99 va_list adx; | |
100 | |
101 /* | |
102 * Get rid of annoying "../common/" prefix to filename. | |
103 */ | |
104 newfile = strrchr(file, '/'); | |
105 if (newfile != NULL) { | |
106 newfile = newfile + 1; /* Get rid of leading / */ | |
107 } else { | |
108 newfile = file; | |
109 } | |
110 | |
111 va_start(adx, fmt); | |
112 (void) vsnprintf(buf, sizeof (buf), fmt, adx); | |
113 va_end(adx); | |
114 | |
115 /* | |
116 * To get this data, use the zfs-dprintf probe as so: | |
117 * dtrace -q -n 'zfs-dprintf \ | |
118 * /stringof(arg0) == "dbuf.c"/ \ | |
119 * {printf("%s: %s", stringof(arg1), stringof(arg3))}' | |
120 * arg0 = file name | |
121 * arg1 = function name | |
122 * arg2 = line number | |
123 * arg3 = message | |
124 */ | |
125 DTRACE_PROBE4(zfs__dprintf, | |
126 char *, newfile, char *, func, int, line, char *, buf); | |
127 } | |
128 | |
4543 | 129 static void |
130 zfs_log_history(zfs_cmd_t *zc) | |
131 { | |
132 spa_t *spa; | |
4603
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
133 char *buf; |
4543 | 134 |
135 if (zc->zc_history == NULL) | |
136 return; | |
137 | |
4577 | 138 if (zc->zc_history_offset != LOG_CMD_POOL_CREATE && |
139 zc->zc_history_offset != LOG_CMD_NORMAL) | |
140 return; | |
141 | |
4543 | 142 buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); |
143 if (copyinstr((void *)(uintptr_t)zc->zc_history, | |
144 buf, HIS_MAX_RECORD_LEN, NULL) != 0) { | |
145 kmem_free(buf, HIS_MAX_RECORD_LEN); | |
146 return; | |
147 } | |
148 | |
149 buf[HIS_MAX_RECORD_LEN -1] = '\0'; | |
150 | |
4603
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
151 if (spa_open(zc->zc_name, &spa, FTAG) != 0) { |
4543 | 152 kmem_free(buf, HIS_MAX_RECORD_LEN); |
153 return; | |
154 } | |
155 | |
4577 | 156 if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) |
4543 | 157 (void) spa_history_log(spa, buf, zc->zc_history_offset); |
158 | |
159 spa_close(spa, FTAG); | |
160 kmem_free(buf, HIS_MAX_RECORD_LEN); | |
161 } | |
162 | |
789 | 163 /* |
164 * Policy for top-level read operations (list pools). Requires no privileges, | |
165 * and can be used in the local zone, as there is no associated dataset. | |
166 */ | |
167 /* ARGSUSED */ | |
168 static int | |
4543 | 169 zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) |
789 | 170 { |
171 return (0); | |
172 } | |
173 | |
174 /* | |
175 * Policy for dataset read operations (list children, get statistics). Requires | |
176 * no privileges, but must be visible in the local zone. | |
177 */ | |
178 /* ARGSUSED */ | |
179 static int | |
4543 | 180 zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) |
789 | 181 { |
182 if (INGLOBALZONE(curproc) || | |
4543 | 183 zone_dataset_visible(zc->zc_name, NULL)) |
789 | 184 return (0); |
185 | |
186 return (ENOENT); | |
187 } | |
188 | |
189 static int | |
190 zfs_dozonecheck(const char *dataset, cred_t *cr) | |
191 { | |
192 uint64_t zoned; | |
193 int writable = 1; | |
194 | |
195 /* | |
196 * The dataset must be visible by this zone -- check this first | |
197 * so they don't see EPERM on something they shouldn't know about. | |
198 */ | |
199 if (!INGLOBALZONE(curproc) && | |
200 !zone_dataset_visible(dataset, &writable)) | |
201 return (ENOENT); | |
202 | |
203 if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) | |
204 return (ENOENT); | |
205 | |
206 if (INGLOBALZONE(curproc)) { | |
207 /* | |
208 * If the fs is zoned, only root can access it from the | |
209 * global zone. | |
210 */ | |
211 if (secpolicy_zfs(cr) && zoned) | |
212 return (EPERM); | |
213 } else { | |
214 /* | |
215 * If we are in a local zone, the 'zoned' property must be set. | |
216 */ | |
217 if (!zoned) | |
218 return (EPERM); | |
219 | |
220 /* must be writable by this zone */ | |
221 if (!writable) | |
222 return (EPERM); | |
223 } | |
224 return (0); | |
225 } | |
226 | |
227 int | |
4543 | 228 zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) |
789 | 229 { |
230 int error; | |
231 | |
4543 | 232 error = zfs_dozonecheck(name, cr); |
233 if (error == 0) { | |
234 error = secpolicy_zfs(cr); | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
235 if (error) |
4543 | 236 error = dsl_deleg_access(name, perm, cr); |
237 } | |
238 return (error); | |
239 } | |
240 | |
241 static int | |
242 zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) | |
243 { | |
244 /* | |
245 * Check permissions for special properties. | |
246 */ | |
247 switch (prop) { | |
248 case ZFS_PROP_ZONED: | |
249 /* | |
250 * Disallow setting of 'zoned' from within a local zone. | |
251 */ | |
252 if (!INGLOBALZONE(curproc)) | |
253 return (EPERM); | |
254 break; | |
789 | 255 |
4543 | 256 case ZFS_PROP_QUOTA: |
257 if (!INGLOBALZONE(curproc)) { | |
258 uint64_t zoned; | |
259 char setpoint[MAXNAMELEN]; | |
260 /* | |
261 * Unprivileged users are allowed to modify the | |
262 * quota on things *under* (ie. contained by) | |
263 * the thing they own. | |
264 */ | |
265 if (dsl_prop_get_integer(name, "zoned", &zoned, | |
266 setpoint)) | |
267 return (EPERM); | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
268 if (!zoned || strlen(name) <= strlen(setpoint)) |
4543 | 269 return (EPERM); |
270 } | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
271 break; |
4543 | 272 } |
273 | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
274 return (zfs_secpolicy_write_perms(name, zfs_prop_perm(prop), cr)); |
789 | 275 } |
276 | |
4543 | 277 int |
278 zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) | |
279 { | |
280 int error; | |
281 | |
282 error = zfs_dozonecheck(zc->zc_name, cr); | |
283 if (error) | |
284 return (error); | |
285 | |
286 /* | |
287 * permission to set permissions will be evaluated later in | |
288 * dsl_deleg_can_allow() | |
289 */ | |
290 return (0); | |
291 } | |
292 | |
293 int | |
294 zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) | |
295 { | |
296 int error; | |
297 error = zfs_secpolicy_write_perms(zc->zc_name, | |
298 ZFS_DELEG_PERM_ROLLBACK, cr); | |
299 if (error == 0) | |
300 error = zfs_secpolicy_write_perms(zc->zc_name, | |
301 ZFS_DELEG_PERM_MOUNT, cr); | |
302 return (error); | |
303 } | |
304 | |
305 int | |
306 zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) | |
307 { | |
308 return (zfs_secpolicy_write_perms(zc->zc_name, | |
309 ZFS_DELEG_PERM_SEND, cr)); | |
310 } | |
311 | |
312 int | |
313 zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) | |
314 { | |
315 if (!INGLOBALZONE(curproc)) | |
316 return (EPERM); | |
317 | |
318 if (secpolicy_nfs(CRED()) == 0) { | |
319 return (0); | |
320 } else { | |
321 vnode_t *vp; | |
322 int error; | |
323 | |
324 if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, | |
325 NO_FOLLOW, NULL, &vp)) != 0) | |
326 return (error); | |
327 | |
328 /* Now make sure mntpnt and dataset are ZFS */ | |
329 | |
330 if (vp->v_vfsp->vfs_fstype != zfsfstype || | |
331 (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), | |
332 zc->zc_name) != 0)) { | |
333 VN_RELE(vp); | |
334 return (EPERM); | |
335 } | |
336 | |
337 VN_RELE(vp); | |
338 return (dsl_deleg_access(zc->zc_name, | |
339 ZFS_DELEG_PERM_SHARE, cr)); | |
340 } | |
341 } | |
342 | |
789 | 343 static int |
4543 | 344 zfs_get_parent(const char *datasetname, char *parent, int parentsize) |
789 | 345 { |
346 char *cp; | |
347 | |
348 /* | |
349 * Remove the @bla or /bla from the end of the name to get the parent. | |
350 */ | |
4543 | 351 (void) strncpy(parent, datasetname, parentsize); |
352 cp = strrchr(parent, '@'); | |
789 | 353 if (cp != NULL) { |
354 cp[0] = '\0'; | |
355 } else { | |
4543 | 356 cp = strrchr(parent, '/'); |
789 | 357 if (cp == NULL) |
358 return (ENOENT); | |
359 cp[0] = '\0'; | |
360 } | |
361 | |
4543 | 362 return (0); |
363 } | |
364 | |
365 int | |
366 zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) | |
367 { | |
368 int error; | |
369 | |
370 if ((error = zfs_secpolicy_write_perms(name, | |
371 ZFS_DELEG_PERM_MOUNT, cr)) != 0) | |
372 return (error); | |
373 | |
374 return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); | |
375 } | |
376 | |
377 static int | |
378 zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) | |
379 { | |
380 return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); | |
381 } | |
382 | |
383 /* | |
384 * Must have sys_config privilege to check the iscsi permission | |
385 */ | |
386 /* ARGSUSED */ | |
387 static int | |
388 zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) | |
389 { | |
390 return (secpolicy_zfs(cr)); | |
391 } | |
392 | |
393 int | |
394 zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) | |
395 { | |
396 char parentname[MAXNAMELEN]; | |
397 int error; | |
398 | |
399 if ((error = zfs_secpolicy_write_perms(from, | |
400 ZFS_DELEG_PERM_RENAME, cr)) != 0) | |
401 return (error); | |
402 | |
403 if ((error = zfs_secpolicy_write_perms(from, | |
404 ZFS_DELEG_PERM_MOUNT, cr)) != 0) | |
405 return (error); | |
406 | |
407 if ((error = zfs_get_parent(to, parentname, | |
408 sizeof (parentname))) != 0) | |
409 return (error); | |
410 | |
411 if ((error = zfs_secpolicy_write_perms(parentname, | |
412 ZFS_DELEG_PERM_CREATE, cr)) != 0) | |
413 return (error); | |
414 | |
415 if ((error = zfs_secpolicy_write_perms(parentname, | |
416 ZFS_DELEG_PERM_MOUNT, cr)) != 0) | |
417 return (error); | |
418 | |
419 return (error); | |
420 } | |
421 | |
422 static int | |
423 zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) | |
424 { | |
425 return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); | |
426 } | |
427 | |
428 static int | |
429 zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) | |
430 { | |
431 char parentname[MAXNAMELEN]; | |
432 objset_t *clone; | |
433 int error; | |
434 | |
435 error = zfs_secpolicy_write_perms(zc->zc_name, | |
436 ZFS_DELEG_PERM_PROMOTE, cr); | |
437 if (error) | |
438 return (error); | |
439 | |
440 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, | |
441 DS_MODE_STANDARD | DS_MODE_READONLY, &clone); | |
442 | |
443 if (error == 0) { | |
444 dsl_dataset_t *pclone = NULL; | |
445 dsl_dir_t *dd; | |
446 dd = clone->os->os_dsl_dataset->ds_dir; | |
447 | |
448 rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); | |
449 error = dsl_dataset_open_obj(dd->dd_pool, | |
450 dd->dd_phys->dd_clone_parent_obj, NULL, | |
451 DS_MODE_NONE, FTAG, &pclone); | |
452 rw_exit(&dd->dd_pool->dp_config_rwlock); | |
453 if (error) { | |
454 dmu_objset_close(clone); | |
455 return (error); | |
456 } | |
457 | |
458 error = zfs_secpolicy_write_perms(zc->zc_name, | |
459 ZFS_DELEG_PERM_MOUNT, cr); | |
460 | |
461 dsl_dataset_name(pclone, parentname); | |
462 dmu_objset_close(clone); | |
463 dsl_dataset_close(pclone, DS_MODE_NONE, FTAG); | |
464 if (error == 0) | |
465 error = zfs_secpolicy_write_perms(parentname, | |
466 ZFS_DELEG_PERM_PROMOTE, cr); | |
467 } | |
468 return (error); | |
469 } | |
470 | |
471 static int | |
472 zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) | |
473 { | |
474 int error; | |
475 | |
476 if ((error = zfs_secpolicy_write_perms(zc->zc_name, | |
477 ZFS_DELEG_PERM_RECEIVE, cr)) != 0) | |
478 return (error); | |
479 | |
480 if ((error = zfs_secpolicy_write_perms(zc->zc_name, | |
481 ZFS_DELEG_PERM_MOUNT, cr)) != 0) | |
482 return (error); | |
483 | |
484 return (zfs_secpolicy_write_perms(zc->zc_name, | |
485 ZFS_DELEG_PERM_CREATE, cr)); | |
486 } | |
487 | |
488 int | |
489 zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) | |
490 { | |
491 int error; | |
492 | |
493 if ((error = zfs_secpolicy_write_perms(name, | |
494 ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) | |
495 return (error); | |
496 | |
497 error = zfs_secpolicy_write_perms(name, | |
498 ZFS_DELEG_PERM_MOUNT, cr); | |
499 | |
500 return (error); | |
501 } | |
502 | |
503 static int | |
504 zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) | |
505 { | |
506 | |
507 return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); | |
508 } | |
509 | |
510 static int | |
511 zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) | |
512 { | |
513 char parentname[MAXNAMELEN]; | |
514 int error; | |
515 | |
516 if ((error = zfs_get_parent(zc->zc_name, parentname, | |
517 sizeof (parentname))) != 0) | |
518 return (error); | |
519 | |
520 if (zc->zc_value[0] != '\0') { | |
521 if ((error = zfs_secpolicy_write_perms(zc->zc_value, | |
522 ZFS_DELEG_PERM_CLONE, cr)) != 0) | |
523 return (error); | |
524 } | |
525 | |
526 if ((error = zfs_secpolicy_write_perms(parentname, | |
527 ZFS_DELEG_PERM_CREATE, cr)) != 0) | |
528 return (error); | |
529 | |
530 error = zfs_secpolicy_write_perms(parentname, | |
531 ZFS_DELEG_PERM_MOUNT, cr); | |
532 | |
533 return (error); | |
534 } | |
535 | |
536 static int | |
537 zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) | |
538 { | |
539 int error; | |
540 | |
541 error = secpolicy_fs_unmount(cr, NULL); | |
542 if (error) { | |
543 error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); | |
544 } | |
545 return (error); | |
789 | 546 } |
547 | |
548 /* | |
549 * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires | |
550 * SYS_CONFIG privilege, which is not available in a local zone. | |
551 */ | |
552 /* ARGSUSED */ | |
553 static int | |
4543 | 554 zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) |
789 | 555 { |
556 if (secpolicy_sys_config(cr, B_FALSE) != 0) | |
557 return (EPERM); | |
558 | |
559 return (0); | |
560 } | |
561 | |
562 /* | |
4543 | 563 * Just like zfs_secpolicy_config, except that we will check for |
564 * mount permission on the dataset for permission to create/remove | |
565 * the minor nodes. | |
566 */ | |
567 static int | |
568 zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) | |
569 { | |
570 if (secpolicy_sys_config(cr, B_FALSE) != 0) { | |
571 return (dsl_deleg_access(zc->zc_name, | |
572 ZFS_DELEG_PERM_MOUNT, cr)); | |
573 } | |
574 | |
575 return (0); | |
576 } | |
577 | |
578 /* | |
1544 | 579 * Policy for fault injection. Requires all privileges. |
580 */ | |
581 /* ARGSUSED */ | |
582 static int | |
4543 | 583 zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) |
1544 | 584 { |
585 return (secpolicy_zinject(cr)); | |
586 } | |
587 | |
588 /* | |
789 | 589 * Returns the nvlist as specified by the user in the zfs_cmd_t. |
590 */ | |
591 static int | |
2676 | 592 get_nvlist(zfs_cmd_t *zc, nvlist_t **nvp) |
789 | 593 { |
594 char *packed; | |
595 size_t size; | |
596 int error; | |
597 nvlist_t *config = NULL; | |
598 | |
599 /* | |
2676 | 600 * Read in and unpack the user-supplied nvlist. |
789 | 601 */ |
2676 | 602 if ((size = zc->zc_nvlist_src_size) == 0) |
789 | 603 return (EINVAL); |
604 | |
605 packed = kmem_alloc(size, KM_SLEEP); | |
606 | |
2676 | 607 if ((error = xcopyin((void *)(uintptr_t)zc->zc_nvlist_src, packed, |
789 | 608 size)) != 0) { |
609 kmem_free(packed, size); | |
610 return (error); | |
611 } | |
612 | |
613 if ((error = nvlist_unpack(packed, size, &config, 0)) != 0) { | |
614 kmem_free(packed, size); | |
615 return (error); | |
616 } | |
617 | |
618 kmem_free(packed, size); | |
619 | |
620 *nvp = config; | |
621 return (0); | |
622 } | |
623 | |
624 static int | |
2676 | 625 put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) |
626 { | |
627 char *packed = NULL; | |
628 size_t size; | |
629 int error; | |
630 | |
631 VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); | |
632 | |
633 if (size > zc->zc_nvlist_dst_size) { | |
634 error = ENOMEM; | |
635 } else { | |
4611 | 636 packed = kmem_alloc(size, KM_SLEEP); |
2676 | 637 VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, |
638 KM_SLEEP) == 0); | |
639 error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, | |
640 size); | |
641 kmem_free(packed, size); | |
642 } | |
643 | |
644 zc->zc_nvlist_dst_size = size; | |
645 return (error); | |
646 } | |
647 | |
648 static int | |
789 | 649 zfs_ioc_pool_create(zfs_cmd_t *zc) |
650 { | |
651 int error; | |
652 nvlist_t *config; | |
653 | |
2676 | 654 if ((error = get_nvlist(zc, &config)) != 0) |
789 | 655 return (error); |
656 | |
2676 | 657 error = spa_create(zc->zc_name, config, zc->zc_value[0] == '\0' ? |
658 NULL : zc->zc_value); | |
789 | 659 |
660 nvlist_free(config); | |
661 | |
662 return (error); | |
663 } | |
664 | |
665 static int | |
666 zfs_ioc_pool_destroy(zfs_cmd_t *zc) | |
667 { | |
4543 | 668 int error; |
669 zfs_log_history(zc); | |
670 error = spa_destroy(zc->zc_name); | |
671 return (error); | |
789 | 672 } |
673 | |
674 static int | |
675 zfs_ioc_pool_import(zfs_cmd_t *zc) | |
676 { | |
677 int error; | |
678 nvlist_t *config; | |
679 uint64_t guid; | |
680 | |
2676 | 681 if ((error = get_nvlist(zc, &config)) != 0) |
789 | 682 return (error); |
683 | |
684 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || | |
1544 | 685 guid != zc->zc_guid) |
789 | 686 error = EINVAL; |
687 else | |
688 error = spa_import(zc->zc_name, config, | |
2676 | 689 zc->zc_value[0] == '\0' ? NULL : zc->zc_value); |
789 | 690 |
691 nvlist_free(config); | |
692 | |
693 return (error); | |
694 } | |
695 | |
696 static int | |
697 zfs_ioc_pool_export(zfs_cmd_t *zc) | |
698 { | |
4543 | 699 int error; |
700 zfs_log_history(zc); | |
701 error = spa_export(zc->zc_name, NULL); | |
702 return (error); | |
789 | 703 } |
704 | |
705 static int | |
706 zfs_ioc_pool_configs(zfs_cmd_t *zc) | |
707 { | |
708 nvlist_t *configs; | |
709 int error; | |
710 | |
711 if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) | |
712 return (EEXIST); | |
713 | |
2676 | 714 error = put_nvlist(zc, configs); |
789 | 715 |
716 nvlist_free(configs); | |
717 | |
718 return (error); | |
719 } | |
720 | |
721 static int | |
722 zfs_ioc_pool_stats(zfs_cmd_t *zc) | |
723 { | |
724 nvlist_t *config; | |
725 int error; | |
1544 | 726 int ret = 0; |
789 | 727 |
2676 | 728 error = spa_get_stats(zc->zc_name, &config, zc->zc_value, |
729 sizeof (zc->zc_value)); | |
789 | 730 |
731 if (config != NULL) { | |
2676 | 732 ret = put_nvlist(zc, config); |
789 | 733 nvlist_free(config); |
1544 | 734 |
735 /* | |
736 * The config may be present even if 'error' is non-zero. | |
737 * In this case we return success, and preserve the real errno | |
738 * in 'zc_cookie'. | |
739 */ | |
740 zc->zc_cookie = error; | |
789 | 741 } else { |
1544 | 742 ret = error; |
789 | 743 } |
744 | |
1544 | 745 return (ret); |
789 | 746 } |
747 | |
748 /* | |
749 * Try to import the given pool, returning pool stats as appropriate so that | |
750 * user land knows which devices are available and overall pool health. | |
751 */ | |
752 static int | |
753 zfs_ioc_pool_tryimport(zfs_cmd_t *zc) | |
754 { | |
755 nvlist_t *tryconfig, *config; | |
756 int error; | |
757 | |
2676 | 758 if ((error = get_nvlist(zc, &tryconfig)) != 0) |
789 | 759 return (error); |
760 | |
761 config = spa_tryimport(tryconfig); | |
762 | |
763 nvlist_free(tryconfig); | |
764 | |
765 if (config == NULL) | |
766 return (EINVAL); | |
767 | |
2676 | 768 error = put_nvlist(zc, config); |
789 | 769 nvlist_free(config); |
770 | |
771 return (error); | |
772 } | |
773 | |
774 static int | |
775 zfs_ioc_pool_scrub(zfs_cmd_t *zc) | |
776 { | |
777 spa_t *spa; | |
778 int error; | |
779 | |
2926 | 780 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
781 return (error); | |
782 | |
4451 | 783 spa_config_enter(spa, RW_READER, FTAG); |
2926 | 784 error = spa_scrub(spa, zc->zc_cookie, B_FALSE); |
4451 | 785 spa_config_exit(spa, FTAG); |
2926 | 786 |
787 spa_close(spa, FTAG); | |
788 | |
789 | 789 return (error); |
790 } | |
791 | |
792 static int | |
793 zfs_ioc_pool_freeze(zfs_cmd_t *zc) | |
794 { | |
795 spa_t *spa; | |
796 int error; | |
797 | |
798 error = spa_open(zc->zc_name, &spa, FTAG); | |
799 if (error == 0) { | |
800 spa_freeze(spa); | |
801 spa_close(spa, FTAG); | |
802 } | |
803 return (error); | |
804 } | |
805 | |
806 static int | |
1760 | 807 zfs_ioc_pool_upgrade(zfs_cmd_t *zc) |
808 { | |
809 spa_t *spa; | |
810 int error; | |
811 | |
2926 | 812 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
813 return (error); | |
814 | |
815 spa_upgrade(spa); | |
816 spa_close(spa, FTAG); | |
817 | |
818 return (error); | |
819 } | |
820 | |
821 static int | |
822 zfs_ioc_pool_get_history(zfs_cmd_t *zc) | |
823 { | |
824 spa_t *spa; | |
825 char *hist_buf; | |
826 uint64_t size; | |
827 int error; | |
828 | |
829 if ((size = zc->zc_history_len) == 0) | |
830 return (EINVAL); | |
831 | |
832 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
833 return (error); | |
834 | |
4577 | 835 if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { |
3863
d56571426115
6529406 zpool history needs to bump the on-disk version
ek110237
parents:
3741
diff
changeset
|
836 spa_close(spa, FTAG); |
d56571426115
6529406 zpool history needs to bump the on-disk version
ek110237
parents:
3741
diff
changeset
|
837 return (ENOTSUP); |
d56571426115
6529406 zpool history needs to bump the on-disk version
ek110237
parents:
3741
diff
changeset
|
838 } |
d56571426115
6529406 zpool history needs to bump the on-disk version
ek110237
parents:
3741
diff
changeset
|
839 |
2926 | 840 hist_buf = kmem_alloc(size, KM_SLEEP); |
841 if ((error = spa_history_get(spa, &zc->zc_history_offset, | |
842 &zc->zc_history_len, hist_buf)) == 0) { | |
4543 | 843 error = xcopyout(hist_buf, |
844 (char *)(uintptr_t)zc->zc_history, | |
2926 | 845 zc->zc_history_len); |
846 } | |
847 | |
848 spa_close(spa, FTAG); | |
849 kmem_free(hist_buf, size); | |
850 return (error); | |
851 } | |
852 | |
853 static int | |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
854 zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc) |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
855 { |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
856 int error; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
857 |
3912 | 858 if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value)) |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
859 return (error); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
860 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
861 return (0); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
862 } |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
863 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
864 static int |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
865 zfs_ioc_obj_to_path(zfs_cmd_t *zc) |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
866 { |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
867 objset_t *osp; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
868 int error; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
869 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
870 if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS, |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
871 DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0) |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
872 return (error); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
873 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
874 error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value, |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
875 sizeof (zc->zc_value)); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
876 dmu_objset_close(osp); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
877 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
878 return (error); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
879 } |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
880 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
881 static int |
789 | 882 zfs_ioc_vdev_add(zfs_cmd_t *zc) |
883 { | |
884 spa_t *spa; | |
885 int error; | |
886 nvlist_t *config; | |
887 | |
888 error = spa_open(zc->zc_name, &spa, FTAG); | |
889 if (error != 0) | |
890 return (error); | |
891 | |
3912 | 892 /* |
893 * A root pool with concatenated devices is not supported. | |
894 * Thus, can not add a device to a root pool with one device. | |
895 */ | |
896 if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) { | |
897 spa_close(spa, FTAG); | |
898 return (EDOM); | |
899 } | |
900 | |
2676 | 901 if ((error = get_nvlist(zc, &config)) == 0) { |
789 | 902 error = spa_vdev_add(spa, config); |
903 nvlist_free(config); | |
904 } | |
905 spa_close(spa, FTAG); | |
906 return (error); | |
907 } | |
908 | |
909 static int | |
910 zfs_ioc_vdev_remove(zfs_cmd_t *zc) | |
911 { | |
2082 | 912 spa_t *spa; |
913 int error; | |
914 | |
915 error = spa_open(zc->zc_name, &spa, FTAG); | |
916 if (error != 0) | |
917 return (error); | |
918 error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); | |
919 spa_close(spa, FTAG); | |
920 return (error); | |
789 | 921 } |
922 | |
923 static int | |
4451 | 924 zfs_ioc_vdev_set_state(zfs_cmd_t *zc) |
789 | 925 { |
926 spa_t *spa; | |
927 int error; | |
4451 | 928 vdev_state_t newstate = VDEV_STATE_UNKNOWN; |
789 | 929 |
2926 | 930 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
789 | 931 return (error); |
4451 | 932 switch (zc->zc_cookie) { |
933 case VDEV_STATE_ONLINE: | |
934 error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); | |
935 break; | |
936 | |
937 case VDEV_STATE_OFFLINE: | |
938 error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); | |
939 break; | |
789 | 940 |
4451 | 941 case VDEV_STATE_FAULTED: |
942 error = vdev_fault(spa, zc->zc_guid); | |
943 break; | |
789 | 944 |
4451 | 945 case VDEV_STATE_DEGRADED: |
946 error = vdev_degrade(spa, zc->zc_guid); | |
947 break; | |
948 | |
949 default: | |
950 error = EINVAL; | |
951 } | |
952 zc->zc_cookie = newstate; | |
789 | 953 spa_close(spa, FTAG); |
954 return (error); | |
955 } | |
956 | |
957 static int | |
958 zfs_ioc_vdev_attach(zfs_cmd_t *zc) | |
959 { | |
960 spa_t *spa; | |
961 int replacing = zc->zc_cookie; | |
962 nvlist_t *config; | |
963 int error; | |
964 | |
2926 | 965 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
789 | 966 return (error); |
967 | |
2676 | 968 if ((error = get_nvlist(zc, &config)) == 0) { |
1544 | 969 error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); |
789 | 970 nvlist_free(config); |
971 } | |
972 | |
973 spa_close(spa, FTAG); | |
974 return (error); | |
975 } | |
976 | |
977 static int | |
978 zfs_ioc_vdev_detach(zfs_cmd_t *zc) | |
979 { | |
980 spa_t *spa; | |
981 int error; | |
982 | |
2926 | 983 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
789 | 984 return (error); |
985 | |
1544 | 986 error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE); |
789 | 987 |
988 spa_close(spa, FTAG); | |
989 return (error); | |
990 } | |
991 | |
992 static int | |
1354
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
993 zfs_ioc_vdev_setpath(zfs_cmd_t *zc) |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
994 { |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
995 spa_t *spa; |
2676 | 996 char *path = zc->zc_value; |
1544 | 997 uint64_t guid = zc->zc_guid; |
1354
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
998 int error; |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
999 |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1000 error = spa_open(zc->zc_name, &spa, FTAG); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1001 if (error != 0) |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1002 return (error); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1003 |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1004 error = spa_vdev_setpath(spa, guid, path); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1005 spa_close(spa, FTAG); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1006 return (error); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1007 } |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1008 |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1009 static int |
789 | 1010 zfs_ioc_objset_stats(zfs_cmd_t *zc) |
1011 { | |
1012 objset_t *os = NULL; | |
1013 int error; | |
1356
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
1014 nvlist_t *nv; |
789 | 1015 |
1016 retry: | |
1017 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, | |
1018 DS_MODE_STANDARD | DS_MODE_READONLY, &os); | |
1019 if (error != 0) { | |
1020 /* | |
1021 * This is ugly: dmu_objset_open() can return EBUSY if | |
1022 * the objset is held exclusively. Fortunately this hold is | |
1023 * only for a short while, so we retry here. | |
1024 * This avoids user code having to handle EBUSY, | |
1025 * for example for a "zfs list". | |
1026 */ | |
1027 if (error == EBUSY) { | |
1028 delay(1); | |
1029 goto retry; | |
1030 } | |
1031 return (error); | |
1032 } | |
1033 | |
2885 | 1034 dmu_objset_fast_stat(os, &zc->zc_objset_stats); |
789 | 1035 |
2856 | 1036 if (zc->zc_nvlist_dst != 0 && |
1356
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
1037 (error = dsl_prop_get_all(os, &nv)) == 0) { |
2885 | 1038 dmu_objset_stats(os, nv); |
3087 | 1039 /* |
4577 | 1040 * NB: {zpl,zvol}_get_stats() will read the objset contents, |
3087 | 1041 * which we aren't supposed to do with a |
1042 * DS_MODE_STANDARD open, because it could be | |
1043 * inconsistent. So this is a bit of a workaround... | |
1044 */ | |
4577 | 1045 if (!zc->zc_objset_stats.dds_inconsistent) { |
1046 if (dmu_objset_type(os) == DMU_OST_ZVOL) | |
1047 VERIFY(zvol_get_stats(os, nv) == 0); | |
1048 else if (dmu_objset_type(os) == DMU_OST_ZFS) | |
1049 (void) zfs_get_stats(os, nv); | |
1050 } | |
2676 | 1051 error = put_nvlist(zc, nv); |
1356
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
1052 nvlist_free(nv); |
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
1053 } |
789 | 1054 |
2676 | 1055 spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value)); |
1544 | 1056 |
789 | 1057 dmu_objset_close(os); |
1058 return (error); | |
1059 } | |
1060 | |
1061 static int | |
1062 zfs_ioc_dataset_list_next(zfs_cmd_t *zc) | |
1063 { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1064 objset_t *os; |
789 | 1065 int error; |
1066 char *p; | |
1067 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1068 retry: |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1069 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
|
1070 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
|
1071 if (error != 0) { |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1072 /* |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1073 * 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
|
1074 * 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
|
1075 * 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
|
1076 * 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
|
1077 * for example for a "zfs list". |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1078 */ |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1079 if (error == EBUSY) { |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1080 delay(1); |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1081 goto retry; |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1082 } |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1083 if (error == ENOENT) |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1084 error = ESRCH; |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1085 return (error); |
789 | 1086 } |
1087 | |
1088 p = strrchr(zc->zc_name, '/'); | |
1089 if (p == NULL || p[1] != '\0') | |
1090 (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); | |
1091 p = zc->zc_name + strlen(zc->zc_name); | |
1092 | |
1093 do { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1094 error = dmu_dir_list_next(os, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1095 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
|
1096 NULL, &zc->zc_cookie); |
789 | 1097 if (error == ENOENT) |
1098 error = ESRCH; | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1099 } while (error == 0 && !INGLOBALZONE(curproc) && |
789 | 1100 !zone_dataset_visible(zc->zc_name, NULL)); |
1101 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1102 /* |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1103 * 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
|
1104 * 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
|
1105 */ |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1106 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
|
1107 error = zfs_ioc_objset_stats(zc); /* fill in the stats */ |
789 | 1108 |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1109 dmu_objset_close(os); |
789 | 1110 return (error); |
1111 } | |
1112 | |
1113 static int | |
1114 zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) | |
1115 { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1116 objset_t *os; |
789 | 1117 int error; |
1118 | |
1119 retry: | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1120 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
|
1121 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
|
1122 if (error != 0) { |
789 | 1123 /* |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1124 * This is ugly: dmu_objset_open() can return EBUSY if |
789 | 1125 * the objset is held exclusively. Fortunately this hold is |
1126 * only for a short while, so we retry here. | |
1127 * 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
|
1128 * for example for a "zfs list". |
789 | 1129 */ |
1130 if (error == EBUSY) { | |
1131 delay(1); | |
1132 goto retry; | |
1133 } | |
1134 if (error == ENOENT) | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1135 error = ESRCH; |
789 | 1136 return (error); |
1137 } | |
1138 | |
1003 | 1139 /* |
1140 * A dataset name of maximum length cannot have any snapshots, | |
1141 * so exit immediately. | |
1142 */ | |
1143 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
|
1144 dmu_objset_close(os); |
1003 | 1145 return (ESRCH); |
789 | 1146 } |
1147 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1148 error = dmu_snapshot_list_next(os, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1149 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
|
1150 zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie); |
789 | 1151 if (error == ENOENT) |
1152 error = ESRCH; | |
1153 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1154 if (error == 0) |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1155 error = zfs_ioc_objset_stats(zc); /* fill in the stats */ |
789 | 1156 |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1157 dmu_objset_close(os); |
789 | 1158 return (error); |
1159 } | |
1160 | |
1161 static int | |
2676 | 1162 zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl) |
789 | 1163 { |
2676 | 1164 nvpair_t *elem; |
1165 int error; | |
1166 uint64_t intval; | |
1167 char *strval; | |
1168 | |
4543 | 1169 /* |
1170 * First validate permission to set all of the properties | |
1171 */ | |
2676 | 1172 elem = NULL; |
1173 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1174 const char *propname = nvpair_name(elem); |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1175 zfs_prop_t prop = zfs_name_to_prop(propname); |
2676 | 1176 |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1177 if (prop == ZFS_PROP_INVAL) { |
2676 | 1178 /* |
1179 * If this is a user-defined property, it must be a | |
1180 * string, and there is no further validation to do. | |
1181 */ | |
1182 if (!zfs_prop_user(propname) || | |
1183 nvpair_type(elem) != DATA_TYPE_STRING) | |
1184 return (EINVAL); | |
1185 | |
4543 | 1186 error = zfs_secpolicy_write_perms(name, |
1187 ZFS_DELEG_PERM_USERPROP, cr); | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1188 if (error) |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1189 return (error); |
4543 | 1190 continue; |
2676 | 1191 } |
1192 | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1193 if ((error = zfs_secpolicy_setprop(name, prop, cr)) != 0) |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1194 return (error); |
2676 | 1195 |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1196 /* |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1197 * Check that this value is valid for this pool version |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1198 */ |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1199 switch (prop) { |
3886
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1200 case ZFS_PROP_COMPRESSION: |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1201 /* |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1202 * If the user specified gzip compression, make sure |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1203 * the SPA supports it. We ignore any errors here since |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1204 * we'll catch them later. |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1205 */ |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1206 if (nvpair_type(elem) == DATA_TYPE_UINT64 && |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1207 nvpair_value_uint64(elem, &intval) == 0 && |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1208 intval >= ZIO_COMPRESS_GZIP_1 && |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1209 intval <= ZIO_COMPRESS_GZIP_9) { |
4543 | 1210 spa_t *spa; |
1211 | |
4603
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1212 if (spa_open(name, &spa, FTAG) == 0) { |
3886
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1213 if (spa_version(spa) < |
4577 | 1214 SPA_VERSION_GZIP_COMPRESSION) { |
3886
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1215 spa_close(spa, FTAG); |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1216 return (ENOTSUP); |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1217 } |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1218 |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1219 spa_close(spa, FTAG); |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1220 } |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1221 } |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1222 break; |
4603
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1223 |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1224 case ZFS_PROP_COPIES: |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1225 { |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1226 spa_t *spa; |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1227 |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1228 if (spa_open(name, &spa, FTAG) == 0) { |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1229 if (spa_version(spa) < |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1230 SPA_VERSION_DITTO_BLOCKS) { |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1231 spa_close(spa, FTAG); |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1232 return (ENOTSUP); |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1233 } |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1234 spa_close(spa, FTAG); |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1235 } |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1236 break; |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1237 } |
2676 | 1238 } |
4543 | 1239 } |
1240 | |
1241 elem = NULL; | |
1242 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1243 const char *propname = nvpair_name(elem); |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1244 zfs_prop_t prop = zfs_name_to_prop(propname); |
4543 | 1245 |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1246 if (prop == ZFS_PROP_INVAL) { |
4543 | 1247 VERIFY(nvpair_value_string(elem, &strval) == 0); |
1248 error = dsl_prop_set(name, propname, 1, | |
1249 strlen(strval) + 1, strval); | |
1250 if (error == 0) | |
1251 continue; | |
1252 else | |
1253 return (error); | |
1254 } | |
2676 | 1255 |
1256 switch (prop) { | |
1257 case ZFS_PROP_QUOTA: | |
1258 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
4577 | 1259 (error = dsl_dir_set_quota(name, intval)) != 0) |
2676 | 1260 return (error); |
1261 break; | |
1262 | |
1263 case ZFS_PROP_RESERVATION: | |
1264 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
1265 (error = dsl_dir_set_reservation(name, | |
1266 intval)) != 0) | |
1267 return (error); | |
1268 break; | |
789 | 1269 |
2676 | 1270 case ZFS_PROP_VOLSIZE: |
1271 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
4577 | 1272 (error = zvol_set_volsize(name, dev, intval)) != 0) |
2676 | 1273 return (error); |
1274 break; | |
1275 | |
1276 case ZFS_PROP_VOLBLOCKSIZE: | |
1277 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
4577 | 1278 (error = zvol_set_volblocksize(name, intval)) != 0) |
1279 return (error); | |
1280 break; | |
1281 | |
1282 case ZFS_PROP_VERSION: | |
1283 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
1284 (error = zfs_set_version(name, intval)) != 0) | |
2676 | 1285 return (error); |
1286 break; | |
1287 | |
1288 default: | |
1289 if (nvpair_type(elem) == DATA_TYPE_STRING) { | |
1290 if (zfs_prop_get_type(prop) != | |
1291 prop_type_string) | |
1292 return (EINVAL); | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1293 VERIFY(nvpair_value_string(elem, &strval) == 0); |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1294 if ((error = dsl_prop_set(name, |
2676 | 1295 nvpair_name(elem), 1, strlen(strval) + 1, |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1296 strval)) != 0) |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1297 return (error); |
2676 | 1298 } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { |
2885 | 1299 const char *unused; |
1300 | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1301 VERIFY(nvpair_value_uint64(elem, &intval) == 0); |
2676 | 1302 |
1303 switch (zfs_prop_get_type(prop)) { | |
1304 case prop_type_number: | |
1305 break; | |
1306 case prop_type_boolean: | |
1307 if (intval > 1) | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1308 return (EINVAL); |
2676 | 1309 break; |
1310 case prop_type_string: | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1311 return (EINVAL); |
2676 | 1312 case prop_type_index: |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1313 if (zfs_prop_index_to_string(prop, |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1314 intval, &unused) != 0) |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1315 return (EINVAL); |
2676 | 1316 break; |
1317 default: | |
4577 | 1318 cmn_err(CE_PANIC, |
1319 "unknown property type"); | |
2676 | 1320 break; |
1321 } | |
1322 | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1323 if ((error = dsl_prop_set(name, propname, |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1324 8, 1, &intval)) != 0) |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1325 return (error); |
2676 | 1326 } else { |
1327 return (EINVAL); | |
1328 } | |
1329 break; | |
1330 } | |
1331 } | |
1332 | |
1333 return (0); | |
789 | 1334 } |
1335 | |
1336 static int | |
2676 | 1337 zfs_ioc_set_prop(zfs_cmd_t *zc) |
789 | 1338 { |
2676 | 1339 nvlist_t *nvl; |
1340 int error; | |
789 | 1341 |
2676 | 1342 /* |
1343 * If zc_value is set, then this is an attempt to inherit a value. | |
1344 * Otherwise, zc_nvlist refers to a list of properties to set. | |
1345 */ | |
1346 if (zc->zc_value[0] != '\0') { | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1347 zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1348 |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1349 if (prop == ZFS_PROP_INVAL) { |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1350 if (!zfs_prop_user(zc->zc_value)) |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1351 return (EINVAL); |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1352 error = zfs_secpolicy_write_perms(zc->zc_name, |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1353 ZFS_DELEG_PERM_USERPROP, |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1354 (cred_t *)(uintptr_t)zc->zc_cred); |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1355 } else { |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1356 if (!zfs_prop_inheritable(prop)) |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1357 return (EINVAL); |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1358 error = zfs_secpolicy_setprop(zc->zc_name, |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1359 prop, (cred_t *)(uintptr_t)zc->zc_cred); |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1360 } |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1361 if (error) |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1362 return (error); |
2676 | 1363 |
1364 return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); | |
1365 } | |
1366 | |
1367 if ((error = get_nvlist(zc, &nvl)) != 0) | |
1368 return (error); | |
1369 | |
1370 error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev, | |
1371 (cred_t *)(uintptr_t)zc->zc_cred, nvl); | |
4543 | 1372 |
2676 | 1373 nvlist_free(nvl); |
1374 return (error); | |
789 | 1375 } |
1376 | |
1377 static int | |
4098
0a182c2128e6
6545726 make ZFS_IOC_POOL_*_PROPS in sync with zfs_ioc_pool_props_*
lling
parents:
4007
diff
changeset
|
1378 zfs_ioc_pool_set_props(zfs_cmd_t *zc) |
3912 | 1379 { |
1380 nvlist_t *nvl; | |
1381 int error, reset_bootfs = 0; | |
1382 uint64_t objnum; | |
4543 | 1383 uint64_t intval; |
3912 | 1384 zpool_prop_t prop; |
1385 nvpair_t *elem; | |
1386 char *propname, *strval; | |
1387 spa_t *spa; | |
1388 vdev_t *rvdev; | |
1389 char *vdev_type; | |
1390 objset_t *os; | |
1391 | |
1392 if ((error = get_nvlist(zc, &nvl)) != 0) | |
1393 return (error); | |
1394 | |
1395 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { | |
1396 nvlist_free(nvl); | |
1397 return (error); | |
1398 } | |
1399 | |
4577 | 1400 if (spa_version(spa) < SPA_VERSION_BOOTFS) { |
3912 | 1401 nvlist_free(nvl); |
1402 spa_close(spa, FTAG); | |
1403 return (ENOTSUP); | |
1404 } | |
1405 | |
1406 elem = NULL; | |
1407 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { | |
1408 | |
1409 propname = nvpair_name(elem); | |
1410 | |
1411 if ((prop = zpool_name_to_prop(propname)) == | |
1412 ZFS_PROP_INVAL) { | |
1413 nvlist_free(nvl); | |
1414 spa_close(spa, FTAG); | |
1415 return (EINVAL); | |
1416 } | |
1417 | |
1418 switch (prop) { | |
4543 | 1419 case ZPOOL_PROP_DELEGATION: |
1420 VERIFY(nvpair_value_uint64(elem, &intval) == 0); | |
1421 if (intval > 1) | |
1422 error = EINVAL; | |
1423 break; | |
4451 | 1424 case ZPOOL_PROP_BOOTFS: |
3912 | 1425 /* |
1426 * A bootable filesystem can not be on a RAIDZ pool | |
1427 * nor a striped pool with more than 1 device. | |
1428 */ | |
1429 rvdev = spa->spa_root_vdev; | |
1430 vdev_type = | |
1431 rvdev->vdev_child[0]->vdev_ops->vdev_op_type; | |
1432 if (strcmp(vdev_type, VDEV_TYPE_RAIDZ) == 0 || | |
1433 (strcmp(vdev_type, VDEV_TYPE_MIRROR) != 0 && | |
1434 rvdev->vdev_children > 1)) { | |
1435 error = ENOTSUP; | |
1436 break; | |
1437 } | |
1438 | |
1439 reset_bootfs = 1; | |
1440 | |
1441 VERIFY(nvpair_value_string(elem, &strval) == 0); | |
1442 if (strval == NULL || strval[0] == '\0') { | |
4451 | 1443 objnum = zpool_prop_default_numeric( |
1444 ZPOOL_PROP_BOOTFS); | |
3912 | 1445 break; |
1446 } | |
1447 | |
1448 if (error = dmu_objset_open(strval, DMU_OST_ZFS, | |
1449 DS_MODE_STANDARD | DS_MODE_READONLY, &os)) | |
1450 break; | |
1451 objnum = dmu_objset_id(os); | |
1452 dmu_objset_close(os); | |
1453 break; | |
1454 } | |
1455 | |
1456 if (error) | |
1457 break; | |
1458 } | |
1459 if (error == 0) { | |
1460 if (reset_bootfs) { | |
1461 VERIFY(nvlist_remove(nvl, | |
4451 | 1462 zpool_prop_to_name(ZPOOL_PROP_BOOTFS), |
3912 | 1463 DATA_TYPE_STRING) == 0); |
1464 VERIFY(nvlist_add_uint64(nvl, | |
4451 | 1465 zpool_prop_to_name(ZPOOL_PROP_BOOTFS), |
1466 objnum) == 0); | |
3912 | 1467 } |
1468 error = spa_set_props(spa, nvl); | |
1469 } | |
1470 | |
1471 nvlist_free(nvl); | |
1472 spa_close(spa, FTAG); | |
1473 | |
1474 return (error); | |
1475 } | |
1476 | |
1477 static int | |
4098
0a182c2128e6
6545726 make ZFS_IOC_POOL_*_PROPS in sync with zfs_ioc_pool_props_*
lling
parents:
4007
diff
changeset
|
1478 zfs_ioc_pool_get_props(zfs_cmd_t *zc) |
3912 | 1479 { |
1480 spa_t *spa; | |
1481 int error; | |
1482 nvlist_t *nvp = NULL; | |
1483 | |
1484 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
1485 return (error); | |
1486 | |
1487 error = spa_get_props(spa, &nvp); | |
1488 | |
1489 if (error == 0 && zc->zc_nvlist_dst != NULL) | |
1490 error = put_nvlist(zc, nvp); | |
1491 else | |
1492 error = EFAULT; | |
1493 | |
1494 spa_close(spa, FTAG); | |
1495 | |
1496 if (nvp) | |
1497 nvlist_free(nvp); | |
1498 return (error); | |
1499 } | |
1500 | |
1501 static int | |
4543 | 1502 zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) |
1503 { | |
1504 nvlist_t *nvp; | |
1505 int error; | |
1506 uint32_t uid; | |
1507 uint32_t gid; | |
1508 uint32_t *groups; | |
1509 uint_t group_cnt; | |
1510 cred_t *usercred; | |
1511 | |
1512 if ((error = get_nvlist(zc, &nvp)) != 0) { | |
1513 return (error); | |
1514 } | |
1515 | |
1516 if ((error = nvlist_lookup_uint32(nvp, | |
1517 ZFS_DELEG_PERM_UID, &uid)) != 0) { | |
1518 nvlist_free(nvp); | |
1519 return (EPERM); | |
1520 } | |
1521 | |
1522 if ((error = nvlist_lookup_uint32(nvp, | |
1523 ZFS_DELEG_PERM_GID, &gid)) != 0) { | |
1524 nvlist_free(nvp); | |
1525 return (EPERM); | |
1526 } | |
1527 | |
1528 if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, | |
1529 &groups, &group_cnt)) != 0) { | |
1530 nvlist_free(nvp); | |
1531 return (EPERM); | |
1532 } | |
1533 usercred = cralloc(); | |
1534 if ((crsetugid(usercred, uid, gid) != 0) || | |
1535 (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { | |
1536 nvlist_free(nvp); | |
1537 crfree(usercred); | |
1538 return (EPERM); | |
1539 } | |
1540 nvlist_free(nvp); | |
1541 error = dsl_deleg_access(zc->zc_name, | |
1542 ZFS_DELEG_PERM_SHAREISCSI, usercred); | |
1543 crfree(usercred); | |
1544 return (error); | |
1545 } | |
1546 | |
1547 static int | |
1548 zfs_ioc_set_fsacl(zfs_cmd_t *zc) | |
1549 { | |
1550 int error; | |
1551 nvlist_t *fsaclnv = NULL; | |
1552 cred_t *cr; | |
1553 | |
1554 if ((error = get_nvlist(zc, &fsaclnv)) != 0) | |
1555 return (error); | |
1556 | |
1557 /* | |
1558 * Verify nvlist is constructed correctly | |
1559 */ | |
1560 if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { | |
1561 nvlist_free(fsaclnv); | |
1562 return (EINVAL); | |
1563 } | |
1564 | |
1565 /* | |
1566 * If we don't have PRIV_SYS_MOUNT, then validate | |
1567 * that user is allowed to hand out each permission in | |
1568 * the nvlist(s) | |
1569 */ | |
1570 | |
1571 cr = (cred_t *)(uintptr_t)zc->zc_cred; | |
1572 error = secpolicy_zfs(cr); | |
1573 if (error) { | |
1574 if (zc->zc_perm_action == B_FALSE) | |
1575 error = dsl_deleg_can_allow(zc->zc_name, fsaclnv, cr); | |
1576 else | |
1577 error = dsl_deleg_can_unallow(zc->zc_name, fsaclnv, cr); | |
1578 } | |
1579 | |
1580 if (error == 0) | |
1581 error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); | |
1582 | |
1583 nvlist_free(fsaclnv); | |
1584 return (error); | |
1585 } | |
1586 | |
1587 static int | |
1588 zfs_ioc_get_fsacl(zfs_cmd_t *zc) | |
1589 { | |
1590 nvlist_t *nvp; | |
1591 int error; | |
1592 | |
1593 if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { | |
1594 error = put_nvlist(zc, nvp); | |
1595 nvlist_free(nvp); | |
1596 } | |
1597 | |
1598 return (error); | |
1599 } | |
1600 | |
1601 static int | |
789 | 1602 zfs_ioc_create_minor(zfs_cmd_t *zc) |
1603 { | |
2676 | 1604 return (zvol_create_minor(zc->zc_name, zc->zc_dev)); |
789 | 1605 } |
1606 | |
1607 static int | |
1608 zfs_ioc_remove_minor(zfs_cmd_t *zc) | |
1609 { | |
2676 | 1610 return (zvol_remove_minor(zc->zc_name)); |
789 | 1611 } |
1612 | |
1613 /* | |
1614 * Search the vfs list for a specified resource. Returns a pointer to it | |
1615 * or NULL if no suitable entry is found. The caller of this routine | |
1616 * is responsible for releasing the returned vfs pointer. | |
1617 */ | |
1618 static vfs_t * | |
1619 zfs_get_vfs(const char *resource) | |
1620 { | |
1621 struct vfs *vfsp; | |
1622 struct vfs *vfs_found = NULL; | |
1623 | |
1624 vfs_list_read_lock(); | |
1625 vfsp = rootvfs; | |
1626 do { | |
1627 if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { | |
1628 VFS_HOLD(vfsp); | |
1629 vfs_found = vfsp; | |
1630 break; | |
1631 } | |
1632 vfsp = vfsp->vfs_next; | |
1633 } while (vfsp != rootvfs); | |
1634 vfs_list_unlock(); | |
1635 return (vfs_found); | |
1636 } | |
1637 | |
4543 | 1638 /* ARGSUSED */ |
789 | 1639 static void |
4543 | 1640 zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) |
789 | 1641 { |
4577 | 1642 nvlist_t *nvprops = arg; |
1643 uint64_t version = ZPL_VERSION; | |
1644 | |
1645 (void) nvlist_lookup_uint64(nvprops, | |
1646 zfs_prop_to_name(ZFS_PROP_VERSION), &version); | |
1647 | |
1648 zfs_create_fs(os, cr, version, tx); | |
789 | 1649 } |
1650 | |
1651 static int | |
1652 zfs_ioc_create(zfs_cmd_t *zc) | |
1653 { | |
1654 objset_t *clone; | |
1655 int error = 0; | |
4543 | 1656 nvlist_t *nvprops = NULL; |
1657 void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); | |
789 | 1658 dmu_objset_type_t type = zc->zc_objset_type; |
1659 | |
1660 switch (type) { | |
1661 | |
1662 case DMU_OST_ZFS: | |
1663 cbfunc = zfs_create_cb; | |
1664 break; | |
1665 | |
1666 case DMU_OST_ZVOL: | |
1667 cbfunc = zvol_create_cb; | |
1668 break; | |
1669 | |
1670 default: | |
2199 | 1671 cbfunc = NULL; |
1672 } | |
1673 if (strchr(zc->zc_name, '@')) | |
789 | 1674 return (EINVAL); |
1675 | |
2676 | 1676 if (zc->zc_nvlist_src != NULL && |
4543 | 1677 (error = get_nvlist(zc, &nvprops)) != 0) |
2676 | 1678 return (error); |
1679 | |
1680 if (zc->zc_value[0] != '\0') { | |
789 | 1681 /* |
1682 * We're creating a clone of an existing snapshot. | |
1683 */ | |
2676 | 1684 zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; |
1685 if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { | |
4543 | 1686 nvlist_free(nvprops); |
789 | 1687 return (EINVAL); |
2676 | 1688 } |
789 | 1689 |
2676 | 1690 error = dmu_objset_open(zc->zc_value, type, |
789 | 1691 DS_MODE_STANDARD | DS_MODE_READONLY, &clone); |
2676 | 1692 if (error) { |
4543 | 1693 nvlist_free(nvprops); |
789 | 1694 return (error); |
2676 | 1695 } |
789 | 1696 error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL); |
1697 dmu_objset_close(clone); | |
1698 } else { | |
2676 | 1699 if (cbfunc == NULL) { |
4543 | 1700 nvlist_free(nvprops); |
2199 | 1701 return (EINVAL); |
2676 | 1702 } |
1703 | |
789 | 1704 if (type == DMU_OST_ZVOL) { |
2676 | 1705 uint64_t volsize, volblocksize; |
1706 | |
4543 | 1707 if (nvprops == NULL || |
1708 nvlist_lookup_uint64(nvprops, | |
2676 | 1709 zfs_prop_to_name(ZFS_PROP_VOLSIZE), |
1710 &volsize) != 0) { | |
4543 | 1711 nvlist_free(nvprops); |
2676 | 1712 return (EINVAL); |
1713 } | |
1714 | |
4543 | 1715 if ((error = nvlist_lookup_uint64(nvprops, |
2676 | 1716 zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), |
1717 &volblocksize)) != 0 && error != ENOENT) { | |
4543 | 1718 nvlist_free(nvprops); |
2676 | 1719 return (EINVAL); |
1720 } | |
1133
335d069294d1
6357470 vdev_raidz.c has unused RAIDZ_SINGLE define, code
eschrock
parents:
1003
diff
changeset
|
1721 |
2676 | 1722 if (error != 0) |
1723 volblocksize = zfs_prop_default_numeric( | |
1724 ZFS_PROP_VOLBLOCKSIZE); | |
1725 | |
1726 if ((error = zvol_check_volblocksize( | |
1727 volblocksize)) != 0 || | |
1728 (error = zvol_check_volsize(volsize, | |
1729 volblocksize)) != 0) { | |
4543 | 1730 nvlist_free(nvprops); |
789 | 1731 return (error); |
2676 | 1732 } |
4577 | 1733 } else if (type == DMU_OST_ZFS) { |
1734 uint64_t version; | |
1735 | |
1736 if (0 == nvlist_lookup_uint64(nvprops, | |
1737 zfs_prop_to_name(ZFS_PROP_VERSION), &version) && | |
1738 (version < ZPL_VERSION_INITIAL || | |
1739 version > ZPL_VERSION)) { | |
1740 nvlist_free(nvprops); | |
1741 return (EINVAL); | |
1742 } | |
2676 | 1743 } |
1133
335d069294d1
6357470 vdev_raidz.c has unused RAIDZ_SINGLE define, code
eschrock
parents:
1003
diff
changeset
|
1744 |
2676 | 1745 error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, |
4543 | 1746 nvprops); |
789 | 1747 } |
2676 | 1748 |
1749 /* | |
1750 * It would be nice to do this atomically. | |
1751 */ | |
1752 if (error == 0) { | |
1753 if ((error = zfs_set_prop_nvlist(zc->zc_name, | |
1754 zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred, | |
4543 | 1755 nvprops)) != 0) |
2676 | 1756 (void) dmu_objset_destroy(zc->zc_name); |
1757 } | |
1758 | |
4543 | 1759 nvlist_free(nvprops); |
789 | 1760 return (error); |
1761 } | |
1762 | |
1763 static int | |
2199 | 1764 zfs_ioc_snapshot(zfs_cmd_t *zc) |
1765 { | |
2676 | 1766 if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) |
2199 | 1767 return (EINVAL); |
1768 return (dmu_objset_snapshot(zc->zc_name, | |
2676 | 1769 zc->zc_value, zc->zc_cookie)); |
2199 | 1770 } |
1771 | |
4007 | 1772 int |
2199 | 1773 zfs_unmount_snap(char *name, void *arg) |
789 | 1774 { |
2199 | 1775 char *snapname = arg; |
1776 char *cp; | |
2417 | 1777 vfs_t *vfsp = NULL; |
2199 | 1778 |
1779 /* | |
1780 * Snapshots (which are under .zfs control) must be unmounted | |
1781 * before they can be destroyed. | |
1782 */ | |
1783 | |
1784 if (snapname) { | |
1785 (void) strcat(name, "@"); | |
1786 (void) strcat(name, snapname); | |
1787 vfsp = zfs_get_vfs(name); | |
1788 cp = strchr(name, '@'); | |
1789 *cp = '\0'; | |
2417 | 1790 } else if (strchr(name, '@')) { |
2199 | 1791 vfsp = zfs_get_vfs(name); |
1792 } | |
1793 | |
1794 if (vfsp) { | |
1795 /* | |
1796 * Always force the unmount for snapshots. | |
1797 */ | |
1798 int flag = MS_FORCE; | |
789 | 1799 int err; |
1800 | |
2199 | 1801 if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { |
1802 VFS_RELE(vfsp); | |
1803 return (err); | |
1804 } | |
1805 VFS_RELE(vfsp); | |
1806 if ((err = dounmount(vfsp, flag, kcred)) != 0) | |
1807 return (err); | |
1808 } | |
1809 return (0); | |
1810 } | |
1811 | |
1812 static int | |
1813 zfs_ioc_destroy_snaps(zfs_cmd_t *zc) | |
1814 { | |
1815 int err; | |
789 | 1816 |
2676 | 1817 if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) |
2199 | 1818 return (EINVAL); |
1819 err = dmu_objset_find(zc->zc_name, | |
2676 | 1820 zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); |
2199 | 1821 if (err) |
1822 return (err); | |
2676 | 1823 return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); |
2199 | 1824 } |
1825 | |
1826 static int | |
1827 zfs_ioc_destroy(zfs_cmd_t *zc) | |
1828 { | |
1829 if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { | |
1830 int err = zfs_unmount_snap(zc->zc_name, NULL); | |
1831 if (err) | |
1832 return (err); | |
789 | 1833 } |
1834 | |
1835 return (dmu_objset_destroy(zc->zc_name)); | |
1836 } | |
1837 | |
1838 static int | |
1839 zfs_ioc_rollback(zfs_cmd_t *zc) | |
1840 { | |
1841 return (dmu_objset_rollback(zc->zc_name)); | |
1842 } | |
1843 | |
1844 static int | |
1845 zfs_ioc_rename(zfs_cmd_t *zc) | |
1846 { | |
4490 | 1847 boolean_t recursive = zc->zc_cookie & 1; |
4007 | 1848 |
2676 | 1849 zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; |
1850 if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) | |
789 | 1851 return (EINVAL); |
1852 | |
4007 | 1853 /* |
1854 * Unmount snapshot unless we're doing a recursive rename, | |
1855 * in which case the dataset code figures out which snapshots | |
1856 * to unmount. | |
1857 */ | |
1858 if (!recursive && strchr(zc->zc_name, '@') != NULL && | |
789 | 1859 zc->zc_objset_type == DMU_OST_ZFS) { |
2199 | 1860 int err = zfs_unmount_snap(zc->zc_name, NULL); |
1861 if (err) | |
1862 return (err); | |
789 | 1863 } |
1864 | |
4007 | 1865 return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); |
789 | 1866 } |
1867 | |
1868 static int | |
1869 zfs_ioc_recvbackup(zfs_cmd_t *zc) | |
1870 { | |
1871 file_t *fp; | |
1872 int error, fd; | |
2885 | 1873 offset_t new_off; |
789 | 1874 |
3265
967e0fca6143
6463140 zfs recv with a snapshot name that has 2 @@ in a row succeeds
ahrens
parents:
3087
diff
changeset
|
1875 if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || |
967e0fca6143
6463140 zfs recv with a snapshot name that has 2 @@ in a row succeeds
ahrens
parents:
3087
diff
changeset
|
1876 strchr(zc->zc_value, '@') == NULL) |
967e0fca6143
6463140 zfs recv with a snapshot name that has 2 @@ in a row succeeds
ahrens
parents:
3087
diff
changeset
|
1877 return (EINVAL); |
967e0fca6143
6463140 zfs recv with a snapshot name that has 2 @@ in a row succeeds
ahrens
parents:
3087
diff
changeset
|
1878 |
789 | 1879 fd = zc->zc_cookie; |
1880 fp = getf(fd); | |
1881 if (fp == NULL) | |
1882 return (EBADF); | |
2676 | 1883 error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record, |
1884 &zc->zc_cookie, (boolean_t)zc->zc_guid, fp->f_vnode, | |
2665 | 1885 fp->f_offset); |
2885 | 1886 |
1887 new_off = fp->f_offset + zc->zc_cookie; | |
1888 if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off) == 0) | |
1889 fp->f_offset = new_off; | |
1890 | |
789 | 1891 releasef(fd); |
1892 return (error); | |
1893 } | |
1894 | |
1895 static int | |
1896 zfs_ioc_sendbackup(zfs_cmd_t *zc) | |
1897 { | |
1898 objset_t *fromsnap = NULL; | |
1899 objset_t *tosnap; | |
1900 file_t *fp; | |
1901 int error; | |
1902 | |
1903 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, | |
1904 DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap); | |
1905 if (error) | |
1906 return (error); | |
1907 | |
2676 | 1908 if (zc->zc_value[0] != '\0') { |
2885 | 1909 char buf[MAXPATHLEN]; |
1910 char *cp; | |
1911 | |
1912 (void) strncpy(buf, zc->zc_name, sizeof (buf)); | |
1913 cp = strchr(buf, '@'); | |
1914 if (cp) | |
1915 *(cp+1) = 0; | |
1916 (void) strncat(buf, zc->zc_value, sizeof (buf)); | |
1917 error = dmu_objset_open(buf, DMU_OST_ANY, | |
789 | 1918 DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap); |
1919 if (error) { | |
1920 dmu_objset_close(tosnap); | |
1921 return (error); | |
1922 } | |
1923 } | |
1924 | |
1925 fp = getf(zc->zc_cookie); | |
1926 if (fp == NULL) { | |
1927 dmu_objset_close(tosnap); | |
1928 if (fromsnap) | |
1929 dmu_objset_close(fromsnap); | |
1930 return (EBADF); | |
1931 } | |
1932 | |
1933 error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode); | |
1934 | |
1935 releasef(zc->zc_cookie); | |
1936 if (fromsnap) | |
1937 dmu_objset_close(fromsnap); | |
1938 dmu_objset_close(tosnap); | |
1939 return (error); | |
1940 } | |
1941 | |
1544 | 1942 static int |
1943 zfs_ioc_inject_fault(zfs_cmd_t *zc) | |
1944 { | |
1945 int id, error; | |
1946 | |
1947 error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, | |
1948 &zc->zc_inject_record); | |
1949 | |
1950 if (error == 0) | |
1951 zc->zc_guid = (uint64_t)id; | |
1952 | |
1953 return (error); | |
1954 } | |
1955 | |
1956 static int | |
1957 zfs_ioc_clear_fault(zfs_cmd_t *zc) | |
1958 { | |
1959 return (zio_clear_fault((int)zc->zc_guid)); | |
1960 } | |
1961 | |
1962 static int | |
1963 zfs_ioc_inject_list_next(zfs_cmd_t *zc) | |
1964 { | |
1965 int id = (int)zc->zc_guid; | |
1966 int error; | |
1967 | |
1968 error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), | |
1969 &zc->zc_inject_record); | |
1970 | |
1971 zc->zc_guid = id; | |
1972 | |
1973 return (error); | |
1974 } | |
1975 | |
1976 static int | |
1977 zfs_ioc_error_log(zfs_cmd_t *zc) | |
1978 { | |
1979 spa_t *spa; | |
1980 int error; | |
2676 | 1981 size_t count = (size_t)zc->zc_nvlist_dst_size; |
1544 | 1982 |
1983 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
1984 return (error); | |
1985 | |
2676 | 1986 error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, |
1544 | 1987 &count); |
1988 if (error == 0) | |
2676 | 1989 zc->zc_nvlist_dst_size = count; |
1544 | 1990 else |
2676 | 1991 zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); |
1544 | 1992 |
1993 spa_close(spa, FTAG); | |
1994 | |
1995 return (error); | |
1996 } | |
1997 | |
1998 static int | |
1999 zfs_ioc_clear(zfs_cmd_t *zc) | |
2000 { | |
2001 spa_t *spa; | |
2002 vdev_t *vd; | |
2003 int error; | |
4451 | 2004 uint64_t txg; |
1544 | 2005 |
2006 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
2007 return (error); | |
2008 | |
4451 | 2009 txg = spa_vdev_enter(spa); |
1544 | 2010 |
2676 | 2011 if (zc->zc_guid == 0) { |
1544 | 2012 vd = NULL; |
2676 | 2013 } else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) { |
4451 | 2014 (void) spa_vdev_exit(spa, NULL, txg, ENODEV); |
1544 | 2015 spa_close(spa, FTAG); |
2016 return (ENODEV); | |
2017 } | |
2018 | |
2019 vdev_clear(spa, vd); | |
2020 | |
4451 | 2021 (void) spa_vdev_exit(spa, NULL, txg, 0); |
1544 | 2022 |
2023 spa_close(spa, FTAG); | |
2024 | |
2025 return (0); | |
2026 } | |
2027 | |
2028 static int | |
2082 | 2029 zfs_ioc_promote(zfs_cmd_t *zc) |
2030 { | |
2417 | 2031 char *cp; |
2032 | |
2033 /* | |
2034 * We don't need to unmount *all* the origin fs's snapshots, but | |
2035 * it's easier. | |
2036 */ | |
2676 | 2037 cp = strchr(zc->zc_value, '@'); |
2417 | 2038 if (cp) |
2039 *cp = '\0'; | |
2676 | 2040 (void) dmu_objset_find(zc->zc_value, |
2417 | 2041 zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); |
2082 | 2042 return (dsl_dataset_promote(zc->zc_name)); |
2043 } | |
2044 | |
4543 | 2045 /* |
2046 * We don't want to have a hard dependency | |
2047 * against some special symbols in sharefs | |
2048 * and nfs. Determine them if needed when | |
2049 * the first file system is shared. | |
2050 * Neither sharefs or nfs are unloadable modules. | |
2051 */ | |
2052 int (*zexport_fs)(void *arg); | |
2053 int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); | |
2054 | |
2055 int zfs_share_inited; | |
2056 ddi_modhandle_t nfs_mod; | |
2057 ddi_modhandle_t sharefs_mod; | |
2058 kmutex_t zfs_share_lock; | |
2059 | |
2060 static int | |
2061 zfs_ioc_share(zfs_cmd_t *zc) | |
2062 { | |
2063 int error; | |
2064 int opcode; | |
2065 | |
2066 if (zfs_share_inited == 0) { | |
2067 mutex_enter(&zfs_share_lock); | |
2068 nfs_mod = ddi_modopen("fs/nfs", KRTLD_MODE_FIRST, &error); | |
2069 sharefs_mod = ddi_modopen("fs/sharefs", | |
2070 KRTLD_MODE_FIRST, &error); | |
2071 if (nfs_mod == NULL || sharefs_mod == NULL) { | |
2072 mutex_exit(&zfs_share_lock); | |
2073 return (ENOSYS); | |
2074 } | |
2075 if (zexport_fs == NULL && ((zexport_fs = (int (*)(void *)) | |
2076 ddi_modsym(nfs_mod, "nfs_export", &error)) == NULL)) { | |
2077 mutex_exit(&zfs_share_lock); | |
2078 return (ENOSYS); | |
2079 } | |
2080 | |
2081 if (zshare_fs == NULL && ((zshare_fs = | |
2082 (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) | |
2083 ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { | |
2084 mutex_exit(&zfs_share_lock); | |
2085 return (ENOSYS); | |
2086 } | |
2087 zfs_share_inited = 1; | |
2088 mutex_exit(&zfs_share_lock); | |
2089 } | |
2090 | |
2091 if (error = zexport_fs((void *)(uintptr_t)zc->zc_share.z_exportdata)) | |
2092 return (error); | |
2093 | |
2094 opcode = (zc->zc_share.z_sharetype == B_TRUE) ? | |
2095 SHAREFS_ADD : SHAREFS_REMOVE; | |
2096 | |
2097 error = zshare_fs(opcode, | |
2098 (void *)(uintptr_t)zc->zc_share.z_sharedata, | |
2099 zc->zc_share.z_sharemax); | |
2100 | |
2101 return (error); | |
2102 | |
2103 } | |
2104 | |
2105 /* | |
2106 * pool destroy and pool export don't log the history as part of zfsdev_ioctl, | |
2107 * but rather zfs_ioc_pool_create, and zfs_ioc_pool_export do the loggin | |
2108 * of those commands. | |
2109 */ | |
789 | 2110 static zfs_ioc_vec_t zfs_ioc_vec[] = { |
4577 | 2111 { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_TRUE }, |
2112 { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE }, | |
2113 { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2114 { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE }, | |
2115 { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE }, | |
2116 { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE }, | |
2117 { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE }, | |
2118 { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2119 { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE }, | |
2120 { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2121 { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE }, | |
2122 { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2123 { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2124 { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2125 { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2126 { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2127 { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE }, | |
2128 { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, | |
4543 | 2129 { zfs_ioc_dataset_list_next, zfs_secpolicy_read, |
4577 | 2130 DATASET_NAME, B_FALSE }, |
4543 | 2131 { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, |
4577 | 2132 DATASET_NAME, B_FALSE }, |
2133 { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE }, | |
2134 { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, | |
2135 { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, | |
2136 { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE }, | |
2137 { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, | |
2138 { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE }, | |
2139 { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE }, | |
2140 { zfs_ioc_recvbackup, zfs_secpolicy_receive, DATASET_NAME, B_TRUE }, | |
2141 { zfs_ioc_sendbackup, zfs_secpolicy_send, DATASET_NAME, B_TRUE }, | |
2142 { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, | |
2143 { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, | |
2144 { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE }, | |
2145 { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE }, | |
2146 { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2147 { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE }, | |
2148 { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, | |
2149 { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE }, | |
2150 { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE }, | |
2151 { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE }, | |
2152 { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2153 { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE }, | |
2154 { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE }, | |
2155 { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, | |
4543 | 2156 { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, |
4577 | 2157 DATASET_NAME, B_FALSE }, |
2158 { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE } | |
789 | 2159 }; |
2160 | |
2161 static int | |
2162 zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) | |
2163 { | |
2164 zfs_cmd_t *zc; | |
2165 uint_t vec; | |
2199 | 2166 int error, rc; |
789 | 2167 |
2168 if (getminor(dev) != 0) | |
2169 return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); | |
2170 | |
2171 vec = cmd - ZFS_IOC; | |
2172 | |
2173 if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) | |
2174 return (EINVAL); | |
2175 | |
2176 zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); | |
2177 | |
2178 error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); | |
2179 | |
2180 if (error == 0) { | |
2181 zc->zc_cred = (uintptr_t)cr; | |
2182 zc->zc_dev = dev; | |
4543 | 2183 error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); |
789 | 2184 } |
2185 | |
2186 /* | |
2187 * Ensure that all pool/dataset names are valid before we pass down to | |
2188 * the lower layers. | |
2189 */ | |
2190 if (error == 0) { | |
2191 zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; | |
2192 switch (zfs_ioc_vec[vec].zvec_namecheck) { | |
4577 | 2193 case POOL_NAME: |
789 | 2194 if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) |
2195 error = EINVAL; | |
2196 break; | |
2197 | |
4577 | 2198 case DATASET_NAME: |
789 | 2199 if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) |
2200 error = EINVAL; | |
2201 break; | |
2856 | 2202 |
4577 | 2203 case NO_NAME: |
2856 | 2204 break; |
789 | 2205 } |
2206 } | |
2207 | |
2208 if (error == 0) | |
2209 error = zfs_ioc_vec[vec].zvec_func(zc); | |
2210 | |
2199 | 2211 rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); |
4543 | 2212 if (error == 0) { |
2199 | 2213 error = rc; |
4543 | 2214 if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE) |
2215 zfs_log_history(zc); | |
2216 } | |
789 | 2217 |
2218 kmem_free(zc, sizeof (zfs_cmd_t)); | |
2219 return (error); | |
2220 } | |
2221 | |
2222 static int | |
2223 zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) | |
2224 { | |
2225 if (cmd != DDI_ATTACH) | |
2226 return (DDI_FAILURE); | |
2227 | |
2228 if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, | |
2229 DDI_PSEUDO, 0) == DDI_FAILURE) | |
2230 return (DDI_FAILURE); | |
2231 | |
2232 zfs_dip = dip; | |
2233 | |
2234 ddi_report_dev(dip); | |
2235 | |
2236 return (DDI_SUCCESS); | |
2237 } | |
2238 | |
2239 static int | |
2240 zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) | |
2241 { | |
2242 if (spa_busy() || zfs_busy() || zvol_busy()) | |
2243 return (DDI_FAILURE); | |
2244 | |
2245 if (cmd != DDI_DETACH) | |
2246 return (DDI_FAILURE); | |
2247 | |
2248 zfs_dip = NULL; | |
2249 | |
2250 ddi_prop_remove_all(dip); | |
2251 ddi_remove_minor_node(dip, NULL); | |
2252 | |
2253 return (DDI_SUCCESS); | |
2254 } | |
2255 | |
2256 /*ARGSUSED*/ | |
2257 static int | |
2258 zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) | |
2259 { | |
2260 switch (infocmd) { | |
2261 case DDI_INFO_DEVT2DEVINFO: | |
2262 *result = zfs_dip; | |
2263 return (DDI_SUCCESS); | |
2264 | |
2265 case DDI_INFO_DEVT2INSTANCE: | |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2266 *result = (void *)0; |
789 | 2267 return (DDI_SUCCESS); |
2268 } | |
2269 | |
2270 return (DDI_FAILURE); | |
2271 } | |
2272 | |
2273 /* | |
2274 * OK, so this is a little weird. | |
2275 * | |
2276 * /dev/zfs is the control node, i.e. minor 0. | |
2277 * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. | |
2278 * | |
2279 * /dev/zfs has basically nothing to do except serve up ioctls, | |
2280 * so most of the standard driver entry points are in zvol.c. | |
2281 */ | |
2282 static struct cb_ops zfs_cb_ops = { | |
2283 zvol_open, /* open */ | |
2284 zvol_close, /* close */ | |
2285 zvol_strategy, /* strategy */ | |
2286 nodev, /* print */ | |
2287 nodev, /* dump */ | |
2288 zvol_read, /* read */ | |
2289 zvol_write, /* write */ | |
2290 zfsdev_ioctl, /* ioctl */ | |
2291 nodev, /* devmap */ | |
2292 nodev, /* mmap */ | |
2293 nodev, /* segmap */ | |
2294 nochpoll, /* poll */ | |
2295 ddi_prop_op, /* prop_op */ | |
2296 NULL, /* streamtab */ | |
2297 D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ | |
2298 CB_REV, /* version */ | |
3638
6b28ebc717aa
6496357 spec_fsync() is useless on devices that do write caching
billm
parents:
3444
diff
changeset
|
2299 nodev, /* async read */ |
6b28ebc717aa
6496357 spec_fsync() is useless on devices that do write caching
billm
parents:
3444
diff
changeset
|
2300 nodev, /* async write */ |
789 | 2301 }; |
2302 | |
2303 static struct dev_ops zfs_dev_ops = { | |
2304 DEVO_REV, /* version */ | |
2305 0, /* refcnt */ | |
2306 zfs_info, /* info */ | |
2307 nulldev, /* identify */ | |
2308 nulldev, /* probe */ | |
2309 zfs_attach, /* attach */ | |
2310 zfs_detach, /* detach */ | |
2311 nodev, /* reset */ | |
2312 &zfs_cb_ops, /* driver operations */ | |
2313 NULL /* no bus operations */ | |
2314 }; | |
2315 | |
2316 static struct modldrv zfs_modldrv = { | |
4577 | 2317 &mod_driverops, "ZFS storage pool version " SPA_VERSION_STRING, |
2676 | 2318 &zfs_dev_ops |
789 | 2319 }; |
2320 | |
2321 static struct modlinkage modlinkage = { | |
2322 MODREV_1, | |
2323 (void *)&zfs_modlfs, | |
2324 (void *)&zfs_modldrv, | |
2325 NULL | |
2326 }; | |
2327 | |
2328 int | |
2329 _init(void) | |
2330 { | |
2331 int error; | |
2332 | |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2333 spa_init(FREAD | FWRITE); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2334 zfs_init(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2335 zvol_init(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2336 |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2337 if ((error = mod_install(&modlinkage)) != 0) { |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2338 zvol_fini(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2339 zfs_fini(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2340 spa_fini(); |
789 | 2341 return (error); |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2342 } |
789 | 2343 |
2344 error = ldi_ident_from_mod(&modlinkage, &zfs_li); | |
2345 ASSERT(error == 0); | |
4543 | 2346 mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); |
789 | 2347 |
2348 return (0); | |
2349 } | |
2350 | |
2351 int | |
2352 _fini(void) | |
2353 { | |
2354 int error; | |
2355 | |
1544 | 2356 if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) |
789 | 2357 return (EBUSY); |
2358 | |
2359 if ((error = mod_remove(&modlinkage)) != 0) | |
2360 return (error); | |
2361 | |
2362 zvol_fini(); | |
2363 zfs_fini(); | |
2364 spa_fini(); | |
4543 | 2365 if (zfs_share_inited) { |
2366 (void) ddi_modclose(nfs_mod); | |
2367 (void) ddi_modclose(sharefs_mod); | |
2368 } | |
789 | 2369 |
2370 ldi_ident_release(zfs_li); | |
2371 zfs_li = NULL; | |
4543 | 2372 mutex_destroy(&zfs_share_lock); |
789 | 2373 |
2374 return (error); | |
2375 } | |
2376 | |
2377 int | |
2378 _info(struct modinfo *modinfop) | |
2379 { | |
2380 return (mod_info(&modlinkage, modinfop)); | |
2381 } |