xref: /illumos-gate/usr/src/uts/common/fs/zfs/zfs_ioctl.c (revision b1b8ab34)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5441d80aaSlling  * Common Development and Distribution License (the "License").
6441d80aaSlling  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
21fa9e4066Sahrens /*
2255434c77Sek  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23fa9e4066Sahrens  * Use is subject to license terms.
24fa9e4066Sahrens  */
25fa9e4066Sahrens 
26fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
27fa9e4066Sahrens 
28fa9e4066Sahrens #include <sys/types.h>
29fa9e4066Sahrens #include <sys/param.h>
30fa9e4066Sahrens #include <sys/errno.h>
31fa9e4066Sahrens #include <sys/uio.h>
32fa9e4066Sahrens #include <sys/buf.h>
33fa9e4066Sahrens #include <sys/modctl.h>
34fa9e4066Sahrens #include <sys/open.h>
35fa9e4066Sahrens #include <sys/file.h>
36fa9e4066Sahrens #include <sys/kmem.h>
37fa9e4066Sahrens #include <sys/conf.h>
38fa9e4066Sahrens #include <sys/cmn_err.h>
39fa9e4066Sahrens #include <sys/stat.h>
40fa9e4066Sahrens #include <sys/zfs_ioctl.h>
41fa9e4066Sahrens #include <sys/zap.h>
42fa9e4066Sahrens #include <sys/spa.h>
43*b1b8ab34Slling #include <sys/spa_impl.h>
44fa9e4066Sahrens #include <sys/vdev.h>
45*b1b8ab34Slling #include <sys/vdev_impl.h>
46fa9e4066Sahrens #include <sys/dmu.h>
47fa9e4066Sahrens #include <sys/dsl_dir.h>
48fa9e4066Sahrens #include <sys/dsl_dataset.h>
49fa9e4066Sahrens #include <sys/dsl_prop.h>
50fa9e4066Sahrens #include <sys/ddi.h>
51fa9e4066Sahrens #include <sys/sunddi.h>
52fa9e4066Sahrens #include <sys/sunldi.h>
53fa9e4066Sahrens #include <sys/policy.h>
54fa9e4066Sahrens #include <sys/zone.h>
55fa9e4066Sahrens #include <sys/nvpair.h>
56fa9e4066Sahrens #include <sys/pathname.h>
57fa9e4066Sahrens #include <sys/mount.h>
58fa9e4066Sahrens #include <sys/sdt.h>
59fa9e4066Sahrens #include <sys/fs/zfs.h>
60fa9e4066Sahrens #include <sys/zfs_ctldir.h>
61a2eea2e1Sahrens #include <sys/zvol.h>
62fa9e4066Sahrens 
63fa9e4066Sahrens #include "zfs_namecheck.h"
64e9dbad6fSeschrock #include "zfs_prop.h"
65fa9e4066Sahrens 
66fa9e4066Sahrens extern struct modlfs zfs_modlfs;
67fa9e4066Sahrens 
68fa9e4066Sahrens extern void zfs_init(void);
69fa9e4066Sahrens extern void zfs_fini(void);
70fa9e4066Sahrens 
71fa9e4066Sahrens ldi_ident_t zfs_li = NULL;
72fa9e4066Sahrens dev_info_t *zfs_dip;
73fa9e4066Sahrens 
74fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *);
75e9dbad6fSeschrock typedef int zfs_secpolicy_func_t(const char *, cred_t *);
76fa9e4066Sahrens 
77fa9e4066Sahrens typedef struct zfs_ioc_vec {
78fa9e4066Sahrens 	zfs_ioc_func_t		*zvec_func;
79fa9e4066Sahrens 	zfs_secpolicy_func_t	*zvec_secpolicy;
80fa9e4066Sahrens 	enum {
81fa9e4066Sahrens 		no_name,
82fa9e4066Sahrens 		pool_name,
83fa9e4066Sahrens 		dataset_name
84fa9e4066Sahrens 	}			zvec_namecheck;
85fa9e4066Sahrens } zfs_ioc_vec_t;
86fa9e4066Sahrens 
87fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */
88fa9e4066Sahrens void
89fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
90fa9e4066Sahrens {
91fa9e4066Sahrens 	const char *newfile;
92fa9e4066Sahrens 	char buf[256];
93fa9e4066Sahrens 	va_list adx;
94fa9e4066Sahrens 
95fa9e4066Sahrens 	/*
96fa9e4066Sahrens 	 * Get rid of annoying "../common/" prefix to filename.
97fa9e4066Sahrens 	 */
98fa9e4066Sahrens 	newfile = strrchr(file, '/');
99fa9e4066Sahrens 	if (newfile != NULL) {
100fa9e4066Sahrens 		newfile = newfile + 1; /* Get rid of leading / */
101fa9e4066Sahrens 	} else {
102fa9e4066Sahrens 		newfile = file;
103fa9e4066Sahrens 	}
104fa9e4066Sahrens 
105fa9e4066Sahrens 	va_start(adx, fmt);
106fa9e4066Sahrens 	(void) vsnprintf(buf, sizeof (buf), fmt, adx);
107fa9e4066Sahrens 	va_end(adx);
108fa9e4066Sahrens 
109fa9e4066Sahrens 	/*
110fa9e4066Sahrens 	 * To get this data, use the zfs-dprintf probe as so:
111fa9e4066Sahrens 	 * dtrace -q -n 'zfs-dprintf \
112fa9e4066Sahrens 	 *	/stringof(arg0) == "dbuf.c"/ \
113fa9e4066Sahrens 	 *	{printf("%s: %s", stringof(arg1), stringof(arg3))}'
114fa9e4066Sahrens 	 * arg0 = file name
115fa9e4066Sahrens 	 * arg1 = function name
116fa9e4066Sahrens 	 * arg2 = line number
117fa9e4066Sahrens 	 * arg3 = message
118fa9e4066Sahrens 	 */
119fa9e4066Sahrens 	DTRACE_PROBE4(zfs__dprintf,
120fa9e4066Sahrens 	    char *, newfile, char *, func, int, line, char *, buf);
121fa9e4066Sahrens }
122fa9e4066Sahrens 
123fa9e4066Sahrens /*
124fa9e4066Sahrens  * Policy for top-level read operations (list pools).  Requires no privileges,
125fa9e4066Sahrens  * and can be used in the local zone, as there is no associated dataset.
126fa9e4066Sahrens  */
127fa9e4066Sahrens /* ARGSUSED */
128fa9e4066Sahrens static int
129e9dbad6fSeschrock zfs_secpolicy_none(const char *unused1, cred_t *cr)
130fa9e4066Sahrens {
131fa9e4066Sahrens 	return (0);
132fa9e4066Sahrens }
133fa9e4066Sahrens 
134fa9e4066Sahrens /*
135fa9e4066Sahrens  * Policy for dataset read operations (list children, get statistics).  Requires
136fa9e4066Sahrens  * no privileges, but must be visible in the local zone.
137fa9e4066Sahrens  */
138fa9e4066Sahrens /* ARGSUSED */
139fa9e4066Sahrens static int
140e9dbad6fSeschrock zfs_secpolicy_read(const char *dataset, cred_t *cr)
141fa9e4066Sahrens {
142fa9e4066Sahrens 	if (INGLOBALZONE(curproc) ||
143fa9e4066Sahrens 	    zone_dataset_visible(dataset, NULL))
144fa9e4066Sahrens 		return (0);
145fa9e4066Sahrens 
146fa9e4066Sahrens 	return (ENOENT);
147fa9e4066Sahrens }
148fa9e4066Sahrens 
149fa9e4066Sahrens static int
150fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr)
151fa9e4066Sahrens {
152fa9e4066Sahrens 	uint64_t zoned;
153fa9e4066Sahrens 	int writable = 1;
154fa9e4066Sahrens 
155fa9e4066Sahrens 	/*
156fa9e4066Sahrens 	 * The dataset must be visible by this zone -- check this first
157fa9e4066Sahrens 	 * so they don't see EPERM on something they shouldn't know about.
158fa9e4066Sahrens 	 */
159fa9e4066Sahrens 	if (!INGLOBALZONE(curproc) &&
160fa9e4066Sahrens 	    !zone_dataset_visible(dataset, &writable))
161fa9e4066Sahrens 		return (ENOENT);
162fa9e4066Sahrens 
163fa9e4066Sahrens 	if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL))
164fa9e4066Sahrens 		return (ENOENT);
165fa9e4066Sahrens 
166fa9e4066Sahrens 	if (INGLOBALZONE(curproc)) {
167fa9e4066Sahrens 		/*
168fa9e4066Sahrens 		 * If the fs is zoned, only root can access it from the
169fa9e4066Sahrens 		 * global zone.
170fa9e4066Sahrens 		 */
171fa9e4066Sahrens 		if (secpolicy_zfs(cr) && zoned)
172fa9e4066Sahrens 			return (EPERM);
173fa9e4066Sahrens 	} else {
174fa9e4066Sahrens 		/*
175fa9e4066Sahrens 		 * If we are in a local zone, the 'zoned' property must be set.
176fa9e4066Sahrens 		 */
177fa9e4066Sahrens 		if (!zoned)
178fa9e4066Sahrens 			return (EPERM);
179fa9e4066Sahrens 
180fa9e4066Sahrens 		/* must be writable by this zone */
181fa9e4066Sahrens 		if (!writable)
182fa9e4066Sahrens 			return (EPERM);
183fa9e4066Sahrens 	}
184fa9e4066Sahrens 	return (0);
185fa9e4066Sahrens }
186fa9e4066Sahrens 
187fa9e4066Sahrens /*
188fa9e4066Sahrens  * Policy for dataset write operations (create children, set properties, etc).
189fa9e4066Sahrens  * Requires SYS_MOUNT privilege, and must be writable in the local zone.
190fa9e4066Sahrens  */
191fa9e4066Sahrens int
192e9dbad6fSeschrock zfs_secpolicy_write(const char *dataset, cred_t *cr)
193fa9e4066Sahrens {
194fa9e4066Sahrens 	int error;
195fa9e4066Sahrens 
196fa9e4066Sahrens 	if (error = zfs_dozonecheck(dataset, cr))
197fa9e4066Sahrens 		return (error);
198fa9e4066Sahrens 
199fa9e4066Sahrens 	return (secpolicy_zfs(cr));
200fa9e4066Sahrens }
201fa9e4066Sahrens 
202fa9e4066Sahrens /*
203fa9e4066Sahrens  * Policy for operations that want to write a dataset's parent:
204fa9e4066Sahrens  * create, destroy, snapshot, clone, restore.
205fa9e4066Sahrens  */
206fa9e4066Sahrens static int
207e9dbad6fSeschrock zfs_secpolicy_parent(const char *dataset, cred_t *cr)
208fa9e4066Sahrens {
209fa9e4066Sahrens 	char parentname[MAXNAMELEN];
210fa9e4066Sahrens 	char *cp;
211fa9e4066Sahrens 
212fa9e4066Sahrens 	/*
213fa9e4066Sahrens 	 * Remove the @bla or /bla from the end of the name to get the parent.
214fa9e4066Sahrens 	 */
215fa9e4066Sahrens 	(void) strncpy(parentname, dataset, sizeof (parentname));
216fa9e4066Sahrens 	cp = strrchr(parentname, '@');
217fa9e4066Sahrens 	if (cp != NULL) {
218fa9e4066Sahrens 		cp[0] = '\0';
219fa9e4066Sahrens 	} else {
220fa9e4066Sahrens 		cp = strrchr(parentname, '/');
221fa9e4066Sahrens 		if (cp == NULL)
222fa9e4066Sahrens 			return (ENOENT);
223fa9e4066Sahrens 		cp[0] = '\0';
224fa9e4066Sahrens 
225fa9e4066Sahrens 	}
226fa9e4066Sahrens 
227e9dbad6fSeschrock 	return (zfs_secpolicy_write(parentname, cr));
228fa9e4066Sahrens }
229fa9e4066Sahrens 
230fa9e4066Sahrens /*
231fa9e4066Sahrens  * Policy for pool operations - create/destroy pools, add vdevs, etc.  Requires
232fa9e4066Sahrens  * SYS_CONFIG privilege, which is not available in a local zone.
233fa9e4066Sahrens  */
234fa9e4066Sahrens /* ARGSUSED */
235fa9e4066Sahrens static int
236e9dbad6fSeschrock zfs_secpolicy_config(const char *unused, cred_t *cr)
237fa9e4066Sahrens {
238fa9e4066Sahrens 	if (secpolicy_sys_config(cr, B_FALSE) != 0)
239fa9e4066Sahrens 		return (EPERM);
240fa9e4066Sahrens 
241fa9e4066Sahrens 	return (0);
242fa9e4066Sahrens }
243fa9e4066Sahrens 
244ea8dc4b6Seschrock /*
245ea8dc4b6Seschrock  * Policy for fault injection.  Requires all privileges.
246ea8dc4b6Seschrock  */
247ea8dc4b6Seschrock /* ARGSUSED */
248ea8dc4b6Seschrock static int
249e9dbad6fSeschrock zfs_secpolicy_inject(const char *unused, cred_t *cr)
250ea8dc4b6Seschrock {
251ea8dc4b6Seschrock 	return (secpolicy_zinject(cr));
252ea8dc4b6Seschrock }
253ea8dc4b6Seschrock 
254fa9e4066Sahrens /*
255fa9e4066Sahrens  * Returns the nvlist as specified by the user in the zfs_cmd_t.
256fa9e4066Sahrens  */
257fa9e4066Sahrens static int
258e9dbad6fSeschrock get_nvlist(zfs_cmd_t *zc, nvlist_t **nvp)
259fa9e4066Sahrens {
260fa9e4066Sahrens 	char *packed;
261fa9e4066Sahrens 	size_t size;
262fa9e4066Sahrens 	int error;
263fa9e4066Sahrens 	nvlist_t *config = NULL;
264fa9e4066Sahrens 
265fa9e4066Sahrens 	/*
266e9dbad6fSeschrock 	 * Read in and unpack the user-supplied nvlist.
267fa9e4066Sahrens 	 */
268e9dbad6fSeschrock 	if ((size = zc->zc_nvlist_src_size) == 0)
269fa9e4066Sahrens 		return (EINVAL);
270fa9e4066Sahrens 
271fa9e4066Sahrens 	packed = kmem_alloc(size, KM_SLEEP);
272fa9e4066Sahrens 
273e9dbad6fSeschrock 	if ((error = xcopyin((void *)(uintptr_t)zc->zc_nvlist_src, packed,
274fa9e4066Sahrens 	    size)) != 0) {
275fa9e4066Sahrens 		kmem_free(packed, size);
276fa9e4066Sahrens 		return (error);
277fa9e4066Sahrens 	}
278fa9e4066Sahrens 
279fa9e4066Sahrens 	if ((error = nvlist_unpack(packed, size, &config, 0)) != 0) {
280fa9e4066Sahrens 		kmem_free(packed, size);
281fa9e4066Sahrens 		return (error);
282fa9e4066Sahrens 	}
283fa9e4066Sahrens 
284fa9e4066Sahrens 	kmem_free(packed, size);
285fa9e4066Sahrens 
286fa9e4066Sahrens 	*nvp = config;
287fa9e4066Sahrens 	return (0);
288fa9e4066Sahrens }
289fa9e4066Sahrens 
290e9dbad6fSeschrock static int
291e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
292e9dbad6fSeschrock {
293e9dbad6fSeschrock 	char *packed = NULL;
294e9dbad6fSeschrock 	size_t size;
295e9dbad6fSeschrock 	int error;
296e9dbad6fSeschrock 
297e9dbad6fSeschrock 	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
298e9dbad6fSeschrock 
299e9dbad6fSeschrock 	if (size > zc->zc_nvlist_dst_size) {
300e9dbad6fSeschrock 		error = ENOMEM;
301e9dbad6fSeschrock 	} else {
302e9dbad6fSeschrock 		VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
303e9dbad6fSeschrock 		    KM_SLEEP) == 0);
304e9dbad6fSeschrock 		error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst,
305e9dbad6fSeschrock 		    size);
306e9dbad6fSeschrock 		kmem_free(packed, size);
307e9dbad6fSeschrock 	}
308e9dbad6fSeschrock 
309e9dbad6fSeschrock 	zc->zc_nvlist_dst_size = size;
310e9dbad6fSeschrock 	return (error);
311e9dbad6fSeschrock }
312e9dbad6fSeschrock 
313fa9e4066Sahrens static int
314fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc)
315fa9e4066Sahrens {
316fa9e4066Sahrens 	int error;
317fa9e4066Sahrens 	nvlist_t *config;
318fa9e4066Sahrens 
319e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) != 0)
320fa9e4066Sahrens 		return (error);
321fa9e4066Sahrens 
322e9dbad6fSeschrock 	error = spa_create(zc->zc_name, config, zc->zc_value[0] == '\0' ?
323e9dbad6fSeschrock 	    NULL : zc->zc_value);
324fa9e4066Sahrens 
325fa9e4066Sahrens 	nvlist_free(config);
326fa9e4066Sahrens 
327fa9e4066Sahrens 	return (error);
328fa9e4066Sahrens }
329fa9e4066Sahrens 
330fa9e4066Sahrens static int
331fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc)
332fa9e4066Sahrens {
333fa9e4066Sahrens 	return (spa_destroy(zc->zc_name));
334fa9e4066Sahrens }
335fa9e4066Sahrens 
336fa9e4066Sahrens static int
337fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc)
338fa9e4066Sahrens {
339fa9e4066Sahrens 	int error;
340fa9e4066Sahrens 	nvlist_t *config;
341fa9e4066Sahrens 	uint64_t guid;
342fa9e4066Sahrens 
343e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) != 0)
344fa9e4066Sahrens 		return (error);
345fa9e4066Sahrens 
346fa9e4066Sahrens 	if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
347ea8dc4b6Seschrock 	    guid != zc->zc_guid)
348fa9e4066Sahrens 		error = EINVAL;
349fa9e4066Sahrens 	else
350fa9e4066Sahrens 		error = spa_import(zc->zc_name, config,
351e9dbad6fSeschrock 		    zc->zc_value[0] == '\0' ? NULL : zc->zc_value);
352fa9e4066Sahrens 
353fa9e4066Sahrens 	nvlist_free(config);
354fa9e4066Sahrens 
355fa9e4066Sahrens 	return (error);
356fa9e4066Sahrens }
357fa9e4066Sahrens 
358fa9e4066Sahrens static int
359fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc)
360fa9e4066Sahrens {
36144cd46caSbillm 	return (spa_export(zc->zc_name, NULL));
362fa9e4066Sahrens }
363fa9e4066Sahrens 
364fa9e4066Sahrens static int
365fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc)
366fa9e4066Sahrens {
367fa9e4066Sahrens 	nvlist_t *configs;
368fa9e4066Sahrens 	int error;
369fa9e4066Sahrens 
370fa9e4066Sahrens 	if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
371fa9e4066Sahrens 		return (EEXIST);
372fa9e4066Sahrens 
373e9dbad6fSeschrock 	error = put_nvlist(zc, configs);
374fa9e4066Sahrens 
375fa9e4066Sahrens 	nvlist_free(configs);
376fa9e4066Sahrens 
377fa9e4066Sahrens 	return (error);
378fa9e4066Sahrens }
379fa9e4066Sahrens 
380fa9e4066Sahrens static int
381fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc)
382fa9e4066Sahrens {
383fa9e4066Sahrens 	nvlist_t *config;
384fa9e4066Sahrens 	int error;
385ea8dc4b6Seschrock 	int ret = 0;
386fa9e4066Sahrens 
387e9dbad6fSeschrock 	error = spa_get_stats(zc->zc_name, &config, zc->zc_value,
388e9dbad6fSeschrock 	    sizeof (zc->zc_value));
389fa9e4066Sahrens 
390fa9e4066Sahrens 	if (config != NULL) {
391e9dbad6fSeschrock 		ret = put_nvlist(zc, config);
392fa9e4066Sahrens 		nvlist_free(config);
393ea8dc4b6Seschrock 
394ea8dc4b6Seschrock 		/*
395ea8dc4b6Seschrock 		 * The config may be present even if 'error' is non-zero.
396ea8dc4b6Seschrock 		 * In this case we return success, and preserve the real errno
397ea8dc4b6Seschrock 		 * in 'zc_cookie'.
398ea8dc4b6Seschrock 		 */
399ea8dc4b6Seschrock 		zc->zc_cookie = error;
400fa9e4066Sahrens 	} else {
401ea8dc4b6Seschrock 		ret = error;
402fa9e4066Sahrens 	}
403fa9e4066Sahrens 
404ea8dc4b6Seschrock 	return (ret);
405fa9e4066Sahrens }
406fa9e4066Sahrens 
407fa9e4066Sahrens /*
408fa9e4066Sahrens  * Try to import the given pool, returning pool stats as appropriate so that
409fa9e4066Sahrens  * user land knows which devices are available and overall pool health.
410fa9e4066Sahrens  */
411fa9e4066Sahrens static int
412fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
413fa9e4066Sahrens {
414fa9e4066Sahrens 	nvlist_t *tryconfig, *config;
415fa9e4066Sahrens 	int error;
416fa9e4066Sahrens 
417e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &tryconfig)) != 0)
418fa9e4066Sahrens 		return (error);
419fa9e4066Sahrens 
420fa9e4066Sahrens 	config = spa_tryimport(tryconfig);
421fa9e4066Sahrens 
422fa9e4066Sahrens 	nvlist_free(tryconfig);
423fa9e4066Sahrens 
424fa9e4066Sahrens 	if (config == NULL)
425fa9e4066Sahrens 		return (EINVAL);
426fa9e4066Sahrens 
427e9dbad6fSeschrock 	error = put_nvlist(zc, config);
428fa9e4066Sahrens 	nvlist_free(config);
429fa9e4066Sahrens 
430fa9e4066Sahrens 	return (error);
431fa9e4066Sahrens }
432fa9e4066Sahrens 
433fa9e4066Sahrens static int
434fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc)
435fa9e4066Sahrens {
436fa9e4066Sahrens 	spa_t *spa;
437fa9e4066Sahrens 	int error;
438fa9e4066Sahrens 
43906eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
44006eeb2adSek 		return (error);
44106eeb2adSek 
44206eeb2adSek 	error = spa_scrub(spa, zc->zc_cookie, B_FALSE);
44306eeb2adSek 
44406eeb2adSek 	spa_close(spa, FTAG);
44506eeb2adSek 
446fa9e4066Sahrens 	return (error);
447fa9e4066Sahrens }
448fa9e4066Sahrens 
449fa9e4066Sahrens static int
450fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc)
451fa9e4066Sahrens {
452fa9e4066Sahrens 	spa_t *spa;
453fa9e4066Sahrens 	int error;
454fa9e4066Sahrens 
455fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
456fa9e4066Sahrens 	if (error == 0) {
457fa9e4066Sahrens 		spa_freeze(spa);
458fa9e4066Sahrens 		spa_close(spa, FTAG);
459fa9e4066Sahrens 	}
460fa9e4066Sahrens 	return (error);
461fa9e4066Sahrens }
462fa9e4066Sahrens 
463eaca9bbdSeschrock static int
464eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc)
465eaca9bbdSeschrock {
466eaca9bbdSeschrock 	spa_t *spa;
467eaca9bbdSeschrock 	int error;
468eaca9bbdSeschrock 
46906eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
47006eeb2adSek 		return (error);
47106eeb2adSek 
47206eeb2adSek 	spa_upgrade(spa);
47306eeb2adSek 
47406eeb2adSek 	spa_close(spa, FTAG);
47506eeb2adSek 
47606eeb2adSek 	return (error);
47706eeb2adSek }
47806eeb2adSek 
47906eeb2adSek static int
48006eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc)
48106eeb2adSek {
48206eeb2adSek 	spa_t *spa;
48306eeb2adSek 	char *hist_buf;
48406eeb2adSek 	uint64_t size;
48506eeb2adSek 	int error;
48606eeb2adSek 
48706eeb2adSek 	if ((size = zc->zc_history_len) == 0)
48806eeb2adSek 		return (EINVAL);
48906eeb2adSek 
49006eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
49106eeb2adSek 		return (error);
49206eeb2adSek 
493d7306b64Sek 	if (spa_version(spa) < ZFS_VERSION_ZPOOL_HISTORY) {
494d7306b64Sek 		spa_close(spa, FTAG);
495d7306b64Sek 		return (ENOTSUP);
496d7306b64Sek 	}
497d7306b64Sek 
49806eeb2adSek 	hist_buf = kmem_alloc(size, KM_SLEEP);
49906eeb2adSek 	if ((error = spa_history_get(spa, &zc->zc_history_offset,
50006eeb2adSek 	    &zc->zc_history_len, hist_buf)) == 0) {
50106eeb2adSek 		error = xcopyout(hist_buf, (char *)(uintptr_t)zc->zc_history,
50206eeb2adSek 		    zc->zc_history_len);
50306eeb2adSek 	}
50406eeb2adSek 
50506eeb2adSek 	spa_close(spa, FTAG);
50606eeb2adSek 	kmem_free(hist_buf, size);
50706eeb2adSek 	return (error);
50806eeb2adSek }
50906eeb2adSek 
51006eeb2adSek static int
51106eeb2adSek zfs_ioc_pool_log_history(zfs_cmd_t *zc)
51206eeb2adSek {
51306eeb2adSek 	spa_t *spa;
51406eeb2adSek 	char *history_str = NULL;
51506eeb2adSek 	size_t size;
51606eeb2adSek 	int error;
51706eeb2adSek 
51806eeb2adSek 	size = zc->zc_history_len;
51906eeb2adSek 	if (size == 0 || size > HIS_MAX_RECORD_LEN)
52006eeb2adSek 		return (EINVAL);
52106eeb2adSek 
52206eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
52306eeb2adSek 		return (error);
52406eeb2adSek 
525d7306b64Sek 	if (spa_version(spa) < ZFS_VERSION_ZPOOL_HISTORY) {
526d7306b64Sek 		spa_close(spa, FTAG);
527d7306b64Sek 		return (ENOTSUP);
528d7306b64Sek 	}
529d7306b64Sek 
53006eeb2adSek 	/* add one for the NULL delimiter */
53106eeb2adSek 	size++;
53206eeb2adSek 	history_str = kmem_alloc(size, KM_SLEEP);
53306eeb2adSek 	if ((error = xcopyin((void *)(uintptr_t)zc->zc_history, history_str,
53406eeb2adSek 	    size)) != 0) {
535eaca9bbdSeschrock 		spa_close(spa, FTAG);
53606eeb2adSek 		kmem_free(history_str, size);
53706eeb2adSek 		return (error);
538eaca9bbdSeschrock 	}
53906eeb2adSek 	history_str[size - 1] = '\0';
54006eeb2adSek 
54106eeb2adSek 	error = spa_history_log(spa, history_str, zc->zc_history_offset);
54206eeb2adSek 
54306eeb2adSek 	spa_close(spa, FTAG);
54406eeb2adSek 	kmem_free(history_str, size);
54506eeb2adSek 
546eaca9bbdSeschrock 	return (error);
547eaca9bbdSeschrock }
548eaca9bbdSeschrock 
54955434c77Sek static int
55055434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc)
55155434c77Sek {
55255434c77Sek 	int error;
55355434c77Sek 
554*b1b8ab34Slling 	if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value))
55555434c77Sek 		return (error);
55655434c77Sek 
55755434c77Sek 	return (0);
55855434c77Sek }
55955434c77Sek 
56055434c77Sek static int
56155434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc)
56255434c77Sek {
56355434c77Sek 	objset_t *osp;
56455434c77Sek 	int error;
56555434c77Sek 
56655434c77Sek 	if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS,
56755434c77Sek 	    DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0)
56855434c77Sek 		return (error);
56955434c77Sek 
57055434c77Sek 	error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value,
57155434c77Sek 	    sizeof (zc->zc_value));
57255434c77Sek 	dmu_objset_close(osp);
57355434c77Sek 
57455434c77Sek 	return (error);
57555434c77Sek }
57655434c77Sek 
577fa9e4066Sahrens static int
578fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc)
579fa9e4066Sahrens {
580fa9e4066Sahrens 	spa_t *spa;
581fa9e4066Sahrens 	int error;
582fa9e4066Sahrens 	nvlist_t *config;
583fa9e4066Sahrens 
584fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
585fa9e4066Sahrens 	if (error != 0)
586fa9e4066Sahrens 		return (error);
587fa9e4066Sahrens 
588*b1b8ab34Slling 	/*
589*b1b8ab34Slling 	 * A root pool with concatenated devices is not supported.
590*b1b8ab34Slling 	 * Thus, can not add a device to a root pool with one device.
591*b1b8ab34Slling 	 */
592*b1b8ab34Slling 	if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) {
593*b1b8ab34Slling 		spa_close(spa, FTAG);
594*b1b8ab34Slling 		return (EDOM);
595*b1b8ab34Slling 	}
596*b1b8ab34Slling 
597e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) == 0) {
598fa9e4066Sahrens 		error = spa_vdev_add(spa, config);
599fa9e4066Sahrens 		nvlist_free(config);
600fa9e4066Sahrens 	}
601fa9e4066Sahrens 
602fa9e4066Sahrens 	spa_close(spa, FTAG);
603fa9e4066Sahrens 	return (error);
604fa9e4066Sahrens }
605fa9e4066Sahrens 
606fa9e4066Sahrens static int
607fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc)
608fa9e4066Sahrens {
60999653d4eSeschrock 	spa_t *spa;
61099653d4eSeschrock 	int error;
61199653d4eSeschrock 
61299653d4eSeschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
61399653d4eSeschrock 	if (error != 0)
61499653d4eSeschrock 		return (error);
61599653d4eSeschrock 	error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE);
61699653d4eSeschrock 	spa_close(spa, FTAG);
61799653d4eSeschrock 	return (error);
618fa9e4066Sahrens }
619fa9e4066Sahrens 
620fa9e4066Sahrens static int
621fa9e4066Sahrens zfs_ioc_vdev_online(zfs_cmd_t *zc)
622fa9e4066Sahrens {
623fa9e4066Sahrens 	spa_t *spa;
624fa9e4066Sahrens 	int error;
625fa9e4066Sahrens 
62606eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
627fa9e4066Sahrens 		return (error);
628ea8dc4b6Seschrock 	error = vdev_online(spa, zc->zc_guid);
629fa9e4066Sahrens 	spa_close(spa, FTAG);
630fa9e4066Sahrens 	return (error);
631fa9e4066Sahrens }
632fa9e4066Sahrens 
633fa9e4066Sahrens static int
634fa9e4066Sahrens zfs_ioc_vdev_offline(zfs_cmd_t *zc)
635fa9e4066Sahrens {
636fa9e4066Sahrens 	spa_t *spa;
637441d80aaSlling 	int istmp = zc->zc_cookie;
638fa9e4066Sahrens 	int error;
639fa9e4066Sahrens 
64006eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
641fa9e4066Sahrens 		return (error);
642ea8dc4b6Seschrock 	error = vdev_offline(spa, zc->zc_guid, istmp);
643fa9e4066Sahrens 	spa_close(spa, FTAG);
644fa9e4066Sahrens 	return (error);
645fa9e4066Sahrens }
646fa9e4066Sahrens 
647fa9e4066Sahrens static int
648fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc)
649fa9e4066Sahrens {
650fa9e4066Sahrens 	spa_t *spa;
651fa9e4066Sahrens 	int replacing = zc->zc_cookie;
652fa9e4066Sahrens 	nvlist_t *config;
653fa9e4066Sahrens 	int error;
654fa9e4066Sahrens 
65506eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
656fa9e4066Sahrens 		return (error);
657fa9e4066Sahrens 
658e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) == 0) {
659ea8dc4b6Seschrock 		error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
660fa9e4066Sahrens 		nvlist_free(config);
661fa9e4066Sahrens 	}
662fa9e4066Sahrens 
663fa9e4066Sahrens 	spa_close(spa, FTAG);
664fa9e4066Sahrens 	return (error);
665fa9e4066Sahrens }
666fa9e4066Sahrens 
667fa9e4066Sahrens static int
668fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc)
669fa9e4066Sahrens {
670fa9e4066Sahrens 	spa_t *spa;
671fa9e4066Sahrens 	int error;
672fa9e4066Sahrens 
67306eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
674fa9e4066Sahrens 		return (error);
675fa9e4066Sahrens 
676ea8dc4b6Seschrock 	error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE);
677fa9e4066Sahrens 
678fa9e4066Sahrens 	spa_close(spa, FTAG);
679fa9e4066Sahrens 	return (error);
680fa9e4066Sahrens }
681fa9e4066Sahrens 
682c67d9675Seschrock static int
683c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
684c67d9675Seschrock {
685c67d9675Seschrock 	spa_t *spa;
686e9dbad6fSeschrock 	char *path = zc->zc_value;
687ea8dc4b6Seschrock 	uint64_t guid = zc->zc_guid;
688c67d9675Seschrock 	int error;
689c67d9675Seschrock 
690c67d9675Seschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
691c67d9675Seschrock 	if (error != 0)
692c67d9675Seschrock 		return (error);
693c67d9675Seschrock 
694c67d9675Seschrock 	error = spa_vdev_setpath(spa, guid, path);
695c67d9675Seschrock 	spa_close(spa, FTAG);
696c67d9675Seschrock 	return (error);
697c67d9675Seschrock }
698c67d9675Seschrock 
699fa9e4066Sahrens static int
700fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc)
701fa9e4066Sahrens {
702fa9e4066Sahrens 	objset_t *os = NULL;
703fa9e4066Sahrens 	int error;
7047f7322feSeschrock 	nvlist_t *nv;
705fa9e4066Sahrens 
706fa9e4066Sahrens retry:
707fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
708fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
709fa9e4066Sahrens 	if (error != 0) {
710fa9e4066Sahrens 		/*
711fa9e4066Sahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
712fa9e4066Sahrens 		 * the objset is held exclusively. Fortunately this hold is
713fa9e4066Sahrens 		 * only for a short while, so we retry here.
714fa9e4066Sahrens 		 * This avoids user code having to handle EBUSY,
715fa9e4066Sahrens 		 * for example for a "zfs list".
716fa9e4066Sahrens 		 */
717fa9e4066Sahrens 		if (error == EBUSY) {
718fa9e4066Sahrens 			delay(1);
719fa9e4066Sahrens 			goto retry;
720fa9e4066Sahrens 		}
721fa9e4066Sahrens 		return (error);
722fa9e4066Sahrens 	}
723fa9e4066Sahrens 
724a2eea2e1Sahrens 	dmu_objset_fast_stat(os, &zc->zc_objset_stats);
725fa9e4066Sahrens 
7265ad82045Snd 	if (zc->zc_nvlist_dst != 0 &&
7277f7322feSeschrock 	    (error = dsl_prop_get_all(os, &nv)) == 0) {
728a2eea2e1Sahrens 		dmu_objset_stats(os, nv);
729432f72fdSahrens 		/*
730432f72fdSahrens 		 * NB: zvol_get_stats() will read the objset contents,
731432f72fdSahrens 		 * which we aren't supposed to do with a
732432f72fdSahrens 		 * DS_MODE_STANDARD open, because it could be
733432f72fdSahrens 		 * inconsistent.  So this is a bit of a workaround...
734432f72fdSahrens 		 */
735432f72fdSahrens 		if (!zc->zc_objset_stats.dds_inconsistent &&
736432f72fdSahrens 		    dmu_objset_type(os) == DMU_OST_ZVOL)
737a2eea2e1Sahrens 			VERIFY(zvol_get_stats(os, nv) == 0);
738e9dbad6fSeschrock 		error = put_nvlist(zc, nv);
7397f7322feSeschrock 		nvlist_free(nv);
7407f7322feSeschrock 	}
741fa9e4066Sahrens 
742e9dbad6fSeschrock 	spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value));
743ea8dc4b6Seschrock 
744fa9e4066Sahrens 	dmu_objset_close(os);
745fa9e4066Sahrens 	return (error);
746fa9e4066Sahrens }
747fa9e4066Sahrens 
748fa9e4066Sahrens static int
749fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc)
750fa9e4066Sahrens {
75187e5029aSahrens 	objset_t *os;
752fa9e4066Sahrens 	int error;
753fa9e4066Sahrens 	char *p;
754fa9e4066Sahrens 
75587e5029aSahrens retry:
75687e5029aSahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
75787e5029aSahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
75887e5029aSahrens 	if (error != 0) {
75987e5029aSahrens 		/*
76087e5029aSahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
76187e5029aSahrens 		 * the objset is held exclusively. Fortunately this hold is
76287e5029aSahrens 		 * only for a short while, so we retry here.
76387e5029aSahrens 		 * This avoids user code having to handle EBUSY,
76487e5029aSahrens 		 * for example for a "zfs list".
76587e5029aSahrens 		 */
76687e5029aSahrens 		if (error == EBUSY) {
76787e5029aSahrens 			delay(1);
76887e5029aSahrens 			goto retry;
76987e5029aSahrens 		}
77087e5029aSahrens 		if (error == ENOENT)
77187e5029aSahrens 			error = ESRCH;
77287e5029aSahrens 		return (error);
773fa9e4066Sahrens 	}
774fa9e4066Sahrens 
775fa9e4066Sahrens 	p = strrchr(zc->zc_name, '/');
776fa9e4066Sahrens 	if (p == NULL || p[1] != '\0')
777fa9e4066Sahrens 		(void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name));
778fa9e4066Sahrens 	p = zc->zc_name + strlen(zc->zc_name);
779fa9e4066Sahrens 
780fa9e4066Sahrens 	do {
78187e5029aSahrens 		error = dmu_dir_list_next(os,
78287e5029aSahrens 		    sizeof (zc->zc_name) - (p - zc->zc_name), p,
78387e5029aSahrens 		    NULL, &zc->zc_cookie);
784fa9e4066Sahrens 		if (error == ENOENT)
785fa9e4066Sahrens 			error = ESRCH;
78687e5029aSahrens 	} while (error == 0 && !INGLOBALZONE(curproc) &&
787fa9e4066Sahrens 	    !zone_dataset_visible(zc->zc_name, NULL));
788fa9e4066Sahrens 
789fa9e4066Sahrens 	/*
79087e5029aSahrens 	 * If it's a hidden dataset (ie. with a '$' in its name), don't
79187e5029aSahrens 	 * try to get stats for it.  Userland will skip over it.
792fa9e4066Sahrens 	 */
79387e5029aSahrens 	if (error == 0 && strchr(zc->zc_name, '$') == NULL)
79487e5029aSahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
795fa9e4066Sahrens 
79687e5029aSahrens 	dmu_objset_close(os);
797fa9e4066Sahrens 	return (error);
798fa9e4066Sahrens }
799fa9e4066Sahrens 
800fa9e4066Sahrens static int
801fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
802fa9e4066Sahrens {
80387e5029aSahrens 	objset_t *os;
804fa9e4066Sahrens 	int error;
805fa9e4066Sahrens 
806fa9e4066Sahrens retry:
80787e5029aSahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
80887e5029aSahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
80987e5029aSahrens 	if (error != 0) {
810fa9e4066Sahrens 		/*
81187e5029aSahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
812fa9e4066Sahrens 		 * the objset is held exclusively. Fortunately this hold is
813fa9e4066Sahrens 		 * only for a short while, so we retry here.
814fa9e4066Sahrens 		 * This avoids user code having to handle EBUSY,
81587e5029aSahrens 		 * for example for a "zfs list".
816fa9e4066Sahrens 		 */
817fa9e4066Sahrens 		if (error == EBUSY) {
818fa9e4066Sahrens 			delay(1);
819fa9e4066Sahrens 			goto retry;
820fa9e4066Sahrens 		}
821fa9e4066Sahrens 		if (error == ENOENT)
82287e5029aSahrens 			error = ESRCH;
823fa9e4066Sahrens 		return (error);
824fa9e4066Sahrens 	}
825fa9e4066Sahrens 
826b81d61a6Slling 	/*
827b81d61a6Slling 	 * A dataset name of maximum length cannot have any snapshots,
828b81d61a6Slling 	 * so exit immediately.
829b81d61a6Slling 	 */
830b81d61a6Slling 	if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) {
83187e5029aSahrens 		dmu_objset_close(os);
832b81d61a6Slling 		return (ESRCH);
833fa9e4066Sahrens 	}
834fa9e4066Sahrens 
83587e5029aSahrens 	error = dmu_snapshot_list_next(os,
83687e5029aSahrens 	    sizeof (zc->zc_name) - strlen(zc->zc_name),
83787e5029aSahrens 	    zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie);
83887e5029aSahrens 	if (error == ENOENT)
83987e5029aSahrens 		error = ESRCH;
840fa9e4066Sahrens 
84187e5029aSahrens 	if (error == 0)
84287e5029aSahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
843fa9e4066Sahrens 
84487e5029aSahrens 	dmu_objset_close(os);
845fa9e4066Sahrens 	return (error);
846fa9e4066Sahrens }
847fa9e4066Sahrens 
848fa9e4066Sahrens static int
849e9dbad6fSeschrock zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl)
850fa9e4066Sahrens {
851e9dbad6fSeschrock 	nvpair_t *elem;
852e9dbad6fSeschrock 	int error;
853e9dbad6fSeschrock 	const char *propname;
854e9dbad6fSeschrock 	zfs_prop_t prop;
855e9dbad6fSeschrock 	uint64_t intval;
856e9dbad6fSeschrock 	char *strval;
857c9431fa1Sahl 	char buf[MAXNAMELEN];
858c9431fa1Sahl 	const char *p;
859c9431fa1Sahl 	spa_t *spa;
860e9dbad6fSeschrock 
861e9dbad6fSeschrock 	elem = NULL;
862e9dbad6fSeschrock 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
863e9dbad6fSeschrock 		propname = nvpair_name(elem);
864e9dbad6fSeschrock 
865e9dbad6fSeschrock 		if ((prop = zfs_name_to_prop(propname)) ==
866e9dbad6fSeschrock 		    ZFS_PROP_INVAL) {
867e9dbad6fSeschrock 			/*
868e9dbad6fSeschrock 			 * If this is a user-defined property, it must be a
869e9dbad6fSeschrock 			 * string, and there is no further validation to do.
870e9dbad6fSeschrock 			 */
871e9dbad6fSeschrock 			if (!zfs_prop_user(propname) ||
872e9dbad6fSeschrock 			    nvpair_type(elem) != DATA_TYPE_STRING)
873e9dbad6fSeschrock 				return (EINVAL);
874e9dbad6fSeschrock 
875e9dbad6fSeschrock 			VERIFY(nvpair_value_string(elem, &strval) == 0);
876e9dbad6fSeschrock 			error = dsl_prop_set(name, propname, 1,
877e9dbad6fSeschrock 			    strlen(strval) + 1, strval);
878e9dbad6fSeschrock 			if (error == 0)
879e9dbad6fSeschrock 				continue;
880e9dbad6fSeschrock 			else
88146657f8dSmmusante 				return (error);
882e9dbad6fSeschrock 		}
883fa9e4066Sahrens 
884e9dbad6fSeschrock 		/*
885e9dbad6fSeschrock 		 * Check permissions for special properties.
886e9dbad6fSeschrock 		 */
887e9dbad6fSeschrock 		switch (prop) {
888e9dbad6fSeschrock 		case ZFS_PROP_ZONED:
889e9dbad6fSeschrock 			/*
890e9dbad6fSeschrock 			 * Disallow setting of 'zoned' from within a local zone.
891e9dbad6fSeschrock 			 */
892e9dbad6fSeschrock 			if (!INGLOBALZONE(curproc))
893e9dbad6fSeschrock 				return (EPERM);
894e9dbad6fSeschrock 			break;
895fa9e4066Sahrens 
896e9dbad6fSeschrock 		case ZFS_PROP_QUOTA:
897e9dbad6fSeschrock 			if (error = zfs_dozonecheck(name, cr))
898e9dbad6fSeschrock 				return (error);
899fa9e4066Sahrens 
900e9dbad6fSeschrock 			if (!INGLOBALZONE(curproc)) {
901e9dbad6fSeschrock 				uint64_t zoned;
902e9dbad6fSeschrock 				char setpoint[MAXNAMELEN];
903e9dbad6fSeschrock 				int dslen;
904e9dbad6fSeschrock 				/*
905e9dbad6fSeschrock 				 * Unprivileged users are allowed to modify the
906e9dbad6fSeschrock 				 * quota on things *under* (ie. contained by)
907e9dbad6fSeschrock 				 * the thing they own.
908e9dbad6fSeschrock 				 */
909e9dbad6fSeschrock 				if (dsl_prop_get_integer(name, "zoned", &zoned,
910e9dbad6fSeschrock 				    setpoint))
911e9dbad6fSeschrock 					return (EPERM);
912e9dbad6fSeschrock 				if (!zoned) /* this shouldn't happen */
913e9dbad6fSeschrock 					return (EPERM);
914e9dbad6fSeschrock 				dslen = strlen(name);
915e9dbad6fSeschrock 				if (dslen <= strlen(setpoint))
916e9dbad6fSeschrock 					return (EPERM);
917e9dbad6fSeschrock 			}
918c9431fa1Sahl 			break;
919c9431fa1Sahl 
920c9431fa1Sahl 		case ZFS_PROP_COMPRESSION:
921c9431fa1Sahl 			/*
922c9431fa1Sahl 			 * If the user specified gzip compression, make sure
923c9431fa1Sahl 			 * the SPA supports it. We ignore any errors here since
924c9431fa1Sahl 			 * we'll catch them later.
925c9431fa1Sahl 			 */
926c9431fa1Sahl 			if (nvpair_type(elem) == DATA_TYPE_UINT64 &&
927c9431fa1Sahl 			    nvpair_value_uint64(elem, &intval) == 0 &&
928c9431fa1Sahl 			    intval >= ZIO_COMPRESS_GZIP_1 &&
929c9431fa1Sahl 			    intval <= ZIO_COMPRESS_GZIP_9) {
930c9431fa1Sahl 				if ((p = strchr(name, '/')) == NULL) {
931c9431fa1Sahl 					p = name;
932c9431fa1Sahl 				} else {
933c9431fa1Sahl 					bcopy(name, buf, p - name);
934c9431fa1Sahl 					buf[p - name] = '\0';
935c9431fa1Sahl 					p = buf;
936c9431fa1Sahl 				}
937c9431fa1Sahl 
938c9431fa1Sahl 				if (spa_open(p, &spa, FTAG) == 0) {
939c9431fa1Sahl 					if (spa_version(spa) <
940c9431fa1Sahl 					    ZFS_VERSION_GZIP_COMPRESSION) {
941c9431fa1Sahl 						spa_close(spa, FTAG);
942c9431fa1Sahl 						return (ENOTSUP);
943c9431fa1Sahl 					}
944c9431fa1Sahl 
945c9431fa1Sahl 					spa_close(spa, FTAG);
946c9431fa1Sahl 				}
947c9431fa1Sahl 			}
948c9431fa1Sahl 			break;
949e9dbad6fSeschrock 		}
950e9dbad6fSeschrock 
951e9dbad6fSeschrock 		switch (prop) {
952e9dbad6fSeschrock 		case ZFS_PROP_QUOTA:
953e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
954e9dbad6fSeschrock 			    (error = dsl_dir_set_quota(name,
955e9dbad6fSeschrock 			    intval)) != 0)
956e9dbad6fSeschrock 				return (error);
957e9dbad6fSeschrock 			break;
958e9dbad6fSeschrock 
959e9dbad6fSeschrock 		case ZFS_PROP_RESERVATION:
960e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
961e9dbad6fSeschrock 			    (error = dsl_dir_set_reservation(name,
962e9dbad6fSeschrock 			    intval)) != 0)
963e9dbad6fSeschrock 				return (error);
964e9dbad6fSeschrock 			break;
965e9dbad6fSeschrock 
966e9dbad6fSeschrock 		case ZFS_PROP_VOLSIZE:
967e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
968e9dbad6fSeschrock 			    (error = zvol_set_volsize(name, dev,
969e9dbad6fSeschrock 			    intval)) != 0)
970e9dbad6fSeschrock 				return (error);
971e9dbad6fSeschrock 			break;
972e9dbad6fSeschrock 
973e9dbad6fSeschrock 		case ZFS_PROP_VOLBLOCKSIZE:
974e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
975e9dbad6fSeschrock 			    (error = zvol_set_volblocksize(name,
976e9dbad6fSeschrock 			    intval)) != 0)
977e9dbad6fSeschrock 				return (error);
978e9dbad6fSeschrock 			break;
979e9dbad6fSeschrock 
980e9dbad6fSeschrock 		default:
981e9dbad6fSeschrock 			if (nvpair_type(elem) == DATA_TYPE_STRING) {
982e9dbad6fSeschrock 				if (zfs_prop_get_type(prop) !=
983e9dbad6fSeschrock 				    prop_type_string)
984e9dbad6fSeschrock 					return (EINVAL);
985acd76fe5Seschrock 				VERIFY(nvpair_value_string(elem, &strval) == 0);
986acd76fe5Seschrock 				if ((error = dsl_prop_set(name,
987e9dbad6fSeschrock 				    nvpair_name(elem), 1, strlen(strval) + 1,
988acd76fe5Seschrock 				    strval)) != 0)
989acd76fe5Seschrock 					return (error);
990e9dbad6fSeschrock 			} else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
991a2eea2e1Sahrens 				const char *unused;
992a2eea2e1Sahrens 
993acd76fe5Seschrock 				VERIFY(nvpair_value_uint64(elem, &intval) == 0);
994e9dbad6fSeschrock 
995e9dbad6fSeschrock 				switch (zfs_prop_get_type(prop)) {
996e9dbad6fSeschrock 				case prop_type_number:
997e9dbad6fSeschrock 					break;
998e9dbad6fSeschrock 				case prop_type_boolean:
999e9dbad6fSeschrock 					if (intval > 1)
1000acd76fe5Seschrock 						return (EINVAL);
1001e9dbad6fSeschrock 					break;
1002e9dbad6fSeschrock 				case prop_type_string:
1003acd76fe5Seschrock 					return (EINVAL);
1004e9dbad6fSeschrock 				case prop_type_index:
1005acd76fe5Seschrock 					if (zfs_prop_index_to_string(prop,
1006acd76fe5Seschrock 					    intval, &unused) != 0)
1007acd76fe5Seschrock 						return (EINVAL);
1008e9dbad6fSeschrock 					break;
1009e9dbad6fSeschrock 				default:
1010e9dbad6fSeschrock 					cmn_err(CE_PANIC, "unknown property "
1011e9dbad6fSeschrock 					    "type");
1012e9dbad6fSeschrock 					break;
1013e9dbad6fSeschrock 				}
1014e9dbad6fSeschrock 
1015acd76fe5Seschrock 				if ((error = dsl_prop_set(name, propname,
1016acd76fe5Seschrock 				    8, 1, &intval)) != 0)
1017acd76fe5Seschrock 					return (error);
1018e9dbad6fSeschrock 			} else {
1019e9dbad6fSeschrock 				return (EINVAL);
1020e9dbad6fSeschrock 			}
1021e9dbad6fSeschrock 			break;
1022e9dbad6fSeschrock 		}
1023e9dbad6fSeschrock 	}
1024e9dbad6fSeschrock 
1025e9dbad6fSeschrock 	return (0);
1026fa9e4066Sahrens }
1027fa9e4066Sahrens 
1028fa9e4066Sahrens static int
1029e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc)
1030fa9e4066Sahrens {
1031e9dbad6fSeschrock 	nvlist_t *nvl;
1032e9dbad6fSeschrock 	int error;
1033e9dbad6fSeschrock 	zfs_prop_t prop;
1034e9dbad6fSeschrock 
1035e9dbad6fSeschrock 	/*
1036e9dbad6fSeschrock 	 * If zc_value is set, then this is an attempt to inherit a value.
1037e9dbad6fSeschrock 	 * Otherwise, zc_nvlist refers to a list of properties to set.
1038e9dbad6fSeschrock 	 */
1039e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1040e9dbad6fSeschrock 		if (!zfs_prop_user(zc->zc_value) &&
1041e9dbad6fSeschrock 		    ((prop = zfs_name_to_prop(zc->zc_value)) ==
1042e9dbad6fSeschrock 		    ZFS_PROP_INVAL ||
1043e9dbad6fSeschrock 		    !zfs_prop_inheritable(prop)))
1044e9dbad6fSeschrock 			return (EINVAL);
1045e9dbad6fSeschrock 
1046e9dbad6fSeschrock 		return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL));
1047e9dbad6fSeschrock 	}
1048e9dbad6fSeschrock 
1049e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &nvl)) != 0)
1050e9dbad6fSeschrock 		return (error);
1051e9dbad6fSeschrock 
1052e9dbad6fSeschrock 	error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev,
1053e9dbad6fSeschrock 	    (cred_t *)(uintptr_t)zc->zc_cred, nvl);
1054e9dbad6fSeschrock 	nvlist_free(nvl);
1055e9dbad6fSeschrock 	return (error);
1056fa9e4066Sahrens }
1057fa9e4066Sahrens 
1058*b1b8ab34Slling static int
1059*b1b8ab34Slling zfs_ioc_pool_props_set(zfs_cmd_t *zc)
1060*b1b8ab34Slling {
1061*b1b8ab34Slling 	nvlist_t *nvl;
1062*b1b8ab34Slling 	int error, reset_bootfs = 0;
1063*b1b8ab34Slling 	uint64_t objnum;
1064*b1b8ab34Slling 	zpool_prop_t prop;
1065*b1b8ab34Slling 	nvpair_t *elem;
1066*b1b8ab34Slling 	char *propname, *strval;
1067*b1b8ab34Slling 	spa_t *spa;
1068*b1b8ab34Slling 	vdev_t *rvdev;
1069*b1b8ab34Slling 	char *vdev_type;
1070*b1b8ab34Slling 	objset_t *os;
1071*b1b8ab34Slling 
1072*b1b8ab34Slling 	if ((error = get_nvlist(zc, &nvl)) != 0)
1073*b1b8ab34Slling 		return (error);
1074*b1b8ab34Slling 
1075*b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) {
1076*b1b8ab34Slling 		nvlist_free(nvl);
1077*b1b8ab34Slling 		return (error);
1078*b1b8ab34Slling 	}
1079*b1b8ab34Slling 
1080*b1b8ab34Slling 	if (spa_version(spa) < ZFS_VERSION_BOOTFS) {
1081*b1b8ab34Slling 		nvlist_free(nvl);
1082*b1b8ab34Slling 		spa_close(spa, FTAG);
1083*b1b8ab34Slling 		return (ENOTSUP);
1084*b1b8ab34Slling 	}
1085*b1b8ab34Slling 
1086*b1b8ab34Slling 	elem = NULL;
1087*b1b8ab34Slling 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1088*b1b8ab34Slling 
1089*b1b8ab34Slling 		propname = nvpair_name(elem);
1090*b1b8ab34Slling 
1091*b1b8ab34Slling 		if ((prop = zpool_name_to_prop(propname)) ==
1092*b1b8ab34Slling 		    ZFS_PROP_INVAL) {
1093*b1b8ab34Slling 			nvlist_free(nvl);
1094*b1b8ab34Slling 			spa_close(spa, FTAG);
1095*b1b8ab34Slling 			return (EINVAL);
1096*b1b8ab34Slling 		}
1097*b1b8ab34Slling 
1098*b1b8ab34Slling 		switch (prop) {
1099*b1b8ab34Slling 		case ZFS_PROP_BOOTFS:
1100*b1b8ab34Slling 			/*
1101*b1b8ab34Slling 			 * A bootable filesystem can not be on a RAIDZ pool
1102*b1b8ab34Slling 			 * nor a striped pool with more than 1 device.
1103*b1b8ab34Slling 			 */
1104*b1b8ab34Slling 			rvdev = spa->spa_root_vdev;
1105*b1b8ab34Slling 			vdev_type =
1106*b1b8ab34Slling 			    rvdev->vdev_child[0]->vdev_ops->vdev_op_type;
1107*b1b8ab34Slling 			if (strcmp(vdev_type, VDEV_TYPE_RAIDZ) == 0 ||
1108*b1b8ab34Slling 			    (strcmp(vdev_type, VDEV_TYPE_MIRROR) != 0 &&
1109*b1b8ab34Slling 			    rvdev->vdev_children > 1)) {
1110*b1b8ab34Slling 				error = ENOTSUP;
1111*b1b8ab34Slling 				break;
1112*b1b8ab34Slling 			}
1113*b1b8ab34Slling 
1114*b1b8ab34Slling 			reset_bootfs = 1;
1115*b1b8ab34Slling 
1116*b1b8ab34Slling 			VERIFY(nvpair_value_string(elem, &strval) == 0);
1117*b1b8ab34Slling 			if (strval == NULL || strval[0] == '\0') {
1118*b1b8ab34Slling 				objnum =
1119*b1b8ab34Slling 				    zfs_prop_default_numeric(ZFS_PROP_BOOTFS);
1120*b1b8ab34Slling 				break;
1121*b1b8ab34Slling 			}
1122*b1b8ab34Slling 
1123*b1b8ab34Slling 			if (error = dmu_objset_open(strval, DMU_OST_ZFS,
1124*b1b8ab34Slling 			    DS_MODE_STANDARD | DS_MODE_READONLY, &os))
1125*b1b8ab34Slling 				break;
1126*b1b8ab34Slling 			objnum = dmu_objset_id(os);
1127*b1b8ab34Slling 			dmu_objset_close(os);
1128*b1b8ab34Slling 			break;
1129*b1b8ab34Slling 
1130*b1b8ab34Slling 		default:
1131*b1b8ab34Slling 			error = EINVAL;
1132*b1b8ab34Slling 		}
1133*b1b8ab34Slling 
1134*b1b8ab34Slling 		if (error)
1135*b1b8ab34Slling 			break;
1136*b1b8ab34Slling 	}
1137*b1b8ab34Slling 	if (error == 0) {
1138*b1b8ab34Slling 		if (reset_bootfs) {
1139*b1b8ab34Slling 			VERIFY(nvlist_remove(nvl,
1140*b1b8ab34Slling 			    zpool_prop_to_name(ZFS_PROP_BOOTFS),
1141*b1b8ab34Slling 			    DATA_TYPE_STRING) == 0);
1142*b1b8ab34Slling 			VERIFY(nvlist_add_uint64(nvl,
1143*b1b8ab34Slling 			    zpool_prop_to_name(ZFS_PROP_BOOTFS), objnum) == 0);
1144*b1b8ab34Slling 		}
1145*b1b8ab34Slling 		error = spa_set_props(spa, nvl);
1146*b1b8ab34Slling 	}
1147*b1b8ab34Slling 
1148*b1b8ab34Slling 	nvlist_free(nvl);
1149*b1b8ab34Slling 	spa_close(spa, FTAG);
1150*b1b8ab34Slling 
1151*b1b8ab34Slling 	return (error);
1152*b1b8ab34Slling }
1153*b1b8ab34Slling 
1154*b1b8ab34Slling static int
1155*b1b8ab34Slling zfs_ioc_pool_props_get(zfs_cmd_t *zc)
1156*b1b8ab34Slling {
1157*b1b8ab34Slling 	spa_t *spa;
1158*b1b8ab34Slling 	int error;
1159*b1b8ab34Slling 	nvlist_t *nvp = NULL;
1160*b1b8ab34Slling 
1161*b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1162*b1b8ab34Slling 		return (error);
1163*b1b8ab34Slling 
1164*b1b8ab34Slling 	error = spa_get_props(spa, &nvp);
1165*b1b8ab34Slling 
1166*b1b8ab34Slling 	if (error == 0 && zc->zc_nvlist_dst != NULL)
1167*b1b8ab34Slling 		error = put_nvlist(zc, nvp);
1168*b1b8ab34Slling 	else
1169*b1b8ab34Slling 		error = EFAULT;
1170*b1b8ab34Slling 
1171*b1b8ab34Slling 	spa_close(spa, FTAG);
1172*b1b8ab34Slling 
1173*b1b8ab34Slling 	if (nvp)
1174*b1b8ab34Slling 		nvlist_free(nvp);
1175*b1b8ab34Slling 	return (error);
1176*b1b8ab34Slling }
1177*b1b8ab34Slling 
1178fa9e4066Sahrens static int
1179fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc)
1180fa9e4066Sahrens {
1181e9dbad6fSeschrock 	return (zvol_create_minor(zc->zc_name, zc->zc_dev));
1182fa9e4066Sahrens }
1183fa9e4066Sahrens 
1184fa9e4066Sahrens static int
1185fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc)
1186fa9e4066Sahrens {
1187e9dbad6fSeschrock 	return (zvol_remove_minor(zc->zc_name));
1188fa9e4066Sahrens }
1189fa9e4066Sahrens 
1190fa9e4066Sahrens /*
1191fa9e4066Sahrens  * Search the vfs list for a specified resource.  Returns a pointer to it
1192fa9e4066Sahrens  * or NULL if no suitable entry is found. The caller of this routine
1193fa9e4066Sahrens  * is responsible for releasing the returned vfs pointer.
1194fa9e4066Sahrens  */
1195fa9e4066Sahrens static vfs_t *
1196fa9e4066Sahrens zfs_get_vfs(const char *resource)
1197fa9e4066Sahrens {
1198fa9e4066Sahrens 	struct vfs *vfsp;
1199fa9e4066Sahrens 	struct vfs *vfs_found = NULL;
1200fa9e4066Sahrens 
1201fa9e4066Sahrens 	vfs_list_read_lock();
1202fa9e4066Sahrens 	vfsp = rootvfs;
1203fa9e4066Sahrens 	do {
1204fa9e4066Sahrens 		if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) {
1205fa9e4066Sahrens 			VFS_HOLD(vfsp);
1206fa9e4066Sahrens 			vfs_found = vfsp;
1207fa9e4066Sahrens 			break;
1208fa9e4066Sahrens 		}
1209fa9e4066Sahrens 		vfsp = vfsp->vfs_next;
1210fa9e4066Sahrens 	} while (vfsp != rootvfs);
1211fa9e4066Sahrens 	vfs_list_unlock();
1212fa9e4066Sahrens 	return (vfs_found);
1213fa9e4066Sahrens }
1214fa9e4066Sahrens 
1215fa9e4066Sahrens static void
1216fa9e4066Sahrens zfs_create_cb(objset_t *os, void *arg, dmu_tx_t *tx)
1217fa9e4066Sahrens {
1218e9dbad6fSeschrock 	zfs_create_data_t *zc = arg;
1219fa9e4066Sahrens 	zfs_create_fs(os, (cred_t *)(uintptr_t)zc->zc_cred, tx);
1220fa9e4066Sahrens }
1221fa9e4066Sahrens 
1222fa9e4066Sahrens static int
1223fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc)
1224fa9e4066Sahrens {
1225fa9e4066Sahrens 	objset_t *clone;
1226fa9e4066Sahrens 	int error = 0;
1227e9dbad6fSeschrock 	zfs_create_data_t cbdata = { 0 };
1228fa9e4066Sahrens 	void (*cbfunc)(objset_t *os, void *arg, dmu_tx_t *tx);
1229fa9e4066Sahrens 	dmu_objset_type_t type = zc->zc_objset_type;
1230fa9e4066Sahrens 
1231fa9e4066Sahrens 	switch (type) {
1232fa9e4066Sahrens 
1233fa9e4066Sahrens 	case DMU_OST_ZFS:
1234fa9e4066Sahrens 		cbfunc = zfs_create_cb;
1235fa9e4066Sahrens 		break;
1236fa9e4066Sahrens 
1237fa9e4066Sahrens 	case DMU_OST_ZVOL:
1238fa9e4066Sahrens 		cbfunc = zvol_create_cb;
1239fa9e4066Sahrens 		break;
1240fa9e4066Sahrens 
1241fa9e4066Sahrens 	default:
12421d452cf5Sahrens 		cbfunc = NULL;
1243fa9e4066Sahrens 	}
12441d452cf5Sahrens 	if (strchr(zc->zc_name, '@'))
12451d452cf5Sahrens 		return (EINVAL);
1246fa9e4066Sahrens 
1247e9dbad6fSeschrock 	if (zc->zc_nvlist_src != NULL &&
1248e9dbad6fSeschrock 	    (error = get_nvlist(zc, &cbdata.zc_props)) != 0)
1249e9dbad6fSeschrock 		return (error);
1250e9dbad6fSeschrock 
1251e9dbad6fSeschrock 	cbdata.zc_cred = (cred_t *)(uintptr_t)zc->zc_cred;
1252e9dbad6fSeschrock 	cbdata.zc_dev = (dev_t)zc->zc_dev;
1253e9dbad6fSeschrock 
1254e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1255fa9e4066Sahrens 		/*
1256fa9e4066Sahrens 		 * We're creating a clone of an existing snapshot.
1257fa9e4066Sahrens 		 */
1258e9dbad6fSeschrock 		zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
1259e9dbad6fSeschrock 		if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) {
1260e9dbad6fSeschrock 			nvlist_free(cbdata.zc_props);
1261fa9e4066Sahrens 			return (EINVAL);
1262e9dbad6fSeschrock 		}
1263fa9e4066Sahrens 
1264e9dbad6fSeschrock 		error = dmu_objset_open(zc->zc_value, type,
1265fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
1266e9dbad6fSeschrock 		if (error) {
1267e9dbad6fSeschrock 			nvlist_free(cbdata.zc_props);
1268fa9e4066Sahrens 			return (error);
1269e9dbad6fSeschrock 		}
1270fa9e4066Sahrens 		error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL);
1271fa9e4066Sahrens 		dmu_objset_close(clone);
1272fa9e4066Sahrens 	} else {
1273e9dbad6fSeschrock 		if (cbfunc == NULL) {
1274e9dbad6fSeschrock 			nvlist_free(cbdata.zc_props);
12751d452cf5Sahrens 			return (EINVAL);
1276e9dbad6fSeschrock 		}
12775c5460e9Seschrock 
1278e9dbad6fSeschrock 		if (type == DMU_OST_ZVOL) {
1279e9dbad6fSeschrock 			uint64_t volsize, volblocksize;
1280e9dbad6fSeschrock 
1281e9dbad6fSeschrock 			if (cbdata.zc_props == NULL ||
1282e9dbad6fSeschrock 			    nvlist_lookup_uint64(cbdata.zc_props,
1283e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1284e9dbad6fSeschrock 			    &volsize) != 0) {
1285e9dbad6fSeschrock 				nvlist_free(cbdata.zc_props);
1286e9dbad6fSeschrock 				return (EINVAL);
1287e9dbad6fSeschrock 			}
1288e9dbad6fSeschrock 
1289e9dbad6fSeschrock 			if ((error = nvlist_lookup_uint64(cbdata.zc_props,
1290e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1291e9dbad6fSeschrock 			    &volblocksize)) != 0 && error != ENOENT) {
1292e9dbad6fSeschrock 				nvlist_free(cbdata.zc_props);
1293e9dbad6fSeschrock 				return (EINVAL);
1294e9dbad6fSeschrock 			}
1295e9dbad6fSeschrock 
1296e9dbad6fSeschrock 			if (error != 0)
1297e9dbad6fSeschrock 				volblocksize = zfs_prop_default_numeric(
1298e9dbad6fSeschrock 				    ZFS_PROP_VOLBLOCKSIZE);
1299e9dbad6fSeschrock 
1300e9dbad6fSeschrock 			if ((error = zvol_check_volblocksize(
1301e9dbad6fSeschrock 			    volblocksize)) != 0 ||
1302e9dbad6fSeschrock 			    (error = zvol_check_volsize(volsize,
1303e9dbad6fSeschrock 			    volblocksize)) != 0) {
1304e9dbad6fSeschrock 				nvlist_free(cbdata.zc_props);
13055c5460e9Seschrock 				return (error);
1306e9dbad6fSeschrock 			}
1307fa9e4066Sahrens 		}
1308e9dbad6fSeschrock 
1309e9dbad6fSeschrock 		error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc,
1310e9dbad6fSeschrock 		    &cbdata);
1311fa9e4066Sahrens 	}
1312e9dbad6fSeschrock 
1313e9dbad6fSeschrock 	/*
1314e9dbad6fSeschrock 	 * It would be nice to do this atomically.
1315e9dbad6fSeschrock 	 */
1316e9dbad6fSeschrock 	if (error == 0) {
1317e9dbad6fSeschrock 		if ((error = zfs_set_prop_nvlist(zc->zc_name,
1318e9dbad6fSeschrock 		    zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred,
1319e9dbad6fSeschrock 		    cbdata.zc_props)) != 0)
1320e9dbad6fSeschrock 			(void) dmu_objset_destroy(zc->zc_name);
1321e9dbad6fSeschrock 	}
1322e9dbad6fSeschrock 
1323e9dbad6fSeschrock 	nvlist_free(cbdata.zc_props);
1324fa9e4066Sahrens 	return (error);
1325fa9e4066Sahrens }
1326fa9e4066Sahrens 
1327fa9e4066Sahrens static int
13281d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc)
1329fa9e4066Sahrens {
1330e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
13311d452cf5Sahrens 		return (EINVAL);
13321d452cf5Sahrens 	return (dmu_objset_snapshot(zc->zc_name,
1333e9dbad6fSeschrock 	    zc->zc_value, zc->zc_cookie));
13341d452cf5Sahrens }
1335fa9e4066Sahrens 
13361d452cf5Sahrens static int
13371d452cf5Sahrens zfs_unmount_snap(char *name, void *arg)
13381d452cf5Sahrens {
13391d452cf5Sahrens 	char *snapname = arg;
13401d452cf5Sahrens 	char *cp;
13410b69c2f0Sahrens 	vfs_t *vfsp = NULL;
13421d452cf5Sahrens 
13431d452cf5Sahrens 	/*
13441d452cf5Sahrens 	 * Snapshots (which are under .zfs control) must be unmounted
13451d452cf5Sahrens 	 * before they can be destroyed.
13461d452cf5Sahrens 	 */
13471d452cf5Sahrens 
13481d452cf5Sahrens 	if (snapname) {
13491d452cf5Sahrens 		(void) strcat(name, "@");
13501d452cf5Sahrens 		(void) strcat(name, snapname);
13511d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
13521d452cf5Sahrens 		cp = strchr(name, '@');
13531d452cf5Sahrens 		*cp = '\0';
13540b69c2f0Sahrens 	} else if (strchr(name, '@')) {
13551d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
13561d452cf5Sahrens 	}
13571d452cf5Sahrens 
13581d452cf5Sahrens 	if (vfsp) {
1359fa9e4066Sahrens 		/*
13601d452cf5Sahrens 		 * Always force the unmount for snapshots.
1361fa9e4066Sahrens 		 */
13621d452cf5Sahrens 		int flag = MS_FORCE;
13631d452cf5Sahrens 		int err;
13641d452cf5Sahrens 
13651d452cf5Sahrens 		if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) {
1366fa9e4066Sahrens 			VFS_RELE(vfsp);
13671d452cf5Sahrens 			return (err);
1368fa9e4066Sahrens 		}
13691d452cf5Sahrens 		VFS_RELE(vfsp);
13701d452cf5Sahrens 		if ((err = dounmount(vfsp, flag, kcred)) != 0)
13711d452cf5Sahrens 			return (err);
13721d452cf5Sahrens 	}
13731d452cf5Sahrens 	return (0);
13741d452cf5Sahrens }
13751d452cf5Sahrens 
13761d452cf5Sahrens static int
13771d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc)
13781d452cf5Sahrens {
13791d452cf5Sahrens 	int err;
13801d452cf5Sahrens 
1381e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
13821d452cf5Sahrens 		return (EINVAL);
13831d452cf5Sahrens 	err = dmu_objset_find(zc->zc_name,
1384e9dbad6fSeschrock 	    zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN);
13851d452cf5Sahrens 	if (err)
13861d452cf5Sahrens 		return (err);
1387e9dbad6fSeschrock 	return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value));
13881d452cf5Sahrens }
13891d452cf5Sahrens 
13901d452cf5Sahrens static int
13911d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc)
13921d452cf5Sahrens {
13931d452cf5Sahrens 	if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) {
13941d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
13951d452cf5Sahrens 		if (err)
13961d452cf5Sahrens 			return (err);
1397fa9e4066Sahrens 	}
1398fa9e4066Sahrens 
1399fa9e4066Sahrens 	return (dmu_objset_destroy(zc->zc_name));
1400fa9e4066Sahrens }
1401fa9e4066Sahrens 
1402fa9e4066Sahrens static int
1403fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc)
1404fa9e4066Sahrens {
1405fa9e4066Sahrens 	return (dmu_objset_rollback(zc->zc_name));
1406fa9e4066Sahrens }
1407fa9e4066Sahrens 
1408fa9e4066Sahrens static int
1409fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc)
1410fa9e4066Sahrens {
1411e9dbad6fSeschrock 	zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
1412e9dbad6fSeschrock 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0)
1413fa9e4066Sahrens 		return (EINVAL);
1414fa9e4066Sahrens 
1415fa9e4066Sahrens 	if (strchr(zc->zc_name, '@') != NULL &&
1416fa9e4066Sahrens 	    zc->zc_objset_type == DMU_OST_ZFS) {
14171d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
14181d452cf5Sahrens 		if (err)
14191d452cf5Sahrens 			return (err);
1420fa9e4066Sahrens 	}
1421fa9e4066Sahrens 
1422e9dbad6fSeschrock 	return (dmu_objset_rename(zc->zc_name, zc->zc_value));
1423fa9e4066Sahrens }
1424fa9e4066Sahrens 
1425fa9e4066Sahrens static int
1426fa9e4066Sahrens zfs_ioc_recvbackup(zfs_cmd_t *zc)
1427fa9e4066Sahrens {
1428fa9e4066Sahrens 	file_t *fp;
1429fa9e4066Sahrens 	int error, fd;
1430a2eea2e1Sahrens 	offset_t new_off;
1431fa9e4066Sahrens 
14323ccfa83cSahrens 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
14333ccfa83cSahrens 	    strchr(zc->zc_value, '@') == NULL)
14343ccfa83cSahrens 		return (EINVAL);
14353ccfa83cSahrens 
1436fa9e4066Sahrens 	fd = zc->zc_cookie;
1437fa9e4066Sahrens 	fp = getf(fd);
1438fa9e4066Sahrens 	if (fp == NULL)
1439fa9e4066Sahrens 		return (EBADF);
1440e9dbad6fSeschrock 	error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record,
1441e9dbad6fSeschrock 	    &zc->zc_cookie, (boolean_t)zc->zc_guid, fp->f_vnode,
144298579b20Snd 	    fp->f_offset);
1443a2eea2e1Sahrens 
1444a2eea2e1Sahrens 	new_off = fp->f_offset + zc->zc_cookie;
1445a2eea2e1Sahrens 	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off) == 0)
1446a2eea2e1Sahrens 		fp->f_offset = new_off;
1447a2eea2e1Sahrens 
1448fa9e4066Sahrens 	releasef(fd);
1449fa9e4066Sahrens 	return (error);
1450fa9e4066Sahrens }
1451fa9e4066Sahrens 
1452fa9e4066Sahrens static int
1453fa9e4066Sahrens zfs_ioc_sendbackup(zfs_cmd_t *zc)
1454fa9e4066Sahrens {
1455fa9e4066Sahrens 	objset_t *fromsnap = NULL;
1456fa9e4066Sahrens 	objset_t *tosnap;
1457fa9e4066Sahrens 	file_t *fp;
1458fa9e4066Sahrens 	int error;
1459fa9e4066Sahrens 
1460fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1461fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap);
1462fa9e4066Sahrens 	if (error)
1463fa9e4066Sahrens 		return (error);
1464fa9e4066Sahrens 
1465e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1466a2eea2e1Sahrens 		char buf[MAXPATHLEN];
1467a2eea2e1Sahrens 		char *cp;
1468a2eea2e1Sahrens 
1469a2eea2e1Sahrens 		(void) strncpy(buf, zc->zc_name, sizeof (buf));
1470a2eea2e1Sahrens 		cp = strchr(buf, '@');
1471a2eea2e1Sahrens 		if (cp)
1472a2eea2e1Sahrens 			*(cp+1) = 0;
1473a2eea2e1Sahrens 		(void) strncat(buf, zc->zc_value, sizeof (buf));
1474a2eea2e1Sahrens 		error = dmu_objset_open(buf, DMU_OST_ANY,
1475fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap);
1476fa9e4066Sahrens 		if (error) {
1477fa9e4066Sahrens 			dmu_objset_close(tosnap);
1478fa9e4066Sahrens 			return (error);
1479fa9e4066Sahrens 		}
1480fa9e4066Sahrens 	}
1481fa9e4066Sahrens 
1482fa9e4066Sahrens 	fp = getf(zc->zc_cookie);
1483fa9e4066Sahrens 	if (fp == NULL) {
1484fa9e4066Sahrens 		dmu_objset_close(tosnap);
1485fa9e4066Sahrens 		if (fromsnap)
1486fa9e4066Sahrens 			dmu_objset_close(fromsnap);
1487fa9e4066Sahrens 		return (EBADF);
1488fa9e4066Sahrens 	}
1489fa9e4066Sahrens 
1490fa9e4066Sahrens 	error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode);
1491fa9e4066Sahrens 
1492fa9e4066Sahrens 	releasef(zc->zc_cookie);
1493fa9e4066Sahrens 	if (fromsnap)
1494fa9e4066Sahrens 		dmu_objset_close(fromsnap);
1495fa9e4066Sahrens 	dmu_objset_close(tosnap);
1496fa9e4066Sahrens 	return (error);
1497fa9e4066Sahrens }
1498fa9e4066Sahrens 
1499ea8dc4b6Seschrock static int
1500ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc)
1501ea8dc4b6Seschrock {
1502ea8dc4b6Seschrock 	int id, error;
1503ea8dc4b6Seschrock 
1504ea8dc4b6Seschrock 	error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id,
1505ea8dc4b6Seschrock 	    &zc->zc_inject_record);
1506ea8dc4b6Seschrock 
1507ea8dc4b6Seschrock 	if (error == 0)
1508ea8dc4b6Seschrock 		zc->zc_guid = (uint64_t)id;
1509ea8dc4b6Seschrock 
1510ea8dc4b6Seschrock 	return (error);
1511ea8dc4b6Seschrock }
1512ea8dc4b6Seschrock 
1513ea8dc4b6Seschrock static int
1514ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc)
1515ea8dc4b6Seschrock {
1516ea8dc4b6Seschrock 	return (zio_clear_fault((int)zc->zc_guid));
1517ea8dc4b6Seschrock }
1518ea8dc4b6Seschrock 
1519ea8dc4b6Seschrock static int
1520ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc)
1521ea8dc4b6Seschrock {
1522ea8dc4b6Seschrock 	int id = (int)zc->zc_guid;
1523ea8dc4b6Seschrock 	int error;
1524ea8dc4b6Seschrock 
1525ea8dc4b6Seschrock 	error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name),
1526ea8dc4b6Seschrock 	    &zc->zc_inject_record);
1527ea8dc4b6Seschrock 
1528ea8dc4b6Seschrock 	zc->zc_guid = id;
1529ea8dc4b6Seschrock 
1530ea8dc4b6Seschrock 	return (error);
1531ea8dc4b6Seschrock }
1532ea8dc4b6Seschrock 
1533ea8dc4b6Seschrock static int
1534ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc)
1535ea8dc4b6Seschrock {
1536ea8dc4b6Seschrock 	spa_t *spa;
1537ea8dc4b6Seschrock 	int error;
1538e9dbad6fSeschrock 	size_t count = (size_t)zc->zc_nvlist_dst_size;
1539ea8dc4b6Seschrock 
1540ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1541ea8dc4b6Seschrock 		return (error);
1542ea8dc4b6Seschrock 
1543e9dbad6fSeschrock 	error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst,
1544ea8dc4b6Seschrock 	    &count);
1545ea8dc4b6Seschrock 	if (error == 0)
1546e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = count;
1547ea8dc4b6Seschrock 	else
1548e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = spa_get_errlog_size(spa);
1549ea8dc4b6Seschrock 
1550ea8dc4b6Seschrock 	spa_close(spa, FTAG);
1551ea8dc4b6Seschrock 
1552ea8dc4b6Seschrock 	return (error);
1553ea8dc4b6Seschrock }
1554ea8dc4b6Seschrock 
1555ea8dc4b6Seschrock static int
1556ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc)
1557ea8dc4b6Seschrock {
1558ea8dc4b6Seschrock 	spa_t *spa;
1559ea8dc4b6Seschrock 	vdev_t *vd;
1560ea8dc4b6Seschrock 	int error;
1561ea8dc4b6Seschrock 
1562ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1563ea8dc4b6Seschrock 		return (error);
1564ea8dc4b6Seschrock 
1565ea8dc4b6Seschrock 	spa_config_enter(spa, RW_WRITER, FTAG);
1566ea8dc4b6Seschrock 
1567e9dbad6fSeschrock 	if (zc->zc_guid == 0) {
1568ea8dc4b6Seschrock 		vd = NULL;
1569e9dbad6fSeschrock 	} else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) {
1570ea8dc4b6Seschrock 		spa_config_exit(spa, FTAG);
1571ea8dc4b6Seschrock 		spa_close(spa, FTAG);
1572ea8dc4b6Seschrock 		return (ENODEV);
1573ea8dc4b6Seschrock 	}
1574ea8dc4b6Seschrock 
1575ea8dc4b6Seschrock 	vdev_clear(spa, vd);
1576ea8dc4b6Seschrock 
1577ea8dc4b6Seschrock 	spa_config_exit(spa, FTAG);
1578ea8dc4b6Seschrock 
1579ea8dc4b6Seschrock 	spa_close(spa, FTAG);
1580ea8dc4b6Seschrock 
1581ea8dc4b6Seschrock 	return (0);
1582ea8dc4b6Seschrock }
1583ea8dc4b6Seschrock 
158499653d4eSeschrock static int
158599653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc)
158699653d4eSeschrock {
15870b69c2f0Sahrens 	char *cp;
15880b69c2f0Sahrens 
15890b69c2f0Sahrens 	/*
15900b69c2f0Sahrens 	 * We don't need to unmount *all* the origin fs's snapshots, but
15910b69c2f0Sahrens 	 * it's easier.
15920b69c2f0Sahrens 	 */
1593e9dbad6fSeschrock 	cp = strchr(zc->zc_value, '@');
15940b69c2f0Sahrens 	if (cp)
15950b69c2f0Sahrens 		*cp = '\0';
1596e9dbad6fSeschrock 	(void) dmu_objset_find(zc->zc_value,
15970b69c2f0Sahrens 	    zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS);
159899653d4eSeschrock 	return (dsl_dataset_promote(zc->zc_name));
159999653d4eSeschrock }
160099653d4eSeschrock 
1601fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = {
1602fa9e4066Sahrens 	{ zfs_ioc_pool_create,		zfs_secpolicy_config,	pool_name },
1603fa9e4066Sahrens 	{ zfs_ioc_pool_destroy,		zfs_secpolicy_config,	pool_name },
1604fa9e4066Sahrens 	{ zfs_ioc_pool_import,		zfs_secpolicy_config,	pool_name },
1605fa9e4066Sahrens 	{ zfs_ioc_pool_export,		zfs_secpolicy_config,	pool_name },
1606fa9e4066Sahrens 	{ zfs_ioc_pool_configs,		zfs_secpolicy_none,	no_name },
1607fa9e4066Sahrens 	{ zfs_ioc_pool_stats,		zfs_secpolicy_read,	pool_name },
1608fa9e4066Sahrens 	{ zfs_ioc_pool_tryimport,	zfs_secpolicy_config,	no_name },
1609fa9e4066Sahrens 	{ zfs_ioc_pool_scrub,		zfs_secpolicy_config,	pool_name },
1610fa9e4066Sahrens 	{ zfs_ioc_pool_freeze,		zfs_secpolicy_config,	no_name },
1611eaca9bbdSeschrock 	{ zfs_ioc_pool_upgrade,		zfs_secpolicy_config,	pool_name },
161206eeb2adSek 	{ zfs_ioc_pool_get_history,	zfs_secpolicy_config,	pool_name },
161306eeb2adSek 	{ zfs_ioc_pool_log_history,	zfs_secpolicy_config,	pool_name },
1614fa9e4066Sahrens 	{ zfs_ioc_vdev_add,		zfs_secpolicy_config,	pool_name },
1615fa9e4066Sahrens 	{ zfs_ioc_vdev_remove,		zfs_secpolicy_config,	pool_name },
1616fa9e4066Sahrens 	{ zfs_ioc_vdev_online,		zfs_secpolicy_config,	pool_name },
1617fa9e4066Sahrens 	{ zfs_ioc_vdev_offline,		zfs_secpolicy_config,	pool_name },
1618fa9e4066Sahrens 	{ zfs_ioc_vdev_attach,		zfs_secpolicy_config,	pool_name },
1619fa9e4066Sahrens 	{ zfs_ioc_vdev_detach,		zfs_secpolicy_config,	pool_name },
1620c67d9675Seschrock 	{ zfs_ioc_vdev_setpath,		zfs_secpolicy_config,	pool_name },
1621fa9e4066Sahrens 	{ zfs_ioc_objset_stats,		zfs_secpolicy_read,	dataset_name },
1622fa9e4066Sahrens 	{ zfs_ioc_dataset_list_next,	zfs_secpolicy_read,	dataset_name },
1623fa9e4066Sahrens 	{ zfs_ioc_snapshot_list_next,	zfs_secpolicy_read,	dataset_name },
1624e9dbad6fSeschrock 	{ zfs_ioc_set_prop,		zfs_secpolicy_write,	dataset_name },
1625fa9e4066Sahrens 	{ zfs_ioc_create_minor,		zfs_secpolicy_config,	dataset_name },
1626fa9e4066Sahrens 	{ zfs_ioc_remove_minor,		zfs_secpolicy_config,	dataset_name },
1627fa9e4066Sahrens 	{ zfs_ioc_create,		zfs_secpolicy_parent,	dataset_name },
1628fa9e4066Sahrens 	{ zfs_ioc_destroy,		zfs_secpolicy_parent,	dataset_name },
1629fa9e4066Sahrens 	{ zfs_ioc_rollback,		zfs_secpolicy_write,	dataset_name },
1630fa9e4066Sahrens 	{ zfs_ioc_rename,		zfs_secpolicy_write,	dataset_name },
1631fa9e4066Sahrens 	{ zfs_ioc_recvbackup,		zfs_secpolicy_write,	dataset_name },
1632fa9e4066Sahrens 	{ zfs_ioc_sendbackup,		zfs_secpolicy_write,	dataset_name },
1633ea8dc4b6Seschrock 	{ zfs_ioc_inject_fault,		zfs_secpolicy_inject,	no_name },
1634ea8dc4b6Seschrock 	{ zfs_ioc_clear_fault,		zfs_secpolicy_inject,	no_name },
1635ea8dc4b6Seschrock 	{ zfs_ioc_inject_list_next,	zfs_secpolicy_inject,	no_name },
1636ea8dc4b6Seschrock 	{ zfs_ioc_error_log,		zfs_secpolicy_inject,	pool_name },
1637ea8dc4b6Seschrock 	{ zfs_ioc_clear,		zfs_secpolicy_config,	pool_name },
16381d452cf5Sahrens 	{ zfs_ioc_promote,		zfs_secpolicy_write,	dataset_name },
16391d452cf5Sahrens 	{ zfs_ioc_destroy_snaps,	zfs_secpolicy_write,	dataset_name },
164055434c77Sek 	{ zfs_ioc_snapshot,		zfs_secpolicy_write,	dataset_name },
164155434c77Sek 	{ zfs_ioc_dsobj_to_dsname,	zfs_secpolicy_config,	pool_name },
1642*b1b8ab34Slling 	{ zfs_ioc_obj_to_path,		zfs_secpolicy_config,	no_name },
1643*b1b8ab34Slling 	{ zfs_ioc_pool_props_set,	zfs_secpolicy_config,	pool_name },
1644*b1b8ab34Slling 	{ zfs_ioc_pool_props_get,	zfs_secpolicy_read,	pool_name },
1645fa9e4066Sahrens };
1646fa9e4066Sahrens 
1647fa9e4066Sahrens static int
1648fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
1649fa9e4066Sahrens {
1650fa9e4066Sahrens 	zfs_cmd_t *zc;
1651fa9e4066Sahrens 	uint_t vec;
16521d452cf5Sahrens 	int error, rc;
1653fa9e4066Sahrens 
1654fa9e4066Sahrens 	if (getminor(dev) != 0)
1655fa9e4066Sahrens 		return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp));
1656fa9e4066Sahrens 
1657fa9e4066Sahrens 	vec = cmd - ZFS_IOC;
1658fa9e4066Sahrens 
1659fa9e4066Sahrens 	if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
1660fa9e4066Sahrens 		return (EINVAL);
1661fa9e4066Sahrens 
1662fa9e4066Sahrens 	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
1663fa9e4066Sahrens 
1664fa9e4066Sahrens 	error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t));
1665fa9e4066Sahrens 
1666fa9e4066Sahrens 	if (error == 0) {
1667fa9e4066Sahrens 		zc->zc_cred = (uintptr_t)cr;
1668fa9e4066Sahrens 		zc->zc_dev = dev;
1669e9dbad6fSeschrock 		error = zfs_ioc_vec[vec].zvec_secpolicy(zc->zc_name, cr);
1670fa9e4066Sahrens 	}
1671fa9e4066Sahrens 
1672fa9e4066Sahrens 	/*
1673fa9e4066Sahrens 	 * Ensure that all pool/dataset names are valid before we pass down to
1674fa9e4066Sahrens 	 * the lower layers.
1675fa9e4066Sahrens 	 */
1676fa9e4066Sahrens 	if (error == 0) {
1677fa9e4066Sahrens 		zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
1678fa9e4066Sahrens 		switch (zfs_ioc_vec[vec].zvec_namecheck) {
1679fa9e4066Sahrens 		case pool_name:
1680fa9e4066Sahrens 			if (pool_namecheck(zc->zc_name, NULL, NULL) != 0)
1681fa9e4066Sahrens 				error = EINVAL;
1682fa9e4066Sahrens 			break;
1683fa9e4066Sahrens 
1684fa9e4066Sahrens 		case dataset_name:
1685fa9e4066Sahrens 			if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0)
1686fa9e4066Sahrens 				error = EINVAL;
1687fa9e4066Sahrens 			break;
16885ad82045Snd 
16895ad82045Snd 		case no_name:
16905ad82045Snd 			break;
1691fa9e4066Sahrens 		}
1692fa9e4066Sahrens 	}
1693fa9e4066Sahrens 
1694fa9e4066Sahrens 	if (error == 0)
1695fa9e4066Sahrens 		error = zfs_ioc_vec[vec].zvec_func(zc);
1696fa9e4066Sahrens 
16971d452cf5Sahrens 	rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t));
16981d452cf5Sahrens 	if (error == 0)
16991d452cf5Sahrens 		error = rc;
1700fa9e4066Sahrens 
1701fa9e4066Sahrens 	kmem_free(zc, sizeof (zfs_cmd_t));
1702fa9e4066Sahrens 	return (error);
1703fa9e4066Sahrens }
1704fa9e4066Sahrens 
1705fa9e4066Sahrens static int
1706fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1707fa9e4066Sahrens {
1708fa9e4066Sahrens 	if (cmd != DDI_ATTACH)
1709fa9e4066Sahrens 		return (DDI_FAILURE);
1710fa9e4066Sahrens 
1711fa9e4066Sahrens 	if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0,
1712fa9e4066Sahrens 	    DDI_PSEUDO, 0) == DDI_FAILURE)
1713fa9e4066Sahrens 		return (DDI_FAILURE);
1714fa9e4066Sahrens 
1715fa9e4066Sahrens 	zfs_dip = dip;
1716fa9e4066Sahrens 
1717fa9e4066Sahrens 	ddi_report_dev(dip);
1718fa9e4066Sahrens 
1719fa9e4066Sahrens 	return (DDI_SUCCESS);
1720fa9e4066Sahrens }
1721fa9e4066Sahrens 
1722fa9e4066Sahrens static int
1723fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1724fa9e4066Sahrens {
1725fa9e4066Sahrens 	if (spa_busy() || zfs_busy() || zvol_busy())
1726fa9e4066Sahrens 		return (DDI_FAILURE);
1727fa9e4066Sahrens 
1728fa9e4066Sahrens 	if (cmd != DDI_DETACH)
1729fa9e4066Sahrens 		return (DDI_FAILURE);
1730fa9e4066Sahrens 
1731fa9e4066Sahrens 	zfs_dip = NULL;
1732fa9e4066Sahrens 
1733fa9e4066Sahrens 	ddi_prop_remove_all(dip);
1734fa9e4066Sahrens 	ddi_remove_minor_node(dip, NULL);
1735fa9e4066Sahrens 
1736fa9e4066Sahrens 	return (DDI_SUCCESS);
1737fa9e4066Sahrens }
1738fa9e4066Sahrens 
1739fa9e4066Sahrens /*ARGSUSED*/
1740fa9e4066Sahrens static int
1741fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
1742fa9e4066Sahrens {
1743fa9e4066Sahrens 	switch (infocmd) {
1744fa9e4066Sahrens 	case DDI_INFO_DEVT2DEVINFO:
1745fa9e4066Sahrens 		*result = zfs_dip;
1746fa9e4066Sahrens 		return (DDI_SUCCESS);
1747fa9e4066Sahrens 
1748fa9e4066Sahrens 	case DDI_INFO_DEVT2INSTANCE:
1749a0965f35Sbonwick 		*result = (void *)0;
1750fa9e4066Sahrens 		return (DDI_SUCCESS);
1751fa9e4066Sahrens 	}
1752fa9e4066Sahrens 
1753fa9e4066Sahrens 	return (DDI_FAILURE);
1754fa9e4066Sahrens }
1755fa9e4066Sahrens 
1756fa9e4066Sahrens /*
1757fa9e4066Sahrens  * OK, so this is a little weird.
1758fa9e4066Sahrens  *
1759fa9e4066Sahrens  * /dev/zfs is the control node, i.e. minor 0.
1760fa9e4066Sahrens  * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0.
1761fa9e4066Sahrens  *
1762fa9e4066Sahrens  * /dev/zfs has basically nothing to do except serve up ioctls,
1763fa9e4066Sahrens  * so most of the standard driver entry points are in zvol.c.
1764fa9e4066Sahrens  */
1765fa9e4066Sahrens static struct cb_ops zfs_cb_ops = {
1766fa9e4066Sahrens 	zvol_open,	/* open */
1767fa9e4066Sahrens 	zvol_close,	/* close */
1768fa9e4066Sahrens 	zvol_strategy,	/* strategy */
1769fa9e4066Sahrens 	nodev,		/* print */
1770fa9e4066Sahrens 	nodev,		/* dump */
1771fa9e4066Sahrens 	zvol_read,	/* read */
1772fa9e4066Sahrens 	zvol_write,	/* write */
1773fa9e4066Sahrens 	zfsdev_ioctl,	/* ioctl */
1774fa9e4066Sahrens 	nodev,		/* devmap */
1775fa9e4066Sahrens 	nodev,		/* mmap */
1776fa9e4066Sahrens 	nodev,		/* segmap */
1777fa9e4066Sahrens 	nochpoll,	/* poll */
1778fa9e4066Sahrens 	ddi_prop_op,	/* prop_op */
1779fa9e4066Sahrens 	NULL,		/* streamtab */
1780fa9e4066Sahrens 	D_NEW | D_MP | D_64BIT,		/* Driver compatibility flag */
1781fa9e4066Sahrens 	CB_REV,		/* version */
1782feb08c6bSbillm 	nodev,		/* async read */
1783feb08c6bSbillm 	nodev,		/* async write */
1784fa9e4066Sahrens };
1785fa9e4066Sahrens 
1786fa9e4066Sahrens static struct dev_ops zfs_dev_ops = {
1787fa9e4066Sahrens 	DEVO_REV,	/* version */
1788fa9e4066Sahrens 	0,		/* refcnt */
1789fa9e4066Sahrens 	zfs_info,	/* info */
1790fa9e4066Sahrens 	nulldev,	/* identify */
1791fa9e4066Sahrens 	nulldev,	/* probe */
1792fa9e4066Sahrens 	zfs_attach,	/* attach */
1793fa9e4066Sahrens 	zfs_detach,	/* detach */
1794fa9e4066Sahrens 	nodev,		/* reset */
1795fa9e4066Sahrens 	&zfs_cb_ops,	/* driver operations */
1796fa9e4066Sahrens 	NULL		/* no bus operations */
1797fa9e4066Sahrens };
1798fa9e4066Sahrens 
1799fa9e4066Sahrens static struct modldrv zfs_modldrv = {
1800e9dbad6fSeschrock 	&mod_driverops, "ZFS storage pool version " ZFS_VERSION_STRING,
1801e9dbad6fSeschrock 	    &zfs_dev_ops
1802fa9e4066Sahrens };
1803fa9e4066Sahrens 
1804fa9e4066Sahrens static struct modlinkage modlinkage = {
1805fa9e4066Sahrens 	MODREV_1,
1806fa9e4066Sahrens 	(void *)&zfs_modlfs,
1807fa9e4066Sahrens 	(void *)&zfs_modldrv,
1808fa9e4066Sahrens 	NULL
1809fa9e4066Sahrens };
1810fa9e4066Sahrens 
1811fa9e4066Sahrens int
1812fa9e4066Sahrens _init(void)
1813fa9e4066Sahrens {
1814fa9e4066Sahrens 	int error;
1815fa9e4066Sahrens 
1816a0965f35Sbonwick 	spa_init(FREAD | FWRITE);
1817a0965f35Sbonwick 	zfs_init();
1818a0965f35Sbonwick 	zvol_init();
1819a0965f35Sbonwick 
1820a0965f35Sbonwick 	if ((error = mod_install(&modlinkage)) != 0) {
1821a0965f35Sbonwick 		zvol_fini();
1822a0965f35Sbonwick 		zfs_fini();
1823a0965f35Sbonwick 		spa_fini();
1824fa9e4066Sahrens 		return (error);
1825a0965f35Sbonwick 	}
1826fa9e4066Sahrens 
1827fa9e4066Sahrens 	error = ldi_ident_from_mod(&modlinkage, &zfs_li);
1828fa9e4066Sahrens 	ASSERT(error == 0);
1829fa9e4066Sahrens 
1830fa9e4066Sahrens 	return (0);
1831fa9e4066Sahrens }
1832fa9e4066Sahrens 
1833fa9e4066Sahrens int
1834fa9e4066Sahrens _fini(void)
1835fa9e4066Sahrens {
1836fa9e4066Sahrens 	int error;
1837fa9e4066Sahrens 
1838ea8dc4b6Seschrock 	if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled)
1839fa9e4066Sahrens 		return (EBUSY);
1840fa9e4066Sahrens 
1841fa9e4066Sahrens 	if ((error = mod_remove(&modlinkage)) != 0)
1842fa9e4066Sahrens 		return (error);
1843fa9e4066Sahrens 
1844fa9e4066Sahrens 	zvol_fini();
1845fa9e4066Sahrens 	zfs_fini();
1846fa9e4066Sahrens 	spa_fini();
1847fa9e4066Sahrens 
1848fa9e4066Sahrens 	ldi_ident_release(zfs_li);
1849fa9e4066Sahrens 	zfs_li = NULL;
1850fa9e4066Sahrens 
1851fa9e4066Sahrens 	return (error);
1852fa9e4066Sahrens }
1853fa9e4066Sahrens 
1854fa9e4066Sahrens int
1855fa9e4066Sahrens _info(struct modinfo *modinfop)
1856fa9e4066Sahrens {
1857fa9e4066Sahrens 	return (mod_info(&modlinkage, modinfop));
1858fa9e4066Sahrens }
1859