Mercurial > illumos > illumos-gate
annotate usr/src/uts/common/fs/zfs/zfs_ioctl.c @ 3444:dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
6504702 zdb -dddv <poolname> chokes on xattrs
6506506 spa_history.c: LE_64(reclen) needs to be cast to uint64_t in case of 32-bit big-endian kernel
author | ek110237 |
---|---|
date | Thu, 18 Jan 2007 14:25:26 -0800 |
parents | 967e0fca6143 |
children | 6b28ebc717aa |
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> | |
43 #include <sys/vdev.h> | |
44 #include <sys/dmu.h> | |
45 #include <sys/dsl_dir.h> | |
46 #include <sys/dsl_dataset.h> | |
47 #include <sys/dsl_prop.h> | |
48 #include <sys/ddi.h> | |
49 #include <sys/sunddi.h> | |
50 #include <sys/sunldi.h> | |
51 #include <sys/policy.h> | |
52 #include <sys/zone.h> | |
53 #include <sys/nvpair.h> | |
54 #include <sys/pathname.h> | |
55 #include <sys/mount.h> | |
56 #include <sys/sdt.h> | |
57 #include <sys/fs/zfs.h> | |
58 #include <sys/zfs_ctldir.h> | |
2885 | 59 #include <sys/zvol.h> |
789 | 60 |
61 #include "zfs_namecheck.h" | |
2676 | 62 #include "zfs_prop.h" |
789 | 63 |
64 extern struct modlfs zfs_modlfs; | |
65 | |
66 extern void zfs_init(void); | |
67 extern void zfs_fini(void); | |
68 | |
69 ldi_ident_t zfs_li = NULL; | |
70 dev_info_t *zfs_dip; | |
71 | |
72 typedef int zfs_ioc_func_t(zfs_cmd_t *); | |
2676 | 73 typedef int zfs_secpolicy_func_t(const char *, cred_t *); |
789 | 74 |
75 typedef struct zfs_ioc_vec { | |
76 zfs_ioc_func_t *zvec_func; | |
77 zfs_secpolicy_func_t *zvec_secpolicy; | |
78 enum { | |
79 no_name, | |
80 pool_name, | |
81 dataset_name | |
82 } zvec_namecheck; | |
83 } zfs_ioc_vec_t; | |
84 | |
85 /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ | |
86 void | |
87 __dprintf(const char *file, const char *func, int line, const char *fmt, ...) | |
88 { | |
89 const char *newfile; | |
90 char buf[256]; | |
91 va_list adx; | |
92 | |
93 /* | |
94 * Get rid of annoying "../common/" prefix to filename. | |
95 */ | |
96 newfile = strrchr(file, '/'); | |
97 if (newfile != NULL) { | |
98 newfile = newfile + 1; /* Get rid of leading / */ | |
99 } else { | |
100 newfile = file; | |
101 } | |
102 | |
103 va_start(adx, fmt); | |
104 (void) vsnprintf(buf, sizeof (buf), fmt, adx); | |
105 va_end(adx); | |
106 | |
107 /* | |
108 * To get this data, use the zfs-dprintf probe as so: | |
109 * dtrace -q -n 'zfs-dprintf \ | |
110 * /stringof(arg0) == "dbuf.c"/ \ | |
111 * {printf("%s: %s", stringof(arg1), stringof(arg3))}' | |
112 * arg0 = file name | |
113 * arg1 = function name | |
114 * arg2 = line number | |
115 * arg3 = message | |
116 */ | |
117 DTRACE_PROBE4(zfs__dprintf, | |
118 char *, newfile, char *, func, int, line, char *, buf); | |
119 } | |
120 | |
121 /* | |
122 * Policy for top-level read operations (list pools). Requires no privileges, | |
123 * and can be used in the local zone, as there is no associated dataset. | |
124 */ | |
125 /* ARGSUSED */ | |
126 static int | |
2676 | 127 zfs_secpolicy_none(const char *unused1, cred_t *cr) |
789 | 128 { |
129 return (0); | |
130 } | |
131 | |
132 /* | |
133 * Policy for dataset read operations (list children, get statistics). Requires | |
134 * no privileges, but must be visible in the local zone. | |
135 */ | |
136 /* ARGSUSED */ | |
137 static int | |
2676 | 138 zfs_secpolicy_read(const char *dataset, cred_t *cr) |
789 | 139 { |
140 if (INGLOBALZONE(curproc) || | |
141 zone_dataset_visible(dataset, NULL)) | |
142 return (0); | |
143 | |
144 return (ENOENT); | |
145 } | |
146 | |
147 static int | |
148 zfs_dozonecheck(const char *dataset, cred_t *cr) | |
149 { | |
150 uint64_t zoned; | |
151 int writable = 1; | |
152 | |
153 /* | |
154 * The dataset must be visible by this zone -- check this first | |
155 * so they don't see EPERM on something they shouldn't know about. | |
156 */ | |
157 if (!INGLOBALZONE(curproc) && | |
158 !zone_dataset_visible(dataset, &writable)) | |
159 return (ENOENT); | |
160 | |
161 if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) | |
162 return (ENOENT); | |
163 | |
164 if (INGLOBALZONE(curproc)) { | |
165 /* | |
166 * If the fs is zoned, only root can access it from the | |
167 * global zone. | |
168 */ | |
169 if (secpolicy_zfs(cr) && zoned) | |
170 return (EPERM); | |
171 } else { | |
172 /* | |
173 * If we are in a local zone, the 'zoned' property must be set. | |
174 */ | |
175 if (!zoned) | |
176 return (EPERM); | |
177 | |
178 /* must be writable by this zone */ | |
179 if (!writable) | |
180 return (EPERM); | |
181 } | |
182 return (0); | |
183 } | |
184 | |
185 /* | |
186 * Policy for dataset write operations (create children, set properties, etc). | |
187 * Requires SYS_MOUNT privilege, and must be writable in the local zone. | |
188 */ | |
189 int | |
2676 | 190 zfs_secpolicy_write(const char *dataset, cred_t *cr) |
789 | 191 { |
192 int error; | |
193 | |
194 if (error = zfs_dozonecheck(dataset, cr)) | |
195 return (error); | |
196 | |
197 return (secpolicy_zfs(cr)); | |
198 } | |
199 | |
200 /* | |
201 * Policy for operations that want to write a dataset's parent: | |
202 * create, destroy, snapshot, clone, restore. | |
203 */ | |
204 static int | |
2676 | 205 zfs_secpolicy_parent(const char *dataset, cred_t *cr) |
789 | 206 { |
207 char parentname[MAXNAMELEN]; | |
208 char *cp; | |
209 | |
210 /* | |
211 * Remove the @bla or /bla from the end of the name to get the parent. | |
212 */ | |
213 (void) strncpy(parentname, dataset, sizeof (parentname)); | |
214 cp = strrchr(parentname, '@'); | |
215 if (cp != NULL) { | |
216 cp[0] = '\0'; | |
217 } else { | |
218 cp = strrchr(parentname, '/'); | |
219 if (cp == NULL) | |
220 return (ENOENT); | |
221 cp[0] = '\0'; | |
222 | |
223 } | |
224 | |
2676 | 225 return (zfs_secpolicy_write(parentname, cr)); |
789 | 226 } |
227 | |
228 /* | |
229 * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires | |
230 * SYS_CONFIG privilege, which is not available in a local zone. | |
231 */ | |
232 /* ARGSUSED */ | |
233 static int | |
2676 | 234 zfs_secpolicy_config(const char *unused, cred_t *cr) |
789 | 235 { |
236 if (secpolicy_sys_config(cr, B_FALSE) != 0) | |
237 return (EPERM); | |
238 | |
239 return (0); | |
240 } | |
241 | |
242 /* | |
1544 | 243 * Policy for fault injection. Requires all privileges. |
244 */ | |
245 /* ARGSUSED */ | |
246 static int | |
2676 | 247 zfs_secpolicy_inject(const char *unused, cred_t *cr) |
1544 | 248 { |
249 return (secpolicy_zinject(cr)); | |
250 } | |
251 | |
252 /* | |
789 | 253 * Returns the nvlist as specified by the user in the zfs_cmd_t. |
254 */ | |
255 static int | |
2676 | 256 get_nvlist(zfs_cmd_t *zc, nvlist_t **nvp) |
789 | 257 { |
258 char *packed; | |
259 size_t size; | |
260 int error; | |
261 nvlist_t *config = NULL; | |
262 | |
263 /* | |
2676 | 264 * Read in and unpack the user-supplied nvlist. |
789 | 265 */ |
2676 | 266 if ((size = zc->zc_nvlist_src_size) == 0) |
789 | 267 return (EINVAL); |
268 | |
269 packed = kmem_alloc(size, KM_SLEEP); | |
270 | |
2676 | 271 if ((error = xcopyin((void *)(uintptr_t)zc->zc_nvlist_src, packed, |
789 | 272 size)) != 0) { |
273 kmem_free(packed, size); | |
274 return (error); | |
275 } | |
276 | |
277 if ((error = nvlist_unpack(packed, size, &config, 0)) != 0) { | |
278 kmem_free(packed, size); | |
279 return (error); | |
280 } | |
281 | |
282 kmem_free(packed, size); | |
283 | |
284 *nvp = config; | |
285 return (0); | |
286 } | |
287 | |
288 static int | |
2676 | 289 put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) |
290 { | |
291 char *packed = NULL; | |
292 size_t size; | |
293 int error; | |
294 | |
295 VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); | |
296 | |
297 if (size > zc->zc_nvlist_dst_size) { | |
298 error = ENOMEM; | |
299 } else { | |
300 VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, | |
301 KM_SLEEP) == 0); | |
302 error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, | |
303 size); | |
304 kmem_free(packed, size); | |
305 } | |
306 | |
307 zc->zc_nvlist_dst_size = size; | |
308 return (error); | |
309 } | |
310 | |
311 static int | |
789 | 312 zfs_ioc_pool_create(zfs_cmd_t *zc) |
313 { | |
314 int error; | |
315 nvlist_t *config; | |
316 | |
2676 | 317 if ((error = get_nvlist(zc, &config)) != 0) |
789 | 318 return (error); |
319 | |
2676 | 320 error = spa_create(zc->zc_name, config, zc->zc_value[0] == '\0' ? |
321 NULL : zc->zc_value); | |
789 | 322 |
323 nvlist_free(config); | |
324 | |
325 return (error); | |
326 } | |
327 | |
328 static int | |
329 zfs_ioc_pool_destroy(zfs_cmd_t *zc) | |
330 { | |
331 return (spa_destroy(zc->zc_name)); | |
332 } | |
333 | |
334 static int | |
335 zfs_ioc_pool_import(zfs_cmd_t *zc) | |
336 { | |
337 int error; | |
338 nvlist_t *config; | |
339 uint64_t guid; | |
340 | |
2676 | 341 if ((error = get_nvlist(zc, &config)) != 0) |
789 | 342 return (error); |
343 | |
344 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || | |
1544 | 345 guid != zc->zc_guid) |
789 | 346 error = EINVAL; |
347 else | |
348 error = spa_import(zc->zc_name, config, | |
2676 | 349 zc->zc_value[0] == '\0' ? NULL : zc->zc_value); |
789 | 350 |
351 nvlist_free(config); | |
352 | |
353 return (error); | |
354 } | |
355 | |
356 static int | |
357 zfs_ioc_pool_export(zfs_cmd_t *zc) | |
358 { | |
1775
e51e26b432c0
6410698 ZFS metadata needs to be more highly replicated (ditto blocks)
billm
parents:
1760
diff
changeset
|
359 return (spa_export(zc->zc_name, NULL)); |
789 | 360 } |
361 | |
362 static int | |
363 zfs_ioc_pool_configs(zfs_cmd_t *zc) | |
364 { | |
365 nvlist_t *configs; | |
366 int error; | |
367 | |
368 if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) | |
369 return (EEXIST); | |
370 | |
2676 | 371 error = put_nvlist(zc, configs); |
789 | 372 |
373 nvlist_free(configs); | |
374 | |
375 return (error); | |
376 } | |
377 | |
378 static int | |
379 zfs_ioc_pool_stats(zfs_cmd_t *zc) | |
380 { | |
381 nvlist_t *config; | |
382 int error; | |
1544 | 383 int ret = 0; |
789 | 384 |
2676 | 385 error = spa_get_stats(zc->zc_name, &config, zc->zc_value, |
386 sizeof (zc->zc_value)); | |
789 | 387 |
388 if (config != NULL) { | |
2676 | 389 ret = put_nvlist(zc, config); |
789 | 390 nvlist_free(config); |
1544 | 391 |
392 /* | |
393 * The config may be present even if 'error' is non-zero. | |
394 * In this case we return success, and preserve the real errno | |
395 * in 'zc_cookie'. | |
396 */ | |
397 zc->zc_cookie = error; | |
789 | 398 } else { |
1544 | 399 ret = error; |
789 | 400 } |
401 | |
1544 | 402 return (ret); |
789 | 403 } |
404 | |
405 /* | |
406 * Try to import the given pool, returning pool stats as appropriate so that | |
407 * user land knows which devices are available and overall pool health. | |
408 */ | |
409 static int | |
410 zfs_ioc_pool_tryimport(zfs_cmd_t *zc) | |
411 { | |
412 nvlist_t *tryconfig, *config; | |
413 int error; | |
414 | |
2676 | 415 if ((error = get_nvlist(zc, &tryconfig)) != 0) |
789 | 416 return (error); |
417 | |
418 config = spa_tryimport(tryconfig); | |
419 | |
420 nvlist_free(tryconfig); | |
421 | |
422 if (config == NULL) | |
423 return (EINVAL); | |
424 | |
2676 | 425 error = put_nvlist(zc, config); |
789 | 426 nvlist_free(config); |
427 | |
428 return (error); | |
429 } | |
430 | |
431 static int | |
432 zfs_ioc_pool_scrub(zfs_cmd_t *zc) | |
433 { | |
434 spa_t *spa; | |
435 int error; | |
436 | |
2926 | 437 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
438 return (error); | |
439 | |
440 error = spa_scrub(spa, zc->zc_cookie, B_FALSE); | |
441 | |
442 spa_close(spa, FTAG); | |
443 | |
789 | 444 return (error); |
445 } | |
446 | |
447 static int | |
448 zfs_ioc_pool_freeze(zfs_cmd_t *zc) | |
449 { | |
450 spa_t *spa; | |
451 int error; | |
452 | |
453 error = spa_open(zc->zc_name, &spa, FTAG); | |
454 if (error == 0) { | |
455 spa_freeze(spa); | |
456 spa_close(spa, FTAG); | |
457 } | |
458 return (error); | |
459 } | |
460 | |
461 static int | |
1760 | 462 zfs_ioc_pool_upgrade(zfs_cmd_t *zc) |
463 { | |
464 spa_t *spa; | |
465 int error; | |
466 | |
2926 | 467 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
468 return (error); | |
469 | |
470 spa_upgrade(spa); | |
471 | |
472 spa_close(spa, FTAG); | |
473 | |
474 return (error); | |
475 } | |
476 | |
477 static int | |
478 zfs_ioc_pool_get_history(zfs_cmd_t *zc) | |
479 { | |
480 spa_t *spa; | |
481 char *hist_buf; | |
482 uint64_t size; | |
483 int error; | |
484 | |
485 if ((size = zc->zc_history_len) == 0) | |
486 return (EINVAL); | |
487 | |
488 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
489 return (error); | |
490 | |
491 hist_buf = kmem_alloc(size, KM_SLEEP); | |
492 if ((error = spa_history_get(spa, &zc->zc_history_offset, | |
493 &zc->zc_history_len, hist_buf)) == 0) { | |
494 error = xcopyout(hist_buf, (char *)(uintptr_t)zc->zc_history, | |
495 zc->zc_history_len); | |
496 } | |
497 | |
498 spa_close(spa, FTAG); | |
499 kmem_free(hist_buf, size); | |
500 return (error); | |
501 } | |
502 | |
503 static int | |
504 zfs_ioc_pool_log_history(zfs_cmd_t *zc) | |
505 { | |
506 spa_t *spa; | |
507 char *history_str = NULL; | |
508 size_t size; | |
509 int error; | |
510 | |
511 size = zc->zc_history_len; | |
512 if (size == 0 || size > HIS_MAX_RECORD_LEN) | |
513 return (EINVAL); | |
514 | |
515 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
516 return (error); | |
517 | |
518 /* add one for the NULL delimiter */ | |
519 size++; | |
520 history_str = kmem_alloc(size, KM_SLEEP); | |
521 if ((error = xcopyin((void *)(uintptr_t)zc->zc_history, history_str, | |
522 size)) != 0) { | |
1760 | 523 spa_close(spa, FTAG); |
2926 | 524 kmem_free(history_str, size); |
525 return (error); | |
1760 | 526 } |
2926 | 527 history_str[size - 1] = '\0'; |
528 | |
529 error = spa_history_log(spa, history_str, zc->zc_history_offset); | |
530 | |
531 spa_close(spa, FTAG); | |
532 kmem_free(history_str, size); | |
533 | |
1760 | 534 return (error); |
535 } | |
536 | |
537 static int | |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
538 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
|
539 { |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
540 spa_t *spa; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
541 dsl_pool_t *dp; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
542 dsl_dataset_t *ds = NULL; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
543 int error; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
544 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
545 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
546 return (error); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
547 dp = spa_get_dsl(spa); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
548 rw_enter(&dp->dp_config_rwlock, RW_READER); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
549 if ((error = dsl_dataset_open_obj(dp, zc->zc_obj, |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
550 NULL, DS_MODE_NONE, FTAG, &ds)) != 0) { |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
551 rw_exit(&dp->dp_config_rwlock); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
552 spa_close(spa, FTAG); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
553 return (error); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
554 } |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
555 dsl_dataset_name(ds, zc->zc_value); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
556 dsl_dataset_close(ds, DS_MODE_NONE, FTAG); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
557 rw_exit(&dp->dp_config_rwlock); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
558 spa_close(spa, FTAG); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
559 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
560 return (0); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
561 } |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
562 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
563 static int |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
564 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
|
565 { |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
566 objset_t *osp; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
567 int error; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
568 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
569 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
|
570 DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0) |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
571 return (error); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
572 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
573 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
|
574 sizeof (zc->zc_value)); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
575 dmu_objset_close(osp); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
576 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
577 return (error); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
578 } |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
579 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
580 static int |
789 | 581 zfs_ioc_vdev_add(zfs_cmd_t *zc) |
582 { | |
583 spa_t *spa; | |
584 int error; | |
585 nvlist_t *config; | |
586 | |
587 error = spa_open(zc->zc_name, &spa, FTAG); | |
588 if (error != 0) | |
589 return (error); | |
590 | |
2676 | 591 if ((error = get_nvlist(zc, &config)) == 0) { |
789 | 592 error = spa_vdev_add(spa, config); |
593 nvlist_free(config); | |
594 } | |
595 | |
596 spa_close(spa, FTAG); | |
597 return (error); | |
598 } | |
599 | |
600 static int | |
601 zfs_ioc_vdev_remove(zfs_cmd_t *zc) | |
602 { | |
2082 | 603 spa_t *spa; |
604 int error; | |
605 | |
606 error = spa_open(zc->zc_name, &spa, FTAG); | |
607 if (error != 0) | |
608 return (error); | |
609 error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); | |
610 spa_close(spa, FTAG); | |
611 return (error); | |
789 | 612 } |
613 | |
614 static int | |
615 zfs_ioc_vdev_online(zfs_cmd_t *zc) | |
616 { | |
617 spa_t *spa; | |
618 int error; | |
619 | |
2926 | 620 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
789 | 621 return (error); |
1544 | 622 error = vdev_online(spa, zc->zc_guid); |
789 | 623 spa_close(spa, FTAG); |
624 return (error); | |
625 } | |
626 | |
627 static int | |
628 zfs_ioc_vdev_offline(zfs_cmd_t *zc) | |
629 { | |
630 spa_t *spa; | |
1485 | 631 int istmp = zc->zc_cookie; |
789 | 632 int error; |
633 | |
2926 | 634 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
789 | 635 return (error); |
1544 | 636 error = vdev_offline(spa, zc->zc_guid, istmp); |
789 | 637 spa_close(spa, FTAG); |
638 return (error); | |
639 } | |
640 | |
641 static int | |
642 zfs_ioc_vdev_attach(zfs_cmd_t *zc) | |
643 { | |
644 spa_t *spa; | |
645 int replacing = zc->zc_cookie; | |
646 nvlist_t *config; | |
647 int error; | |
648 | |
2926 | 649 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
789 | 650 return (error); |
651 | |
2676 | 652 if ((error = get_nvlist(zc, &config)) == 0) { |
1544 | 653 error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); |
789 | 654 nvlist_free(config); |
655 } | |
656 | |
657 spa_close(spa, FTAG); | |
658 return (error); | |
659 } | |
660 | |
661 static int | |
662 zfs_ioc_vdev_detach(zfs_cmd_t *zc) | |
663 { | |
664 spa_t *spa; | |
665 int error; | |
666 | |
2926 | 667 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
789 | 668 return (error); |
669 | |
1544 | 670 error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE); |
789 | 671 |
672 spa_close(spa, FTAG); | |
673 return (error); | |
674 } | |
675 | |
676 static int | |
1354
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
677 zfs_ioc_vdev_setpath(zfs_cmd_t *zc) |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
678 { |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
679 spa_t *spa; |
2676 | 680 char *path = zc->zc_value; |
1544 | 681 uint64_t guid = zc->zc_guid; |
1354
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
682 int error; |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
683 |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
684 error = spa_open(zc->zc_name, &spa, FTAG); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
685 if (error != 0) |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
686 return (error); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
687 |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
688 error = spa_vdev_setpath(spa, guid, path); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
689 spa_close(spa, FTAG); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
690 return (error); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
691 } |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
692 |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
693 static int |
789 | 694 zfs_ioc_objset_stats(zfs_cmd_t *zc) |
695 { | |
696 objset_t *os = NULL; | |
697 int error; | |
1356
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
698 nvlist_t *nv; |
789 | 699 |
700 retry: | |
701 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, | |
702 DS_MODE_STANDARD | DS_MODE_READONLY, &os); | |
703 if (error != 0) { | |
704 /* | |
705 * This is ugly: dmu_objset_open() can return EBUSY if | |
706 * the objset is held exclusively. Fortunately this hold is | |
707 * only for a short while, so we retry here. | |
708 * This avoids user code having to handle EBUSY, | |
709 * for example for a "zfs list". | |
710 */ | |
711 if (error == EBUSY) { | |
712 delay(1); | |
713 goto retry; | |
714 } | |
715 return (error); | |
716 } | |
717 | |
2885 | 718 dmu_objset_fast_stat(os, &zc->zc_objset_stats); |
789 | 719 |
2856 | 720 if (zc->zc_nvlist_dst != 0 && |
1356
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
721 (error = dsl_prop_get_all(os, &nv)) == 0) { |
2885 | 722 dmu_objset_stats(os, nv); |
3087 | 723 /* |
724 * NB: zvol_get_stats() will read the objset contents, | |
725 * which we aren't supposed to do with a | |
726 * DS_MODE_STANDARD open, because it could be | |
727 * inconsistent. So this is a bit of a workaround... | |
728 */ | |
729 if (!zc->zc_objset_stats.dds_inconsistent && | |
730 dmu_objset_type(os) == DMU_OST_ZVOL) | |
2885 | 731 VERIFY(zvol_get_stats(os, nv) == 0); |
2676 | 732 error = put_nvlist(zc, nv); |
1356
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
733 nvlist_free(nv); |
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
734 } |
789 | 735 |
2676 | 736 spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value)); |
1544 | 737 |
789 | 738 dmu_objset_close(os); |
739 return (error); | |
740 } | |
741 | |
742 static int | |
743 zfs_ioc_dataset_list_next(zfs_cmd_t *zc) | |
744 { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
745 objset_t *os; |
789 | 746 int error; |
747 char *p; | |
748 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
749 retry: |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
750 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
|
751 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
|
752 if (error != 0) { |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
753 /* |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
754 * 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
|
755 * 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
|
756 * 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
|
757 * 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
|
758 * for example for a "zfs list". |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
759 */ |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
760 if (error == EBUSY) { |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
761 delay(1); |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
762 goto retry; |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
763 } |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
764 if (error == ENOENT) |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
765 error = ESRCH; |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
766 return (error); |
789 | 767 } |
768 | |
769 p = strrchr(zc->zc_name, '/'); | |
770 if (p == NULL || p[1] != '\0') | |
771 (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); | |
772 p = zc->zc_name + strlen(zc->zc_name); | |
773 | |
774 do { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
775 error = dmu_dir_list_next(os, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
776 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
|
777 NULL, &zc->zc_cookie); |
789 | 778 if (error == ENOENT) |
779 error = ESRCH; | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
780 } while (error == 0 && !INGLOBALZONE(curproc) && |
789 | 781 !zone_dataset_visible(zc->zc_name, NULL)); |
782 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
783 /* |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
784 * 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
|
785 * 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
|
786 */ |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
787 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
|
788 error = zfs_ioc_objset_stats(zc); /* fill in the stats */ |
789 | 789 |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
790 dmu_objset_close(os); |
789 | 791 return (error); |
792 } | |
793 | |
794 static int | |
795 zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) | |
796 { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
797 objset_t *os; |
789 | 798 int error; |
799 | |
800 retry: | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
801 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
|
802 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
|
803 if (error != 0) { |
789 | 804 /* |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
805 * This is ugly: dmu_objset_open() can return EBUSY if |
789 | 806 * the objset is held exclusively. Fortunately this hold is |
807 * only for a short while, so we retry here. | |
808 * 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
|
809 * for example for a "zfs list". |
789 | 810 */ |
811 if (error == EBUSY) { | |
812 delay(1); | |
813 goto retry; | |
814 } | |
815 if (error == ENOENT) | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
816 error = ESRCH; |
789 | 817 return (error); |
818 } | |
819 | |
1003 | 820 /* |
821 * A dataset name of maximum length cannot have any snapshots, | |
822 * so exit immediately. | |
823 */ | |
824 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
|
825 dmu_objset_close(os); |
1003 | 826 return (ESRCH); |
789 | 827 } |
828 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
829 error = dmu_snapshot_list_next(os, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
830 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
|
831 zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie); |
789 | 832 if (error == ENOENT) |
833 error = ESRCH; | |
834 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
835 if (error == 0) |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
836 error = zfs_ioc_objset_stats(zc); /* fill in the stats */ |
789 | 837 |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
838 dmu_objset_close(os); |
789 | 839 return (error); |
840 } | |
841 | |
842 static int | |
2676 | 843 zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl) |
789 | 844 { |
2676 | 845 nvpair_t *elem; |
846 int error; | |
847 const char *propname; | |
848 zfs_prop_t prop; | |
849 uint64_t intval; | |
850 char *strval; | |
851 | |
852 elem = NULL; | |
853 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { | |
854 propname = nvpair_name(elem); | |
855 | |
856 if ((prop = zfs_name_to_prop(propname)) == | |
857 ZFS_PROP_INVAL) { | |
858 /* | |
859 * If this is a user-defined property, it must be a | |
860 * string, and there is no further validation to do. | |
861 */ | |
862 if (!zfs_prop_user(propname) || | |
863 nvpair_type(elem) != DATA_TYPE_STRING) | |
864 return (EINVAL); | |
865 | |
866 VERIFY(nvpair_value_string(elem, &strval) == 0); | |
867 error = dsl_prop_set(name, propname, 1, | |
868 strlen(strval) + 1, strval); | |
869 if (error == 0) | |
870 continue; | |
871 else | |
872 break; | |
873 } | |
874 | |
875 /* | |
876 * Check permissions for special properties. | |
877 */ | |
878 switch (prop) { | |
879 case ZFS_PROP_ZONED: | |
880 /* | |
881 * Disallow setting of 'zoned' from within a local zone. | |
882 */ | |
883 if (!INGLOBALZONE(curproc)) | |
884 return (EPERM); | |
885 break; | |
886 | |
887 case ZFS_PROP_QUOTA: | |
888 if (error = zfs_dozonecheck(name, cr)) | |
889 return (error); | |
890 | |
891 if (!INGLOBALZONE(curproc)) { | |
892 uint64_t zoned; | |
893 char setpoint[MAXNAMELEN]; | |
894 int dslen; | |
895 /* | |
896 * Unprivileged users are allowed to modify the | |
897 * quota on things *under* (ie. contained by) | |
898 * the thing they own. | |
899 */ | |
900 if (dsl_prop_get_integer(name, "zoned", &zoned, | |
901 setpoint)) | |
902 return (EPERM); | |
903 if (!zoned) /* this shouldn't happen */ | |
904 return (EPERM); | |
905 dslen = strlen(name); | |
906 if (dslen <= strlen(setpoint)) | |
907 return (EPERM); | |
908 } | |
909 } | |
910 | |
911 switch (prop) { | |
912 case ZFS_PROP_QUOTA: | |
913 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
914 (error = dsl_dir_set_quota(name, | |
915 intval)) != 0) | |
916 return (error); | |
917 break; | |
918 | |
919 case ZFS_PROP_RESERVATION: | |
920 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
921 (error = dsl_dir_set_reservation(name, | |
922 intval)) != 0) | |
923 return (error); | |
924 break; | |
789 | 925 |
2676 | 926 case ZFS_PROP_VOLSIZE: |
927 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
928 (error = zvol_set_volsize(name, dev, | |
929 intval)) != 0) | |
930 return (error); | |
931 break; | |
932 | |
933 case ZFS_PROP_VOLBLOCKSIZE: | |
934 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
935 (error = zvol_set_volblocksize(name, | |
936 intval)) != 0) | |
937 return (error); | |
938 break; | |
939 | |
940 default: | |
941 if (nvpair_type(elem) == DATA_TYPE_STRING) { | |
942 if (zfs_prop_get_type(prop) != | |
943 prop_type_string) | |
944 return (EINVAL); | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
945 VERIFY(nvpair_value_string(elem, &strval) == 0); |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
946 if ((error = dsl_prop_set(name, |
2676 | 947 nvpair_name(elem), 1, strlen(strval) + 1, |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
948 strval)) != 0) |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
949 return (error); |
2676 | 950 } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { |
2885 | 951 const char *unused; |
952 | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
953 VERIFY(nvpair_value_uint64(elem, &intval) == 0); |
2676 | 954 |
955 switch (zfs_prop_get_type(prop)) { | |
956 case prop_type_number: | |
957 break; | |
958 case prop_type_boolean: | |
959 if (intval > 1) | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
960 return (EINVAL); |
2676 | 961 break; |
962 case prop_type_string: | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
963 return (EINVAL); |
2676 | 964 case prop_type_index: |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
965 if (zfs_prop_index_to_string(prop, |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
966 intval, &unused) != 0) |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
967 return (EINVAL); |
2676 | 968 break; |
969 default: | |
970 cmn_err(CE_PANIC, "unknown property " | |
971 "type"); | |
972 break; | |
973 } | |
974 | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
975 if ((error = dsl_prop_set(name, propname, |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
976 8, 1, &intval)) != 0) |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
977 return (error); |
2676 | 978 } else { |
979 return (EINVAL); | |
980 } | |
981 break; | |
982 } | |
983 } | |
984 | |
985 return (0); | |
789 | 986 } |
987 | |
988 static int | |
2676 | 989 zfs_ioc_set_prop(zfs_cmd_t *zc) |
789 | 990 { |
2676 | 991 nvlist_t *nvl; |
992 int error; | |
993 zfs_prop_t prop; | |
789 | 994 |
2676 | 995 /* |
996 * If zc_value is set, then this is an attempt to inherit a value. | |
997 * Otherwise, zc_nvlist refers to a list of properties to set. | |
998 */ | |
999 if (zc->zc_value[0] != '\0') { | |
1000 if (!zfs_prop_user(zc->zc_value) && | |
1001 ((prop = zfs_name_to_prop(zc->zc_value)) == | |
1002 ZFS_PROP_INVAL || | |
1003 !zfs_prop_inheritable(prop))) | |
1004 return (EINVAL); | |
1005 | |
1006 return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); | |
1007 } | |
1008 | |
1009 if ((error = get_nvlist(zc, &nvl)) != 0) | |
1010 return (error); | |
1011 | |
1012 error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev, | |
1013 (cred_t *)(uintptr_t)zc->zc_cred, nvl); | |
1014 nvlist_free(nvl); | |
1015 return (error); | |
789 | 1016 } |
1017 | |
1018 static int | |
1019 zfs_ioc_create_minor(zfs_cmd_t *zc) | |
1020 { | |
2676 | 1021 return (zvol_create_minor(zc->zc_name, zc->zc_dev)); |
789 | 1022 } |
1023 | |
1024 static int | |
1025 zfs_ioc_remove_minor(zfs_cmd_t *zc) | |
1026 { | |
2676 | 1027 return (zvol_remove_minor(zc->zc_name)); |
789 | 1028 } |
1029 | |
1030 /* | |
1031 * Search the vfs list for a specified resource. Returns a pointer to it | |
1032 * or NULL if no suitable entry is found. The caller of this routine | |
1033 * is responsible for releasing the returned vfs pointer. | |
1034 */ | |
1035 static vfs_t * | |
1036 zfs_get_vfs(const char *resource) | |
1037 { | |
1038 struct vfs *vfsp; | |
1039 struct vfs *vfs_found = NULL; | |
1040 | |
1041 vfs_list_read_lock(); | |
1042 vfsp = rootvfs; | |
1043 do { | |
1044 if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { | |
1045 VFS_HOLD(vfsp); | |
1046 vfs_found = vfsp; | |
1047 break; | |
1048 } | |
1049 vfsp = vfsp->vfs_next; | |
1050 } while (vfsp != rootvfs); | |
1051 vfs_list_unlock(); | |
1052 return (vfs_found); | |
1053 } | |
1054 | |
1055 static void | |
1056 zfs_create_cb(objset_t *os, void *arg, dmu_tx_t *tx) | |
1057 { | |
2676 | 1058 zfs_create_data_t *zc = arg; |
789 | 1059 zfs_create_fs(os, (cred_t *)(uintptr_t)zc->zc_cred, tx); |
1060 } | |
1061 | |
1062 static int | |
1063 zfs_ioc_create(zfs_cmd_t *zc) | |
1064 { | |
1065 objset_t *clone; | |
1066 int error = 0; | |
2676 | 1067 zfs_create_data_t cbdata = { 0 }; |
789 | 1068 void (*cbfunc)(objset_t *os, void *arg, dmu_tx_t *tx); |
1069 dmu_objset_type_t type = zc->zc_objset_type; | |
1070 | |
1071 switch (type) { | |
1072 | |
1073 case DMU_OST_ZFS: | |
1074 cbfunc = zfs_create_cb; | |
1075 break; | |
1076 | |
1077 case DMU_OST_ZVOL: | |
1078 cbfunc = zvol_create_cb; | |
1079 break; | |
1080 | |
1081 default: | |
2199 | 1082 cbfunc = NULL; |
1083 } | |
1084 if (strchr(zc->zc_name, '@')) | |
789 | 1085 return (EINVAL); |
1086 | |
2676 | 1087 if (zc->zc_nvlist_src != NULL && |
1088 (error = get_nvlist(zc, &cbdata.zc_props)) != 0) | |
1089 return (error); | |
1090 | |
1091 cbdata.zc_cred = (cred_t *)(uintptr_t)zc->zc_cred; | |
1092 cbdata.zc_dev = (dev_t)zc->zc_dev; | |
1093 | |
1094 if (zc->zc_value[0] != '\0') { | |
789 | 1095 /* |
1096 * We're creating a clone of an existing snapshot. | |
1097 */ | |
2676 | 1098 zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; |
1099 if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { | |
1100 nvlist_free(cbdata.zc_props); | |
789 | 1101 return (EINVAL); |
2676 | 1102 } |
789 | 1103 |
2676 | 1104 error = dmu_objset_open(zc->zc_value, type, |
789 | 1105 DS_MODE_STANDARD | DS_MODE_READONLY, &clone); |
2676 | 1106 if (error) { |
1107 nvlist_free(cbdata.zc_props); | |
789 | 1108 return (error); |
2676 | 1109 } |
789 | 1110 error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL); |
1111 dmu_objset_close(clone); | |
1112 } else { | |
2676 | 1113 if (cbfunc == NULL) { |
1114 nvlist_free(cbdata.zc_props); | |
2199 | 1115 return (EINVAL); |
2676 | 1116 } |
1117 | |
789 | 1118 if (type == DMU_OST_ZVOL) { |
2676 | 1119 uint64_t volsize, volblocksize; |
1120 | |
1121 if (cbdata.zc_props == NULL || | |
1122 nvlist_lookup_uint64(cbdata.zc_props, | |
1123 zfs_prop_to_name(ZFS_PROP_VOLSIZE), | |
1124 &volsize) != 0) { | |
1125 nvlist_free(cbdata.zc_props); | |
1126 return (EINVAL); | |
1127 } | |
1128 | |
1129 if ((error = nvlist_lookup_uint64(cbdata.zc_props, | |
1130 zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), | |
1131 &volblocksize)) != 0 && error != ENOENT) { | |
1132 nvlist_free(cbdata.zc_props); | |
1133 return (EINVAL); | |
1134 } | |
1133
335d069294d1
6357470 vdev_raidz.c has unused RAIDZ_SINGLE define, code
eschrock
parents:
1003
diff
changeset
|
1135 |
2676 | 1136 if (error != 0) |
1137 volblocksize = zfs_prop_default_numeric( | |
1138 ZFS_PROP_VOLBLOCKSIZE); | |
1139 | |
1140 if ((error = zvol_check_volblocksize( | |
1141 volblocksize)) != 0 || | |
1142 (error = zvol_check_volsize(volsize, | |
1143 volblocksize)) != 0) { | |
1144 nvlist_free(cbdata.zc_props); | |
789 | 1145 return (error); |
2676 | 1146 } |
1147 } | |
1133
335d069294d1
6357470 vdev_raidz.c has unused RAIDZ_SINGLE define, code
eschrock
parents:
1003
diff
changeset
|
1148 |
2676 | 1149 error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, |
1150 &cbdata); | |
789 | 1151 } |
2676 | 1152 |
1153 /* | |
1154 * It would be nice to do this atomically. | |
1155 */ | |
1156 if (error == 0) { | |
1157 if ((error = zfs_set_prop_nvlist(zc->zc_name, | |
1158 zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred, | |
1159 cbdata.zc_props)) != 0) | |
1160 (void) dmu_objset_destroy(zc->zc_name); | |
1161 } | |
1162 | |
1163 nvlist_free(cbdata.zc_props); | |
789 | 1164 return (error); |
1165 } | |
1166 | |
1167 static int | |
2199 | 1168 zfs_ioc_snapshot(zfs_cmd_t *zc) |
1169 { | |
2676 | 1170 if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) |
2199 | 1171 return (EINVAL); |
1172 return (dmu_objset_snapshot(zc->zc_name, | |
2676 | 1173 zc->zc_value, zc->zc_cookie)); |
2199 | 1174 } |
1175 | |
1176 static int | |
1177 zfs_unmount_snap(char *name, void *arg) | |
789 | 1178 { |
2199 | 1179 char *snapname = arg; |
1180 char *cp; | |
2417 | 1181 vfs_t *vfsp = NULL; |
2199 | 1182 |
1183 /* | |
1184 * Snapshots (which are under .zfs control) must be unmounted | |
1185 * before they can be destroyed. | |
1186 */ | |
1187 | |
1188 if (snapname) { | |
1189 (void) strcat(name, "@"); | |
1190 (void) strcat(name, snapname); | |
1191 vfsp = zfs_get_vfs(name); | |
1192 cp = strchr(name, '@'); | |
1193 *cp = '\0'; | |
2417 | 1194 } else if (strchr(name, '@')) { |
2199 | 1195 vfsp = zfs_get_vfs(name); |
1196 } | |
1197 | |
1198 if (vfsp) { | |
1199 /* | |
1200 * Always force the unmount for snapshots. | |
1201 */ | |
1202 int flag = MS_FORCE; | |
789 | 1203 int err; |
1204 | |
2199 | 1205 if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { |
1206 VFS_RELE(vfsp); | |
1207 return (err); | |
1208 } | |
1209 VFS_RELE(vfsp); | |
1210 if ((err = dounmount(vfsp, flag, kcred)) != 0) | |
1211 return (err); | |
1212 } | |
1213 return (0); | |
1214 } | |
1215 | |
1216 static int | |
1217 zfs_ioc_destroy_snaps(zfs_cmd_t *zc) | |
1218 { | |
1219 int err; | |
789 | 1220 |
2676 | 1221 if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) |
2199 | 1222 return (EINVAL); |
1223 err = dmu_objset_find(zc->zc_name, | |
2676 | 1224 zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); |
2199 | 1225 if (err) |
1226 return (err); | |
2676 | 1227 return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); |
2199 | 1228 } |
1229 | |
1230 static int | |
1231 zfs_ioc_destroy(zfs_cmd_t *zc) | |
1232 { | |
1233 if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { | |
1234 int err = zfs_unmount_snap(zc->zc_name, NULL); | |
1235 if (err) | |
1236 return (err); | |
789 | 1237 } |
1238 | |
1239 return (dmu_objset_destroy(zc->zc_name)); | |
1240 } | |
1241 | |
1242 static int | |
1243 zfs_ioc_rollback(zfs_cmd_t *zc) | |
1244 { | |
1245 return (dmu_objset_rollback(zc->zc_name)); | |
1246 } | |
1247 | |
1248 static int | |
1249 zfs_ioc_rename(zfs_cmd_t *zc) | |
1250 { | |
2676 | 1251 zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; |
1252 if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) | |
789 | 1253 return (EINVAL); |
1254 | |
1255 if (strchr(zc->zc_name, '@') != NULL && | |
1256 zc->zc_objset_type == DMU_OST_ZFS) { | |
2199 | 1257 int err = zfs_unmount_snap(zc->zc_name, NULL); |
1258 if (err) | |
1259 return (err); | |
789 | 1260 } |
1261 | |
2676 | 1262 return (dmu_objset_rename(zc->zc_name, zc->zc_value)); |
789 | 1263 } |
1264 | |
1265 static int | |
1266 zfs_ioc_recvbackup(zfs_cmd_t *zc) | |
1267 { | |
1268 file_t *fp; | |
1269 int error, fd; | |
2885 | 1270 offset_t new_off; |
789 | 1271 |
3265
967e0fca6143
6463140 zfs recv with a snapshot name that has 2 @@ in a row succeeds
ahrens
parents:
3087
diff
changeset
|
1272 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
|
1273 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
|
1274 return (EINVAL); |
967e0fca6143
6463140 zfs recv with a snapshot name that has 2 @@ in a row succeeds
ahrens
parents:
3087
diff
changeset
|
1275 |
789 | 1276 fd = zc->zc_cookie; |
1277 fp = getf(fd); | |
1278 if (fp == NULL) | |
1279 return (EBADF); | |
2676 | 1280 error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record, |
1281 &zc->zc_cookie, (boolean_t)zc->zc_guid, fp->f_vnode, | |
2665 | 1282 fp->f_offset); |
2885 | 1283 |
1284 new_off = fp->f_offset + zc->zc_cookie; | |
1285 if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off) == 0) | |
1286 fp->f_offset = new_off; | |
1287 | |
789 | 1288 releasef(fd); |
1289 return (error); | |
1290 } | |
1291 | |
1292 static int | |
1293 zfs_ioc_sendbackup(zfs_cmd_t *zc) | |
1294 { | |
1295 objset_t *fromsnap = NULL; | |
1296 objset_t *tosnap; | |
1297 file_t *fp; | |
1298 int error; | |
1299 | |
1300 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, | |
1301 DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap); | |
1302 if (error) | |
1303 return (error); | |
1304 | |
2676 | 1305 if (zc->zc_value[0] != '\0') { |
2885 | 1306 char buf[MAXPATHLEN]; |
1307 char *cp; | |
1308 | |
1309 (void) strncpy(buf, zc->zc_name, sizeof (buf)); | |
1310 cp = strchr(buf, '@'); | |
1311 if (cp) | |
1312 *(cp+1) = 0; | |
1313 (void) strncat(buf, zc->zc_value, sizeof (buf)); | |
1314 error = dmu_objset_open(buf, DMU_OST_ANY, | |
789 | 1315 DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap); |
1316 if (error) { | |
1317 dmu_objset_close(tosnap); | |
1318 return (error); | |
1319 } | |
1320 } | |
1321 | |
1322 fp = getf(zc->zc_cookie); | |
1323 if (fp == NULL) { | |
1324 dmu_objset_close(tosnap); | |
1325 if (fromsnap) | |
1326 dmu_objset_close(fromsnap); | |
1327 return (EBADF); | |
1328 } | |
1329 | |
1330 error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode); | |
1331 | |
1332 releasef(zc->zc_cookie); | |
1333 if (fromsnap) | |
1334 dmu_objset_close(fromsnap); | |
1335 dmu_objset_close(tosnap); | |
1336 return (error); | |
1337 } | |
1338 | |
1544 | 1339 static int |
1340 zfs_ioc_inject_fault(zfs_cmd_t *zc) | |
1341 { | |
1342 int id, error; | |
1343 | |
1344 error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, | |
1345 &zc->zc_inject_record); | |
1346 | |
1347 if (error == 0) | |
1348 zc->zc_guid = (uint64_t)id; | |
1349 | |
1350 return (error); | |
1351 } | |
1352 | |
1353 static int | |
1354 zfs_ioc_clear_fault(zfs_cmd_t *zc) | |
1355 { | |
1356 return (zio_clear_fault((int)zc->zc_guid)); | |
1357 } | |
1358 | |
1359 static int | |
1360 zfs_ioc_inject_list_next(zfs_cmd_t *zc) | |
1361 { | |
1362 int id = (int)zc->zc_guid; | |
1363 int error; | |
1364 | |
1365 error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), | |
1366 &zc->zc_inject_record); | |
1367 | |
1368 zc->zc_guid = id; | |
1369 | |
1370 return (error); | |
1371 } | |
1372 | |
1373 static int | |
1374 zfs_ioc_error_log(zfs_cmd_t *zc) | |
1375 { | |
1376 spa_t *spa; | |
1377 int error; | |
2676 | 1378 size_t count = (size_t)zc->zc_nvlist_dst_size; |
1544 | 1379 |
1380 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
1381 return (error); | |
1382 | |
2676 | 1383 error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, |
1544 | 1384 &count); |
1385 if (error == 0) | |
2676 | 1386 zc->zc_nvlist_dst_size = count; |
1544 | 1387 else |
2676 | 1388 zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); |
1544 | 1389 |
1390 spa_close(spa, FTAG); | |
1391 | |
1392 return (error); | |
1393 } | |
1394 | |
1395 static int | |
1396 zfs_ioc_clear(zfs_cmd_t *zc) | |
1397 { | |
1398 spa_t *spa; | |
1399 vdev_t *vd; | |
1400 int error; | |
1401 | |
1402 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
1403 return (error); | |
1404 | |
1405 spa_config_enter(spa, RW_WRITER, FTAG); | |
1406 | |
2676 | 1407 if (zc->zc_guid == 0) { |
1544 | 1408 vd = NULL; |
2676 | 1409 } else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) { |
1544 | 1410 spa_config_exit(spa, FTAG); |
1411 spa_close(spa, FTAG); | |
1412 return (ENODEV); | |
1413 } | |
1414 | |
1415 vdev_clear(spa, vd); | |
1416 | |
1417 spa_config_exit(spa, FTAG); | |
1418 | |
1419 spa_close(spa, FTAG); | |
1420 | |
1421 return (0); | |
1422 } | |
1423 | |
1424 static int | |
2082 | 1425 zfs_ioc_promote(zfs_cmd_t *zc) |
1426 { | |
2417 | 1427 char *cp; |
1428 | |
1429 /* | |
1430 * We don't need to unmount *all* the origin fs's snapshots, but | |
1431 * it's easier. | |
1432 */ | |
2676 | 1433 cp = strchr(zc->zc_value, '@'); |
2417 | 1434 if (cp) |
1435 *cp = '\0'; | |
2676 | 1436 (void) dmu_objset_find(zc->zc_value, |
2417 | 1437 zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); |
2082 | 1438 return (dsl_dataset_promote(zc->zc_name)); |
1439 } | |
1440 | |
789 | 1441 static zfs_ioc_vec_t zfs_ioc_vec[] = { |
1442 { zfs_ioc_pool_create, zfs_secpolicy_config, pool_name }, | |
1443 { zfs_ioc_pool_destroy, zfs_secpolicy_config, pool_name }, | |
1444 { zfs_ioc_pool_import, zfs_secpolicy_config, pool_name }, | |
1445 { zfs_ioc_pool_export, zfs_secpolicy_config, pool_name }, | |
1446 { zfs_ioc_pool_configs, zfs_secpolicy_none, no_name }, | |
1447 { zfs_ioc_pool_stats, zfs_secpolicy_read, pool_name }, | |
1448 { zfs_ioc_pool_tryimport, zfs_secpolicy_config, no_name }, | |
1449 { zfs_ioc_pool_scrub, zfs_secpolicy_config, pool_name }, | |
1450 { zfs_ioc_pool_freeze, zfs_secpolicy_config, no_name }, | |
1760 | 1451 { zfs_ioc_pool_upgrade, zfs_secpolicy_config, pool_name }, |
2926 | 1452 { zfs_ioc_pool_get_history, zfs_secpolicy_config, pool_name }, |
1453 { zfs_ioc_pool_log_history, zfs_secpolicy_config, pool_name }, | |
789 | 1454 { zfs_ioc_vdev_add, zfs_secpolicy_config, pool_name }, |
1455 { zfs_ioc_vdev_remove, zfs_secpolicy_config, pool_name }, | |
1456 { zfs_ioc_vdev_online, zfs_secpolicy_config, pool_name }, | |
1457 { zfs_ioc_vdev_offline, zfs_secpolicy_config, pool_name }, | |
1458 { zfs_ioc_vdev_attach, zfs_secpolicy_config, pool_name }, | |
1459 { zfs_ioc_vdev_detach, zfs_secpolicy_config, pool_name }, | |
1354
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1460 { zfs_ioc_vdev_setpath, zfs_secpolicy_config, pool_name }, |
789 | 1461 { zfs_ioc_objset_stats, zfs_secpolicy_read, dataset_name }, |
1462 { zfs_ioc_dataset_list_next, zfs_secpolicy_read, dataset_name }, | |
1463 { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, dataset_name }, | |
2676 | 1464 { zfs_ioc_set_prop, zfs_secpolicy_write, dataset_name }, |
789 | 1465 { zfs_ioc_create_minor, zfs_secpolicy_config, dataset_name }, |
1466 { zfs_ioc_remove_minor, zfs_secpolicy_config, dataset_name }, | |
1467 { zfs_ioc_create, zfs_secpolicy_parent, dataset_name }, | |
1468 { zfs_ioc_destroy, zfs_secpolicy_parent, dataset_name }, | |
1469 { zfs_ioc_rollback, zfs_secpolicy_write, dataset_name }, | |
1470 { zfs_ioc_rename, zfs_secpolicy_write, dataset_name }, | |
1471 { zfs_ioc_recvbackup, zfs_secpolicy_write, dataset_name }, | |
1472 { zfs_ioc_sendbackup, zfs_secpolicy_write, dataset_name }, | |
1544 | 1473 { zfs_ioc_inject_fault, zfs_secpolicy_inject, no_name }, |
1474 { zfs_ioc_clear_fault, zfs_secpolicy_inject, no_name }, | |
1475 { zfs_ioc_inject_list_next, zfs_secpolicy_inject, no_name }, | |
1476 { zfs_ioc_error_log, zfs_secpolicy_inject, pool_name }, | |
1477 { zfs_ioc_clear, zfs_secpolicy_config, pool_name }, | |
2199 | 1478 { zfs_ioc_promote, zfs_secpolicy_write, dataset_name }, |
1479 { zfs_ioc_destroy_snaps, zfs_secpolicy_write, dataset_name }, | |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
1480 { zfs_ioc_snapshot, zfs_secpolicy_write, dataset_name }, |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
1481 { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, pool_name }, |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
1482 { zfs_ioc_obj_to_path, zfs_secpolicy_config, no_name } |
789 | 1483 }; |
1484 | |
1485 static int | |
1486 zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) | |
1487 { | |
1488 zfs_cmd_t *zc; | |
1489 uint_t vec; | |
2199 | 1490 int error, rc; |
789 | 1491 |
1492 if (getminor(dev) != 0) | |
1493 return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); | |
1494 | |
1495 vec = cmd - ZFS_IOC; | |
1496 | |
1497 if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) | |
1498 return (EINVAL); | |
1499 | |
1500 zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); | |
1501 | |
1502 error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); | |
1503 | |
1504 if (error == 0) { | |
1505 zc->zc_cred = (uintptr_t)cr; | |
1506 zc->zc_dev = dev; | |
2676 | 1507 error = zfs_ioc_vec[vec].zvec_secpolicy(zc->zc_name, cr); |
789 | 1508 } |
1509 | |
1510 /* | |
1511 * Ensure that all pool/dataset names are valid before we pass down to | |
1512 * the lower layers. | |
1513 */ | |
1514 if (error == 0) { | |
1515 zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; | |
1516 switch (zfs_ioc_vec[vec].zvec_namecheck) { | |
1517 case pool_name: | |
1518 if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) | |
1519 error = EINVAL; | |
1520 break; | |
1521 | |
1522 case dataset_name: | |
1523 if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) | |
1524 error = EINVAL; | |
1525 break; | |
2856 | 1526 |
1527 case no_name: | |
1528 break; | |
789 | 1529 } |
1530 } | |
1531 | |
1532 if (error == 0) | |
1533 error = zfs_ioc_vec[vec].zvec_func(zc); | |
1534 | |
2199 | 1535 rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); |
1536 if (error == 0) | |
1537 error = rc; | |
789 | 1538 |
1539 kmem_free(zc, sizeof (zfs_cmd_t)); | |
1540 return (error); | |
1541 } | |
1542 | |
1543 static int | |
1544 zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) | |
1545 { | |
1546 if (cmd != DDI_ATTACH) | |
1547 return (DDI_FAILURE); | |
1548 | |
1549 if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, | |
1550 DDI_PSEUDO, 0) == DDI_FAILURE) | |
1551 return (DDI_FAILURE); | |
1552 | |
1553 zfs_dip = dip; | |
1554 | |
1555 ddi_report_dev(dip); | |
1556 | |
1557 return (DDI_SUCCESS); | |
1558 } | |
1559 | |
1560 static int | |
1561 zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) | |
1562 { | |
1563 if (spa_busy() || zfs_busy() || zvol_busy()) | |
1564 return (DDI_FAILURE); | |
1565 | |
1566 if (cmd != DDI_DETACH) | |
1567 return (DDI_FAILURE); | |
1568 | |
1569 zfs_dip = NULL; | |
1570 | |
1571 ddi_prop_remove_all(dip); | |
1572 ddi_remove_minor_node(dip, NULL); | |
1573 | |
1574 return (DDI_SUCCESS); | |
1575 } | |
1576 | |
1577 /*ARGSUSED*/ | |
1578 static int | |
1579 zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) | |
1580 { | |
1581 switch (infocmd) { | |
1582 case DDI_INFO_DEVT2DEVINFO: | |
1583 *result = zfs_dip; | |
1584 return (DDI_SUCCESS); | |
1585 | |
1586 case DDI_INFO_DEVT2INSTANCE: | |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1587 *result = (void *)0; |
789 | 1588 return (DDI_SUCCESS); |
1589 } | |
1590 | |
1591 return (DDI_FAILURE); | |
1592 } | |
1593 | |
1594 /* | |
1595 * OK, so this is a little weird. | |
1596 * | |
1597 * /dev/zfs is the control node, i.e. minor 0. | |
1598 * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. | |
1599 * | |
1600 * /dev/zfs has basically nothing to do except serve up ioctls, | |
1601 * so most of the standard driver entry points are in zvol.c. | |
1602 */ | |
1603 static struct cb_ops zfs_cb_ops = { | |
1604 zvol_open, /* open */ | |
1605 zvol_close, /* close */ | |
1606 zvol_strategy, /* strategy */ | |
1607 nodev, /* print */ | |
1608 nodev, /* dump */ | |
1609 zvol_read, /* read */ | |
1610 zvol_write, /* write */ | |
1611 zfsdev_ioctl, /* ioctl */ | |
1612 nodev, /* devmap */ | |
1613 nodev, /* mmap */ | |
1614 nodev, /* segmap */ | |
1615 nochpoll, /* poll */ | |
1616 ddi_prop_op, /* prop_op */ | |
1617 NULL, /* streamtab */ | |
1618 D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ | |
1619 CB_REV, /* version */ | |
1620 zvol_aread, /* async read */ | |
1621 zvol_awrite, /* async write */ | |
1622 }; | |
1623 | |
1624 static struct dev_ops zfs_dev_ops = { | |
1625 DEVO_REV, /* version */ | |
1626 0, /* refcnt */ | |
1627 zfs_info, /* info */ | |
1628 nulldev, /* identify */ | |
1629 nulldev, /* probe */ | |
1630 zfs_attach, /* attach */ | |
1631 zfs_detach, /* detach */ | |
1632 nodev, /* reset */ | |
1633 &zfs_cb_ops, /* driver operations */ | |
1634 NULL /* no bus operations */ | |
1635 }; | |
1636 | |
1637 static struct modldrv zfs_modldrv = { | |
2676 | 1638 &mod_driverops, "ZFS storage pool version " ZFS_VERSION_STRING, |
1639 &zfs_dev_ops | |
789 | 1640 }; |
1641 | |
1642 static struct modlinkage modlinkage = { | |
1643 MODREV_1, | |
1644 (void *)&zfs_modlfs, | |
1645 (void *)&zfs_modldrv, | |
1646 NULL | |
1647 }; | |
1648 | |
1649 int | |
1650 _init(void) | |
1651 { | |
1652 int error; | |
1653 | |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1654 spa_init(FREAD | FWRITE); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1655 zfs_init(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1656 zvol_init(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1657 |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1658 if ((error = mod_install(&modlinkage)) != 0) { |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1659 zvol_fini(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1660 zfs_fini(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1661 spa_fini(); |
789 | 1662 return (error); |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
1663 } |
789 | 1664 |
1665 error = ldi_ident_from_mod(&modlinkage, &zfs_li); | |
1666 ASSERT(error == 0); | |
1667 | |
1668 return (0); | |
1669 } | |
1670 | |
1671 int | |
1672 _fini(void) | |
1673 { | |
1674 int error; | |
1675 | |
1544 | 1676 if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) |
789 | 1677 return (EBUSY); |
1678 | |
1679 if ((error = mod_remove(&modlinkage)) != 0) | |
1680 return (error); | |
1681 | |
1682 zvol_fini(); | |
1683 zfs_fini(); | |
1684 spa_fini(); | |
1685 | |
1686 ldi_ident_release(zfs_li); | |
1687 zfs_li = NULL; | |
1688 | |
1689 return (error); | |
1690 } | |
1691 | |
1692 int | |
1693 _info(struct modinfo *modinfop) | |
1694 { | |
1695 return (mod_info(&modlinkage, modinfop)); | |
1696 } |