Mercurial > illumos > illumos-gate
annotate usr/src/uts/common/fs/zfs/zfs_ioctl.c @ 5378:111aa1baa84a onnv_77
PSARC 2007/555 zfs fs-only quotas and reservations
6431277 want filesystem-only quotas
6483677 need immediate reservation
author | ck153898 |
---|---|
date | Mon, 29 Oct 2007 22:45:33 -0700 |
parents | c682f8c5f5e3 |
children | 51fbc14b301d |
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> | |
5331 | 41 #include <sys/zfs_i18n.h> |
42 #include <sys/zfs_znode.h> | |
789 | 43 #include <sys/zap.h> |
44 #include <sys/spa.h> | |
3912 | 45 #include <sys/spa_impl.h> |
789 | 46 #include <sys/vdev.h> |
3912 | 47 #include <sys/vdev_impl.h> |
789 | 48 #include <sys/dmu.h> |
49 #include <sys/dsl_dir.h> | |
50 #include <sys/dsl_dataset.h> | |
51 #include <sys/dsl_prop.h> | |
4543 | 52 #include <sys/dsl_deleg.h> |
53 #include <sys/dmu_objset.h> | |
789 | 54 #include <sys/ddi.h> |
55 #include <sys/sunddi.h> | |
56 #include <sys/sunldi.h> | |
57 #include <sys/policy.h> | |
58 #include <sys/zone.h> | |
59 #include <sys/nvpair.h> | |
60 #include <sys/pathname.h> | |
61 #include <sys/mount.h> | |
62 #include <sys/sdt.h> | |
63 #include <sys/fs/zfs.h> | |
64 #include <sys/zfs_ctldir.h> | |
5331 | 65 #include <sys/zfs_dir.h> |
2885 | 66 #include <sys/zvol.h> |
4543 | 67 #include <sharefs/share.h> |
4577 | 68 #include <sys/zfs_znode.h> |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
69 #include <sys/zfs_vfsops.h> |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
70 #include <sys/dmu_objset.h> |
789 | 71 |
72 #include "zfs_namecheck.h" | |
2676 | 73 #include "zfs_prop.h" |
4543 | 74 #include "zfs_deleg.h" |
789 | 75 |
76 extern struct modlfs zfs_modlfs; | |
77 | |
78 extern void zfs_init(void); | |
79 extern void zfs_fini(void); | |
80 | |
81 ldi_ident_t zfs_li = NULL; | |
82 dev_info_t *zfs_dip; | |
83 | |
84 typedef int zfs_ioc_func_t(zfs_cmd_t *); | |
4543 | 85 typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *); |
789 | 86 |
87 typedef struct zfs_ioc_vec { | |
88 zfs_ioc_func_t *zvec_func; | |
89 zfs_secpolicy_func_t *zvec_secpolicy; | |
90 enum { | |
4577 | 91 NO_NAME, |
92 POOL_NAME, | |
93 DATASET_NAME | |
4543 | 94 } zvec_namecheck; |
95 boolean_t zvec_his_log; | |
789 | 96 } zfs_ioc_vec_t; |
97 | |
98 /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */ | |
99 void | |
100 __dprintf(const char *file, const char *func, int line, const char *fmt, ...) | |
101 { | |
102 const char *newfile; | |
103 char buf[256]; | |
104 va_list adx; | |
105 | |
106 /* | |
107 * Get rid of annoying "../common/" prefix to filename. | |
108 */ | |
109 newfile = strrchr(file, '/'); | |
110 if (newfile != NULL) { | |
111 newfile = newfile + 1; /* Get rid of leading / */ | |
112 } else { | |
113 newfile = file; | |
114 } | |
115 | |
116 va_start(adx, fmt); | |
117 (void) vsnprintf(buf, sizeof (buf), fmt, adx); | |
118 va_end(adx); | |
119 | |
120 /* | |
121 * To get this data, use the zfs-dprintf probe as so: | |
122 * dtrace -q -n 'zfs-dprintf \ | |
123 * /stringof(arg0) == "dbuf.c"/ \ | |
124 * {printf("%s: %s", stringof(arg1), stringof(arg3))}' | |
125 * arg0 = file name | |
126 * arg1 = function name | |
127 * arg2 = line number | |
128 * arg3 = message | |
129 */ | |
130 DTRACE_PROBE4(zfs__dprintf, | |
131 char *, newfile, char *, func, int, line, char *, buf); | |
132 } | |
133 | |
4543 | 134 static void |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
135 history_str_free(char *buf) |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
136 { |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
137 kmem_free(buf, HIS_MAX_RECORD_LEN); |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
138 } |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
139 |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
140 static char * |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
141 history_str_get(zfs_cmd_t *zc) |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
142 { |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
143 char *buf; |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
144 |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
145 if (zc->zc_history == NULL) |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
146 return (NULL); |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
147 |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
148 buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
149 if (copyinstr((void *)(uintptr_t)zc->zc_history, |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
150 buf, HIS_MAX_RECORD_LEN, NULL) != 0) { |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
151 history_str_free(buf); |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
152 return (NULL); |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
153 } |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
154 |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
155 buf[HIS_MAX_RECORD_LEN -1] = '\0'; |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
156 |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
157 return (buf); |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
158 } |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
159 |
5375 | 160 /* |
161 * zfs_check_version | |
162 * | |
163 * Return non-zero if the spa version is less than requested version. | |
164 */ | |
5331 | 165 static int |
166 zfs_check_version(const char *name, int version) | |
167 { | |
168 | |
169 spa_t *spa; | |
170 | |
171 if (spa_open(name, &spa, FTAG) == 0) { | |
172 if (spa_version(spa) < version) { | |
173 spa_close(spa, FTAG); | |
174 return (1); | |
175 } | |
176 spa_close(spa, FTAG); | |
177 } | |
178 return (0); | |
179 } | |
180 | |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
181 static void |
4543 | 182 zfs_log_history(zfs_cmd_t *zc) |
183 { | |
184 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
|
185 char *buf; |
4543 | 186 |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
187 if ((buf = history_str_get(zc)) == NULL) |
4577 | 188 return; |
189 | |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
190 if (spa_open(zc->zc_name, &spa, FTAG) == 0) { |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
191 if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
192 (void) spa_history_log(spa, buf, LOG_CMD_NORMAL); |
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
193 spa_close(spa, FTAG); |
4543 | 194 } |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
195 history_str_free(buf); |
4543 | 196 } |
197 | |
789 | 198 /* |
199 * Policy for top-level read operations (list pools). Requires no privileges, | |
200 * and can be used in the local zone, as there is no associated dataset. | |
201 */ | |
202 /* ARGSUSED */ | |
203 static int | |
4543 | 204 zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr) |
789 | 205 { |
206 return (0); | |
207 } | |
208 | |
209 /* | |
210 * Policy for dataset read operations (list children, get statistics). Requires | |
211 * no privileges, but must be visible in the local zone. | |
212 */ | |
213 /* ARGSUSED */ | |
214 static int | |
4543 | 215 zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr) |
789 | 216 { |
217 if (INGLOBALZONE(curproc) || | |
4543 | 218 zone_dataset_visible(zc->zc_name, NULL)) |
789 | 219 return (0); |
220 | |
221 return (ENOENT); | |
222 } | |
223 | |
224 static int | |
225 zfs_dozonecheck(const char *dataset, cred_t *cr) | |
226 { | |
227 uint64_t zoned; | |
228 int writable = 1; | |
229 | |
230 /* | |
231 * The dataset must be visible by this zone -- check this first | |
232 * so they don't see EPERM on something they shouldn't know about. | |
233 */ | |
234 if (!INGLOBALZONE(curproc) && | |
235 !zone_dataset_visible(dataset, &writable)) | |
236 return (ENOENT); | |
237 | |
238 if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL)) | |
239 return (ENOENT); | |
240 | |
241 if (INGLOBALZONE(curproc)) { | |
242 /* | |
243 * If the fs is zoned, only root can access it from the | |
244 * global zone. | |
245 */ | |
246 if (secpolicy_zfs(cr) && zoned) | |
247 return (EPERM); | |
248 } else { | |
249 /* | |
250 * If we are in a local zone, the 'zoned' property must be set. | |
251 */ | |
252 if (!zoned) | |
253 return (EPERM); | |
254 | |
255 /* must be writable by this zone */ | |
256 if (!writable) | |
257 return (EPERM); | |
258 } | |
259 return (0); | |
260 } | |
261 | |
262 int | |
4543 | 263 zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr) |
789 | 264 { |
265 int error; | |
266 | |
4543 | 267 error = zfs_dozonecheck(name, cr); |
268 if (error == 0) { | |
269 error = secpolicy_zfs(cr); | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
270 if (error) |
4543 | 271 error = dsl_deleg_access(name, perm, cr); |
272 } | |
273 return (error); | |
274 } | |
275 | |
276 static int | |
277 zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr) | |
278 { | |
279 /* | |
280 * Check permissions for special properties. | |
281 */ | |
282 switch (prop) { | |
283 case ZFS_PROP_ZONED: | |
284 /* | |
285 * Disallow setting of 'zoned' from within a local zone. | |
286 */ | |
287 if (!INGLOBALZONE(curproc)) | |
288 return (EPERM); | |
289 break; | |
789 | 290 |
4543 | 291 case ZFS_PROP_QUOTA: |
292 if (!INGLOBALZONE(curproc)) { | |
293 uint64_t zoned; | |
294 char setpoint[MAXNAMELEN]; | |
295 /* | |
296 * Unprivileged users are allowed to modify the | |
297 * quota on things *under* (ie. contained by) | |
298 * the thing they own. | |
299 */ | |
300 if (dsl_prop_get_integer(name, "zoned", &zoned, | |
301 setpoint)) | |
302 return (EPERM); | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
303 if (!zoned || strlen(name) <= strlen(setpoint)) |
4543 | 304 return (EPERM); |
305 } | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
306 break; |
4543 | 307 } |
308 | |
4787 | 309 return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr)); |
789 | 310 } |
311 | |
4543 | 312 int |
313 zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr) | |
314 { | |
315 int error; | |
316 | |
317 error = zfs_dozonecheck(zc->zc_name, cr); | |
318 if (error) | |
319 return (error); | |
320 | |
321 /* | |
322 * permission to set permissions will be evaluated later in | |
323 * dsl_deleg_can_allow() | |
324 */ | |
325 return (0); | |
326 } | |
327 | |
328 int | |
329 zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr) | |
330 { | |
331 int error; | |
332 error = zfs_secpolicy_write_perms(zc->zc_name, | |
333 ZFS_DELEG_PERM_ROLLBACK, cr); | |
334 if (error == 0) | |
335 error = zfs_secpolicy_write_perms(zc->zc_name, | |
336 ZFS_DELEG_PERM_MOUNT, cr); | |
337 return (error); | |
338 } | |
339 | |
340 int | |
341 zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr) | |
342 { | |
343 return (zfs_secpolicy_write_perms(zc->zc_name, | |
344 ZFS_DELEG_PERM_SEND, cr)); | |
345 } | |
346 | |
347 int | |
348 zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr) | |
349 { | |
350 if (!INGLOBALZONE(curproc)) | |
351 return (EPERM); | |
352 | |
5367 | 353 if (secpolicy_nfs(cr) == 0) { |
4543 | 354 return (0); |
355 } else { | |
356 vnode_t *vp; | |
357 int error; | |
358 | |
359 if ((error = lookupname(zc->zc_value, UIO_SYSSPACE, | |
360 NO_FOLLOW, NULL, &vp)) != 0) | |
361 return (error); | |
362 | |
363 /* Now make sure mntpnt and dataset are ZFS */ | |
364 | |
365 if (vp->v_vfsp->vfs_fstype != zfsfstype || | |
366 (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource), | |
367 zc->zc_name) != 0)) { | |
368 VN_RELE(vp); | |
369 return (EPERM); | |
370 } | |
371 | |
372 VN_RELE(vp); | |
373 return (dsl_deleg_access(zc->zc_name, | |
374 ZFS_DELEG_PERM_SHARE, cr)); | |
375 } | |
376 } | |
377 | |
789 | 378 static int |
4543 | 379 zfs_get_parent(const char *datasetname, char *parent, int parentsize) |
789 | 380 { |
381 char *cp; | |
382 | |
383 /* | |
384 * Remove the @bla or /bla from the end of the name to get the parent. | |
385 */ | |
4543 | 386 (void) strncpy(parent, datasetname, parentsize); |
387 cp = strrchr(parent, '@'); | |
789 | 388 if (cp != NULL) { |
389 cp[0] = '\0'; | |
390 } else { | |
4543 | 391 cp = strrchr(parent, '/'); |
789 | 392 if (cp == NULL) |
393 return (ENOENT); | |
394 cp[0] = '\0'; | |
395 } | |
396 | |
4543 | 397 return (0); |
398 } | |
399 | |
400 int | |
401 zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) | |
402 { | |
403 int error; | |
404 | |
405 if ((error = zfs_secpolicy_write_perms(name, | |
406 ZFS_DELEG_PERM_MOUNT, cr)) != 0) | |
407 return (error); | |
408 | |
409 return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr)); | |
410 } | |
411 | |
412 static int | |
413 zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr) | |
414 { | |
415 return (zfs_secpolicy_destroy_perms(zc->zc_name, cr)); | |
416 } | |
417 | |
418 /* | |
419 * Must have sys_config privilege to check the iscsi permission | |
420 */ | |
421 /* ARGSUSED */ | |
422 static int | |
423 zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) | |
424 { | |
425 return (secpolicy_zfs(cr)); | |
426 } | |
427 | |
428 int | |
429 zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) | |
430 { | |
431 char parentname[MAXNAMELEN]; | |
432 int error; | |
433 | |
434 if ((error = zfs_secpolicy_write_perms(from, | |
435 ZFS_DELEG_PERM_RENAME, cr)) != 0) | |
436 return (error); | |
437 | |
438 if ((error = zfs_secpolicy_write_perms(from, | |
439 ZFS_DELEG_PERM_MOUNT, cr)) != 0) | |
440 return (error); | |
441 | |
442 if ((error = zfs_get_parent(to, parentname, | |
443 sizeof (parentname))) != 0) | |
444 return (error); | |
445 | |
446 if ((error = zfs_secpolicy_write_perms(parentname, | |
447 ZFS_DELEG_PERM_CREATE, cr)) != 0) | |
448 return (error); | |
449 | |
450 if ((error = zfs_secpolicy_write_perms(parentname, | |
451 ZFS_DELEG_PERM_MOUNT, cr)) != 0) | |
452 return (error); | |
453 | |
454 return (error); | |
455 } | |
456 | |
457 static int | |
458 zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr) | |
459 { | |
460 return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr)); | |
461 } | |
462 | |
463 static int | |
464 zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr) | |
465 { | |
466 char parentname[MAXNAMELEN]; | |
467 objset_t *clone; | |
468 int error; | |
469 | |
470 error = zfs_secpolicy_write_perms(zc->zc_name, | |
471 ZFS_DELEG_PERM_PROMOTE, cr); | |
472 if (error) | |
473 return (error); | |
474 | |
475 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, | |
476 DS_MODE_STANDARD | DS_MODE_READONLY, &clone); | |
477 | |
478 if (error == 0) { | |
479 dsl_dataset_t *pclone = NULL; | |
480 dsl_dir_t *dd; | |
481 dd = clone->os->os_dsl_dataset->ds_dir; | |
482 | |
483 rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); | |
484 error = dsl_dataset_open_obj(dd->dd_pool, | |
5367 | 485 dd->dd_phys->dd_origin_obj, NULL, |
4543 | 486 DS_MODE_NONE, FTAG, &pclone); |
487 rw_exit(&dd->dd_pool->dp_config_rwlock); | |
488 if (error) { | |
489 dmu_objset_close(clone); | |
490 return (error); | |
491 } | |
492 | |
493 error = zfs_secpolicy_write_perms(zc->zc_name, | |
494 ZFS_DELEG_PERM_MOUNT, cr); | |
495 | |
496 dsl_dataset_name(pclone, parentname); | |
497 dmu_objset_close(clone); | |
498 dsl_dataset_close(pclone, DS_MODE_NONE, FTAG); | |
499 if (error == 0) | |
500 error = zfs_secpolicy_write_perms(parentname, | |
501 ZFS_DELEG_PERM_PROMOTE, cr); | |
502 } | |
503 return (error); | |
504 } | |
505 | |
506 static int | |
507 zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr) | |
508 { | |
509 int error; | |
510 | |
511 if ((error = zfs_secpolicy_write_perms(zc->zc_name, | |
512 ZFS_DELEG_PERM_RECEIVE, cr)) != 0) | |
513 return (error); | |
514 | |
515 if ((error = zfs_secpolicy_write_perms(zc->zc_name, | |
516 ZFS_DELEG_PERM_MOUNT, cr)) != 0) | |
517 return (error); | |
518 | |
519 return (zfs_secpolicy_write_perms(zc->zc_name, | |
520 ZFS_DELEG_PERM_CREATE, cr)); | |
521 } | |
522 | |
523 int | |
524 zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) | |
525 { | |
526 int error; | |
527 | |
528 if ((error = zfs_secpolicy_write_perms(name, | |
529 ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0) | |
530 return (error); | |
531 | |
532 error = zfs_secpolicy_write_perms(name, | |
533 ZFS_DELEG_PERM_MOUNT, cr); | |
534 | |
535 return (error); | |
536 } | |
537 | |
538 static int | |
539 zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) | |
540 { | |
541 | |
542 return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); | |
543 } | |
544 | |
545 static int | |
546 zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) | |
547 { | |
548 char parentname[MAXNAMELEN]; | |
549 int error; | |
550 | |
551 if ((error = zfs_get_parent(zc->zc_name, parentname, | |
552 sizeof (parentname))) != 0) | |
553 return (error); | |
554 | |
555 if (zc->zc_value[0] != '\0') { | |
556 if ((error = zfs_secpolicy_write_perms(zc->zc_value, | |
557 ZFS_DELEG_PERM_CLONE, cr)) != 0) | |
558 return (error); | |
559 } | |
560 | |
561 if ((error = zfs_secpolicy_write_perms(parentname, | |
562 ZFS_DELEG_PERM_CREATE, cr)) != 0) | |
563 return (error); | |
564 | |
565 error = zfs_secpolicy_write_perms(parentname, | |
566 ZFS_DELEG_PERM_MOUNT, cr); | |
567 | |
568 return (error); | |
569 } | |
570 | |
571 static int | |
572 zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr) | |
573 { | |
574 int error; | |
575 | |
576 error = secpolicy_fs_unmount(cr, NULL); | |
577 if (error) { | |
578 error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr); | |
579 } | |
580 return (error); | |
789 | 581 } |
582 | |
583 /* | |
584 * Policy for pool operations - create/destroy pools, add vdevs, etc. Requires | |
585 * SYS_CONFIG privilege, which is not available in a local zone. | |
586 */ | |
587 /* ARGSUSED */ | |
588 static int | |
4543 | 589 zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr) |
789 | 590 { |
591 if (secpolicy_sys_config(cr, B_FALSE) != 0) | |
592 return (EPERM); | |
593 | |
594 return (0); | |
595 } | |
596 | |
597 /* | |
4543 | 598 * Just like zfs_secpolicy_config, except that we will check for |
599 * mount permission on the dataset for permission to create/remove | |
600 * the minor nodes. | |
601 */ | |
602 static int | |
603 zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr) | |
604 { | |
605 if (secpolicy_sys_config(cr, B_FALSE) != 0) { | |
606 return (dsl_deleg_access(zc->zc_name, | |
607 ZFS_DELEG_PERM_MOUNT, cr)); | |
608 } | |
609 | |
610 return (0); | |
611 } | |
612 | |
613 /* | |
1544 | 614 * Policy for fault injection. Requires all privileges. |
615 */ | |
616 /* ARGSUSED */ | |
617 static int | |
4543 | 618 zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr) |
1544 | 619 { |
620 return (secpolicy_zinject(cr)); | |
621 } | |
622 | |
4849
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
623 static int |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
624 zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr) |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
625 { |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
626 zfs_prop_t prop = zfs_name_to_prop(zc->zc_value); |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
627 |
5094 | 628 if (prop == ZPROP_INVAL) { |
4849
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
629 if (!zfs_prop_user(zc->zc_value)) |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
630 return (EINVAL); |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
631 return (zfs_secpolicy_write_perms(zc->zc_name, |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
632 ZFS_DELEG_PERM_USERPROP, cr)); |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
633 } else { |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
634 if (!zfs_prop_inheritable(prop)) |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
635 return (EINVAL); |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
636 return (zfs_secpolicy_setprop(zc->zc_name, prop, cr)); |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
637 } |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
638 } |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
639 |
1544 | 640 /* |
789 | 641 * Returns the nvlist as specified by the user in the zfs_cmd_t. |
642 */ | |
643 static int | |
5094 | 644 get_nvlist(uint64_t nvl, uint64_t size, nvlist_t **nvp) |
789 | 645 { |
646 char *packed; | |
647 int error; | |
5094 | 648 nvlist_t *list = NULL; |
789 | 649 |
650 /* | |
2676 | 651 * Read in and unpack the user-supplied nvlist. |
789 | 652 */ |
5094 | 653 if (size == 0) |
789 | 654 return (EINVAL); |
655 | |
656 packed = kmem_alloc(size, KM_SLEEP); | |
657 | |
5094 | 658 if ((error = xcopyin((void *)(uintptr_t)nvl, packed, size)) != 0) { |
789 | 659 kmem_free(packed, size); |
660 return (error); | |
661 } | |
662 | |
5094 | 663 if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) { |
789 | 664 kmem_free(packed, size); |
665 return (error); | |
666 } | |
667 | |
668 kmem_free(packed, size); | |
669 | |
5094 | 670 *nvp = list; |
789 | 671 return (0); |
672 } | |
673 | |
674 static int | |
2676 | 675 put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl) |
676 { | |
677 char *packed = NULL; | |
678 size_t size; | |
679 int error; | |
680 | |
681 VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0); | |
682 | |
683 if (size > zc->zc_nvlist_dst_size) { | |
684 error = ENOMEM; | |
685 } else { | |
4611 | 686 packed = kmem_alloc(size, KM_SLEEP); |
2676 | 687 VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE, |
688 KM_SLEEP) == 0); | |
689 error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst, | |
690 size); | |
691 kmem_free(packed, size); | |
692 } | |
693 | |
694 zc->zc_nvlist_dst_size = size; | |
695 return (error); | |
696 } | |
697 | |
698 static int | |
789 | 699 zfs_ioc_pool_create(zfs_cmd_t *zc) |
700 { | |
701 int error; | |
5094 | 702 nvlist_t *config, *props = NULL; |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
703 char *buf; |
789 | 704 |
5094 | 705 if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, |
706 &config)) | |
4988
db8abd9846d4
6595467 libzfs consumers should be allowed to write their own history (or none at all)
ek110237
parents:
4849
diff
changeset
|
707 return (error); |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
708 |
5094 | 709 if (zc->zc_nvlist_src_size != 0 && (error = |
710 get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { | |
711 nvlist_free(config); | |
712 return (error); | |
713 } | |
714 | |
4988
db8abd9846d4
6595467 libzfs consumers should be allowed to write their own history (or none at all)
ek110237
parents:
4849
diff
changeset
|
715 buf = history_str_get(zc); |
789 | 716 |
5094 | 717 error = spa_create(zc->zc_name, config, props, buf); |
789 | 718 |
4988
db8abd9846d4
6595467 libzfs consumers should be allowed to write their own history (or none at all)
ek110237
parents:
4849
diff
changeset
|
719 if (buf != NULL) |
db8abd9846d4
6595467 libzfs consumers should be allowed to write their own history (or none at all)
ek110237
parents:
4849
diff
changeset
|
720 history_str_free(buf); |
5094 | 721 |
789 | 722 nvlist_free(config); |
723 | |
5094 | 724 if (props) |
725 nvlist_free(props); | |
726 | |
789 | 727 return (error); |
728 } | |
729 | |
730 static int | |
731 zfs_ioc_pool_destroy(zfs_cmd_t *zc) | |
732 { | |
4543 | 733 int error; |
734 zfs_log_history(zc); | |
735 error = spa_destroy(zc->zc_name); | |
736 return (error); | |
789 | 737 } |
738 | |
739 static int | |
740 zfs_ioc_pool_import(zfs_cmd_t *zc) | |
741 { | |
742 int error; | |
5094 | 743 nvlist_t *config, *props = NULL; |
789 | 744 uint64_t guid; |
745 | |
5094 | 746 if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, |
747 &config)) != 0) | |
789 | 748 return (error); |
749 | |
5094 | 750 if (zc->zc_nvlist_src_size != 0 && (error = |
751 get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) { | |
752 nvlist_free(config); | |
753 return (error); | |
754 } | |
755 | |
789 | 756 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 || |
1544 | 757 guid != zc->zc_guid) |
789 | 758 error = EINVAL; |
759 else | |
5094 | 760 error = spa_import(zc->zc_name, config, props); |
789 | 761 |
762 nvlist_free(config); | |
763 | |
5094 | 764 if (props) |
765 nvlist_free(props); | |
766 | |
789 | 767 return (error); |
768 } | |
769 | |
770 static int | |
771 zfs_ioc_pool_export(zfs_cmd_t *zc) | |
772 { | |
4543 | 773 int error; |
774 zfs_log_history(zc); | |
775 error = spa_export(zc->zc_name, NULL); | |
776 return (error); | |
789 | 777 } |
778 | |
779 static int | |
780 zfs_ioc_pool_configs(zfs_cmd_t *zc) | |
781 { | |
782 nvlist_t *configs; | |
783 int error; | |
784 | |
785 if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL) | |
786 return (EEXIST); | |
787 | |
2676 | 788 error = put_nvlist(zc, configs); |
789 | 789 |
790 nvlist_free(configs); | |
791 | |
792 return (error); | |
793 } | |
794 | |
795 static int | |
796 zfs_ioc_pool_stats(zfs_cmd_t *zc) | |
797 { | |
798 nvlist_t *config; | |
799 int error; | |
1544 | 800 int ret = 0; |
789 | 801 |
2676 | 802 error = spa_get_stats(zc->zc_name, &config, zc->zc_value, |
803 sizeof (zc->zc_value)); | |
789 | 804 |
805 if (config != NULL) { | |
2676 | 806 ret = put_nvlist(zc, config); |
789 | 807 nvlist_free(config); |
1544 | 808 |
809 /* | |
810 * The config may be present even if 'error' is non-zero. | |
811 * In this case we return success, and preserve the real errno | |
812 * in 'zc_cookie'. | |
813 */ | |
814 zc->zc_cookie = error; | |
789 | 815 } else { |
1544 | 816 ret = error; |
789 | 817 } |
818 | |
1544 | 819 return (ret); |
789 | 820 } |
821 | |
822 /* | |
823 * Try to import the given pool, returning pool stats as appropriate so that | |
824 * user land knows which devices are available and overall pool health. | |
825 */ | |
826 static int | |
827 zfs_ioc_pool_tryimport(zfs_cmd_t *zc) | |
828 { | |
829 nvlist_t *tryconfig, *config; | |
830 int error; | |
831 | |
5094 | 832 if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, |
833 &tryconfig)) != 0) | |
789 | 834 return (error); |
835 | |
836 config = spa_tryimport(tryconfig); | |
837 | |
838 nvlist_free(tryconfig); | |
839 | |
840 if (config == NULL) | |
841 return (EINVAL); | |
842 | |
2676 | 843 error = put_nvlist(zc, config); |
789 | 844 nvlist_free(config); |
845 | |
846 return (error); | |
847 } | |
848 | |
849 static int | |
850 zfs_ioc_pool_scrub(zfs_cmd_t *zc) | |
851 { | |
852 spa_t *spa; | |
853 int error; | |
854 | |
2926 | 855 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
856 return (error); | |
857 | |
4808 | 858 mutex_enter(&spa_namespace_lock); |
2926 | 859 error = spa_scrub(spa, zc->zc_cookie, B_FALSE); |
4808 | 860 mutex_exit(&spa_namespace_lock); |
2926 | 861 |
862 spa_close(spa, FTAG); | |
863 | |
789 | 864 return (error); |
865 } | |
866 | |
867 static int | |
868 zfs_ioc_pool_freeze(zfs_cmd_t *zc) | |
869 { | |
870 spa_t *spa; | |
871 int error; | |
872 | |
873 error = spa_open(zc->zc_name, &spa, FTAG); | |
874 if (error == 0) { | |
875 spa_freeze(spa); | |
876 spa_close(spa, FTAG); | |
877 } | |
878 return (error); | |
879 } | |
880 | |
881 static int | |
1760 | 882 zfs_ioc_pool_upgrade(zfs_cmd_t *zc) |
883 { | |
884 spa_t *spa; | |
885 int error; | |
886 | |
2926 | 887 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
888 return (error); | |
889 | |
5118
c723b1aa9f79
6607671 Able to zpool upgrade a pool to an unknown version number
lling
parents:
5094
diff
changeset
|
890 if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) { |
c723b1aa9f79
6607671 Able to zpool upgrade a pool to an unknown version number
lling
parents:
5094
diff
changeset
|
891 spa_close(spa, FTAG); |
c723b1aa9f79
6607671 Able to zpool upgrade a pool to an unknown version number
lling
parents:
5094
diff
changeset
|
892 return (EINVAL); |
c723b1aa9f79
6607671 Able to zpool upgrade a pool to an unknown version number
lling
parents:
5094
diff
changeset
|
893 } |
c723b1aa9f79
6607671 Able to zpool upgrade a pool to an unknown version number
lling
parents:
5094
diff
changeset
|
894 |
5094 | 895 spa_upgrade(spa, zc->zc_cookie); |
2926 | 896 spa_close(spa, FTAG); |
897 | |
898 return (error); | |
899 } | |
900 | |
901 static int | |
902 zfs_ioc_pool_get_history(zfs_cmd_t *zc) | |
903 { | |
904 spa_t *spa; | |
905 char *hist_buf; | |
906 uint64_t size; | |
907 int error; | |
908 | |
909 if ((size = zc->zc_history_len) == 0) | |
910 return (EINVAL); | |
911 | |
912 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
913 return (error); | |
914 | |
4577 | 915 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
|
916 spa_close(spa, FTAG); |
d56571426115
6529406 zpool history needs to bump the on-disk version
ek110237
parents:
3741
diff
changeset
|
917 return (ENOTSUP); |
d56571426115
6529406 zpool history needs to bump the on-disk version
ek110237
parents:
3741
diff
changeset
|
918 } |
d56571426115
6529406 zpool history needs to bump the on-disk version
ek110237
parents:
3741
diff
changeset
|
919 |
2926 | 920 hist_buf = kmem_alloc(size, KM_SLEEP); |
921 if ((error = spa_history_get(spa, &zc->zc_history_offset, | |
922 &zc->zc_history_len, hist_buf)) == 0) { | |
4543 | 923 error = xcopyout(hist_buf, |
924 (char *)(uintptr_t)zc->zc_history, | |
2926 | 925 zc->zc_history_len); |
926 } | |
927 | |
928 spa_close(spa, FTAG); | |
929 kmem_free(hist_buf, size); | |
930 return (error); | |
931 } | |
932 | |
933 static int | |
3444
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
934 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
|
935 { |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
936 int error; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
937 |
3912 | 938 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
|
939 return (error); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
940 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
941 return (0); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
942 } |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
943 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
944 static int |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
945 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
|
946 { |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
947 objset_t *osp; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
948 int error; |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
949 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
950 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
|
951 DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0) |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
952 return (error); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
953 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
954 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
|
955 sizeof (zc->zc_value)); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
956 dmu_objset_close(osp); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
957 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
958 return (error); |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
959 } |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
960 |
dc160a70a50d
6410433 'zpool status -v' would be more useful with filenames
ek110237
parents:
3265
diff
changeset
|
961 static int |
789 | 962 zfs_ioc_vdev_add(zfs_cmd_t *zc) |
963 { | |
964 spa_t *spa; | |
965 int error; | |
966 nvlist_t *config; | |
967 | |
968 error = spa_open(zc->zc_name, &spa, FTAG); | |
969 if (error != 0) | |
970 return (error); | |
971 | |
3912 | 972 /* |
973 * A root pool with concatenated devices is not supported. | |
974 * Thus, can not add a device to a root pool with one device. | |
975 */ | |
976 if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) { | |
977 spa_close(spa, FTAG); | |
978 return (EDOM); | |
979 } | |
980 | |
5094 | 981 if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, |
982 &config)) == 0) { | |
789 | 983 error = spa_vdev_add(spa, config); |
984 nvlist_free(config); | |
985 } | |
986 spa_close(spa, FTAG); | |
987 return (error); | |
988 } | |
989 | |
990 static int | |
991 zfs_ioc_vdev_remove(zfs_cmd_t *zc) | |
992 { | |
2082 | 993 spa_t *spa; |
994 int error; | |
995 | |
996 error = spa_open(zc->zc_name, &spa, FTAG); | |
997 if (error != 0) | |
998 return (error); | |
999 error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE); | |
1000 spa_close(spa, FTAG); | |
1001 return (error); | |
789 | 1002 } |
1003 | |
1004 static int | |
4451 | 1005 zfs_ioc_vdev_set_state(zfs_cmd_t *zc) |
789 | 1006 { |
1007 spa_t *spa; | |
1008 int error; | |
4451 | 1009 vdev_state_t newstate = VDEV_STATE_UNKNOWN; |
789 | 1010 |
2926 | 1011 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
789 | 1012 return (error); |
4451 | 1013 switch (zc->zc_cookie) { |
1014 case VDEV_STATE_ONLINE: | |
1015 error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate); | |
1016 break; | |
1017 | |
1018 case VDEV_STATE_OFFLINE: | |
1019 error = vdev_offline(spa, zc->zc_guid, zc->zc_obj); | |
1020 break; | |
789 | 1021 |
4451 | 1022 case VDEV_STATE_FAULTED: |
1023 error = vdev_fault(spa, zc->zc_guid); | |
1024 break; | |
789 | 1025 |
4451 | 1026 case VDEV_STATE_DEGRADED: |
1027 error = vdev_degrade(spa, zc->zc_guid); | |
1028 break; | |
1029 | |
1030 default: | |
1031 error = EINVAL; | |
1032 } | |
1033 zc->zc_cookie = newstate; | |
789 | 1034 spa_close(spa, FTAG); |
1035 return (error); | |
1036 } | |
1037 | |
1038 static int | |
1039 zfs_ioc_vdev_attach(zfs_cmd_t *zc) | |
1040 { | |
1041 spa_t *spa; | |
1042 int replacing = zc->zc_cookie; | |
1043 nvlist_t *config; | |
1044 int error; | |
1045 | |
2926 | 1046 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
789 | 1047 return (error); |
1048 | |
5094 | 1049 if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, |
1050 &config)) == 0) { | |
1544 | 1051 error = spa_vdev_attach(spa, zc->zc_guid, config, replacing); |
789 | 1052 nvlist_free(config); |
1053 } | |
1054 | |
1055 spa_close(spa, FTAG); | |
1056 return (error); | |
1057 } | |
1058 | |
1059 static int | |
1060 zfs_ioc_vdev_detach(zfs_cmd_t *zc) | |
1061 { | |
1062 spa_t *spa; | |
1063 int error; | |
1064 | |
2926 | 1065 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) |
789 | 1066 return (error); |
1067 | |
1544 | 1068 error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE); |
789 | 1069 |
1070 spa_close(spa, FTAG); | |
1071 return (error); | |
1072 } | |
1073 | |
1074 static int | |
1354
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1075 zfs_ioc_vdev_setpath(zfs_cmd_t *zc) |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1076 { |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1077 spa_t *spa; |
2676 | 1078 char *path = zc->zc_value; |
1544 | 1079 uint64_t guid = zc->zc_guid; |
1354
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1080 int error; |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1081 |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1082 error = spa_open(zc->zc_name, &spa, FTAG); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1083 if (error != 0) |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1084 return (error); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1085 |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1086 error = spa_vdev_setpath(spa, guid, path); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1087 spa_close(spa, FTAG); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1088 return (error); |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1089 } |
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1090 |
5367 | 1091 /* |
1092 * inputs: | |
1093 * zc_name name of filesystem | |
1094 * zc_nvlist_dst_size size of buffer for property nvlist | |
1095 * | |
1096 * outputs: | |
1097 * zc_objset_stats stats | |
1098 * zc_nvlist_dst property nvlist | |
1099 * zc_nvlist_dst_size size of property nvlist | |
1100 * zc_value alternate root | |
1101 */ | |
1354
81359ee1ee63
6362672 import gets confused about overlapping slices
eschrock
parents:
1133
diff
changeset
|
1102 static int |
789 | 1103 zfs_ioc_objset_stats(zfs_cmd_t *zc) |
1104 { | |
1105 objset_t *os = NULL; | |
1106 int error; | |
1356
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
1107 nvlist_t *nv; |
789 | 1108 |
1109 retry: | |
1110 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, | |
1111 DS_MODE_STANDARD | DS_MODE_READONLY, &os); | |
1112 if (error != 0) { | |
1113 /* | |
1114 * This is ugly: dmu_objset_open() can return EBUSY if | |
1115 * the objset is held exclusively. Fortunately this hold is | |
1116 * only for a short while, so we retry here. | |
1117 * This avoids user code having to handle EBUSY, | |
1118 * for example for a "zfs list". | |
1119 */ | |
1120 if (error == EBUSY) { | |
1121 delay(1); | |
1122 goto retry; | |
1123 } | |
1124 return (error); | |
1125 } | |
1126 | |
2885 | 1127 dmu_objset_fast_stat(os, &zc->zc_objset_stats); |
789 | 1128 |
2856 | 1129 if (zc->zc_nvlist_dst != 0 && |
1356
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
1130 (error = dsl_prop_get_all(os, &nv)) == 0) { |
2885 | 1131 dmu_objset_stats(os, nv); |
3087 | 1132 /* |
5147
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1133 * NB: zvol_get_stats() will read the objset contents, |
3087 | 1134 * which we aren't supposed to do with a |
1135 * DS_MODE_STANDARD open, because it could be | |
1136 * inconsistent. So this is a bit of a workaround... | |
1137 */ | |
4577 | 1138 if (!zc->zc_objset_stats.dds_inconsistent) { |
1139 if (dmu_objset_type(os) == DMU_OST_ZVOL) | |
1140 VERIFY(zvol_get_stats(os, nv) == 0); | |
1141 } | |
2676 | 1142 error = put_nvlist(zc, nv); |
1356
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
1143 nvlist_free(nv); |
e021b5e4aa0e
6377671 zfs mount -a shouldn't bother checking snapshots
eschrock
parents:
1354
diff
changeset
|
1144 } |
789 | 1145 |
2676 | 1146 spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value)); |
1544 | 1147 |
789 | 1148 dmu_objset_close(os); |
1149 return (error); | |
1150 } | |
1151 | |
5367 | 1152 /* |
1153 * inputs: | |
1154 * zc_name name of filesystem | |
1155 * zc_cookie zap cursor | |
1156 * zc_nvlist_dst_size size of buffer for property nvlist | |
1157 * | |
1158 * outputs: | |
1159 * zc_name name of next filesystem | |
1160 * zc_objset_stats stats | |
1161 * zc_nvlist_dst property nvlist | |
1162 * zc_nvlist_dst_size size of property nvlist | |
1163 * zc_value alternate root | |
1164 */ | |
789 | 1165 static int |
5147
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1166 zfs_ioc_objset_version(zfs_cmd_t *zc) |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1167 { |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1168 objset_t *os = NULL; |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1169 int error; |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1170 |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1171 retry: |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1172 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1173 DS_MODE_STANDARD | DS_MODE_READONLY, &os); |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1174 if (error != 0) { |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1175 /* |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1176 * This is ugly: dmu_objset_open() can return EBUSY if |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1177 * the objset is held exclusively. Fortunately this hold is |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1178 * only for a short while, so we retry here. |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1179 * This avoids user code having to handle EBUSY, |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1180 * for example for a "zfs list". |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1181 */ |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1182 if (error == EBUSY) { |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1183 delay(1); |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1184 goto retry; |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1185 } |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1186 return (error); |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1187 } |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1188 |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1189 dmu_objset_fast_stat(os, &zc->zc_objset_stats); |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1190 |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1191 /* |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1192 * NB: zfs_get_version() will read the objset contents, |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1193 * which we aren't supposed to do with a |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1194 * DS_MODE_STANDARD open, because it could be |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1195 * inconsistent. So this is a bit of a workaround... |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1196 */ |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1197 zc->zc_cookie = 0; |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1198 if (!zc->zc_objset_stats.dds_inconsistent) |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1199 if (dmu_objset_type(os) == DMU_OST_ZFS) |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1200 (void) zfs_get_version(os, &zc->zc_cookie); |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1201 |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1202 dmu_objset_close(os); |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1203 return (0); |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1204 } |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1205 |
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
1206 static int |
789 | 1207 zfs_ioc_dataset_list_next(zfs_cmd_t *zc) |
1208 { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1209 objset_t *os; |
789 | 1210 int error; |
1211 char *p; | |
1212 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1213 retry: |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1214 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
|
1215 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
|
1216 if (error != 0) { |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1217 /* |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1218 * 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
|
1219 * 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
|
1220 * 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
|
1221 * 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
|
1222 * for example for a "zfs list". |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1223 */ |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1224 if (error == EBUSY) { |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1225 delay(1); |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1226 goto retry; |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1227 } |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1228 if (error == ENOENT) |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1229 error = ESRCH; |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1230 return (error); |
789 | 1231 } |
1232 | |
1233 p = strrchr(zc->zc_name, '/'); | |
1234 if (p == NULL || p[1] != '\0') | |
1235 (void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name)); | |
1236 p = zc->zc_name + strlen(zc->zc_name); | |
1237 | |
1238 do { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1239 error = dmu_dir_list_next(os, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1240 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
|
1241 NULL, &zc->zc_cookie); |
789 | 1242 if (error == ENOENT) |
1243 error = ESRCH; | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1244 } while (error == 0 && !INGLOBALZONE(curproc) && |
789 | 1245 !zone_dataset_visible(zc->zc_name, NULL)); |
1246 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1247 /* |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1248 * 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
|
1249 * 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
|
1250 */ |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1251 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
|
1252 error = zfs_ioc_objset_stats(zc); /* fill in the stats */ |
789 | 1253 |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1254 dmu_objset_close(os); |
789 | 1255 return (error); |
1256 } | |
1257 | |
5367 | 1258 /* |
1259 * inputs: | |
1260 * zc_name name of filesystem | |
1261 * zc_cookie zap cursor | |
1262 * zc_nvlist_dst_size size of buffer for property nvlist | |
1263 * | |
1264 * outputs: | |
1265 * zc_name name of next snapshot | |
1266 * zc_objset_stats stats | |
1267 * zc_nvlist_dst property nvlist | |
1268 * zc_nvlist_dst_size size of property nvlist | |
1269 * zc_value alternate root | |
1270 */ | |
789 | 1271 static int |
1272 zfs_ioc_snapshot_list_next(zfs_cmd_t *zc) | |
1273 { | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1274 objset_t *os; |
789 | 1275 int error; |
1276 | |
1277 retry: | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1278 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
|
1279 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
|
1280 if (error != 0) { |
789 | 1281 /* |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1282 * This is ugly: dmu_objset_open() can return EBUSY if |
789 | 1283 * the objset is held exclusively. Fortunately this hold is |
1284 * only for a short while, so we retry here. | |
1285 * 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
|
1286 * for example for a "zfs list". |
789 | 1287 */ |
1288 if (error == EBUSY) { | |
1289 delay(1); | |
1290 goto retry; | |
1291 } | |
1292 if (error == ENOENT) | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1293 error = ESRCH; |
789 | 1294 return (error); |
1295 } | |
1296 | |
1003 | 1297 /* |
1298 * A dataset name of maximum length cannot have any snapshots, | |
1299 * so exit immediately. | |
1300 */ | |
1301 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
|
1302 dmu_objset_close(os); |
1003 | 1303 return (ESRCH); |
789 | 1304 } |
1305 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1306 error = dmu_snapshot_list_next(os, |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1307 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
|
1308 zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie); |
789 | 1309 if (error == ENOENT) |
1310 error = ESRCH; | |
1311 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1312 if (error == 0) |
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1313 error = zfs_ioc_objset_stats(zc); /* fill in the stats */ |
789 | 1314 |
5367 | 1315 /* if we failed, undo the @ that we tacked on to zc_name */ |
1316 if (error != 0) | |
1317 *strchr(zc->zc_name, '@') = '\0'; | |
1318 | |
885
d925b21dba78
6347493 tar of 25K empty directory entries in ZFS takes 30+ seconds ...
ahrens
parents:
849
diff
changeset
|
1319 dmu_objset_close(os); |
789 | 1320 return (error); |
1321 } | |
1322 | |
1323 static int | |
4787 | 1324 zfs_set_prop_nvlist(const char *name, nvlist_t *nvl) |
789 | 1325 { |
2676 | 1326 nvpair_t *elem; |
1327 int error; | |
1328 uint64_t intval; | |
1329 char *strval; | |
1330 | |
4543 | 1331 /* |
1332 * First validate permission to set all of the properties | |
1333 */ | |
2676 | 1334 elem = NULL; |
1335 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1336 const char *propname = nvpair_name(elem); |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1337 zfs_prop_t prop = zfs_name_to_prop(propname); |
2676 | 1338 |
5094 | 1339 if (prop == ZPROP_INVAL) { |
2676 | 1340 /* |
1341 * If this is a user-defined property, it must be a | |
1342 * string, and there is no further validation to do. | |
1343 */ | |
1344 if (!zfs_prop_user(propname) || | |
1345 nvpair_type(elem) != DATA_TYPE_STRING) | |
1346 return (EINVAL); | |
1347 | |
5331 | 1348 if (error = zfs_secpolicy_write_perms(name, |
1349 ZFS_DELEG_PERM_USERPROP, CRED())) | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1350 return (error); |
4543 | 1351 continue; |
2676 | 1352 } |
1353 | |
4787 | 1354 if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1355 return (error); |
2676 | 1356 |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1357 /* |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1358 * 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
|
1359 */ |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1360 switch (prop) { |
3886
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1361 case ZFS_PROP_COMPRESSION: |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1362 /* |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1363 * 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
|
1364 * 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
|
1365 * we'll catch them later. |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1366 */ |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1367 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
|
1368 nvpair_value_uint64(elem, &intval) == 0 && |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1369 intval >= ZIO_COMPRESS_GZIP_1 && |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1370 intval <= ZIO_COMPRESS_GZIP_9) { |
5331 | 1371 if (zfs_check_version(name, |
1372 SPA_VERSION_GZIP_COMPRESSION)) | |
1373 return (ENOTSUP); | |
3886
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1374 } |
3291401d66a6
6536602 add zlib compression support and upgrade to version 1.2.3
ahl
parents:
3863
diff
changeset
|
1375 break; |
4603
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1376 |
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1377 case ZFS_PROP_COPIES: |
5331 | 1378 if (zfs_check_version(name, SPA_VERSION_DITTO_BLOCKS)) |
1379 return (ENOTSUP); | |
4603
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1380 break; |
5331 | 1381 case ZFS_PROP_NORMALIZE: |
1382 case ZFS_PROP_UTF8ONLY: | |
1383 case ZFS_PROP_CASE: | |
1384 if (zfs_check_version(name, SPA_VERSION_NORMALIZATION)) | |
1385 return (ENOTSUP); | |
1386 | |
4603
c7840c367d00
6494569 zfs recv -d pool/<doesn't exist> core dumps for top-level filesystem backups
ahrens
parents:
4577
diff
changeset
|
1387 } |
5331 | 1388 if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) |
1389 return (error); | |
4543 | 1390 } |
1391 | |
1392 elem = NULL; | |
1393 while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) { | |
4670
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1394 const char *propname = nvpair_name(elem); |
002728040e28
6580745 "zfs inherit" can be executed by ordinary user
ahrens
parents:
4611
diff
changeset
|
1395 zfs_prop_t prop = zfs_name_to_prop(propname); |
4543 | 1396 |
5094 | 1397 if (prop == ZPROP_INVAL) { |
4543 | 1398 VERIFY(nvpair_value_string(elem, &strval) == 0); |
1399 error = dsl_prop_set(name, propname, 1, | |
1400 strlen(strval) + 1, strval); | |
1401 if (error == 0) | |
1402 continue; | |
1403 else | |
1404 return (error); | |
1405 } | |
2676 | 1406 |
1407 switch (prop) { | |
1408 case ZFS_PROP_QUOTA: | |
1409 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
4577 | 1410 (error = dsl_dir_set_quota(name, intval)) != 0) |
2676 | 1411 return (error); |
1412 break; | |
1413 | |
5378
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1414 case ZFS_PROP_REFQUOTA: |
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1415 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || |
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1416 (error = dsl_dataset_set_quota(name, intval)) != 0) |
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1417 return (error); |
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1418 break; |
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1419 |
2676 | 1420 case ZFS_PROP_RESERVATION: |
1421 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
1422 (error = dsl_dir_set_reservation(name, | |
1423 intval)) != 0) | |
1424 return (error); | |
1425 break; | |
789 | 1426 |
5378
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1427 case ZFS_PROP_REFRESERVATION: |
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1428 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || |
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1429 (error = dsl_dataset_set_reservation(name, |
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1430 intval)) != 0) |
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1431 return (error); |
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1432 break; |
111aa1baa84a
PSARC 2007/555 zfs fs-only quotas and reservations
ck153898
parents:
5375
diff
changeset
|
1433 |
2676 | 1434 case ZFS_PROP_VOLSIZE: |
1435 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
4787 | 1436 (error = zvol_set_volsize(name, |
1437 ddi_driver_major(zfs_dip), intval)) != 0) | |
2676 | 1438 return (error); |
1439 break; | |
1440 | |
1441 case ZFS_PROP_VOLBLOCKSIZE: | |
1442 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
4577 | 1443 (error = zvol_set_volblocksize(name, intval)) != 0) |
1444 return (error); | |
1445 break; | |
1446 | |
1447 case ZFS_PROP_VERSION: | |
1448 if ((error = nvpair_value_uint64(elem, &intval)) != 0 || | |
1449 (error = zfs_set_version(name, intval)) != 0) | |
2676 | 1450 return (error); |
1451 break; | |
1452 | |
1453 default: | |
1454 if (nvpair_type(elem) == DATA_TYPE_STRING) { | |
1455 if (zfs_prop_get_type(prop) != | |
4787 | 1456 PROP_TYPE_STRING) |
2676 | 1457 return (EINVAL); |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1458 VERIFY(nvpair_value_string(elem, &strval) == 0); |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1459 if ((error = dsl_prop_set(name, |
2676 | 1460 nvpair_name(elem), 1, strlen(strval) + 1, |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1461 strval)) != 0) |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1462 return (error); |
2676 | 1463 } else if (nvpair_type(elem) == DATA_TYPE_UINT64) { |
2885 | 1464 const char *unused; |
1465 | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1466 VERIFY(nvpair_value_uint64(elem, &intval) == 0); |
2676 | 1467 |
1468 switch (zfs_prop_get_type(prop)) { | |
4787 | 1469 case PROP_TYPE_NUMBER: |
2676 | 1470 break; |
4787 | 1471 case PROP_TYPE_STRING: |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1472 return (EINVAL); |
4787 | 1473 case PROP_TYPE_INDEX: |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1474 if (zfs_prop_index_to_string(prop, |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1475 intval, &unused) != 0) |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1476 return (EINVAL); |
2676 | 1477 break; |
1478 default: | |
4577 | 1479 cmn_err(CE_PANIC, |
1480 "unknown property type"); | |
2676 | 1481 break; |
1482 } | |
1483 | |
2717
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1484 if ((error = dsl_prop_set(name, propname, |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1485 8, 1, &intval)) != 0) |
ed589a32259d
6469385 zfs_set_prop_nvlist range checking is busted
eschrock
parents:
2676
diff
changeset
|
1486 return (error); |
2676 | 1487 } else { |
1488 return (EINVAL); | |
1489 } | |
1490 break; | |
1491 } | |
1492 } | |
1493 | |
1494 return (0); | |
789 | 1495 } |
1496 | |
5367 | 1497 /* |
1498 * inputs: | |
1499 * zc_name name of filesystem | |
1500 * zc_value name of property to inherit | |
1501 * zc_nvlist_src{_size} nvlist of properties to apply | |
1502 * | |
1503 * outputs: none | |
1504 */ | |
789 | 1505 static int |
2676 | 1506 zfs_ioc_set_prop(zfs_cmd_t *zc) |
789 | 1507 { |
2676 | 1508 nvlist_t *nvl; |
1509 int error; | |
789 | 1510 |
5094 | 1511 if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, |
1512 &nvl)) != 0) | |
2676 | 1513 return (error); |
1514 | |
4787 | 1515 error = zfs_set_prop_nvlist(zc->zc_name, nvl); |
4543 | 1516 |
2676 | 1517 nvlist_free(nvl); |
1518 return (error); | |
789 | 1519 } |
1520 | |
5367 | 1521 /* |
1522 * inputs: | |
1523 * zc_name name of filesystem | |
1524 * zc_value name of property to inherit | |
1525 * | |
1526 * outputs: none | |
1527 */ | |
789 | 1528 static int |
4849
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
1529 zfs_ioc_inherit_prop(zfs_cmd_t *zc) |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
1530 { |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
1531 /* the property name has been validated by zfs_secpolicy_inherit() */ |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
1532 return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL)); |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
1533 } |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
1534 |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
1535 static int |
4098
0a182c2128e6
6545726 make ZFS_IOC_POOL_*_PROPS in sync with zfs_ioc_pool_props_*
lling
parents:
4007
diff
changeset
|
1536 zfs_ioc_pool_set_props(zfs_cmd_t *zc) |
3912 | 1537 { |
5094 | 1538 nvlist_t *props; |
3912 | 1539 spa_t *spa; |
5094 | 1540 int error; |
3912 | 1541 |
5094 | 1542 if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, |
1543 &props))) | |
3912 | 1544 return (error); |
1545 | |
1546 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) { | |
5094 | 1547 nvlist_free(props); |
3912 | 1548 return (error); |
1549 } | |
1550 | |
5094 | 1551 error = spa_prop_set(spa, props); |
3912 | 1552 |
5094 | 1553 nvlist_free(props); |
3912 | 1554 spa_close(spa, FTAG); |
1555 | |
1556 return (error); | |
1557 } | |
1558 | |
1559 static int | |
4098
0a182c2128e6
6545726 make ZFS_IOC_POOL_*_PROPS in sync with zfs_ioc_pool_props_*
lling
parents:
4007
diff
changeset
|
1560 zfs_ioc_pool_get_props(zfs_cmd_t *zc) |
3912 | 1561 { |
1562 spa_t *spa; | |
1563 int error; | |
1564 nvlist_t *nvp = NULL; | |
1565 | |
1566 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
1567 return (error); | |
1568 | |
5094 | 1569 error = spa_prop_get(spa, &nvp); |
3912 | 1570 |
1571 if (error == 0 && zc->zc_nvlist_dst != NULL) | |
1572 error = put_nvlist(zc, nvp); | |
1573 else | |
1574 error = EFAULT; | |
1575 | |
1576 spa_close(spa, FTAG); | |
1577 | |
1578 if (nvp) | |
1579 nvlist_free(nvp); | |
1580 return (error); | |
1581 } | |
1582 | |
1583 static int | |
4543 | 1584 zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) |
1585 { | |
1586 nvlist_t *nvp; | |
1587 int error; | |
1588 uint32_t uid; | |
1589 uint32_t gid; | |
1590 uint32_t *groups; | |
1591 uint_t group_cnt; | |
1592 cred_t *usercred; | |
1593 | |
5094 | 1594 if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, |
1595 &nvp)) != 0) { | |
4543 | 1596 return (error); |
1597 } | |
1598 | |
1599 if ((error = nvlist_lookup_uint32(nvp, | |
1600 ZFS_DELEG_PERM_UID, &uid)) != 0) { | |
1601 nvlist_free(nvp); | |
1602 return (EPERM); | |
1603 } | |
1604 | |
1605 if ((error = nvlist_lookup_uint32(nvp, | |
1606 ZFS_DELEG_PERM_GID, &gid)) != 0) { | |
1607 nvlist_free(nvp); | |
1608 return (EPERM); | |
1609 } | |
1610 | |
1611 if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, | |
1612 &groups, &group_cnt)) != 0) { | |
1613 nvlist_free(nvp); | |
1614 return (EPERM); | |
1615 } | |
1616 usercred = cralloc(); | |
1617 if ((crsetugid(usercred, uid, gid) != 0) || | |
1618 (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { | |
1619 nvlist_free(nvp); | |
1620 crfree(usercred); | |
1621 return (EPERM); | |
1622 } | |
1623 nvlist_free(nvp); | |
1624 error = dsl_deleg_access(zc->zc_name, | |
4787 | 1625 zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); |
4543 | 1626 crfree(usercred); |
1627 return (error); | |
1628 } | |
1629 | |
5367 | 1630 /* |
1631 * inputs: | |
1632 * zc_name name of filesystem | |
1633 * zc_nvlist_src{_size} nvlist of delegated permissions | |
1634 * zc_perm_action allow/unallow flag | |
1635 * | |
1636 * outputs: none | |
1637 */ | |
4543 | 1638 static int |
1639 zfs_ioc_set_fsacl(zfs_cmd_t *zc) | |
1640 { | |
1641 int error; | |
1642 nvlist_t *fsaclnv = NULL; | |
1643 | |
5094 | 1644 if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, |
1645 &fsaclnv)) != 0) | |
4543 | 1646 return (error); |
1647 | |
1648 /* | |
1649 * Verify nvlist is constructed correctly | |
1650 */ | |
1651 if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) { | |
1652 nvlist_free(fsaclnv); | |
1653 return (EINVAL); | |
1654 } | |
1655 | |
1656 /* | |
1657 * If we don't have PRIV_SYS_MOUNT, then validate | |
1658 * that user is allowed to hand out each permission in | |
1659 * the nvlist(s) | |
1660 */ | |
1661 | |
4787 | 1662 error = secpolicy_zfs(CRED()); |
4543 | 1663 if (error) { |
4787 | 1664 if (zc->zc_perm_action == B_FALSE) { |
1665 error = dsl_deleg_can_allow(zc->zc_name, | |
1666 fsaclnv, CRED()); | |
1667 } else { | |
1668 error = dsl_deleg_can_unallow(zc->zc_name, | |
1669 fsaclnv, CRED()); | |
1670 } | |
4543 | 1671 } |
1672 | |
1673 if (error == 0) | |
1674 error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action); | |
1675 | |
1676 nvlist_free(fsaclnv); | |
1677 return (error); | |
1678 } | |
1679 | |
5367 | 1680 /* |
1681 * inputs: | |
1682 * zc_name name of filesystem | |
1683 * | |
1684 * outputs: | |
1685 * zc_nvlist_src{_size} nvlist of delegated permissions | |
1686 */ | |
4543 | 1687 static int |
1688 zfs_ioc_get_fsacl(zfs_cmd_t *zc) | |
1689 { | |
1690 nvlist_t *nvp; | |
1691 int error; | |
1692 | |
1693 if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) { | |
1694 error = put_nvlist(zc, nvp); | |
1695 nvlist_free(nvp); | |
1696 } | |
1697 | |
1698 return (error); | |
1699 } | |
1700 | |
5367 | 1701 /* |
1702 * inputs: | |
1703 * zc_name name of volume | |
1704 * | |
1705 * outputs: none | |
1706 */ | |
4543 | 1707 static int |
789 | 1708 zfs_ioc_create_minor(zfs_cmd_t *zc) |
1709 { | |
4787 | 1710 return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip))); |
789 | 1711 } |
1712 | |
5367 | 1713 /* |
1714 * inputs: | |
1715 * zc_name name of volume | |
1716 * | |
1717 * outputs: none | |
1718 */ | |
789 | 1719 static int |
1720 zfs_ioc_remove_minor(zfs_cmd_t *zc) | |
1721 { | |
2676 | 1722 return (zvol_remove_minor(zc->zc_name)); |
789 | 1723 } |
1724 | |
1725 /* | |
1726 * Search the vfs list for a specified resource. Returns a pointer to it | |
1727 * or NULL if no suitable entry is found. The caller of this routine | |
1728 * is responsible for releasing the returned vfs pointer. | |
1729 */ | |
1730 static vfs_t * | |
1731 zfs_get_vfs(const char *resource) | |
1732 { | |
1733 struct vfs *vfsp; | |
1734 struct vfs *vfs_found = NULL; | |
1735 | |
1736 vfs_list_read_lock(); | |
1737 vfsp = rootvfs; | |
1738 do { | |
1739 if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) { | |
1740 VFS_HOLD(vfsp); | |
1741 vfs_found = vfsp; | |
1742 break; | |
1743 } | |
1744 vfsp = vfsp->vfs_next; | |
1745 } while (vfsp != rootvfs); | |
1746 vfs_list_unlock(); | |
1747 return (vfs_found); | |
1748 } | |
1749 | |
4543 | 1750 /* ARGSUSED */ |
789 | 1751 static void |
4543 | 1752 zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) |
789 | 1753 { |
5331 | 1754 zfs_creat_t *zct = arg; |
1755 uint64_t version; | |
1756 | |
1757 if (spa_version(dmu_objset_spa(os)) >= SPA_VERSION_FUID) | |
1758 version = ZPL_VERSION; | |
1759 else | |
1760 version = ZPL_VERSION_FUID - 1; | |
1761 | |
1762 (void) nvlist_lookup_uint64(zct->zct_props, | |
4577 | 1763 zfs_prop_to_name(ZFS_PROP_VERSION), &version); |
1764 | |
5331 | 1765 zfs_create_fs(os, cr, version, zct->zct_norm, tx); |
1766 } | |
1767 | |
1768 /* | |
1769 * zfs_prop_lookup() | |
1770 * | |
1771 * Look for the property first in the existing property nvlist. If | |
1772 * it's already present, you're done. If it's not there, attempt to | |
1773 * find the property value from a parent dataset. If that fails, fall | |
1774 * back to the property's default value. In either of these two | |
1775 * cases, if update is TRUE, add a value for the property to the | |
1776 * property nvlist. | |
1777 * | |
1778 * If the rval pointer is non-NULL, copy the discovered value to rval. | |
1779 * | |
1780 * If we get any unexpected errors, bail and return the error number | |
1781 * to the caller. | |
1782 * | |
1783 * If we succeed, return 0. | |
1784 */ | |
1785 static int | |
1786 zfs_prop_lookup(const char *parentname, zfs_prop_t propnum, | |
1787 nvlist_t *proplist, uint64_t *rval, boolean_t update) | |
1788 { | |
1789 const char *propname; | |
1790 uint64_t value; | |
1791 int error = ENOENT; | |
1792 | |
1793 propname = zfs_prop_to_name(propnum); | |
1794 if (proplist != NULL) | |
1795 error = nvlist_lookup_uint64(proplist, propname, &value); | |
1796 if (error == ENOENT) { | |
1797 error = dsl_prop_get_integer(parentname, propname, | |
1798 &value, NULL); | |
1799 if (error == ENOENT) | |
1800 value = zfs_prop_default_numeric(propnum); | |
1801 else if (error != 0) | |
1802 return (error); | |
1803 if (update) { | |
1804 ASSERT(proplist != NULL); | |
1805 error = nvlist_add_uint64(proplist, propname, value); | |
1806 } | |
1807 } | |
1808 if (error == 0 && rval) | |
1809 *rval = value; | |
1810 return (error); | |
1811 } | |
1812 | |
1813 /* | |
1814 * zfs_normalization_get | |
1815 * | |
1816 * Get the normalization flag value. If the properties have | |
1817 * non-default values, make sure the pool version is recent enough to | |
1818 * support these choices. | |
1819 */ | |
1820 static int | |
1821 zfs_normalization_get(const char *dataset, nvlist_t *proplist, int *norm, | |
1822 boolean_t update) | |
1823 { | |
1824 char parentname[MAXNAMELEN]; | |
1825 char poolname[MAXNAMELEN]; | |
1826 char *cp; | |
1827 uint64_t value; | |
1828 int check = 0; | |
1829 int error; | |
1830 | |
1831 ASSERT(norm != NULL); | |
1832 *norm = 0; | |
1833 | |
1834 (void) strncpy(parentname, dataset, sizeof (parentname)); | |
1835 cp = strrchr(parentname, '@'); | |
1836 if (cp != NULL) { | |
1837 cp[0] = '\0'; | |
1838 } else { | |
1839 cp = strrchr(parentname, '/'); | |
1840 if (cp == NULL) | |
1841 return (ENOENT); | |
1842 cp[0] = '\0'; | |
1843 } | |
1844 | |
1845 (void) strncpy(poolname, dataset, sizeof (poolname)); | |
1846 cp = strchr(poolname, '/'); | |
1847 if (cp != NULL) | |
1848 cp[0] = '\0'; | |
1849 | |
5375 | 1850 /* |
1851 * Make sure pool is of new enough vintage to support normalization. | |
1852 */ | |
1853 if (zfs_check_version(poolname, SPA_VERSION_NORMALIZATION)) | |
1854 return (0); | |
1855 | |
5331 | 1856 error = zfs_prop_lookup(parentname, ZFS_PROP_UTF8ONLY, |
1857 proplist, &value, update); | |
1858 if (error != 0) | |
1859 return (error); | |
1860 if (value != zfs_prop_default_numeric(ZFS_PROP_UTF8ONLY)) | |
1861 check = 1; | |
1862 | |
1863 error = zfs_prop_lookup(parentname, ZFS_PROP_NORMALIZE, | |
1864 proplist, &value, update); | |
1865 if (error != 0) | |
1866 return (error); | |
1867 if (value != zfs_prop_default_numeric(ZFS_PROP_NORMALIZE)) { | |
1868 check = 1; | |
1869 switch ((int)value) { | |
1870 case ZFS_NORMALIZE_NONE: | |
1871 break; | |
1872 case ZFS_NORMALIZE_C: | |
1873 *norm |= U8_TEXTPREP_NFC; | |
1874 break; | |
1875 case ZFS_NORMALIZE_D: | |
1876 *norm |= U8_TEXTPREP_NFD; | |
1877 break; | |
1878 case ZFS_NORMALIZE_KC: | |
1879 *norm |= U8_TEXTPREP_NFKC; | |
1880 break; | |
1881 case ZFS_NORMALIZE_KD: | |
1882 *norm |= U8_TEXTPREP_NFKD; | |
1883 break; | |
1884 default: | |
1885 ASSERT((int)value >= ZFS_NORMALIZE_NONE); | |
1886 ASSERT((int)value <= ZFS_NORMALIZE_KD); | |
1887 break; | |
1888 } | |
1889 } | |
1890 | |
1891 error = zfs_prop_lookup(parentname, ZFS_PROP_CASE, | |
1892 proplist, &value, update); | |
1893 if (error != 0) | |
1894 return (error); | |
1895 if (value != zfs_prop_default_numeric(ZFS_PROP_CASE)) { | |
1896 check = 1; | |
1897 switch ((int)value) { | |
1898 case ZFS_CASE_SENSITIVE: | |
1899 break; | |
1900 case ZFS_CASE_INSENSITIVE: | |
1901 *norm |= U8_TEXTPREP_TOUPPER; | |
1902 break; | |
1903 case ZFS_CASE_MIXED: | |
1904 *norm |= U8_TEXTPREP_TOUPPER; | |
1905 break; | |
1906 default: | |
1907 ASSERT((int)value >= ZFS_CASE_SENSITIVE); | |
1908 ASSERT((int)value <= ZFS_CASE_MIXED); | |
1909 break; | |
1910 } | |
1911 } | |
1912 | |
5375 | 1913 /* |
1914 * At the moment we are disabling non-default values for these | |
1915 * properties because they cannot be preserved properly with a | |
1916 * zfs send. | |
1917 */ | |
5331 | 1918 if (check == 1) |
5375 | 1919 return (ENOTSUP); |
1920 | |
5331 | 1921 return (0); |
789 | 1922 } |
1923 | |
5367 | 1924 /* |
1925 * inputs: | |
1926 * zc_objset_type type of objset to create (fs vs zvol) | |
1927 * zc_name name of new objset | |
1928 * zc_value name of snapshot to clone from (may be empty) | |
1929 * zc_nvlist_src{_size} nvlist of properties to apply | |
1930 * | |
1931 * outputs: none | |
1932 */ | |
789 | 1933 static int |
1934 zfs_ioc_create(zfs_cmd_t *zc) | |
1935 { | |
1936 objset_t *clone; | |
1937 int error = 0; | |
5331 | 1938 zfs_creat_t zct; |
4543 | 1939 nvlist_t *nvprops = NULL; |
1940 void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); | |
789 | 1941 dmu_objset_type_t type = zc->zc_objset_type; |
1942 | |
1943 switch (type) { | |
1944 | |
1945 case DMU_OST_ZFS: | |
1946 cbfunc = zfs_create_cb; | |
1947 break; | |
1948 | |
1949 case DMU_OST_ZVOL: | |
1950 cbfunc = zvol_create_cb; | |
1951 break; | |
1952 | |
1953 default: | |
2199 | 1954 cbfunc = NULL; |
1955 } | |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
1956 if (strchr(zc->zc_name, '@') || |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
1957 strchr(zc->zc_name, '%')) |
789 | 1958 return (EINVAL); |
1959 | |
2676 | 1960 if (zc->zc_nvlist_src != NULL && |
5094 | 1961 (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, |
1962 &nvprops)) != 0) | |
2676 | 1963 return (error); |
1964 | |
5331 | 1965 zct.zct_norm = 0; |
1966 zct.zct_props = nvprops; | |
1967 | |
2676 | 1968 if (zc->zc_value[0] != '\0') { |
789 | 1969 /* |
1970 * We're creating a clone of an existing snapshot. | |
1971 */ | |
2676 | 1972 zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; |
1973 if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) { | |
4543 | 1974 nvlist_free(nvprops); |
789 | 1975 return (EINVAL); |
2676 | 1976 } |
789 | 1977 |
2676 | 1978 error = dmu_objset_open(zc->zc_value, type, |
789 | 1979 DS_MODE_STANDARD | DS_MODE_READONLY, &clone); |
2676 | 1980 if (error) { |
4543 | 1981 nvlist_free(nvprops); |
789 | 1982 return (error); |
2676 | 1983 } |
789 | 1984 error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL); |
5331 | 1985 if (error) { |
1986 dmu_objset_close(clone); | |
1987 nvlist_free(nvprops); | |
1988 return (error); | |
1989 } | |
1990 /* | |
1991 * If caller did not provide any properties, allocate | |
1992 * an nvlist for properties, as we will be adding our set-once | |
1993 * properties to it. This carries the choices made on the | |
1994 * original file system into the clone. | |
1995 */ | |
1996 if (nvprops == NULL) | |
1997 VERIFY(nvlist_alloc(&nvprops, | |
1998 NV_UNIQUE_NAME, KM_SLEEP) == 0); | |
1999 | |
2000 /* | |
2001 * We have to have normalization and case-folding | |
2002 * flags correct when we do the file system creation, | |
2003 * so go figure them out now. All we really care about | |
2004 * here is getting these values into the property list. | |
2005 */ | |
2006 error = zfs_normalization_get(zc->zc_value, nvprops, | |
2007 &zct.zct_norm, B_TRUE); | |
2008 if (error != 0) { | |
2009 dmu_objset_close(clone); | |
2010 nvlist_free(nvprops); | |
2011 return (error); | |
2012 } | |
789 | 2013 dmu_objset_close(clone); |
2014 } else { | |
2676 | 2015 if (cbfunc == NULL) { |
4543 | 2016 nvlist_free(nvprops); |
2199 | 2017 return (EINVAL); |
2676 | 2018 } |
2019 | |
789 | 2020 if (type == DMU_OST_ZVOL) { |
2676 | 2021 uint64_t volsize, volblocksize; |
2022 | |
4543 | 2023 if (nvprops == NULL || |
2024 nvlist_lookup_uint64(nvprops, | |
2676 | 2025 zfs_prop_to_name(ZFS_PROP_VOLSIZE), |
2026 &volsize) != 0) { | |
4543 | 2027 nvlist_free(nvprops); |
2676 | 2028 return (EINVAL); |
2029 } | |
2030 | |
4543 | 2031 if ((error = nvlist_lookup_uint64(nvprops, |
2676 | 2032 zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), |
2033 &volblocksize)) != 0 && error != ENOENT) { | |
4543 | 2034 nvlist_free(nvprops); |
2676 | 2035 return (EINVAL); |
2036 } | |
1133
335d069294d1
6357470 vdev_raidz.c has unused RAIDZ_SINGLE define, code
eschrock
parents:
1003
diff
changeset
|
2037 |
2676 | 2038 if (error != 0) |
2039 volblocksize = zfs_prop_default_numeric( | |
2040 ZFS_PROP_VOLBLOCKSIZE); | |
2041 | |
2042 if ((error = zvol_check_volblocksize( | |
2043 volblocksize)) != 0 || | |
2044 (error = zvol_check_volsize(volsize, | |
2045 volblocksize)) != 0) { | |
4543 | 2046 nvlist_free(nvprops); |
789 | 2047 return (error); |
2676 | 2048 } |
4577 | 2049 } else if (type == DMU_OST_ZFS) { |
2050 uint64_t version; | |
5331 | 2051 int error; |
2052 | |
2053 error = nvlist_lookup_uint64(nvprops, | |
2054 zfs_prop_to_name(ZFS_PROP_VERSION), &version); | |
2055 | |
2056 if (error == 0 && (version < ZPL_VERSION_INITIAL || | |
4577 | 2057 version > ZPL_VERSION)) { |
2058 nvlist_free(nvprops); | |
5331 | 2059 return (ENOTSUP); |
2060 } else if (error == 0 && version >= ZPL_VERSION_FUID && | |
2061 zfs_check_version(zc->zc_name, SPA_VERSION_FUID)) { | |
2062 nvlist_free(nvprops); | |
2063 return (ENOTSUP); | |
2064 } | |
2065 | |
2066 /* | |
2067 * We have to have normalization and | |
2068 * case-folding flags correct when we do the | |
2069 * file system creation, so go figure them out | |
2070 * now. The final argument to zfs_normalization_get() | |
2071 * tells that routine not to update the nvprops | |
2072 * list. | |
2073 */ | |
2074 error = zfs_normalization_get(zc->zc_name, nvprops, | |
2075 &zct.zct_norm, B_FALSE); | |
2076 if (error != 0) { | |
2077 nvlist_free(nvprops); | |
2078 return (error); | |
4577 | 2079 } |
2676 | 2080 } |
2081 error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, | |
5331 | 2082 &zct); |
789 | 2083 } |
2676 | 2084 |
2085 /* | |
2086 * It would be nice to do this atomically. | |
2087 */ | |
2088 if (error == 0) { | |
4787 | 2089 if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0) |
2676 | 2090 (void) dmu_objset_destroy(zc->zc_name); |
2091 } | |
2092 | |
4543 | 2093 nvlist_free(nvprops); |
789 | 2094 return (error); |
2095 } | |
2096 | |
5367 | 2097 /* |
2098 * inputs: | |
2099 * zc_name name of filesystem | |
2100 * zc_value short name of snapshot | |
2101 * zc_cookie recursive flag | |
2102 * | |
2103 * outputs: none | |
2104 */ | |
789 | 2105 static int |
2199 | 2106 zfs_ioc_snapshot(zfs_cmd_t *zc) |
2107 { | |
2676 | 2108 if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) |
2199 | 2109 return (EINVAL); |
2110 return (dmu_objset_snapshot(zc->zc_name, | |
2676 | 2111 zc->zc_value, zc->zc_cookie)); |
2199 | 2112 } |
2113 | |
4007 | 2114 int |
2199 | 2115 zfs_unmount_snap(char *name, void *arg) |
789 | 2116 { |
2199 | 2117 char *snapname = arg; |
2118 char *cp; | |
2417 | 2119 vfs_t *vfsp = NULL; |
2199 | 2120 |
2121 /* | |
2122 * Snapshots (which are under .zfs control) must be unmounted | |
2123 * before they can be destroyed. | |
2124 */ | |
2125 | |
2126 if (snapname) { | |
2127 (void) strcat(name, "@"); | |
2128 (void) strcat(name, snapname); | |
2129 vfsp = zfs_get_vfs(name); | |
2130 cp = strchr(name, '@'); | |
2131 *cp = '\0'; | |
2417 | 2132 } else if (strchr(name, '@')) { |
2199 | 2133 vfsp = zfs_get_vfs(name); |
2134 } | |
2135 | |
2136 if (vfsp) { | |
2137 /* | |
2138 * Always force the unmount for snapshots. | |
2139 */ | |
2140 int flag = MS_FORCE; | |
789 | 2141 int err; |
2142 | |
2199 | 2143 if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) { |
2144 VFS_RELE(vfsp); | |
2145 return (err); | |
2146 } | |
2147 VFS_RELE(vfsp); | |
2148 if ((err = dounmount(vfsp, flag, kcred)) != 0) | |
2149 return (err); | |
2150 } | |
2151 return (0); | |
2152 } | |
2153 | |
5367 | 2154 /* |
2155 * inputs: | |
2156 * zc_name name of filesystem | |
2157 * zc_value short name of snapshot | |
2158 * | |
2159 * outputs: none | |
2160 */ | |
2199 | 2161 static int |
2162 zfs_ioc_destroy_snaps(zfs_cmd_t *zc) | |
2163 { | |
2164 int err; | |
789 | 2165 |
2676 | 2166 if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) |
2199 | 2167 return (EINVAL); |
2168 err = dmu_objset_find(zc->zc_name, | |
2676 | 2169 zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN); |
2199 | 2170 if (err) |
2171 return (err); | |
2676 | 2172 return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value)); |
2199 | 2173 } |
2174 | |
5367 | 2175 /* |
2176 * inputs: | |
2177 * zc_name name of dataset to destroy | |
2178 * zc_objset_type type of objset | |
2179 * | |
2180 * outputs: none | |
2181 */ | |
2199 | 2182 static int |
2183 zfs_ioc_destroy(zfs_cmd_t *zc) | |
2184 { | |
2185 if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) { | |
2186 int err = zfs_unmount_snap(zc->zc_name, NULL); | |
2187 if (err) | |
2188 return (err); | |
789 | 2189 } |
2190 | |
2191 return (dmu_objset_destroy(zc->zc_name)); | |
2192 } | |
2193 | |
5367 | 2194 /* |
2195 * inputs: | |
2196 * zc_name name of snapshot to roll back to | |
2197 * | |
2198 * outputs: none | |
2199 */ | |
789 | 2200 static int |
2201 zfs_ioc_rollback(zfs_cmd_t *zc) | |
2202 { | |
2203 return (dmu_objset_rollback(zc->zc_name)); | |
2204 } | |
2205 | |
5367 | 2206 /* |
2207 * inputs: | |
2208 * zc_name old name of dataset | |
2209 * zc_value new name of dataset | |
2210 * zc_cookie recursive flag (only valid for snapshots) | |
2211 * | |
2212 * outputs: none | |
2213 */ | |
789 | 2214 static int |
2215 zfs_ioc_rename(zfs_cmd_t *zc) | |
2216 { | |
4490 | 2217 boolean_t recursive = zc->zc_cookie & 1; |
4007 | 2218 |
2676 | 2219 zc->zc_value[sizeof (zc->zc_value) - 1] = '\0'; |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2220 if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2221 strchr(zc->zc_value, '%')) |
789 | 2222 return (EINVAL); |
2223 | |
4007 | 2224 /* |
2225 * Unmount snapshot unless we're doing a recursive rename, | |
2226 * in which case the dataset code figures out which snapshots | |
2227 * to unmount. | |
2228 */ | |
2229 if (!recursive && strchr(zc->zc_name, '@') != NULL && | |
789 | 2230 zc->zc_objset_type == DMU_OST_ZFS) { |
2199 | 2231 int err = zfs_unmount_snap(zc->zc_name, NULL); |
2232 if (err) | |
2233 return (err); | |
789 | 2234 } |
2235 | |
4007 | 2236 return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive)); |
789 | 2237 } |
2238 | |
5367 | 2239 /* |
2240 * inputs: | |
2241 * zc_name name of containing filesystem | |
2242 * zc_nvlist_src{_size} nvlist of properties to apply | |
2243 * zc_value name of snapshot to create | |
2244 * zc_string name of clone origin (if DRR_FLAG_CLONE) | |
2245 * zc_cookie file descriptor to recv from | |
2246 * zc_begin_record the BEGIN record of the stream (not byteswapped) | |
2247 * zc_guid force flag | |
2248 * | |
2249 * outputs: | |
2250 * zc_cookie number of bytes read | |
2251 */ | |
789 | 2252 static int |
5367 | 2253 zfs_ioc_recv(zfs_cmd_t *zc) |
789 | 2254 { |
2255 file_t *fp; | |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2256 objset_t *os; |
5367 | 2257 dmu_recv_cookie_t drc; |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2258 zfsvfs_t *zfsvfs = NULL; |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2259 boolean_t force = (boolean_t)zc->zc_guid; |
789 | 2260 int error, fd; |
5367 | 2261 offset_t off; |
2262 nvlist_t *props = NULL; | |
2263 objset_t *origin = NULL; | |
2264 char *tosnap; | |
2265 char tofs[ZFS_MAXNAMELEN]; | |
789 | 2266 |
3265
967e0fca6143
6463140 zfs recv with a snapshot name that has 2 @@ in a row succeeds
ahrens
parents:
3087
diff
changeset
|
2267 if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2268 strchr(zc->zc_value, '@') == NULL || |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2269 strchr(zc->zc_value, '%')) |
3265
967e0fca6143
6463140 zfs recv with a snapshot name that has 2 @@ in a row succeeds
ahrens
parents:
3087
diff
changeset
|
2270 return (EINVAL); |
967e0fca6143
6463140 zfs recv with a snapshot name that has 2 @@ in a row succeeds
ahrens
parents:
3087
diff
changeset
|
2271 |
5367 | 2272 (void) strcpy(tofs, zc->zc_value); |
2273 tosnap = strchr(tofs, '@'); | |
2274 *tosnap = '\0'; | |
2275 tosnap++; | |
2276 | |
2277 if (zc->zc_nvlist_src != NULL && | |
2278 (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, | |
2279 &props)) != 0) | |
2280 return (error); | |
2281 | |
789 | 2282 fd = zc->zc_cookie; |
2283 fp = getf(fd); | |
5367 | 2284 if (fp == NULL) { |
2285 nvlist_free(props); | |
789 | 2286 return (EBADF); |
5367 | 2287 } |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2288 |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2289 /* |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2290 * Get the zfsvfs for the receiving objset. There |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2291 * won't be one if we're operating on a zvol, if the |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2292 * objset doesn't exist yet, or is not mounted. |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2293 */ |
5367 | 2294 |
2295 error = dmu_objset_open(tofs, DMU_OST_ANY, | |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2296 DS_MODE_STANDARD | DS_MODE_READONLY, &os); |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2297 if (!error) { |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2298 if (dmu_objset_type(os) == DMU_OST_ZFS) { |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2299 mutex_enter(&os->os->os_user_ptr_lock); |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2300 zfsvfs = dmu_objset_get_user(os); |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2301 if (zfsvfs != NULL) |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2302 VFS_HOLD(zfsvfs->z_vfs); |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2303 mutex_exit(&os->os->os_user_ptr_lock); |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2304 } |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2305 dmu_objset_close(os); |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2306 } |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2307 |
5367 | 2308 if (zc->zc_string[0]) { |
2309 error = dmu_objset_open(zc->zc_string, DMU_OST_ANY, | |
2310 DS_MODE_STANDARD | DS_MODE_READONLY, &origin); | |
2311 if (error) { | |
2312 if (zfsvfs != NULL) | |
2313 VFS_RELE(zfsvfs->z_vfs); | |
2314 nvlist_free(props); | |
2315 releasef(fd); | |
2316 return (error); | |
2317 } | |
2318 } | |
2319 | |
2320 error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record, | |
2321 force, origin, zfsvfs != NULL, &drc); | |
2322 if (origin) | |
2323 dmu_objset_close(origin); | |
2324 if (error) { | |
2325 if (zfsvfs != NULL) | |
2326 VFS_RELE(zfsvfs->z_vfs); | |
2327 nvlist_free(props); | |
2328 releasef(fd); | |
2329 return (error); | |
2330 } | |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2331 |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2332 /* |
5367 | 2333 * If properties are supplied, they are to completely replace |
2334 * the existing ones; "inherit" any existing properties. | |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2335 */ |
5367 | 2336 if (props) { |
2337 objset_t *os; | |
2338 nvlist_t *nv = NULL; | |
2339 | |
2340 error = dmu_objset_open(tofs, DMU_OST_ANY, | |
2341 DS_MODE_STANDARD | DS_MODE_READONLY | DS_MODE_INCONSISTENT, | |
2342 &os); | |
2343 if (error == 0) { | |
2344 error = dsl_prop_get_all(os, &nv); | |
2345 dmu_objset_close(os); | |
2346 } | |
2347 if (error == 0) { | |
2348 nvpair_t *elem; | |
2349 zfs_cmd_t zc2 = { 0 }; | |
2350 | |
2351 (void) strcpy(zc2.zc_name, tofs); | |
2352 for (elem = nvlist_next_nvpair(nv, NULL); elem; | |
2353 elem = nvlist_next_nvpair(nv, elem)) { | |
2354 (void) strcpy(zc2.zc_value, nvpair_name(elem)); | |
2355 if (zfs_secpolicy_inherit(&zc2, CRED()) == 0) | |
2356 (void) zfs_ioc_inherit_prop(&zc2); | |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2357 } |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2358 } |
5367 | 2359 if (nv) |
2360 nvlist_free(nv); | |
2361 } | |
2362 | |
2363 /* | |
2364 * Set properties. Note, we ignore errors. Would be better to | |
2365 * do best-effort in zfs_set_prop_nvlist, too. | |
2366 */ | |
2367 (void) zfs_set_prop_nvlist(tofs, props); | |
2368 nvlist_free(props); | |
2369 | |
2370 off = fp->f_offset; | |
2371 error = dmu_recv_stream(&drc, fp->f_vnode, &off); | |
2372 | |
2373 if (error == 0) { | |
2374 if (zfsvfs != NULL) { | |
2375 char osname[MAXNAMELEN]; | |
2376 int mode; | |
2377 | |
2378 (void) zfs_suspend_fs(zfsvfs, osname, &mode); | |
2379 error = dmu_recv_end(&drc); | |
2380 error |= zfs_resume_fs(zfsvfs, osname, mode); | |
2381 } else { | |
2382 error = dmu_recv_end(&drc); | |
2383 } | |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2384 } |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2385 if (zfsvfs != NULL) |
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2386 VFS_RELE(zfsvfs->z_vfs); |
5367 | 2387 |
2388 zc->zc_cookie = off - fp->f_offset; | |
2389 if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) | |
2390 fp->f_offset = off; | |
2885 | 2391 |
789 | 2392 releasef(fd); |
2393 return (error); | |
2394 } | |
2395 | |
5367 | 2396 /* |
2397 * inputs: | |
2398 * zc_name name of snapshot to send | |
2399 * zc_value short name of incremental fromsnap (may be empty) | |
2400 * zc_cookie file descriptor to send stream to | |
2401 * zc_obj fromorigin flag (mutually exclusive with zc_value) | |
2402 * | |
2403 * outputs: none | |
2404 */ | |
789 | 2405 static int |
5367 | 2406 zfs_ioc_send(zfs_cmd_t *zc) |
789 | 2407 { |
2408 objset_t *fromsnap = NULL; | |
2409 objset_t *tosnap; | |
2410 file_t *fp; | |
2411 int error; | |
5367 | 2412 offset_t off; |
789 | 2413 |
2414 error = dmu_objset_open(zc->zc_name, DMU_OST_ANY, | |
2415 DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap); | |
2416 if (error) | |
2417 return (error); | |
2418 | |
2676 | 2419 if (zc->zc_value[0] != '\0') { |
2885 | 2420 char buf[MAXPATHLEN]; |
2421 char *cp; | |
2422 | |
2423 (void) strncpy(buf, zc->zc_name, sizeof (buf)); | |
2424 cp = strchr(buf, '@'); | |
2425 if (cp) | |
2426 *(cp+1) = 0; | |
2427 (void) strncat(buf, zc->zc_value, sizeof (buf)); | |
2428 error = dmu_objset_open(buf, DMU_OST_ANY, | |
789 | 2429 DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap); |
2430 if (error) { | |
2431 dmu_objset_close(tosnap); | |
2432 return (error); | |
2433 } | |
2434 } | |
2435 | |
2436 fp = getf(zc->zc_cookie); | |
2437 if (fp == NULL) { | |
2438 dmu_objset_close(tosnap); | |
2439 if (fromsnap) | |
2440 dmu_objset_close(fromsnap); | |
2441 return (EBADF); | |
2442 } | |
2443 | |
5367 | 2444 off = fp->f_offset; |
2445 error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off); | |
2446 | |
2447 if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) | |
2448 fp->f_offset = off; | |
789 | 2449 releasef(zc->zc_cookie); |
2450 if (fromsnap) | |
2451 dmu_objset_close(fromsnap); | |
2452 dmu_objset_close(tosnap); | |
2453 return (error); | |
2454 } | |
2455 | |
1544 | 2456 static int |
2457 zfs_ioc_inject_fault(zfs_cmd_t *zc) | |
2458 { | |
2459 int id, error; | |
2460 | |
2461 error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id, | |
2462 &zc->zc_inject_record); | |
2463 | |
2464 if (error == 0) | |
2465 zc->zc_guid = (uint64_t)id; | |
2466 | |
2467 return (error); | |
2468 } | |
2469 | |
2470 static int | |
2471 zfs_ioc_clear_fault(zfs_cmd_t *zc) | |
2472 { | |
2473 return (zio_clear_fault((int)zc->zc_guid)); | |
2474 } | |
2475 | |
2476 static int | |
2477 zfs_ioc_inject_list_next(zfs_cmd_t *zc) | |
2478 { | |
2479 int id = (int)zc->zc_guid; | |
2480 int error; | |
2481 | |
2482 error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name), | |
2483 &zc->zc_inject_record); | |
2484 | |
2485 zc->zc_guid = id; | |
2486 | |
2487 return (error); | |
2488 } | |
2489 | |
2490 static int | |
2491 zfs_ioc_error_log(zfs_cmd_t *zc) | |
2492 { | |
2493 spa_t *spa; | |
2494 int error; | |
2676 | 2495 size_t count = (size_t)zc->zc_nvlist_dst_size; |
1544 | 2496 |
2497 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
2498 return (error); | |
2499 | |
2676 | 2500 error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst, |
1544 | 2501 &count); |
2502 if (error == 0) | |
2676 | 2503 zc->zc_nvlist_dst_size = count; |
1544 | 2504 else |
2676 | 2505 zc->zc_nvlist_dst_size = spa_get_errlog_size(spa); |
1544 | 2506 |
2507 spa_close(spa, FTAG); | |
2508 | |
2509 return (error); | |
2510 } | |
2511 | |
2512 static int | |
2513 zfs_ioc_clear(zfs_cmd_t *zc) | |
2514 { | |
2515 spa_t *spa; | |
2516 vdev_t *vd; | |
4808 | 2517 uint64_t txg; |
1544 | 2518 int error; |
2519 | |
2520 if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) | |
2521 return (error); | |
2522 | |
5329 | 2523 /* |
2524 * Try to resume any I/Os which may have been suspended | |
2525 * as a result of a complete pool failure. | |
2526 */ | |
2527 if (!list_is_empty(&spa->spa_zio_list)) { | |
2528 if (zio_vdev_resume_io(spa) != 0) { | |
2529 spa_close(spa, FTAG); | |
2530 return (EIO); | |
2531 } | |
2532 } | |
2533 | |
4451 | 2534 txg = spa_vdev_enter(spa); |
1544 | 2535 |
2676 | 2536 if (zc->zc_guid == 0) { |
1544 | 2537 vd = NULL; |
2676 | 2538 } else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) { |
4451 | 2539 (void) spa_vdev_exit(spa, NULL, txg, ENODEV); |
1544 | 2540 spa_close(spa, FTAG); |
2541 return (ENODEV); | |
2542 } | |
2543 | |
5329 | 2544 vdev_clear(spa, vd, B_TRUE); |
1544 | 2545 |
4451 | 2546 (void) spa_vdev_exit(spa, NULL, txg, 0); |
1544 | 2547 |
2548 spa_close(spa, FTAG); | |
2549 | |
2550 return (0); | |
2551 } | |
2552 | |
5367 | 2553 /* |
2554 * inputs: | |
2555 * zc_name name of filesystem | |
2556 * zc_value name of origin snapshot | |
2557 * | |
2558 * outputs: none | |
2559 */ | |
1544 | 2560 static int |
2082 | 2561 zfs_ioc_promote(zfs_cmd_t *zc) |
2562 { | |
2417 | 2563 char *cp; |
2564 | |
2565 /* | |
2566 * We don't need to unmount *all* the origin fs's snapshots, but | |
2567 * it's easier. | |
2568 */ | |
2676 | 2569 cp = strchr(zc->zc_value, '@'); |
2417 | 2570 if (cp) |
2571 *cp = '\0'; | |
2676 | 2572 (void) dmu_objset_find(zc->zc_value, |
2417 | 2573 zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS); |
2082 | 2574 return (dsl_dataset_promote(zc->zc_name)); |
2575 } | |
2576 | |
4543 | 2577 /* |
2578 * We don't want to have a hard dependency | |
2579 * against some special symbols in sharefs | |
5331 | 2580 * nfs, and smbsrv. Determine them if needed when |
4543 | 2581 * the first file system is shared. |
5331 | 2582 * Neither sharefs, nfs or smbsrv are unloadable modules. |
4543 | 2583 */ |
5331 | 2584 int (*znfsexport_fs)(void *arg); |
4543 | 2585 int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t); |
5331 | 2586 int (*zsmbexport_fs)(void *arg, boolean_t add_share); |
2587 | |
2588 int zfs_nfsshare_inited; | |
2589 int zfs_smbshare_inited; | |
2590 | |
4543 | 2591 ddi_modhandle_t nfs_mod; |
2592 ddi_modhandle_t sharefs_mod; | |
5331 | 2593 ddi_modhandle_t smbsrv_mod; |
4543 | 2594 kmutex_t zfs_share_lock; |
2595 | |
2596 static int | |
5331 | 2597 zfs_init_sharefs() |
2598 { | |
2599 int error; | |
2600 | |
2601 ASSERT(MUTEX_HELD(&zfs_share_lock)); | |
2602 /* Both NFS and SMB shares also require sharetab support. */ | |
2603 if (sharefs_mod == NULL && ((sharefs_mod = | |
2604 ddi_modopen("fs/sharefs", | |
2605 KRTLD_MODE_FIRST, &error)) == NULL)) { | |
2606 return (ENOSYS); | |
2607 } | |
2608 if (zshare_fs == NULL && ((zshare_fs = | |
2609 (int (*)(enum sharefs_sys_op, share_t *, uint32_t)) | |
2610 ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) { | |
2611 return (ENOSYS); | |
2612 } | |
2613 return (0); | |
2614 } | |
2615 | |
2616 static int | |
4543 | 2617 zfs_ioc_share(zfs_cmd_t *zc) |
2618 { | |
2619 int error; | |
2620 int opcode; | |
2621 | |
5331 | 2622 switch (zc->zc_share.z_sharetype) { |
2623 case ZFS_SHARE_NFS: | |
2624 case ZFS_UNSHARE_NFS: | |
2625 if (zfs_nfsshare_inited == 0) { | |
2626 mutex_enter(&zfs_share_lock); | |
2627 if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs", | |
2628 KRTLD_MODE_FIRST, &error)) == NULL)) { | |
2629 mutex_exit(&zfs_share_lock); | |
2630 return (ENOSYS); | |
2631 } | |
2632 if (znfsexport_fs == NULL && | |
2633 ((znfsexport_fs = (int (*)(void *)) | |
2634 ddi_modsym(nfs_mod, | |
2635 "nfs_export", &error)) == NULL)) { | |
2636 mutex_exit(&zfs_share_lock); | |
2637 return (ENOSYS); | |
2638 } | |
2639 error = zfs_init_sharefs(); | |
2640 if (error) { | |
2641 mutex_exit(&zfs_share_lock); | |
2642 return (ENOSYS); | |
2643 } | |
2644 zfs_nfsshare_inited = 1; | |
4543 | 2645 mutex_exit(&zfs_share_lock); |
2646 } | |
5331 | 2647 break; |
2648 case ZFS_SHARE_SMB: | |
2649 case ZFS_UNSHARE_SMB: | |
2650 if (zfs_smbshare_inited == 0) { | |
2651 mutex_enter(&zfs_share_lock); | |
2652 if (smbsrv_mod == NULL && ((smbsrv_mod = | |
2653 ddi_modopen("drv/smbsrv", | |
2654 KRTLD_MODE_FIRST, &error)) == NULL)) { | |
2655 mutex_exit(&zfs_share_lock); | |
2656 return (ENOSYS); | |
2657 } | |
2658 if (zsmbexport_fs == NULL && ((zsmbexport_fs = | |
2659 (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod, | |
2660 "lmshrd_share_upcall", &error)) == NULL)) { | |
2661 mutex_exit(&zfs_share_lock); | |
2662 return (ENOSYS); | |
2663 } | |
2664 error = zfs_init_sharefs(); | |
2665 if (error) { | |
2666 mutex_exit(&zfs_share_lock); | |
2667 return (ENOSYS); | |
2668 } | |
2669 zfs_smbshare_inited = 1; | |
4543 | 2670 mutex_exit(&zfs_share_lock); |
2671 } | |
5331 | 2672 break; |
2673 default: | |
2674 return (EINVAL); | |
4543 | 2675 } |
2676 | |
5331 | 2677 switch (zc->zc_share.z_sharetype) { |
2678 case ZFS_SHARE_NFS: | |
2679 case ZFS_UNSHARE_NFS: | |
2680 if (error = | |
2681 znfsexport_fs((void *) | |
2682 (uintptr_t)zc->zc_share.z_exportdata)) | |
2683 return (error); | |
2684 break; | |
2685 case ZFS_SHARE_SMB: | |
2686 case ZFS_UNSHARE_SMB: | |
2687 if (error = zsmbexport_fs((void *) | |
2688 (uintptr_t)zc->zc_share.z_exportdata, | |
2689 zc->zc_share.z_sharetype == ZFS_SHARE_SMB ? | |
2690 B_TRUE : B_FALSE)) { | |
2691 return (error); | |
2692 } | |
2693 break; | |
2694 } | |
2695 | |
2696 opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS || | |
2697 zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ? | |
4543 | 2698 SHAREFS_ADD : SHAREFS_REMOVE; |
2699 | |
5331 | 2700 /* |
2701 * Add or remove share from sharetab | |
2702 */ | |
4543 | 2703 error = zshare_fs(opcode, |
2704 (void *)(uintptr_t)zc->zc_share.z_sharedata, | |
2705 zc->zc_share.z_sharemax); | |
2706 | |
2707 return (error); | |
2708 | |
2709 } | |
2710 | |
2711 /* | |
4988
db8abd9846d4
6595467 libzfs consumers should be allowed to write their own history (or none at all)
ek110237
parents:
4849
diff
changeset
|
2712 * pool create, destroy, and export don't log the history as part of |
db8abd9846d4
6595467 libzfs consumers should be allowed to write their own history (or none at all)
ek110237
parents:
4849
diff
changeset
|
2713 * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export |
db8abd9846d4
6595467 libzfs consumers should be allowed to write their own history (or none at all)
ek110237
parents:
4849
diff
changeset
|
2714 * do the logging of those commands. |
4543 | 2715 */ |
789 | 2716 static zfs_ioc_vec_t zfs_ioc_vec[] = { |
4715
e8d212dda064
6535695 Panic: shpp->sh_eof == shpp->sh_pool_create_len, file: ../../common/fs/zfs/spa_history.c, line: 235
ek110237
parents:
4670
diff
changeset
|
2717 { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE }, |
4577 | 2718 { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE }, |
2719 { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2720 { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE }, | |
2721 { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE }, | |
2722 { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE }, | |
2723 { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE }, | |
2724 { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2725 { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE }, | |
2726 { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2727 { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE }, | |
2728 { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2729 { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2730 { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2731 { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2732 { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2733 { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE }, | |
2734 { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, | |
5147
5e950ccc9585
6596190 "zfs list" is slow due to version property
rm160521
parents:
5118
diff
changeset
|
2735 { zfs_ioc_objset_version, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, |
4543 | 2736 { zfs_ioc_dataset_list_next, zfs_secpolicy_read, |
4577 | 2737 DATASET_NAME, B_FALSE }, |
4543 | 2738 { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, |
4577 | 2739 DATASET_NAME, B_FALSE }, |
2740 { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE }, | |
2741 { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, | |
2742 { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, | |
2743 { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE }, | |
2744 { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, | |
2745 { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE }, | |
2746 { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE }, | |
5367 | 2747 { zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE }, |
2748 { zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE }, | |
4577 | 2749 { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, |
2750 { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, | |
2751 { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE }, | |
2752 { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE }, | |
2753 { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2754 { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE }, | |
2755 { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, | |
2756 { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE }, | |
2757 { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE }, | |
2758 { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE }, | |
2759 { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE }, | |
2760 { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE }, | |
2761 { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE }, | |
2762 { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, | |
4543 | 2763 { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, |
4577 | 2764 DATASET_NAME, B_FALSE }, |
4849
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
2765 { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE }, |
3a61e0a9a953
6536043 arc_byteswap_func_t and dmu_byteswap_func_t are redundant
ahrens
parents:
4808
diff
changeset
|
2766 { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE }, |
789 | 2767 }; |
2768 | |
2769 static int | |
2770 zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) | |
2771 { | |
2772 zfs_cmd_t *zc; | |
2773 uint_t vec; | |
2199 | 2774 int error, rc; |
789 | 2775 |
2776 if (getminor(dev) != 0) | |
2777 return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp)); | |
2778 | |
2779 vec = cmd - ZFS_IOC; | |
4787 | 2780 ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip)); |
789 | 2781 |
2782 if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0])) | |
2783 return (EINVAL); | |
2784 | |
2785 zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); | |
2786 | |
2787 error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t)); | |
2788 | |
4787 | 2789 if (error == 0) |
4543 | 2790 error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr); |
789 | 2791 |
2792 /* | |
2793 * Ensure that all pool/dataset names are valid before we pass down to | |
2794 * the lower layers. | |
2795 */ | |
2796 if (error == 0) { | |
2797 zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; | |
2798 switch (zfs_ioc_vec[vec].zvec_namecheck) { | |
4577 | 2799 case POOL_NAME: |
789 | 2800 if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) |
2801 error = EINVAL; | |
2802 break; | |
2803 | |
4577 | 2804 case DATASET_NAME: |
789 | 2805 if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) |
2806 error = EINVAL; | |
2807 break; | |
2856 | 2808 |
4577 | 2809 case NO_NAME: |
2856 | 2810 break; |
789 | 2811 } |
2812 } | |
2813 | |
2814 if (error == 0) | |
2815 error = zfs_ioc_vec[vec].zvec_func(zc); | |
2816 | |
2199 | 2817 rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t)); |
4543 | 2818 if (error == 0) { |
2199 | 2819 error = rc; |
4543 | 2820 if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE) |
2821 zfs_log_history(zc); | |
2822 } | |
789 | 2823 |
2824 kmem_free(zc, sizeof (zfs_cmd_t)); | |
2825 return (error); | |
2826 } | |
2827 | |
2828 static int | |
2829 zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) | |
2830 { | |
2831 if (cmd != DDI_ATTACH) | |
2832 return (DDI_FAILURE); | |
2833 | |
2834 if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0, | |
2835 DDI_PSEUDO, 0) == DDI_FAILURE) | |
2836 return (DDI_FAILURE); | |
2837 | |
2838 zfs_dip = dip; | |
2839 | |
2840 ddi_report_dev(dip); | |
2841 | |
2842 return (DDI_SUCCESS); | |
2843 } | |
2844 | |
2845 static int | |
2846 zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) | |
2847 { | |
2848 if (spa_busy() || zfs_busy() || zvol_busy()) | |
2849 return (DDI_FAILURE); | |
2850 | |
2851 if (cmd != DDI_DETACH) | |
2852 return (DDI_FAILURE); | |
2853 | |
2854 zfs_dip = NULL; | |
2855 | |
2856 ddi_prop_remove_all(dip); | |
2857 ddi_remove_minor_node(dip, NULL); | |
2858 | |
2859 return (DDI_SUCCESS); | |
2860 } | |
2861 | |
2862 /*ARGSUSED*/ | |
2863 static int | |
2864 zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) | |
2865 { | |
2866 switch (infocmd) { | |
2867 case DDI_INFO_DEVT2DEVINFO: | |
2868 *result = zfs_dip; | |
2869 return (DDI_SUCCESS); | |
2870 | |
2871 case DDI_INFO_DEVT2INSTANCE: | |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2872 *result = (void *)0; |
789 | 2873 return (DDI_SUCCESS); |
2874 } | |
2875 | |
2876 return (DDI_FAILURE); | |
2877 } | |
2878 | |
2879 /* | |
2880 * OK, so this is a little weird. | |
2881 * | |
2882 * /dev/zfs is the control node, i.e. minor 0. | |
2883 * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0. | |
2884 * | |
2885 * /dev/zfs has basically nothing to do except serve up ioctls, | |
2886 * so most of the standard driver entry points are in zvol.c. | |
2887 */ | |
2888 static struct cb_ops zfs_cb_ops = { | |
2889 zvol_open, /* open */ | |
2890 zvol_close, /* close */ | |
2891 zvol_strategy, /* strategy */ | |
2892 nodev, /* print */ | |
2893 nodev, /* dump */ | |
2894 zvol_read, /* read */ | |
2895 zvol_write, /* write */ | |
2896 zfsdev_ioctl, /* ioctl */ | |
2897 nodev, /* devmap */ | |
2898 nodev, /* mmap */ | |
2899 nodev, /* segmap */ | |
2900 nochpoll, /* poll */ | |
2901 ddi_prop_op, /* prop_op */ | |
2902 NULL, /* streamtab */ | |
2903 D_NEW | D_MP | D_64BIT, /* Driver compatibility flag */ | |
2904 CB_REV, /* version */ | |
3638
6b28ebc717aa
6496357 spec_fsync() is useless on devices that do write caching
billm
parents:
3444
diff
changeset
|
2905 nodev, /* async read */ |
6b28ebc717aa
6496357 spec_fsync() is useless on devices that do write caching
billm
parents:
3444
diff
changeset
|
2906 nodev, /* async write */ |
789 | 2907 }; |
2908 | |
2909 static struct dev_ops zfs_dev_ops = { | |
2910 DEVO_REV, /* version */ | |
2911 0, /* refcnt */ | |
2912 zfs_info, /* info */ | |
2913 nulldev, /* identify */ | |
2914 nulldev, /* probe */ | |
2915 zfs_attach, /* attach */ | |
2916 zfs_detach, /* detach */ | |
2917 nodev, /* reset */ | |
2918 &zfs_cb_ops, /* driver operations */ | |
2919 NULL /* no bus operations */ | |
2920 }; | |
2921 | |
2922 static struct modldrv zfs_modldrv = { | |
4577 | 2923 &mod_driverops, "ZFS storage pool version " SPA_VERSION_STRING, |
2676 | 2924 &zfs_dev_ops |
789 | 2925 }; |
2926 | |
2927 static struct modlinkage modlinkage = { | |
2928 MODREV_1, | |
2929 (void *)&zfs_modlfs, | |
2930 (void *)&zfs_modldrv, | |
2931 NULL | |
2932 }; | |
2933 | |
4720
8edc0d2e6f3f
6535160 Lock contention on zl_lock from zil_commit
fr157268
parents:
4715
diff
changeset
|
2934 |
8edc0d2e6f3f
6535160 Lock contention on zl_lock from zil_commit
fr157268
parents:
4715
diff
changeset
|
2935 uint_t zfs_fsyncer_key; |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2936 extern uint_t rrw_tsd_key; |
4720
8edc0d2e6f3f
6535160 Lock contention on zl_lock from zil_commit
fr157268
parents:
4715
diff
changeset
|
2937 |
789 | 2938 int |
2939 _init(void) | |
2940 { | |
2941 int error; | |
2942 | |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2943 spa_init(FREAD | FWRITE); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2944 zfs_init(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2945 zvol_init(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2946 |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2947 if ((error = mod_install(&modlinkage)) != 0) { |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2948 zvol_fini(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2949 zfs_fini(); |
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2950 spa_fini(); |
789 | 2951 return (error); |
849
8d799fd81a9b
6345023 /dev/zfs fails to open once ZFS module is unloaded
bonwick
parents:
789
diff
changeset
|
2952 } |
789 | 2953 |
4720
8edc0d2e6f3f
6535160 Lock contention on zl_lock from zil_commit
fr157268
parents:
4715
diff
changeset
|
2954 tsd_create(&zfs_fsyncer_key, NULL); |
5326
6752aa2bd5bc
6425096 want online 'zfs recv' (read only and read/write)
ek110237
parents:
5147
diff
changeset
|
2955 tsd_create(&rrw_tsd_key, NULL); |
4720
8edc0d2e6f3f
6535160 Lock contention on zl_lock from zil_commit
fr157268
parents:
4715
diff
changeset
|
2956 |
789 | 2957 error = ldi_ident_from_mod(&modlinkage, &zfs_li); |
2958 ASSERT(error == 0); | |
4543 | 2959 mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL); |
789 | 2960 |
2961 return (0); | |
2962 } | |
2963 | |
2964 int | |
2965 _fini(void) | |
2966 { | |
2967 int error; | |
2968 | |
1544 | 2969 if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled) |
789 | 2970 return (EBUSY); |
2971 | |
2972 if ((error = mod_remove(&modlinkage)) != 0) | |
2973 return (error); | |
2974 | |
2975 zvol_fini(); | |
2976 zfs_fini(); | |
2977 spa_fini(); | |
5331 | 2978 if (zfs_nfsshare_inited) |
4543 | 2979 (void) ddi_modclose(nfs_mod); |
5331 | 2980 if (zfs_smbshare_inited) |
2981 (void) ddi_modclose(smbsrv_mod); | |
2982 if (zfs_nfsshare_inited || zfs_smbshare_inited) | |
4543 | 2983 (void) ddi_modclose(sharefs_mod); |
789 | 2984 |
4720
8edc0d2e6f3f
6535160 Lock contention on zl_lock from zil_commit
fr157268
parents:
4715
diff
changeset
|
2985 tsd_destroy(&zfs_fsyncer_key); |
789 | 2986 ldi_ident_release(zfs_li); |
2987 zfs_li = NULL; | |
4543 | 2988 mutex_destroy(&zfs_share_lock); |
789 | 2989 |
2990 return (error); | |
2991 } | |
2992 | |
2993 int | |
2994 _info(struct modinfo *modinfop) | |
2995 { | |
2996 return (mod_info(&modlinkage, modinfop)); | |
2997 } |