xref: /illumos-gate/usr/src/uts/common/fs/zfs/zfs_ioctl.c (revision f18faf3f)
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>
43b1b8ab34Slling #include <sys/spa_impl.h>
44fa9e4066Sahrens #include <sys/vdev.h>
45b1b8ab34Slling #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>
50ecd6cf80Smarks #include <sys/dsl_deleg.h>
51ecd6cf80Smarks #include <sys/dmu_objset.h>
52fa9e4066Sahrens #include <sys/ddi.h>
53fa9e4066Sahrens #include <sys/sunddi.h>
54fa9e4066Sahrens #include <sys/sunldi.h>
55fa9e4066Sahrens #include <sys/policy.h>
56fa9e4066Sahrens #include <sys/zone.h>
57fa9e4066Sahrens #include <sys/nvpair.h>
58fa9e4066Sahrens #include <sys/pathname.h>
59fa9e4066Sahrens #include <sys/mount.h>
60fa9e4066Sahrens #include <sys/sdt.h>
61fa9e4066Sahrens #include <sys/fs/zfs.h>
62fa9e4066Sahrens #include <sys/zfs_ctldir.h>
63a2eea2e1Sahrens #include <sys/zvol.h>
64ecd6cf80Smarks #include <sharefs/share.h>
65e7437265Sahrens #include <sys/zfs_znode.h>
66*f18faf3fSek #include <sys/zfs_vfsops.h>
67*f18faf3fSek #include <sys/dmu_objset.h>
68fa9e4066Sahrens 
69fa9e4066Sahrens #include "zfs_namecheck.h"
70e9dbad6fSeschrock #include "zfs_prop.h"
71ecd6cf80Smarks #include "zfs_deleg.h"
72fa9e4066Sahrens 
73fa9e4066Sahrens extern struct modlfs zfs_modlfs;
74fa9e4066Sahrens 
75fa9e4066Sahrens extern void zfs_init(void);
76fa9e4066Sahrens extern void zfs_fini(void);
77fa9e4066Sahrens 
78fa9e4066Sahrens ldi_ident_t zfs_li = NULL;
79fa9e4066Sahrens dev_info_t *zfs_dip;
80fa9e4066Sahrens 
81fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *);
82ecd6cf80Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *);
83fa9e4066Sahrens 
84fa9e4066Sahrens typedef struct zfs_ioc_vec {
85fa9e4066Sahrens 	zfs_ioc_func_t		*zvec_func;
86fa9e4066Sahrens 	zfs_secpolicy_func_t	*zvec_secpolicy;
87fa9e4066Sahrens 	enum {
88e7437265Sahrens 		NO_NAME,
89e7437265Sahrens 		POOL_NAME,
90e7437265Sahrens 		DATASET_NAME
91ecd6cf80Smarks 	} zvec_namecheck;
92ecd6cf80Smarks 	boolean_t		zvec_his_log;
93fa9e4066Sahrens } zfs_ioc_vec_t;
94fa9e4066Sahrens 
95fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */
96fa9e4066Sahrens void
97fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
98fa9e4066Sahrens {
99fa9e4066Sahrens 	const char *newfile;
100fa9e4066Sahrens 	char buf[256];
101fa9e4066Sahrens 	va_list adx;
102fa9e4066Sahrens 
103fa9e4066Sahrens 	/*
104fa9e4066Sahrens 	 * Get rid of annoying "../common/" prefix to filename.
105fa9e4066Sahrens 	 */
106fa9e4066Sahrens 	newfile = strrchr(file, '/');
107fa9e4066Sahrens 	if (newfile != NULL) {
108fa9e4066Sahrens 		newfile = newfile + 1; /* Get rid of leading / */
109fa9e4066Sahrens 	} else {
110fa9e4066Sahrens 		newfile = file;
111fa9e4066Sahrens 	}
112fa9e4066Sahrens 
113fa9e4066Sahrens 	va_start(adx, fmt);
114fa9e4066Sahrens 	(void) vsnprintf(buf, sizeof (buf), fmt, adx);
115fa9e4066Sahrens 	va_end(adx);
116fa9e4066Sahrens 
117fa9e4066Sahrens 	/*
118fa9e4066Sahrens 	 * To get this data, use the zfs-dprintf probe as so:
119fa9e4066Sahrens 	 * dtrace -q -n 'zfs-dprintf \
120fa9e4066Sahrens 	 *	/stringof(arg0) == "dbuf.c"/ \
121fa9e4066Sahrens 	 *	{printf("%s: %s", stringof(arg1), stringof(arg3))}'
122fa9e4066Sahrens 	 * arg0 = file name
123fa9e4066Sahrens 	 * arg1 = function name
124fa9e4066Sahrens 	 * arg2 = line number
125fa9e4066Sahrens 	 * arg3 = message
126fa9e4066Sahrens 	 */
127fa9e4066Sahrens 	DTRACE_PROBE4(zfs__dprintf,
128fa9e4066Sahrens 	    char *, newfile, char *, func, int, line, char *, buf);
129fa9e4066Sahrens }
130fa9e4066Sahrens 
131ecd6cf80Smarks static void
132228975ccSek history_str_free(char *buf)
133228975ccSek {
134228975ccSek 	kmem_free(buf, HIS_MAX_RECORD_LEN);
135228975ccSek }
136228975ccSek 
137228975ccSek static char *
138228975ccSek history_str_get(zfs_cmd_t *zc)
139ecd6cf80Smarks {
14040feaa91Sahrens 	char *buf;
141ecd6cf80Smarks 
142ecd6cf80Smarks 	if (zc->zc_history == NULL)
143228975ccSek 		return (NULL);
144e7437265Sahrens 
145ecd6cf80Smarks 	buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP);
146ecd6cf80Smarks 	if (copyinstr((void *)(uintptr_t)zc->zc_history,
147ecd6cf80Smarks 	    buf, HIS_MAX_RECORD_LEN, NULL) != 0) {
148228975ccSek 		history_str_free(buf);
149228975ccSek 		return (NULL);
150ecd6cf80Smarks 	}
151ecd6cf80Smarks 
152ecd6cf80Smarks 	buf[HIS_MAX_RECORD_LEN -1] = '\0';
153ecd6cf80Smarks 
154228975ccSek 	return (buf);
155228975ccSek }
156ecd6cf80Smarks 
157228975ccSek static void
158228975ccSek zfs_log_history(zfs_cmd_t *zc)
159228975ccSek {
160228975ccSek 	spa_t *spa;
161228975ccSek 	char *buf;
162ecd6cf80Smarks 
163228975ccSek 	if ((buf = history_str_get(zc)) == NULL)
164228975ccSek 		return;
165228975ccSek 
166228975ccSek 	if (spa_open(zc->zc_name, &spa, FTAG) == 0) {
167228975ccSek 		if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY)
168228975ccSek 			(void) spa_history_log(spa, buf, LOG_CMD_NORMAL);
169228975ccSek 		spa_close(spa, FTAG);
170228975ccSek 	}
171228975ccSek 	history_str_free(buf);
172ecd6cf80Smarks }
173ecd6cf80Smarks 
174fa9e4066Sahrens /*
175fa9e4066Sahrens  * Policy for top-level read operations (list pools).  Requires no privileges,
176fa9e4066Sahrens  * and can be used in the local zone, as there is no associated dataset.
177fa9e4066Sahrens  */
178fa9e4066Sahrens /* ARGSUSED */
179fa9e4066Sahrens static int
180ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr)
181fa9e4066Sahrens {
182fa9e4066Sahrens 	return (0);
183fa9e4066Sahrens }
184fa9e4066Sahrens 
185fa9e4066Sahrens /*
186fa9e4066Sahrens  * Policy for dataset read operations (list children, get statistics).  Requires
187fa9e4066Sahrens  * no privileges, but must be visible in the local zone.
188fa9e4066Sahrens  */
189fa9e4066Sahrens /* ARGSUSED */
190fa9e4066Sahrens static int
191ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr)
192fa9e4066Sahrens {
193fa9e4066Sahrens 	if (INGLOBALZONE(curproc) ||
194ecd6cf80Smarks 	    zone_dataset_visible(zc->zc_name, NULL))
195fa9e4066Sahrens 		return (0);
196fa9e4066Sahrens 
197fa9e4066Sahrens 	return (ENOENT);
198fa9e4066Sahrens }
199fa9e4066Sahrens 
200fa9e4066Sahrens static int
201fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr)
202fa9e4066Sahrens {
203fa9e4066Sahrens 	uint64_t zoned;
204fa9e4066Sahrens 	int writable = 1;
205fa9e4066Sahrens 
206fa9e4066Sahrens 	/*
207fa9e4066Sahrens 	 * The dataset must be visible by this zone -- check this first
208fa9e4066Sahrens 	 * so they don't see EPERM on something they shouldn't know about.
209fa9e4066Sahrens 	 */
210fa9e4066Sahrens 	if (!INGLOBALZONE(curproc) &&
211fa9e4066Sahrens 	    !zone_dataset_visible(dataset, &writable))
212fa9e4066Sahrens 		return (ENOENT);
213fa9e4066Sahrens 
214fa9e4066Sahrens 	if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL))
215fa9e4066Sahrens 		return (ENOENT);
216fa9e4066Sahrens 
217fa9e4066Sahrens 	if (INGLOBALZONE(curproc)) {
218fa9e4066Sahrens 		/*
219fa9e4066Sahrens 		 * If the fs is zoned, only root can access it from the
220fa9e4066Sahrens 		 * global zone.
221fa9e4066Sahrens 		 */
222fa9e4066Sahrens 		if (secpolicy_zfs(cr) && zoned)
223fa9e4066Sahrens 			return (EPERM);
224fa9e4066Sahrens 	} else {
225fa9e4066Sahrens 		/*
226fa9e4066Sahrens 		 * If we are in a local zone, the 'zoned' property must be set.
227fa9e4066Sahrens 		 */
228fa9e4066Sahrens 		if (!zoned)
229fa9e4066Sahrens 			return (EPERM);
230fa9e4066Sahrens 
231fa9e4066Sahrens 		/* must be writable by this zone */
232fa9e4066Sahrens 		if (!writable)
233fa9e4066Sahrens 			return (EPERM);
234fa9e4066Sahrens 	}
235fa9e4066Sahrens 	return (0);
236fa9e4066Sahrens }
237fa9e4066Sahrens 
238fa9e4066Sahrens int
239ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr)
240fa9e4066Sahrens {
241fa9e4066Sahrens 	int error;
242fa9e4066Sahrens 
243ecd6cf80Smarks 	error = zfs_dozonecheck(name, cr);
244ecd6cf80Smarks 	if (error == 0) {
245ecd6cf80Smarks 		error = secpolicy_zfs(cr);
246db870a07Sahrens 		if (error)
247ecd6cf80Smarks 			error = dsl_deleg_access(name, perm, cr);
248ecd6cf80Smarks 	}
249ecd6cf80Smarks 	return (error);
250ecd6cf80Smarks }
251ecd6cf80Smarks 
252ecd6cf80Smarks static int
253ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr)
254ecd6cf80Smarks {
255ecd6cf80Smarks 	/*
256ecd6cf80Smarks 	 * Check permissions for special properties.
257ecd6cf80Smarks 	 */
258ecd6cf80Smarks 	switch (prop) {
259ecd6cf80Smarks 	case ZFS_PROP_ZONED:
260ecd6cf80Smarks 		/*
261ecd6cf80Smarks 		 * Disallow setting of 'zoned' from within a local zone.
262ecd6cf80Smarks 		 */
263ecd6cf80Smarks 		if (!INGLOBALZONE(curproc))
264ecd6cf80Smarks 			return (EPERM);
265ecd6cf80Smarks 		break;
266ecd6cf80Smarks 
267ecd6cf80Smarks 	case ZFS_PROP_QUOTA:
268ecd6cf80Smarks 		if (!INGLOBALZONE(curproc)) {
269ecd6cf80Smarks 			uint64_t zoned;
270ecd6cf80Smarks 			char setpoint[MAXNAMELEN];
271ecd6cf80Smarks 			/*
272ecd6cf80Smarks 			 * Unprivileged users are allowed to modify the
273ecd6cf80Smarks 			 * quota on things *under* (ie. contained by)
274ecd6cf80Smarks 			 * the thing they own.
275ecd6cf80Smarks 			 */
276ecd6cf80Smarks 			if (dsl_prop_get_integer(name, "zoned", &zoned,
277ecd6cf80Smarks 			    setpoint))
278ecd6cf80Smarks 				return (EPERM);
279db870a07Sahrens 			if (!zoned || strlen(name) <= strlen(setpoint))
280ecd6cf80Smarks 				return (EPERM);
281ecd6cf80Smarks 		}
282db870a07Sahrens 		break;
283ecd6cf80Smarks 	}
284ecd6cf80Smarks 
28591ebeef5Sahrens 	return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr));
286ecd6cf80Smarks }
287ecd6cf80Smarks 
288ecd6cf80Smarks int
289ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr)
290ecd6cf80Smarks {
291ecd6cf80Smarks 	int error;
292ecd6cf80Smarks 
293ecd6cf80Smarks 	error = zfs_dozonecheck(zc->zc_name, cr);
294ecd6cf80Smarks 	if (error)
295fa9e4066Sahrens 		return (error);
296fa9e4066Sahrens 
297ecd6cf80Smarks 	/*
298ecd6cf80Smarks 	 * permission to set permissions will be evaluated later in
299ecd6cf80Smarks 	 * dsl_deleg_can_allow()
300ecd6cf80Smarks 	 */
301ecd6cf80Smarks 	return (0);
302ecd6cf80Smarks }
303ecd6cf80Smarks 
304ecd6cf80Smarks int
305ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr)
306ecd6cf80Smarks {
307ecd6cf80Smarks 	int error;
308ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(zc->zc_name,
309ecd6cf80Smarks 	    ZFS_DELEG_PERM_ROLLBACK, cr);
310ecd6cf80Smarks 	if (error == 0)
311ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(zc->zc_name,
312ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr);
313ecd6cf80Smarks 	return (error);
314ecd6cf80Smarks }
315ecd6cf80Smarks 
316ecd6cf80Smarks int
317ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr)
318ecd6cf80Smarks {
319ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(zc->zc_name,
320ecd6cf80Smarks 	    ZFS_DELEG_PERM_SEND, cr));
321ecd6cf80Smarks }
322ecd6cf80Smarks 
323ecd6cf80Smarks int
324ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr)
325ecd6cf80Smarks {
326ecd6cf80Smarks 	if (!INGLOBALZONE(curproc))
327ecd6cf80Smarks 		return (EPERM);
328ecd6cf80Smarks 
329ecd6cf80Smarks 	if (secpolicy_nfs(CRED()) == 0) {
330ecd6cf80Smarks 		return (0);
331ecd6cf80Smarks 	} else {
332ecd6cf80Smarks 		vnode_t *vp;
333ecd6cf80Smarks 		int error;
334ecd6cf80Smarks 
335ecd6cf80Smarks 		if ((error = lookupname(zc->zc_value, UIO_SYSSPACE,
336ecd6cf80Smarks 		    NO_FOLLOW, NULL, &vp)) != 0)
337ecd6cf80Smarks 			return (error);
338ecd6cf80Smarks 
339ecd6cf80Smarks 		/* Now make sure mntpnt and dataset are ZFS */
340ecd6cf80Smarks 
341ecd6cf80Smarks 		if (vp->v_vfsp->vfs_fstype != zfsfstype ||
342ecd6cf80Smarks 		    (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource),
343ecd6cf80Smarks 		    zc->zc_name) != 0)) {
344ecd6cf80Smarks 			VN_RELE(vp);
345ecd6cf80Smarks 			return (EPERM);
346ecd6cf80Smarks 		}
347ecd6cf80Smarks 
348ecd6cf80Smarks 		VN_RELE(vp);
349ecd6cf80Smarks 		return (dsl_deleg_access(zc->zc_name,
350ecd6cf80Smarks 		    ZFS_DELEG_PERM_SHARE, cr));
351ecd6cf80Smarks 	}
352fa9e4066Sahrens }
353fa9e4066Sahrens 
354fa9e4066Sahrens static int
355ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize)
356fa9e4066Sahrens {
357fa9e4066Sahrens 	char *cp;
358fa9e4066Sahrens 
359fa9e4066Sahrens 	/*
360fa9e4066Sahrens 	 * Remove the @bla or /bla from the end of the name to get the parent.
361fa9e4066Sahrens 	 */
362ecd6cf80Smarks 	(void) strncpy(parent, datasetname, parentsize);
363ecd6cf80Smarks 	cp = strrchr(parent, '@');
364fa9e4066Sahrens 	if (cp != NULL) {
365fa9e4066Sahrens 		cp[0] = '\0';
366fa9e4066Sahrens 	} else {
367ecd6cf80Smarks 		cp = strrchr(parent, '/');
368fa9e4066Sahrens 		if (cp == NULL)
369fa9e4066Sahrens 			return (ENOENT);
370fa9e4066Sahrens 		cp[0] = '\0';
371ecd6cf80Smarks 	}
372ecd6cf80Smarks 
373ecd6cf80Smarks 	return (0);
374ecd6cf80Smarks }
375ecd6cf80Smarks 
376ecd6cf80Smarks int
377ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr)
378ecd6cf80Smarks {
379ecd6cf80Smarks 	int error;
380ecd6cf80Smarks 
381ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(name,
382ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
383ecd6cf80Smarks 		return (error);
384ecd6cf80Smarks 
385ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr));
386ecd6cf80Smarks }
387ecd6cf80Smarks 
388ecd6cf80Smarks static int
389ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr)
390ecd6cf80Smarks {
391ecd6cf80Smarks 	return (zfs_secpolicy_destroy_perms(zc->zc_name, cr));
392ecd6cf80Smarks }
393ecd6cf80Smarks 
394ecd6cf80Smarks /*
395ecd6cf80Smarks  * Must have sys_config privilege to check the iscsi permission
396ecd6cf80Smarks  */
397ecd6cf80Smarks /* ARGSUSED */
398ecd6cf80Smarks static int
399ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr)
400ecd6cf80Smarks {
401ecd6cf80Smarks 	return (secpolicy_zfs(cr));
402ecd6cf80Smarks }
403ecd6cf80Smarks 
404ecd6cf80Smarks int
405ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
406ecd6cf80Smarks {
407ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
408ecd6cf80Smarks 	int	error;
409ecd6cf80Smarks 
410ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(from,
411ecd6cf80Smarks 	    ZFS_DELEG_PERM_RENAME, cr)) != 0)
412ecd6cf80Smarks 		return (error);
413ecd6cf80Smarks 
414ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(from,
415ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
416ecd6cf80Smarks 		return (error);
417ecd6cf80Smarks 
418ecd6cf80Smarks 	if ((error = zfs_get_parent(to, parentname,
419ecd6cf80Smarks 	    sizeof (parentname))) != 0)
420ecd6cf80Smarks 		return (error);
421ecd6cf80Smarks 
422ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
423ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr)) != 0)
424ecd6cf80Smarks 		return (error);
425ecd6cf80Smarks 
426ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
427ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
428ecd6cf80Smarks 		return (error);
429ecd6cf80Smarks 
430ecd6cf80Smarks 	return (error);
431ecd6cf80Smarks }
432ecd6cf80Smarks 
433ecd6cf80Smarks static int
434ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr)
435ecd6cf80Smarks {
436ecd6cf80Smarks 	return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr));
437ecd6cf80Smarks }
438ecd6cf80Smarks 
439ecd6cf80Smarks static int
440ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr)
441ecd6cf80Smarks {
442ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
443ecd6cf80Smarks 	objset_t *clone;
444ecd6cf80Smarks 	int error;
445ecd6cf80Smarks 
446ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(zc->zc_name,
447ecd6cf80Smarks 	    ZFS_DELEG_PERM_PROMOTE, cr);
448ecd6cf80Smarks 	if (error)
449ecd6cf80Smarks 		return (error);
450ecd6cf80Smarks 
451ecd6cf80Smarks 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
452ecd6cf80Smarks 	    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
453ecd6cf80Smarks 
454ecd6cf80Smarks 	if (error == 0) {
455ecd6cf80Smarks 		dsl_dataset_t *pclone = NULL;
456ecd6cf80Smarks 		dsl_dir_t *dd;
457ecd6cf80Smarks 		dd = clone->os->os_dsl_dataset->ds_dir;
458ecd6cf80Smarks 
459ecd6cf80Smarks 		rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
460ecd6cf80Smarks 		error = dsl_dataset_open_obj(dd->dd_pool,
461ecd6cf80Smarks 		    dd->dd_phys->dd_clone_parent_obj, NULL,
462ecd6cf80Smarks 		    DS_MODE_NONE, FTAG, &pclone);
463ecd6cf80Smarks 		rw_exit(&dd->dd_pool->dp_config_rwlock);
464ecd6cf80Smarks 		if (error) {
465ecd6cf80Smarks 			dmu_objset_close(clone);
466ecd6cf80Smarks 			return (error);
467ecd6cf80Smarks 		}
468ecd6cf80Smarks 
469ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(zc->zc_name,
470ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr);
471ecd6cf80Smarks 
472ecd6cf80Smarks 		dsl_dataset_name(pclone, parentname);
473ecd6cf80Smarks 		dmu_objset_close(clone);
474ecd6cf80Smarks 		dsl_dataset_close(pclone, DS_MODE_NONE, FTAG);
475ecd6cf80Smarks 		if (error == 0)
476ecd6cf80Smarks 			error = zfs_secpolicy_write_perms(parentname,
477ecd6cf80Smarks 			    ZFS_DELEG_PERM_PROMOTE, cr);
478ecd6cf80Smarks 	}
479ecd6cf80Smarks 	return (error);
480ecd6cf80Smarks }
481ecd6cf80Smarks 
482ecd6cf80Smarks static int
483ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr)
484ecd6cf80Smarks {
485ecd6cf80Smarks 	int error;
486ecd6cf80Smarks 
487ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(zc->zc_name,
488ecd6cf80Smarks 	    ZFS_DELEG_PERM_RECEIVE, cr)) != 0)
489ecd6cf80Smarks 		return (error);
490ecd6cf80Smarks 
491ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(zc->zc_name,
492ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
493ecd6cf80Smarks 		return (error);
494ecd6cf80Smarks 
495ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(zc->zc_name,
496ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr));
497ecd6cf80Smarks }
498ecd6cf80Smarks 
499ecd6cf80Smarks int
500ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
501ecd6cf80Smarks {
502ecd6cf80Smarks 	int error;
503ecd6cf80Smarks 
504ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(name,
505ecd6cf80Smarks 	    ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0)
506ecd6cf80Smarks 		return (error);
507ecd6cf80Smarks 
508ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(name,
509ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr);
510ecd6cf80Smarks 
511ecd6cf80Smarks 	return (error);
512ecd6cf80Smarks }
513ecd6cf80Smarks 
514ecd6cf80Smarks static int
515ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr)
516ecd6cf80Smarks {
517ecd6cf80Smarks 
518ecd6cf80Smarks 	return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr));
519ecd6cf80Smarks }
520ecd6cf80Smarks 
521ecd6cf80Smarks static int
522ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr)
523ecd6cf80Smarks {
524ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
525ecd6cf80Smarks 	int 	error;
526ecd6cf80Smarks 
527ecd6cf80Smarks 	if ((error = zfs_get_parent(zc->zc_name, parentname,
528ecd6cf80Smarks 	    sizeof (parentname))) != 0)
529ecd6cf80Smarks 		return (error);
530fa9e4066Sahrens 
531ecd6cf80Smarks 	if (zc->zc_value[0] != '\0') {
532ecd6cf80Smarks 		if ((error = zfs_secpolicy_write_perms(zc->zc_value,
533ecd6cf80Smarks 		    ZFS_DELEG_PERM_CLONE, cr)) != 0)
534ecd6cf80Smarks 			return (error);
535fa9e4066Sahrens 	}
536fa9e4066Sahrens 
537ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
538ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr)) != 0)
539ecd6cf80Smarks 		return (error);
540ecd6cf80Smarks 
541ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(parentname,
542ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr);
543ecd6cf80Smarks 
544ecd6cf80Smarks 	return (error);
545ecd6cf80Smarks }
546ecd6cf80Smarks 
547ecd6cf80Smarks static int
548ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr)
549ecd6cf80Smarks {
550ecd6cf80Smarks 	int error;
551ecd6cf80Smarks 
552ecd6cf80Smarks 	error = secpolicy_fs_unmount(cr, NULL);
553ecd6cf80Smarks 	if (error) {
554ecd6cf80Smarks 		error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr);
555ecd6cf80Smarks 	}
556ecd6cf80Smarks 	return (error);
557fa9e4066Sahrens }
558fa9e4066Sahrens 
559fa9e4066Sahrens /*
560fa9e4066Sahrens  * Policy for pool operations - create/destroy pools, add vdevs, etc.  Requires
561fa9e4066Sahrens  * SYS_CONFIG privilege, which is not available in a local zone.
562fa9e4066Sahrens  */
563fa9e4066Sahrens /* ARGSUSED */
564fa9e4066Sahrens static int
565ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr)
566fa9e4066Sahrens {
567fa9e4066Sahrens 	if (secpolicy_sys_config(cr, B_FALSE) != 0)
568fa9e4066Sahrens 		return (EPERM);
569fa9e4066Sahrens 
570fa9e4066Sahrens 	return (0);
571fa9e4066Sahrens }
572fa9e4066Sahrens 
573ecd6cf80Smarks /*
574ecd6cf80Smarks  * Just like zfs_secpolicy_config, except that we will check for
575ecd6cf80Smarks  * mount permission on the dataset for permission to create/remove
576ecd6cf80Smarks  * the minor nodes.
577ecd6cf80Smarks  */
578ecd6cf80Smarks static int
579ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr)
580ecd6cf80Smarks {
581ecd6cf80Smarks 	if (secpolicy_sys_config(cr, B_FALSE) != 0) {
582ecd6cf80Smarks 		return (dsl_deleg_access(zc->zc_name,
583ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr));
584ecd6cf80Smarks 	}
585ecd6cf80Smarks 
586ecd6cf80Smarks 	return (0);
587ecd6cf80Smarks }
588ecd6cf80Smarks 
589ea8dc4b6Seschrock /*
590ea8dc4b6Seschrock  * Policy for fault injection.  Requires all privileges.
591ea8dc4b6Seschrock  */
592ea8dc4b6Seschrock /* ARGSUSED */
593ea8dc4b6Seschrock static int
594ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr)
595ea8dc4b6Seschrock {
596ea8dc4b6Seschrock 	return (secpolicy_zinject(cr));
597ea8dc4b6Seschrock }
598ea8dc4b6Seschrock 
599e45ce728Sahrens static int
600e45ce728Sahrens zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr)
601e45ce728Sahrens {
602e45ce728Sahrens 	zfs_prop_t prop = zfs_name_to_prop(zc->zc_value);
603e45ce728Sahrens 
604990b4856Slling 	if (prop == ZPROP_INVAL) {
605e45ce728Sahrens 		if (!zfs_prop_user(zc->zc_value))
606e45ce728Sahrens 			return (EINVAL);
607e45ce728Sahrens 		return (zfs_secpolicy_write_perms(zc->zc_name,
608e45ce728Sahrens 		    ZFS_DELEG_PERM_USERPROP, cr));
609e45ce728Sahrens 	} else {
610e45ce728Sahrens 		if (!zfs_prop_inheritable(prop))
611e45ce728Sahrens 			return (EINVAL);
612e45ce728Sahrens 		return (zfs_secpolicy_setprop(zc->zc_name, prop, cr));
613e45ce728Sahrens 	}
614e45ce728Sahrens }
615e45ce728Sahrens 
616fa9e4066Sahrens /*
617fa9e4066Sahrens  * Returns the nvlist as specified by the user in the zfs_cmd_t.
618fa9e4066Sahrens  */
619fa9e4066Sahrens static int
620990b4856Slling get_nvlist(uint64_t nvl, uint64_t size, nvlist_t **nvp)
621fa9e4066Sahrens {
622fa9e4066Sahrens 	char *packed;
623fa9e4066Sahrens 	int error;
624990b4856Slling 	nvlist_t *list = NULL;
625fa9e4066Sahrens 
626fa9e4066Sahrens 	/*
627e9dbad6fSeschrock 	 * Read in and unpack the user-supplied nvlist.
628fa9e4066Sahrens 	 */
629990b4856Slling 	if (size == 0)
630fa9e4066Sahrens 		return (EINVAL);
631fa9e4066Sahrens 
632fa9e4066Sahrens 	packed = kmem_alloc(size, KM_SLEEP);
633fa9e4066Sahrens 
634990b4856Slling 	if ((error = xcopyin((void *)(uintptr_t)nvl, packed, size)) != 0) {
635fa9e4066Sahrens 		kmem_free(packed, size);
636fa9e4066Sahrens 		return (error);
637fa9e4066Sahrens 	}
638fa9e4066Sahrens 
639990b4856Slling 	if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) {
640fa9e4066Sahrens 		kmem_free(packed, size);
641fa9e4066Sahrens 		return (error);
642fa9e4066Sahrens 	}
643fa9e4066Sahrens 
644fa9e4066Sahrens 	kmem_free(packed, size);
645fa9e4066Sahrens 
646990b4856Slling 	*nvp = list;
647fa9e4066Sahrens 	return (0);
648fa9e4066Sahrens }
649fa9e4066Sahrens 
650e9dbad6fSeschrock static int
651e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
652e9dbad6fSeschrock {
653e9dbad6fSeschrock 	char *packed = NULL;
654e9dbad6fSeschrock 	size_t size;
655e9dbad6fSeschrock 	int error;
656e9dbad6fSeschrock 
657e9dbad6fSeschrock 	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
658e9dbad6fSeschrock 
659e9dbad6fSeschrock 	if (size > zc->zc_nvlist_dst_size) {
660e9dbad6fSeschrock 		error = ENOMEM;
661e9dbad6fSeschrock 	} else {
662da165920Smarks 		packed = kmem_alloc(size, KM_SLEEP);
663e9dbad6fSeschrock 		VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
664e9dbad6fSeschrock 		    KM_SLEEP) == 0);
665e9dbad6fSeschrock 		error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst,
666e9dbad6fSeschrock 		    size);
667e9dbad6fSeschrock 		kmem_free(packed, size);
668e9dbad6fSeschrock 	}
669e9dbad6fSeschrock 
670e9dbad6fSeschrock 	zc->zc_nvlist_dst_size = size;
671e9dbad6fSeschrock 	return (error);
672e9dbad6fSeschrock }
673e9dbad6fSeschrock 
674fa9e4066Sahrens static int
675fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc)
676fa9e4066Sahrens {
677fa9e4066Sahrens 	int error;
678990b4856Slling 	nvlist_t *config, *props = NULL;
679228975ccSek 	char *buf;
680fa9e4066Sahrens 
681990b4856Slling 	if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
682990b4856Slling 	    &config))
683fa9e4066Sahrens 		return (error);
6842a6b87f0Sek 
685990b4856Slling 	if (zc->zc_nvlist_src_size != 0 && (error =
686990b4856Slling 	    get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) {
687990b4856Slling 		nvlist_free(config);
688990b4856Slling 		return (error);
689990b4856Slling 	}
690990b4856Slling 
6912a6b87f0Sek 	buf = history_str_get(zc);
692fa9e4066Sahrens 
693990b4856Slling 	error = spa_create(zc->zc_name, config, props, buf);
694fa9e4066Sahrens 
6952a6b87f0Sek 	if (buf != NULL)
6962a6b87f0Sek 		history_str_free(buf);
697990b4856Slling 
698fa9e4066Sahrens 	nvlist_free(config);
699fa9e4066Sahrens 
700990b4856Slling 	if (props)
701990b4856Slling 		nvlist_free(props);
702990b4856Slling 
703fa9e4066Sahrens 	return (error);
704fa9e4066Sahrens }
705fa9e4066Sahrens 
706fa9e4066Sahrens static int
707fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc)
708fa9e4066Sahrens {
709ecd6cf80Smarks 	int error;
710ecd6cf80Smarks 	zfs_log_history(zc);
711ecd6cf80Smarks 	error = spa_destroy(zc->zc_name);
712ecd6cf80Smarks 	return (error);
713fa9e4066Sahrens }
714fa9e4066Sahrens 
715fa9e4066Sahrens static int
716fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc)
717fa9e4066Sahrens {
718fa9e4066Sahrens 	int error;
719990b4856Slling 	nvlist_t *config, *props = NULL;
720fa9e4066Sahrens 	uint64_t guid;
721fa9e4066Sahrens 
722990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
723990b4856Slling 	    &config)) != 0)
724990b4856Slling 		return (error);
725990b4856Slling 
726990b4856Slling 	if (zc->zc_nvlist_src_size != 0 && (error =
727990b4856Slling 	    get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) {
728990b4856Slling 		nvlist_free(config);
729fa9e4066Sahrens 		return (error);
730990b4856Slling 	}
731fa9e4066Sahrens 
732fa9e4066Sahrens 	if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
733ea8dc4b6Seschrock 	    guid != zc->zc_guid)
734fa9e4066Sahrens 		error = EINVAL;
735fa9e4066Sahrens 	else
736990b4856Slling 		error = spa_import(zc->zc_name, config, props);
737fa9e4066Sahrens 
738fa9e4066Sahrens 	nvlist_free(config);
739fa9e4066Sahrens 
740990b4856Slling 	if (props)
741990b4856Slling 		nvlist_free(props);
742990b4856Slling 
743fa9e4066Sahrens 	return (error);
744fa9e4066Sahrens }
745fa9e4066Sahrens 
746fa9e4066Sahrens static int
747fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc)
748fa9e4066Sahrens {
749ecd6cf80Smarks 	int error;
750ecd6cf80Smarks 	zfs_log_history(zc);
751ecd6cf80Smarks 	error = spa_export(zc->zc_name, NULL);
752ecd6cf80Smarks 	return (error);
753fa9e4066Sahrens }
754fa9e4066Sahrens 
755fa9e4066Sahrens static int
756fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc)
757fa9e4066Sahrens {
758fa9e4066Sahrens 	nvlist_t *configs;
759fa9e4066Sahrens 	int error;
760fa9e4066Sahrens 
761fa9e4066Sahrens 	if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
762fa9e4066Sahrens 		return (EEXIST);
763fa9e4066Sahrens 
764e9dbad6fSeschrock 	error = put_nvlist(zc, configs);
765fa9e4066Sahrens 
766fa9e4066Sahrens 	nvlist_free(configs);
767fa9e4066Sahrens 
768fa9e4066Sahrens 	return (error);
769fa9e4066Sahrens }
770fa9e4066Sahrens 
771fa9e4066Sahrens static int
772fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc)
773fa9e4066Sahrens {
774fa9e4066Sahrens 	nvlist_t *config;
775fa9e4066Sahrens 	int error;
776ea8dc4b6Seschrock 	int ret = 0;
777fa9e4066Sahrens 
778e9dbad6fSeschrock 	error = spa_get_stats(zc->zc_name, &config, zc->zc_value,
779e9dbad6fSeschrock 	    sizeof (zc->zc_value));
780fa9e4066Sahrens 
781fa9e4066Sahrens 	if (config != NULL) {
782e9dbad6fSeschrock 		ret = put_nvlist(zc, config);
783fa9e4066Sahrens 		nvlist_free(config);
784ea8dc4b6Seschrock 
785ea8dc4b6Seschrock 		/*
786ea8dc4b6Seschrock 		 * The config may be present even if 'error' is non-zero.
787ea8dc4b6Seschrock 		 * In this case we return success, and preserve the real errno
788ea8dc4b6Seschrock 		 * in 'zc_cookie'.
789ea8dc4b6Seschrock 		 */
790ea8dc4b6Seschrock 		zc->zc_cookie = error;
791fa9e4066Sahrens 	} else {
792ea8dc4b6Seschrock 		ret = error;
793fa9e4066Sahrens 	}
794fa9e4066Sahrens 
795ea8dc4b6Seschrock 	return (ret);
796fa9e4066Sahrens }
797fa9e4066Sahrens 
798fa9e4066Sahrens /*
799fa9e4066Sahrens  * Try to import the given pool, returning pool stats as appropriate so that
800fa9e4066Sahrens  * user land knows which devices are available and overall pool health.
801fa9e4066Sahrens  */
802fa9e4066Sahrens static int
803fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
804fa9e4066Sahrens {
805fa9e4066Sahrens 	nvlist_t *tryconfig, *config;
806fa9e4066Sahrens 	int error;
807fa9e4066Sahrens 
808990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
809990b4856Slling 	    &tryconfig)) != 0)
810fa9e4066Sahrens 		return (error);
811fa9e4066Sahrens 
812fa9e4066Sahrens 	config = spa_tryimport(tryconfig);
813fa9e4066Sahrens 
814fa9e4066Sahrens 	nvlist_free(tryconfig);
815fa9e4066Sahrens 
816fa9e4066Sahrens 	if (config == NULL)
817fa9e4066Sahrens 		return (EINVAL);
818fa9e4066Sahrens 
819e9dbad6fSeschrock 	error = put_nvlist(zc, config);
820fa9e4066Sahrens 	nvlist_free(config);
821fa9e4066Sahrens 
822fa9e4066Sahrens 	return (error);
823fa9e4066Sahrens }
824fa9e4066Sahrens 
825fa9e4066Sahrens static int
826fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc)
827fa9e4066Sahrens {
828fa9e4066Sahrens 	spa_t *spa;
829fa9e4066Sahrens 	int error;
830fa9e4066Sahrens 
83106eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
83206eeb2adSek 		return (error);
83306eeb2adSek 
834bb8b5132Sek 	mutex_enter(&spa_namespace_lock);
83506eeb2adSek 	error = spa_scrub(spa, zc->zc_cookie, B_FALSE);
836bb8b5132Sek 	mutex_exit(&spa_namespace_lock);
83706eeb2adSek 
83806eeb2adSek 	spa_close(spa, FTAG);
83906eeb2adSek 
840fa9e4066Sahrens 	return (error);
841fa9e4066Sahrens }
842fa9e4066Sahrens 
843fa9e4066Sahrens static int
844fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc)
845fa9e4066Sahrens {
846fa9e4066Sahrens 	spa_t *spa;
847fa9e4066Sahrens 	int error;
848fa9e4066Sahrens 
849fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
850fa9e4066Sahrens 	if (error == 0) {
851fa9e4066Sahrens 		spa_freeze(spa);
852fa9e4066Sahrens 		spa_close(spa, FTAG);
853fa9e4066Sahrens 	}
854fa9e4066Sahrens 	return (error);
855fa9e4066Sahrens }
856fa9e4066Sahrens 
857eaca9bbdSeschrock static int
858eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc)
859eaca9bbdSeschrock {
860eaca9bbdSeschrock 	spa_t *spa;
861eaca9bbdSeschrock 	int error;
862eaca9bbdSeschrock 
86306eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
86406eeb2adSek 		return (error);
86506eeb2adSek 
866558d2d50Slling 	if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) {
867558d2d50Slling 		spa_close(spa, FTAG);
868558d2d50Slling 		return (EINVAL);
869558d2d50Slling 	}
870558d2d50Slling 
871990b4856Slling 	spa_upgrade(spa, zc->zc_cookie);
87206eeb2adSek 	spa_close(spa, FTAG);
87306eeb2adSek 
87406eeb2adSek 	return (error);
87506eeb2adSek }
87606eeb2adSek 
87706eeb2adSek static int
87806eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc)
87906eeb2adSek {
88006eeb2adSek 	spa_t *spa;
88106eeb2adSek 	char *hist_buf;
88206eeb2adSek 	uint64_t size;
88306eeb2adSek 	int error;
88406eeb2adSek 
88506eeb2adSek 	if ((size = zc->zc_history_len) == 0)
88606eeb2adSek 		return (EINVAL);
88706eeb2adSek 
88806eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
88906eeb2adSek 		return (error);
89006eeb2adSek 
891e7437265Sahrens 	if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) {
892d7306b64Sek 		spa_close(spa, FTAG);
893d7306b64Sek 		return (ENOTSUP);
894d7306b64Sek 	}
895d7306b64Sek 
89606eeb2adSek 	hist_buf = kmem_alloc(size, KM_SLEEP);
89706eeb2adSek 	if ((error = spa_history_get(spa, &zc->zc_history_offset,
89806eeb2adSek 	    &zc->zc_history_len, hist_buf)) == 0) {
899ecd6cf80Smarks 		error = xcopyout(hist_buf,
900ecd6cf80Smarks 		    (char *)(uintptr_t)zc->zc_history,
90106eeb2adSek 		    zc->zc_history_len);
90206eeb2adSek 	}
90306eeb2adSek 
90406eeb2adSek 	spa_close(spa, FTAG);
90506eeb2adSek 	kmem_free(hist_buf, size);
90606eeb2adSek 	return (error);
90706eeb2adSek }
90806eeb2adSek 
90955434c77Sek static int
91055434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc)
91155434c77Sek {
91255434c77Sek 	int error;
91355434c77Sek 
914b1b8ab34Slling 	if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value))
91555434c77Sek 		return (error);
91655434c77Sek 
91755434c77Sek 	return (0);
91855434c77Sek }
91955434c77Sek 
92055434c77Sek static int
92155434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc)
92255434c77Sek {
92355434c77Sek 	objset_t *osp;
92455434c77Sek 	int error;
92555434c77Sek 
92655434c77Sek 	if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS,
92755434c77Sek 	    DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0)
92855434c77Sek 		return (error);
92955434c77Sek 
93055434c77Sek 	error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value,
93155434c77Sek 	    sizeof (zc->zc_value));
93255434c77Sek 	dmu_objset_close(osp);
93355434c77Sek 
93455434c77Sek 	return (error);
93555434c77Sek }
93655434c77Sek 
937fa9e4066Sahrens static int
938fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc)
939fa9e4066Sahrens {
940fa9e4066Sahrens 	spa_t *spa;
941fa9e4066Sahrens 	int error;
942fa9e4066Sahrens 	nvlist_t *config;
943fa9e4066Sahrens 
944fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
945fa9e4066Sahrens 	if (error != 0)
946fa9e4066Sahrens 		return (error);
947fa9e4066Sahrens 
948b1b8ab34Slling 	/*
949b1b8ab34Slling 	 * A root pool with concatenated devices is not supported.
950b1b8ab34Slling 	 * Thus, can not add a device to a root pool with one device.
951b1b8ab34Slling 	 */
952b1b8ab34Slling 	if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) {
953b1b8ab34Slling 		spa_close(spa, FTAG);
954b1b8ab34Slling 		return (EDOM);
955b1b8ab34Slling 	}
956b1b8ab34Slling 
957990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
958990b4856Slling 	    &config)) == 0) {
959fa9e4066Sahrens 		error = spa_vdev_add(spa, config);
960fa9e4066Sahrens 		nvlist_free(config);
961fa9e4066Sahrens 	}
962fa9e4066Sahrens 	spa_close(spa, FTAG);
963fa9e4066Sahrens 	return (error);
964fa9e4066Sahrens }
965fa9e4066Sahrens 
966fa9e4066Sahrens static int
967fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc)
968fa9e4066Sahrens {
96999653d4eSeschrock 	spa_t *spa;
97099653d4eSeschrock 	int error;
97199653d4eSeschrock 
97299653d4eSeschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
97399653d4eSeschrock 	if (error != 0)
97499653d4eSeschrock 		return (error);
97599653d4eSeschrock 	error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE);
97699653d4eSeschrock 	spa_close(spa, FTAG);
97799653d4eSeschrock 	return (error);
978fa9e4066Sahrens }
979fa9e4066Sahrens 
980fa9e4066Sahrens static int
9813d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc)
982fa9e4066Sahrens {
983fa9e4066Sahrens 	spa_t *spa;
984fa9e4066Sahrens 	int error;
9853d7072f8Seschrock 	vdev_state_t newstate = VDEV_STATE_UNKNOWN;
986fa9e4066Sahrens 
98706eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
988fa9e4066Sahrens 		return (error);
9893d7072f8Seschrock 	switch (zc->zc_cookie) {
9903d7072f8Seschrock 	case VDEV_STATE_ONLINE:
9913d7072f8Seschrock 		error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate);
9923d7072f8Seschrock 		break;
993fa9e4066Sahrens 
9943d7072f8Seschrock 	case VDEV_STATE_OFFLINE:
9953d7072f8Seschrock 		error = vdev_offline(spa, zc->zc_guid, zc->zc_obj);
9963d7072f8Seschrock 		break;
997fa9e4066Sahrens 
9983d7072f8Seschrock 	case VDEV_STATE_FAULTED:
9993d7072f8Seschrock 		error = vdev_fault(spa, zc->zc_guid);
10003d7072f8Seschrock 		break;
10013d7072f8Seschrock 
10023d7072f8Seschrock 	case VDEV_STATE_DEGRADED:
10033d7072f8Seschrock 		error = vdev_degrade(spa, zc->zc_guid);
10043d7072f8Seschrock 		break;
10053d7072f8Seschrock 
10063d7072f8Seschrock 	default:
10073d7072f8Seschrock 		error = EINVAL;
10083d7072f8Seschrock 	}
10093d7072f8Seschrock 	zc->zc_cookie = newstate;
1010fa9e4066Sahrens 	spa_close(spa, FTAG);
1011fa9e4066Sahrens 	return (error);
1012fa9e4066Sahrens }
1013fa9e4066Sahrens 
1014fa9e4066Sahrens static int
1015fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc)
1016fa9e4066Sahrens {
1017fa9e4066Sahrens 	spa_t *spa;
1018fa9e4066Sahrens 	int replacing = zc->zc_cookie;
1019fa9e4066Sahrens 	nvlist_t *config;
1020fa9e4066Sahrens 	int error;
1021fa9e4066Sahrens 
102206eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1023fa9e4066Sahrens 		return (error);
1024fa9e4066Sahrens 
1025990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
1026990b4856Slling 	    &config)) == 0) {
1027ea8dc4b6Seschrock 		error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
1028fa9e4066Sahrens 		nvlist_free(config);
1029fa9e4066Sahrens 	}
1030fa9e4066Sahrens 
1031fa9e4066Sahrens 	spa_close(spa, FTAG);
1032fa9e4066Sahrens 	return (error);
1033fa9e4066Sahrens }
1034fa9e4066Sahrens 
1035fa9e4066Sahrens static int
1036fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc)
1037fa9e4066Sahrens {
1038fa9e4066Sahrens 	spa_t *spa;
1039fa9e4066Sahrens 	int error;
1040fa9e4066Sahrens 
104106eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1042fa9e4066Sahrens 		return (error);
1043fa9e4066Sahrens 
1044ea8dc4b6Seschrock 	error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE);
1045fa9e4066Sahrens 
1046fa9e4066Sahrens 	spa_close(spa, FTAG);
1047fa9e4066Sahrens 	return (error);
1048fa9e4066Sahrens }
1049fa9e4066Sahrens 
1050c67d9675Seschrock static int
1051c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
1052c67d9675Seschrock {
1053c67d9675Seschrock 	spa_t *spa;
1054e9dbad6fSeschrock 	char *path = zc->zc_value;
1055ea8dc4b6Seschrock 	uint64_t guid = zc->zc_guid;
1056c67d9675Seschrock 	int error;
1057c67d9675Seschrock 
1058c67d9675Seschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
1059c67d9675Seschrock 	if (error != 0)
1060c67d9675Seschrock 		return (error);
1061c67d9675Seschrock 
1062c67d9675Seschrock 	error = spa_vdev_setpath(spa, guid, path);
1063c67d9675Seschrock 	spa_close(spa, FTAG);
1064c67d9675Seschrock 	return (error);
1065c67d9675Seschrock }
1066c67d9675Seschrock 
1067fa9e4066Sahrens static int
1068fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc)
1069fa9e4066Sahrens {
1070fa9e4066Sahrens 	objset_t *os = NULL;
1071fa9e4066Sahrens 	int error;
10727f7322feSeschrock 	nvlist_t *nv;
1073fa9e4066Sahrens 
1074fa9e4066Sahrens retry:
1075fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1076fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
1077fa9e4066Sahrens 	if (error != 0) {
1078fa9e4066Sahrens 		/*
1079fa9e4066Sahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
1080fa9e4066Sahrens 		 * the objset is held exclusively. Fortunately this hold is
1081fa9e4066Sahrens 		 * only for a short while, so we retry here.
1082fa9e4066Sahrens 		 * This avoids user code having to handle EBUSY,
1083fa9e4066Sahrens 		 * for example for a "zfs list".
1084fa9e4066Sahrens 		 */
1085fa9e4066Sahrens 		if (error == EBUSY) {
1086fa9e4066Sahrens 			delay(1);
1087fa9e4066Sahrens 			goto retry;
1088fa9e4066Sahrens 		}
1089fa9e4066Sahrens 		return (error);
1090fa9e4066Sahrens 	}
1091fa9e4066Sahrens 
1092a2eea2e1Sahrens 	dmu_objset_fast_stat(os, &zc->zc_objset_stats);
1093fa9e4066Sahrens 
10945ad82045Snd 	if (zc->zc_nvlist_dst != 0 &&
10957f7322feSeschrock 	    (error = dsl_prop_get_all(os, &nv)) == 0) {
1096a2eea2e1Sahrens 		dmu_objset_stats(os, nv);
1097432f72fdSahrens 		/*
1098bd00f61bSrm 		 * NB: zvol_get_stats() will read the objset contents,
1099432f72fdSahrens 		 * which we aren't supposed to do with a
1100432f72fdSahrens 		 * DS_MODE_STANDARD open, because it could be
1101432f72fdSahrens 		 * inconsistent.  So this is a bit of a workaround...
1102432f72fdSahrens 		 */
1103e7437265Sahrens 		if (!zc->zc_objset_stats.dds_inconsistent) {
1104e7437265Sahrens 			if (dmu_objset_type(os) == DMU_OST_ZVOL)
1105e7437265Sahrens 				VERIFY(zvol_get_stats(os, nv) == 0);
1106e7437265Sahrens 		}
1107e9dbad6fSeschrock 		error = put_nvlist(zc, nv);
11087f7322feSeschrock 		nvlist_free(nv);
11097f7322feSeschrock 	}
1110fa9e4066Sahrens 
1111e9dbad6fSeschrock 	spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value));
1112ea8dc4b6Seschrock 
1113fa9e4066Sahrens 	dmu_objset_close(os);
1114fa9e4066Sahrens 	return (error);
1115fa9e4066Sahrens }
1116fa9e4066Sahrens 
1117bd00f61bSrm static int
1118bd00f61bSrm zfs_ioc_objset_version(zfs_cmd_t *zc)
1119bd00f61bSrm {
1120bd00f61bSrm 	objset_t *os = NULL;
1121bd00f61bSrm 	int error;
1122bd00f61bSrm 
1123bd00f61bSrm retry:
1124bd00f61bSrm 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1125bd00f61bSrm 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
1126bd00f61bSrm 	if (error != 0) {
1127bd00f61bSrm 		/*
1128bd00f61bSrm 		 * This is ugly: dmu_objset_open() can return EBUSY if
1129bd00f61bSrm 		 * the objset is held exclusively. Fortunately this hold is
1130bd00f61bSrm 		 * only for a short while, so we retry here.
1131bd00f61bSrm 		 * This avoids user code having to handle EBUSY,
1132bd00f61bSrm 		 * for example for a "zfs list".
1133bd00f61bSrm 		 */
1134bd00f61bSrm 		if (error == EBUSY) {
1135bd00f61bSrm 			delay(1);
1136bd00f61bSrm 			goto retry;
1137bd00f61bSrm 		}
1138bd00f61bSrm 		return (error);
1139bd00f61bSrm 	}
1140bd00f61bSrm 
1141bd00f61bSrm 	dmu_objset_fast_stat(os, &zc->zc_objset_stats);
1142bd00f61bSrm 
1143bd00f61bSrm 	/*
1144bd00f61bSrm 	 * NB: zfs_get_version() will read the objset contents,
1145bd00f61bSrm 	 * which we aren't supposed to do with a
1146bd00f61bSrm 	 * DS_MODE_STANDARD open, because it could be
1147bd00f61bSrm 	 * inconsistent.  So this is a bit of a workaround...
1148bd00f61bSrm 	 */
1149bd00f61bSrm 	zc->zc_cookie = 0;
1150bd00f61bSrm 	if (!zc->zc_objset_stats.dds_inconsistent)
1151bd00f61bSrm 		if (dmu_objset_type(os) == DMU_OST_ZFS)
1152bd00f61bSrm 			(void) zfs_get_version(os, &zc->zc_cookie);
1153bd00f61bSrm 
1154bd00f61bSrm 	dmu_objset_close(os);
1155bd00f61bSrm 	return (0);
1156bd00f61bSrm }
1157bd00f61bSrm 
1158fa9e4066Sahrens static int
1159fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc)
1160fa9e4066Sahrens {
116187e5029aSahrens 	objset_t *os;
1162fa9e4066Sahrens 	int error;
1163fa9e4066Sahrens 	char *p;
1164fa9e4066Sahrens 
116587e5029aSahrens retry:
116687e5029aSahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
116787e5029aSahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
116887e5029aSahrens 	if (error != 0) {
116987e5029aSahrens 		/*
117087e5029aSahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
117187e5029aSahrens 		 * the objset is held exclusively. Fortunately this hold is
117287e5029aSahrens 		 * only for a short while, so we retry here.
117387e5029aSahrens 		 * This avoids user code having to handle EBUSY,
117487e5029aSahrens 		 * for example for a "zfs list".
117587e5029aSahrens 		 */
117687e5029aSahrens 		if (error == EBUSY) {
117787e5029aSahrens 			delay(1);
117887e5029aSahrens 			goto retry;
117987e5029aSahrens 		}
118087e5029aSahrens 		if (error == ENOENT)
118187e5029aSahrens 			error = ESRCH;
118287e5029aSahrens 		return (error);
1183fa9e4066Sahrens 	}
1184fa9e4066Sahrens 
1185fa9e4066Sahrens 	p = strrchr(zc->zc_name, '/');
1186fa9e4066Sahrens 	if (p == NULL || p[1] != '\0')
1187fa9e4066Sahrens 		(void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name));
1188fa9e4066Sahrens 	p = zc->zc_name + strlen(zc->zc_name);
1189fa9e4066Sahrens 
1190fa9e4066Sahrens 	do {
119187e5029aSahrens 		error = dmu_dir_list_next(os,
119287e5029aSahrens 		    sizeof (zc->zc_name) - (p - zc->zc_name), p,
119387e5029aSahrens 		    NULL, &zc->zc_cookie);
1194fa9e4066Sahrens 		if (error == ENOENT)
1195fa9e4066Sahrens 			error = ESRCH;
119687e5029aSahrens 	} while (error == 0 && !INGLOBALZONE(curproc) &&
1197fa9e4066Sahrens 	    !zone_dataset_visible(zc->zc_name, NULL));
1198fa9e4066Sahrens 
1199fa9e4066Sahrens 	/*
120087e5029aSahrens 	 * If it's a hidden dataset (ie. with a '$' in its name), don't
120187e5029aSahrens 	 * try to get stats for it.  Userland will skip over it.
1202fa9e4066Sahrens 	 */
120387e5029aSahrens 	if (error == 0 && strchr(zc->zc_name, '$') == NULL)
120487e5029aSahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
1205fa9e4066Sahrens 
120687e5029aSahrens 	dmu_objset_close(os);
1207fa9e4066Sahrens 	return (error);
1208fa9e4066Sahrens }
1209fa9e4066Sahrens 
1210fa9e4066Sahrens static int
1211fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
1212fa9e4066Sahrens {
121387e5029aSahrens 	objset_t *os;
1214fa9e4066Sahrens 	int error;
1215fa9e4066Sahrens 
1216fa9e4066Sahrens retry:
121787e5029aSahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
121887e5029aSahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
121987e5029aSahrens 	if (error != 0) {
1220fa9e4066Sahrens 		/*
122187e5029aSahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
1222fa9e4066Sahrens 		 * the objset is held exclusively. Fortunately this hold is
1223fa9e4066Sahrens 		 * only for a short while, so we retry here.
1224fa9e4066Sahrens 		 * This avoids user code having to handle EBUSY,
122587e5029aSahrens 		 * for example for a "zfs list".
1226fa9e4066Sahrens 		 */
1227fa9e4066Sahrens 		if (error == EBUSY) {
1228fa9e4066Sahrens 			delay(1);
1229fa9e4066Sahrens 			goto retry;
1230fa9e4066Sahrens 		}
1231fa9e4066Sahrens 		if (error == ENOENT)
123287e5029aSahrens 			error = ESRCH;
1233fa9e4066Sahrens 		return (error);
1234fa9e4066Sahrens 	}
1235fa9e4066Sahrens 
1236b81d61a6Slling 	/*
1237b81d61a6Slling 	 * A dataset name of maximum length cannot have any snapshots,
1238b81d61a6Slling 	 * so exit immediately.
1239b81d61a6Slling 	 */
1240b81d61a6Slling 	if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) {
124187e5029aSahrens 		dmu_objset_close(os);
1242b81d61a6Slling 		return (ESRCH);
1243fa9e4066Sahrens 	}
1244fa9e4066Sahrens 
124587e5029aSahrens 	error = dmu_snapshot_list_next(os,
124687e5029aSahrens 	    sizeof (zc->zc_name) - strlen(zc->zc_name),
124787e5029aSahrens 	    zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie);
124887e5029aSahrens 	if (error == ENOENT)
124987e5029aSahrens 		error = ESRCH;
1250fa9e4066Sahrens 
125187e5029aSahrens 	if (error == 0)
125287e5029aSahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
1253fa9e4066Sahrens 
125487e5029aSahrens 	dmu_objset_close(os);
1255fa9e4066Sahrens 	return (error);
1256fa9e4066Sahrens }
1257fa9e4066Sahrens 
1258fa9e4066Sahrens static int
125991ebeef5Sahrens zfs_set_prop_nvlist(const char *name, nvlist_t *nvl)
1260fa9e4066Sahrens {
1261e9dbad6fSeschrock 	nvpair_t *elem;
1262e9dbad6fSeschrock 	int error;
1263e9dbad6fSeschrock 	uint64_t intval;
1264e9dbad6fSeschrock 	char *strval;
1265e9dbad6fSeschrock 
1266ecd6cf80Smarks 	/*
1267ecd6cf80Smarks 	 * First validate permission to set all of the properties
1268ecd6cf80Smarks 	 */
1269e9dbad6fSeschrock 	elem = NULL;
1270e9dbad6fSeschrock 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1271db870a07Sahrens 		const char *propname = nvpair_name(elem);
1272db870a07Sahrens 		zfs_prop_t prop = zfs_name_to_prop(propname);
1273e9dbad6fSeschrock 
1274990b4856Slling 		if (prop == ZPROP_INVAL) {
1275e9dbad6fSeschrock 			/*
1276e9dbad6fSeschrock 			 * If this is a user-defined property, it must be a
1277e9dbad6fSeschrock 			 * string, and there is no further validation to do.
1278e9dbad6fSeschrock 			 */
1279e9dbad6fSeschrock 			if (!zfs_prop_user(propname) ||
1280e9dbad6fSeschrock 			    nvpair_type(elem) != DATA_TYPE_STRING)
1281e9dbad6fSeschrock 				return (EINVAL);
1282e9dbad6fSeschrock 
1283ecd6cf80Smarks 			error = zfs_secpolicy_write_perms(name,
128491ebeef5Sahrens 			    ZFS_DELEG_PERM_USERPROP, CRED());
1285db870a07Sahrens 			if (error)
1286db870a07Sahrens 				return (error);
1287ecd6cf80Smarks 			continue;
1288e9dbad6fSeschrock 		}
1289fa9e4066Sahrens 
129091ebeef5Sahrens 		if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0)
1291db870a07Sahrens 			return (error);
1292db870a07Sahrens 
1293e9dbad6fSeschrock 		/*
1294db870a07Sahrens 		 * Check that this value is valid for this pool version
1295e9dbad6fSeschrock 		 */
1296e9dbad6fSeschrock 		switch (prop) {
1297c9431fa1Sahl 		case ZFS_PROP_COMPRESSION:
1298c9431fa1Sahl 			/*
1299c9431fa1Sahl 			 * If the user specified gzip compression, make sure
1300c9431fa1Sahl 			 * the SPA supports it. We ignore any errors here since
1301c9431fa1Sahl 			 * we'll catch them later.
1302c9431fa1Sahl 			 */
1303c9431fa1Sahl 			if (nvpair_type(elem) == DATA_TYPE_UINT64 &&
1304c9431fa1Sahl 			    nvpair_value_uint64(elem, &intval) == 0 &&
1305c9431fa1Sahl 			    intval >= ZIO_COMPRESS_GZIP_1 &&
1306c9431fa1Sahl 			    intval <= ZIO_COMPRESS_GZIP_9) {
1307ecd6cf80Smarks 				spa_t *spa;
1308c9431fa1Sahl 
130940feaa91Sahrens 				if (spa_open(name, &spa, FTAG) == 0) {
1310c9431fa1Sahl 					if (spa_version(spa) <
1311e7437265Sahrens 					    SPA_VERSION_GZIP_COMPRESSION) {
1312c9431fa1Sahl 						spa_close(spa, FTAG);
1313c9431fa1Sahl 						return (ENOTSUP);
1314c9431fa1Sahl 					}
1315c9431fa1Sahl 
1316c9431fa1Sahl 					spa_close(spa, FTAG);
1317c9431fa1Sahl 				}
1318c9431fa1Sahl 			}
1319c9431fa1Sahl 			break;
132040feaa91Sahrens 
132140feaa91Sahrens 		case ZFS_PROP_COPIES:
132240feaa91Sahrens 		{
132340feaa91Sahrens 			spa_t *spa;
132440feaa91Sahrens 
132540feaa91Sahrens 			if (spa_open(name, &spa, FTAG) == 0) {
132640feaa91Sahrens 				if (spa_version(spa) <
132740feaa91Sahrens 				    SPA_VERSION_DITTO_BLOCKS) {
132840feaa91Sahrens 					spa_close(spa, FTAG);
132940feaa91Sahrens 					return (ENOTSUP);
133040feaa91Sahrens 				}
133140feaa91Sahrens 				spa_close(spa, FTAG);
133240feaa91Sahrens 			}
133340feaa91Sahrens 			break;
133440feaa91Sahrens 		}
1335e9dbad6fSeschrock 		}
1336ecd6cf80Smarks 	}
1337ecd6cf80Smarks 
1338ecd6cf80Smarks 	elem = NULL;
1339ecd6cf80Smarks 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1340db870a07Sahrens 		const char *propname = nvpair_name(elem);
1341db870a07Sahrens 		zfs_prop_t prop = zfs_name_to_prop(propname);
1342ecd6cf80Smarks 
1343990b4856Slling 		if (prop == ZPROP_INVAL) {
1344ecd6cf80Smarks 			VERIFY(nvpair_value_string(elem, &strval) == 0);
1345ecd6cf80Smarks 			error = dsl_prop_set(name, propname, 1,
1346ecd6cf80Smarks 			    strlen(strval) + 1, strval);
1347ecd6cf80Smarks 			if (error == 0)
1348ecd6cf80Smarks 				continue;
1349ecd6cf80Smarks 			else
1350ecd6cf80Smarks 				return (error);
1351ecd6cf80Smarks 		}
1352e9dbad6fSeschrock 
1353e9dbad6fSeschrock 		switch (prop) {
1354e9dbad6fSeschrock 		case ZFS_PROP_QUOTA:
1355e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1356e7437265Sahrens 			    (error = dsl_dir_set_quota(name, intval)) != 0)
1357e9dbad6fSeschrock 				return (error);
1358e9dbad6fSeschrock 			break;
1359e9dbad6fSeschrock 
1360e9dbad6fSeschrock 		case ZFS_PROP_RESERVATION:
1361e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1362e9dbad6fSeschrock 			    (error = dsl_dir_set_reservation(name,
1363e9dbad6fSeschrock 			    intval)) != 0)
1364e9dbad6fSeschrock 				return (error);
1365e9dbad6fSeschrock 			break;
1366e9dbad6fSeschrock 
1367e9dbad6fSeschrock 		case ZFS_PROP_VOLSIZE:
1368e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
136991ebeef5Sahrens 			    (error = zvol_set_volsize(name,
137091ebeef5Sahrens 			    ddi_driver_major(zfs_dip), intval)) != 0)
1371e9dbad6fSeschrock 				return (error);
1372e9dbad6fSeschrock 			break;
1373e9dbad6fSeschrock 
1374e9dbad6fSeschrock 		case ZFS_PROP_VOLBLOCKSIZE:
1375e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1376e7437265Sahrens 			    (error = zvol_set_volblocksize(name, intval)) != 0)
1377e7437265Sahrens 				return (error);
1378e7437265Sahrens 			break;
1379e7437265Sahrens 
1380e7437265Sahrens 		case ZFS_PROP_VERSION:
1381e7437265Sahrens 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1382e7437265Sahrens 			    (error = zfs_set_version(name, intval)) != 0)
1383e9dbad6fSeschrock 				return (error);
1384e9dbad6fSeschrock 			break;
1385e9dbad6fSeschrock 
1386e9dbad6fSeschrock 		default:
1387e9dbad6fSeschrock 			if (nvpair_type(elem) == DATA_TYPE_STRING) {
1388e9dbad6fSeschrock 				if (zfs_prop_get_type(prop) !=
138991ebeef5Sahrens 				    PROP_TYPE_STRING)
1390e9dbad6fSeschrock 					return (EINVAL);
1391acd76fe5Seschrock 				VERIFY(nvpair_value_string(elem, &strval) == 0);
1392acd76fe5Seschrock 				if ((error = dsl_prop_set(name,
1393e9dbad6fSeschrock 				    nvpair_name(elem), 1, strlen(strval) + 1,
1394acd76fe5Seschrock 				    strval)) != 0)
1395acd76fe5Seschrock 					return (error);
1396e9dbad6fSeschrock 			} else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
1397a2eea2e1Sahrens 				const char *unused;
1398a2eea2e1Sahrens 
1399acd76fe5Seschrock 				VERIFY(nvpair_value_uint64(elem, &intval) == 0);
1400e9dbad6fSeschrock 
1401e9dbad6fSeschrock 				switch (zfs_prop_get_type(prop)) {
140291ebeef5Sahrens 				case PROP_TYPE_NUMBER:
1403e9dbad6fSeschrock 					break;
140491ebeef5Sahrens 				case PROP_TYPE_STRING:
1405acd76fe5Seschrock 					return (EINVAL);
140691ebeef5Sahrens 				case PROP_TYPE_INDEX:
1407acd76fe5Seschrock 					if (zfs_prop_index_to_string(prop,
1408acd76fe5Seschrock 					    intval, &unused) != 0)
1409acd76fe5Seschrock 						return (EINVAL);
1410e9dbad6fSeschrock 					break;
1411e9dbad6fSeschrock 				default:
1412e7437265Sahrens 					cmn_err(CE_PANIC,
1413e7437265Sahrens 					    "unknown property type");
1414e9dbad6fSeschrock 					break;
1415e9dbad6fSeschrock 				}
1416e9dbad6fSeschrock 
1417acd76fe5Seschrock 				if ((error = dsl_prop_set(name, propname,
1418acd76fe5Seschrock 				    8, 1, &intval)) != 0)
1419acd76fe5Seschrock 					return (error);
1420e9dbad6fSeschrock 			} else {
1421e9dbad6fSeschrock 				return (EINVAL);
1422e9dbad6fSeschrock 			}
1423e9dbad6fSeschrock 			break;
1424e9dbad6fSeschrock 		}
1425e9dbad6fSeschrock 	}
1426e9dbad6fSeschrock 
1427e9dbad6fSeschrock 	return (0);
1428fa9e4066Sahrens }
1429fa9e4066Sahrens 
1430fa9e4066Sahrens static int
1431e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc)
1432fa9e4066Sahrens {
1433e9dbad6fSeschrock 	nvlist_t *nvl;
1434e9dbad6fSeschrock 	int error;
1435e9dbad6fSeschrock 
1436990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1437990b4856Slling 	    &nvl)) != 0)
1438e9dbad6fSeschrock 		return (error);
1439e9dbad6fSeschrock 
144091ebeef5Sahrens 	error = zfs_set_prop_nvlist(zc->zc_name, nvl);
1441ecd6cf80Smarks 
1442e9dbad6fSeschrock 	nvlist_free(nvl);
1443e9dbad6fSeschrock 	return (error);
1444fa9e4066Sahrens }
1445fa9e4066Sahrens 
1446e45ce728Sahrens static int
1447e45ce728Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc)
1448e45ce728Sahrens {
1449e45ce728Sahrens 	/* the property name has been validated by zfs_secpolicy_inherit() */
1450e45ce728Sahrens 	return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL));
1451e45ce728Sahrens }
1452e45ce728Sahrens 
1453b1b8ab34Slling static int
145411a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc)
1455b1b8ab34Slling {
1456990b4856Slling 	nvlist_t *props;
1457b1b8ab34Slling 	spa_t *spa;
1458990b4856Slling 	int error;
1459b1b8ab34Slling 
1460990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1461990b4856Slling 	    &props)))
1462b1b8ab34Slling 		return (error);
1463b1b8ab34Slling 
1464b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) {
1465990b4856Slling 		nvlist_free(props);
1466b1b8ab34Slling 		return (error);
1467b1b8ab34Slling 	}
1468b1b8ab34Slling 
1469990b4856Slling 	error = spa_prop_set(spa, props);
1470b1b8ab34Slling 
1471990b4856Slling 	nvlist_free(props);
1472b1b8ab34Slling 	spa_close(spa, FTAG);
1473b1b8ab34Slling 
1474b1b8ab34Slling 	return (error);
1475b1b8ab34Slling }
1476b1b8ab34Slling 
1477b1b8ab34Slling static int
147811a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc)
1479b1b8ab34Slling {
1480b1b8ab34Slling 	spa_t *spa;
1481b1b8ab34Slling 	int error;
1482b1b8ab34Slling 	nvlist_t *nvp = NULL;
1483b1b8ab34Slling 
1484b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1485b1b8ab34Slling 		return (error);
1486b1b8ab34Slling 
1487990b4856Slling 	error = spa_prop_get(spa, &nvp);
1488b1b8ab34Slling 
1489b1b8ab34Slling 	if (error == 0 && zc->zc_nvlist_dst != NULL)
1490b1b8ab34Slling 		error = put_nvlist(zc, nvp);
1491b1b8ab34Slling 	else
1492b1b8ab34Slling 		error = EFAULT;
1493b1b8ab34Slling 
1494b1b8ab34Slling 	spa_close(spa, FTAG);
1495b1b8ab34Slling 
1496b1b8ab34Slling 	if (nvp)
1497b1b8ab34Slling 		nvlist_free(nvp);
1498b1b8ab34Slling 	return (error);
1499b1b8ab34Slling }
1500b1b8ab34Slling 
1501ecd6cf80Smarks static int
1502ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc)
1503ecd6cf80Smarks {
1504ecd6cf80Smarks 	nvlist_t *nvp;
1505ecd6cf80Smarks 	int error;
1506ecd6cf80Smarks 	uint32_t uid;
1507ecd6cf80Smarks 	uint32_t gid;
1508ecd6cf80Smarks 	uint32_t *groups;
1509ecd6cf80Smarks 	uint_t group_cnt;
1510ecd6cf80Smarks 	cred_t	*usercred;
1511ecd6cf80Smarks 
1512990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1513990b4856Slling 	    &nvp)) != 0) {
1514ecd6cf80Smarks 		return (error);
1515ecd6cf80Smarks 	}
1516ecd6cf80Smarks 
1517ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32(nvp,
1518ecd6cf80Smarks 	    ZFS_DELEG_PERM_UID, &uid)) != 0) {
1519ecd6cf80Smarks 		nvlist_free(nvp);
1520ecd6cf80Smarks 		return (EPERM);
1521ecd6cf80Smarks 	}
1522ecd6cf80Smarks 
1523ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32(nvp,
1524ecd6cf80Smarks 	    ZFS_DELEG_PERM_GID, &gid)) != 0) {
1525ecd6cf80Smarks 		nvlist_free(nvp);
1526ecd6cf80Smarks 		return (EPERM);
1527ecd6cf80Smarks 	}
1528ecd6cf80Smarks 
1529ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS,
1530ecd6cf80Smarks 	    &groups, &group_cnt)) != 0) {
1531ecd6cf80Smarks 		nvlist_free(nvp);
1532ecd6cf80Smarks 		return (EPERM);
1533ecd6cf80Smarks 	}
1534ecd6cf80Smarks 	usercred = cralloc();
1535ecd6cf80Smarks 	if ((crsetugid(usercred, uid, gid) != 0) ||
1536ecd6cf80Smarks 	    (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) {
1537ecd6cf80Smarks 		nvlist_free(nvp);
1538ecd6cf80Smarks 		crfree(usercred);
1539ecd6cf80Smarks 		return (EPERM);
1540ecd6cf80Smarks 	}
1541ecd6cf80Smarks 	nvlist_free(nvp);
1542ecd6cf80Smarks 	error = dsl_deleg_access(zc->zc_name,
154391ebeef5Sahrens 	    zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred);
1544ecd6cf80Smarks 	crfree(usercred);
1545ecd6cf80Smarks 	return (error);
1546ecd6cf80Smarks }
1547ecd6cf80Smarks 
1548ecd6cf80Smarks static int
1549ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc)
1550ecd6cf80Smarks {
1551ecd6cf80Smarks 	int error;
1552ecd6cf80Smarks 	nvlist_t *fsaclnv = NULL;
1553ecd6cf80Smarks 
1554990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1555990b4856Slling 	    &fsaclnv)) != 0)
1556ecd6cf80Smarks 		return (error);
1557ecd6cf80Smarks 
1558ecd6cf80Smarks 	/*
1559ecd6cf80Smarks 	 * Verify nvlist is constructed correctly
1560ecd6cf80Smarks 	 */
1561ecd6cf80Smarks 	if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) {
1562ecd6cf80Smarks 		nvlist_free(fsaclnv);
1563ecd6cf80Smarks 		return (EINVAL);
1564ecd6cf80Smarks 	}
1565ecd6cf80Smarks 
1566ecd6cf80Smarks 	/*
1567ecd6cf80Smarks 	 * If we don't have PRIV_SYS_MOUNT, then validate
1568ecd6cf80Smarks 	 * that user is allowed to hand out each permission in
1569ecd6cf80Smarks 	 * the nvlist(s)
1570ecd6cf80Smarks 	 */
1571ecd6cf80Smarks 
157291ebeef5Sahrens 	error = secpolicy_zfs(CRED());
1573ecd6cf80Smarks 	if (error) {
157491ebeef5Sahrens 		if (zc->zc_perm_action == B_FALSE) {
157591ebeef5Sahrens 			error = dsl_deleg_can_allow(zc->zc_name,
157691ebeef5Sahrens 			    fsaclnv, CRED());
157791ebeef5Sahrens 		} else {
157891ebeef5Sahrens 			error = dsl_deleg_can_unallow(zc->zc_name,
157991ebeef5Sahrens 			    fsaclnv, CRED());
158091ebeef5Sahrens 		}
1581ecd6cf80Smarks 	}
1582ecd6cf80Smarks 
1583ecd6cf80Smarks 	if (error == 0)
1584ecd6cf80Smarks 		error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action);
1585ecd6cf80Smarks 
1586ecd6cf80Smarks 	nvlist_free(fsaclnv);
1587ecd6cf80Smarks 	return (error);
1588ecd6cf80Smarks }
1589ecd6cf80Smarks 
1590ecd6cf80Smarks static int
1591ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc)
1592ecd6cf80Smarks {
1593ecd6cf80Smarks 	nvlist_t *nvp;
1594ecd6cf80Smarks 	int error;
1595ecd6cf80Smarks 
1596ecd6cf80Smarks 	if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) {
1597ecd6cf80Smarks 		error = put_nvlist(zc, nvp);
1598ecd6cf80Smarks 		nvlist_free(nvp);
1599ecd6cf80Smarks 	}
1600ecd6cf80Smarks 
1601ecd6cf80Smarks 	return (error);
1602ecd6cf80Smarks }
1603ecd6cf80Smarks 
1604fa9e4066Sahrens static int
1605fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc)
1606fa9e4066Sahrens {
160791ebeef5Sahrens 	return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip)));
1608fa9e4066Sahrens }
1609fa9e4066Sahrens 
1610fa9e4066Sahrens static int
1611fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc)
1612fa9e4066Sahrens {
1613e9dbad6fSeschrock 	return (zvol_remove_minor(zc->zc_name));
1614fa9e4066Sahrens }
1615fa9e4066Sahrens 
1616fa9e4066Sahrens /*
1617fa9e4066Sahrens  * Search the vfs list for a specified resource.  Returns a pointer to it
1618fa9e4066Sahrens  * or NULL if no suitable entry is found. The caller of this routine
1619fa9e4066Sahrens  * is responsible for releasing the returned vfs pointer.
1620fa9e4066Sahrens  */
1621fa9e4066Sahrens static vfs_t *
1622fa9e4066Sahrens zfs_get_vfs(const char *resource)
1623fa9e4066Sahrens {
1624fa9e4066Sahrens 	struct vfs *vfsp;
1625fa9e4066Sahrens 	struct vfs *vfs_found = NULL;
1626fa9e4066Sahrens 
1627fa9e4066Sahrens 	vfs_list_read_lock();
1628fa9e4066Sahrens 	vfsp = rootvfs;
1629fa9e4066Sahrens 	do {
1630fa9e4066Sahrens 		if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) {
1631fa9e4066Sahrens 			VFS_HOLD(vfsp);
1632fa9e4066Sahrens 			vfs_found = vfsp;
1633fa9e4066Sahrens 			break;
1634fa9e4066Sahrens 		}
1635fa9e4066Sahrens 		vfsp = vfsp->vfs_next;
1636fa9e4066Sahrens 	} while (vfsp != rootvfs);
1637fa9e4066Sahrens 	vfs_list_unlock();
1638fa9e4066Sahrens 	return (vfs_found);
1639fa9e4066Sahrens }
1640fa9e4066Sahrens 
1641ecd6cf80Smarks /* ARGSUSED */
1642fa9e4066Sahrens static void
1643ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
1644fa9e4066Sahrens {
1645e7437265Sahrens 	nvlist_t *nvprops = arg;
1646e7437265Sahrens 	uint64_t version = ZPL_VERSION;
1647e7437265Sahrens 
1648e7437265Sahrens 	(void) nvlist_lookup_uint64(nvprops,
1649e7437265Sahrens 	    zfs_prop_to_name(ZFS_PROP_VERSION), &version);
1650e7437265Sahrens 
1651e7437265Sahrens 	zfs_create_fs(os, cr, version, tx);
1652fa9e4066Sahrens }
1653fa9e4066Sahrens 
1654fa9e4066Sahrens static int
1655fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc)
1656fa9e4066Sahrens {
1657fa9e4066Sahrens 	objset_t *clone;
1658fa9e4066Sahrens 	int error = 0;
1659ecd6cf80Smarks 	nvlist_t *nvprops = NULL;
1660ecd6cf80Smarks 	void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
1661fa9e4066Sahrens 	dmu_objset_type_t type = zc->zc_objset_type;
1662fa9e4066Sahrens 
1663fa9e4066Sahrens 	switch (type) {
1664fa9e4066Sahrens 
1665fa9e4066Sahrens 	case DMU_OST_ZFS:
1666fa9e4066Sahrens 		cbfunc = zfs_create_cb;
1667fa9e4066Sahrens 		break;
1668fa9e4066Sahrens 
1669fa9e4066Sahrens 	case DMU_OST_ZVOL:
1670fa9e4066Sahrens 		cbfunc = zvol_create_cb;
1671fa9e4066Sahrens 		break;
1672fa9e4066Sahrens 
1673fa9e4066Sahrens 	default:
16741d452cf5Sahrens 		cbfunc = NULL;
1675fa9e4066Sahrens 	}
1676*f18faf3fSek 	if (strchr(zc->zc_name, '@') ||
1677*f18faf3fSek 	    strchr(zc->zc_name, '%'))
16781d452cf5Sahrens 		return (EINVAL);
1679fa9e4066Sahrens 
1680e9dbad6fSeschrock 	if (zc->zc_nvlist_src != NULL &&
1681990b4856Slling 	    (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1682990b4856Slling 	    &nvprops)) != 0)
1683e9dbad6fSeschrock 		return (error);
1684e9dbad6fSeschrock 
1685e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1686fa9e4066Sahrens 		/*
1687fa9e4066Sahrens 		 * We're creating a clone of an existing snapshot.
1688fa9e4066Sahrens 		 */
1689e9dbad6fSeschrock 		zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
1690e9dbad6fSeschrock 		if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) {
1691ecd6cf80Smarks 			nvlist_free(nvprops);
1692fa9e4066Sahrens 			return (EINVAL);
1693e9dbad6fSeschrock 		}
1694fa9e4066Sahrens 
1695e9dbad6fSeschrock 		error = dmu_objset_open(zc->zc_value, type,
1696fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
1697e9dbad6fSeschrock 		if (error) {
1698ecd6cf80Smarks 			nvlist_free(nvprops);
1699fa9e4066Sahrens 			return (error);
1700e9dbad6fSeschrock 		}
1701fa9e4066Sahrens 		error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL);
1702fa9e4066Sahrens 		dmu_objset_close(clone);
1703fa9e4066Sahrens 	} else {
1704e9dbad6fSeschrock 		if (cbfunc == NULL) {
1705ecd6cf80Smarks 			nvlist_free(nvprops);
17061d452cf5Sahrens 			return (EINVAL);
1707e9dbad6fSeschrock 		}
17085c5460e9Seschrock 
1709e9dbad6fSeschrock 		if (type == DMU_OST_ZVOL) {
1710e9dbad6fSeschrock 			uint64_t volsize, volblocksize;
1711e9dbad6fSeschrock 
1712ecd6cf80Smarks 			if (nvprops == NULL ||
1713ecd6cf80Smarks 			    nvlist_lookup_uint64(nvprops,
1714e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1715e9dbad6fSeschrock 			    &volsize) != 0) {
1716ecd6cf80Smarks 				nvlist_free(nvprops);
1717e9dbad6fSeschrock 				return (EINVAL);
1718e9dbad6fSeschrock 			}
1719e9dbad6fSeschrock 
1720ecd6cf80Smarks 			if ((error = nvlist_lookup_uint64(nvprops,
1721e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1722e9dbad6fSeschrock 			    &volblocksize)) != 0 && error != ENOENT) {
1723ecd6cf80Smarks 				nvlist_free(nvprops);
1724e9dbad6fSeschrock 				return (EINVAL);
1725e9dbad6fSeschrock 			}
1726e9dbad6fSeschrock 
1727e9dbad6fSeschrock 			if (error != 0)
1728e9dbad6fSeschrock 				volblocksize = zfs_prop_default_numeric(
1729e9dbad6fSeschrock 				    ZFS_PROP_VOLBLOCKSIZE);
1730e9dbad6fSeschrock 
1731e9dbad6fSeschrock 			if ((error = zvol_check_volblocksize(
1732e9dbad6fSeschrock 			    volblocksize)) != 0 ||
1733e9dbad6fSeschrock 			    (error = zvol_check_volsize(volsize,
1734e9dbad6fSeschrock 			    volblocksize)) != 0) {
1735ecd6cf80Smarks 				nvlist_free(nvprops);
17365c5460e9Seschrock 				return (error);
1737e9dbad6fSeschrock 			}
1738e7437265Sahrens 		} else if (type == DMU_OST_ZFS) {
1739e7437265Sahrens 			uint64_t version;
1740e7437265Sahrens 
1741e7437265Sahrens 			if (0 == nvlist_lookup_uint64(nvprops,
1742e7437265Sahrens 			    zfs_prop_to_name(ZFS_PROP_VERSION), &version) &&
1743e7437265Sahrens 			    (version < ZPL_VERSION_INITIAL ||
1744e7437265Sahrens 			    version > ZPL_VERSION)) {
1745e7437265Sahrens 				nvlist_free(nvprops);
1746e7437265Sahrens 				return (EINVAL);
1747e7437265Sahrens 			}
1748fa9e4066Sahrens 		}
1749e9dbad6fSeschrock 
1750e9dbad6fSeschrock 		error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc,
1751ecd6cf80Smarks 		    nvprops);
1752fa9e4066Sahrens 	}
1753e9dbad6fSeschrock 
1754e9dbad6fSeschrock 	/*
1755e9dbad6fSeschrock 	 * It would be nice to do this atomically.
1756e9dbad6fSeschrock 	 */
1757e9dbad6fSeschrock 	if (error == 0) {
175891ebeef5Sahrens 		if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0)
1759e9dbad6fSeschrock 			(void) dmu_objset_destroy(zc->zc_name);
1760e9dbad6fSeschrock 	}
1761e9dbad6fSeschrock 
1762ecd6cf80Smarks 	nvlist_free(nvprops);
1763fa9e4066Sahrens 	return (error);
1764fa9e4066Sahrens }
1765fa9e4066Sahrens 
1766fa9e4066Sahrens static int
17671d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc)
1768fa9e4066Sahrens {
1769e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
17701d452cf5Sahrens 		return (EINVAL);
17711d452cf5Sahrens 	return (dmu_objset_snapshot(zc->zc_name,
1772e9dbad6fSeschrock 	    zc->zc_value, zc->zc_cookie));
17731d452cf5Sahrens }
1774fa9e4066Sahrens 
1775cdf5b4caSmmusante int
17761d452cf5Sahrens zfs_unmount_snap(char *name, void *arg)
17771d452cf5Sahrens {
17781d452cf5Sahrens 	char *snapname = arg;
17791d452cf5Sahrens 	char *cp;
17800b69c2f0Sahrens 	vfs_t *vfsp = NULL;
17811d452cf5Sahrens 
17821d452cf5Sahrens 	/*
17831d452cf5Sahrens 	 * Snapshots (which are under .zfs control) must be unmounted
17841d452cf5Sahrens 	 * before they can be destroyed.
17851d452cf5Sahrens 	 */
17861d452cf5Sahrens 
17871d452cf5Sahrens 	if (snapname) {
17881d452cf5Sahrens 		(void) strcat(name, "@");
17891d452cf5Sahrens 		(void) strcat(name, snapname);
17901d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
17911d452cf5Sahrens 		cp = strchr(name, '@');
17921d452cf5Sahrens 		*cp = '\0';
17930b69c2f0Sahrens 	} else if (strchr(name, '@')) {
17941d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
17951d452cf5Sahrens 	}
17961d452cf5Sahrens 
17971d452cf5Sahrens 	if (vfsp) {
1798fa9e4066Sahrens 		/*
17991d452cf5Sahrens 		 * Always force the unmount for snapshots.
1800fa9e4066Sahrens 		 */
18011d452cf5Sahrens 		int flag = MS_FORCE;
18021d452cf5Sahrens 		int err;
18031d452cf5Sahrens 
18041d452cf5Sahrens 		if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) {
1805fa9e4066Sahrens 			VFS_RELE(vfsp);
18061d452cf5Sahrens 			return (err);
1807fa9e4066Sahrens 		}
18081d452cf5Sahrens 		VFS_RELE(vfsp);
18091d452cf5Sahrens 		if ((err = dounmount(vfsp, flag, kcred)) != 0)
18101d452cf5Sahrens 			return (err);
18111d452cf5Sahrens 	}
18121d452cf5Sahrens 	return (0);
18131d452cf5Sahrens }
18141d452cf5Sahrens 
18151d452cf5Sahrens static int
18161d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc)
18171d452cf5Sahrens {
18181d452cf5Sahrens 	int err;
18191d452cf5Sahrens 
1820e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
18211d452cf5Sahrens 		return (EINVAL);
18221d452cf5Sahrens 	err = dmu_objset_find(zc->zc_name,
1823e9dbad6fSeschrock 	    zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN);
18241d452cf5Sahrens 	if (err)
18251d452cf5Sahrens 		return (err);
1826e9dbad6fSeschrock 	return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value));
18271d452cf5Sahrens }
18281d452cf5Sahrens 
18291d452cf5Sahrens static int
18301d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc)
18311d452cf5Sahrens {
18321d452cf5Sahrens 	if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) {
18331d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
18341d452cf5Sahrens 		if (err)
18351d452cf5Sahrens 			return (err);
1836fa9e4066Sahrens 	}
1837fa9e4066Sahrens 
1838fa9e4066Sahrens 	return (dmu_objset_destroy(zc->zc_name));
1839fa9e4066Sahrens }
1840fa9e4066Sahrens 
1841fa9e4066Sahrens static int
1842fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc)
1843fa9e4066Sahrens {
1844fa9e4066Sahrens 	return (dmu_objset_rollback(zc->zc_name));
1845fa9e4066Sahrens }
1846fa9e4066Sahrens 
1847fa9e4066Sahrens static int
1848fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc)
1849fa9e4066Sahrens {
18507f1f55eaSvb 	boolean_t recursive = zc->zc_cookie & 1;
1851cdf5b4caSmmusante 
1852e9dbad6fSeschrock 	zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
1853*f18faf3fSek 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
1854*f18faf3fSek 	    strchr(zc->zc_value, '%'))
1855fa9e4066Sahrens 		return (EINVAL);
1856fa9e4066Sahrens 
1857cdf5b4caSmmusante 	/*
1858cdf5b4caSmmusante 	 * Unmount snapshot unless we're doing a recursive rename,
1859cdf5b4caSmmusante 	 * in which case the dataset code figures out which snapshots
1860cdf5b4caSmmusante 	 * to unmount.
1861cdf5b4caSmmusante 	 */
1862cdf5b4caSmmusante 	if (!recursive && strchr(zc->zc_name, '@') != NULL &&
1863fa9e4066Sahrens 	    zc->zc_objset_type == DMU_OST_ZFS) {
18641d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
18651d452cf5Sahrens 		if (err)
18661d452cf5Sahrens 			return (err);
1867fa9e4066Sahrens 	}
1868fa9e4066Sahrens 
1869cdf5b4caSmmusante 	return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive));
1870fa9e4066Sahrens }
1871fa9e4066Sahrens 
1872fa9e4066Sahrens static int
1873fa9e4066Sahrens zfs_ioc_recvbackup(zfs_cmd_t *zc)
1874fa9e4066Sahrens {
1875fa9e4066Sahrens 	file_t *fp;
1876a2eea2e1Sahrens 	offset_t new_off;
1877*f18faf3fSek 	objset_t *os;
1878*f18faf3fSek 	zfsvfs_t *zfsvfs = NULL;
1879*f18faf3fSek 	char *cp;
1880*f18faf3fSek 	char cosname[MAXNAMELEN];
1881*f18faf3fSek 	boolean_t force = (boolean_t)zc->zc_guid;
1882*f18faf3fSek 	int error, fd;
1883fa9e4066Sahrens 
18843ccfa83cSahrens 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
1885*f18faf3fSek 	    strchr(zc->zc_value, '@') == NULL ||
1886*f18faf3fSek 	    strchr(zc->zc_value, '%'))
18873ccfa83cSahrens 		return (EINVAL);
18883ccfa83cSahrens 
1889fa9e4066Sahrens 	fd = zc->zc_cookie;
1890fa9e4066Sahrens 	fp = getf(fd);
1891fa9e4066Sahrens 	if (fp == NULL)
1892fa9e4066Sahrens 		return (EBADF);
1893*f18faf3fSek 
1894*f18faf3fSek 	/*
1895*f18faf3fSek 	 * Get the zfsvfs for the receiving objset. There
1896*f18faf3fSek 	 * won't be one if we're operating on a zvol, if the
1897*f18faf3fSek 	 * objset doesn't exist yet, or is not mounted.
1898*f18faf3fSek 	 */
1899*f18faf3fSek 	cp = strchr(zc->zc_value, '@');
1900*f18faf3fSek 	*cp = '\0';
1901*f18faf3fSek 	error = dmu_objset_open(zc->zc_value, DMU_OST_ANY,
1902*f18faf3fSek 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
1903*f18faf3fSek 	*cp = '@';
1904*f18faf3fSek 	if (!error) {
1905*f18faf3fSek 		if (dmu_objset_type(os) == DMU_OST_ZFS) {
1906*f18faf3fSek 			mutex_enter(&os->os->os_user_ptr_lock);
1907*f18faf3fSek 			zfsvfs = dmu_objset_get_user(os);
1908*f18faf3fSek 			if (zfsvfs != NULL)
1909*f18faf3fSek 				VFS_HOLD(zfsvfs->z_vfs);
1910*f18faf3fSek 			mutex_exit(&os->os->os_user_ptr_lock);
1911*f18faf3fSek 		}
1912*f18faf3fSek 		dmu_objset_close(os);
1913*f18faf3fSek 	}
1914*f18faf3fSek 
1915e9dbad6fSeschrock 	error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record,
1916*f18faf3fSek 	    &zc->zc_cookie, force, zfsvfs != NULL, fp->f_vnode,
1917*f18faf3fSek 	    fp->f_offset, cosname);
1918*f18faf3fSek 
1919*f18faf3fSek 	/*
1920*f18faf3fSek 	 * For incremental snapshots where we created a
1921*f18faf3fSek 	 * temporary clone, we now swap zfsvfs::z_os with
1922*f18faf3fSek 	 * the newly created and received "cosname".
1923*f18faf3fSek 	 */
1924*f18faf3fSek 	if (!error && zfsvfs != NULL) {
1925*f18faf3fSek 		char osname[MAXNAMELEN];
1926*f18faf3fSek 		int mode;
1927*f18faf3fSek 
1928*f18faf3fSek 		error = zfs_suspend_fs(zfsvfs, osname, &mode);
1929*f18faf3fSek 		if (!error) {
1930*f18faf3fSek 			int swap_err;
1931*f18faf3fSek 			int snap_err = 0;
1932*f18faf3fSek 
1933*f18faf3fSek 			swap_err = dsl_dataset_clone_swap(cosname, force);
1934*f18faf3fSek 			if (!swap_err) {
1935*f18faf3fSek 				char *cp = strrchr(zc->zc_value, '@');
1936*f18faf3fSek 
1937*f18faf3fSek 				*cp = '\0';
1938*f18faf3fSek 				snap_err = dmu_replay_end_snapshot(zc->zc_value,
1939*f18faf3fSek 				    &zc->zc_begin_record);
1940*f18faf3fSek 				*cp = '@';
1941*f18faf3fSek 			}
1942*f18faf3fSek 			error = zfs_resume_fs(zfsvfs, osname, mode);
1943*f18faf3fSek 			if (!error)
1944*f18faf3fSek 				error = swap_err;
1945*f18faf3fSek 			if (!error)
1946*f18faf3fSek 				error = snap_err;
1947*f18faf3fSek 		}
1948a2eea2e1Sahrens 
1949*f18faf3fSek 		/* destroy the clone we created */
1950*f18faf3fSek 		(void) dmu_objset_destroy(cosname);
1951*f18faf3fSek 	}
1952*f18faf3fSek 	if (zfsvfs != NULL)
1953*f18faf3fSek 		VFS_RELE(zfsvfs->z_vfs);
1954a2eea2e1Sahrens 	new_off = fp->f_offset + zc->zc_cookie;
1955a2eea2e1Sahrens 	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off) == 0)
1956a2eea2e1Sahrens 		fp->f_offset = new_off;
1957a2eea2e1Sahrens 
1958fa9e4066Sahrens 	releasef(fd);
1959fa9e4066Sahrens 	return (error);
1960fa9e4066Sahrens }
1961fa9e4066Sahrens 
1962fa9e4066Sahrens static int
1963fa9e4066Sahrens zfs_ioc_sendbackup(zfs_cmd_t *zc)
1964fa9e4066Sahrens {
1965fa9e4066Sahrens 	objset_t *fromsnap = NULL;
1966fa9e4066Sahrens 	objset_t *tosnap;
1967fa9e4066Sahrens 	file_t *fp;
1968fa9e4066Sahrens 	int error;
1969fa9e4066Sahrens 
1970fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1971fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap);
1972fa9e4066Sahrens 	if (error)
1973fa9e4066Sahrens 		return (error);
1974fa9e4066Sahrens 
1975e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1976a2eea2e1Sahrens 		char buf[MAXPATHLEN];
1977a2eea2e1Sahrens 		char *cp;
1978a2eea2e1Sahrens 
1979a2eea2e1Sahrens 		(void) strncpy(buf, zc->zc_name, sizeof (buf));
1980a2eea2e1Sahrens 		cp = strchr(buf, '@');
1981a2eea2e1Sahrens 		if (cp)
1982a2eea2e1Sahrens 			*(cp+1) = 0;
1983a2eea2e1Sahrens 		(void) strncat(buf, zc->zc_value, sizeof (buf));
1984a2eea2e1Sahrens 		error = dmu_objset_open(buf, DMU_OST_ANY,
1985fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap);
1986fa9e4066Sahrens 		if (error) {
1987fa9e4066Sahrens 			dmu_objset_close(tosnap);
1988fa9e4066Sahrens 			return (error);
1989fa9e4066Sahrens 		}
1990fa9e4066Sahrens 	}
1991fa9e4066Sahrens 
1992fa9e4066Sahrens 	fp = getf(zc->zc_cookie);
1993fa9e4066Sahrens 	if (fp == NULL) {
1994fa9e4066Sahrens 		dmu_objset_close(tosnap);
1995fa9e4066Sahrens 		if (fromsnap)
1996fa9e4066Sahrens 			dmu_objset_close(fromsnap);
1997fa9e4066Sahrens 		return (EBADF);
1998fa9e4066Sahrens 	}
1999fa9e4066Sahrens 
2000fa9e4066Sahrens 	error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode);
2001fa9e4066Sahrens 
2002fa9e4066Sahrens 	releasef(zc->zc_cookie);
2003fa9e4066Sahrens 	if (fromsnap)
2004fa9e4066Sahrens 		dmu_objset_close(fromsnap);
2005fa9e4066Sahrens 	dmu_objset_close(tosnap);
2006fa9e4066Sahrens 	return (error);
2007fa9e4066Sahrens }
2008fa9e4066Sahrens 
2009ea8dc4b6Seschrock static int
2010ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc)
2011ea8dc4b6Seschrock {
2012ea8dc4b6Seschrock 	int id, error;
2013ea8dc4b6Seschrock 
2014ea8dc4b6Seschrock 	error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id,
2015ea8dc4b6Seschrock 	    &zc->zc_inject_record);
2016ea8dc4b6Seschrock 
2017ea8dc4b6Seschrock 	if (error == 0)
2018ea8dc4b6Seschrock 		zc->zc_guid = (uint64_t)id;
2019ea8dc4b6Seschrock 
2020ea8dc4b6Seschrock 	return (error);
2021ea8dc4b6Seschrock }
2022ea8dc4b6Seschrock 
2023ea8dc4b6Seschrock static int
2024ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc)
2025ea8dc4b6Seschrock {
2026ea8dc4b6Seschrock 	return (zio_clear_fault((int)zc->zc_guid));
2027ea8dc4b6Seschrock }
2028ea8dc4b6Seschrock 
2029ea8dc4b6Seschrock static int
2030ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc)
2031ea8dc4b6Seschrock {
2032ea8dc4b6Seschrock 	int id = (int)zc->zc_guid;
2033ea8dc4b6Seschrock 	int error;
2034ea8dc4b6Seschrock 
2035ea8dc4b6Seschrock 	error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name),
2036ea8dc4b6Seschrock 	    &zc->zc_inject_record);
2037ea8dc4b6Seschrock 
2038ea8dc4b6Seschrock 	zc->zc_guid = id;
2039ea8dc4b6Seschrock 
2040ea8dc4b6Seschrock 	return (error);
2041ea8dc4b6Seschrock }
2042ea8dc4b6Seschrock 
2043ea8dc4b6Seschrock static int
2044ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc)
2045ea8dc4b6Seschrock {
2046ea8dc4b6Seschrock 	spa_t *spa;
2047ea8dc4b6Seschrock 	int error;
2048e9dbad6fSeschrock 	size_t count = (size_t)zc->zc_nvlist_dst_size;
2049ea8dc4b6Seschrock 
2050ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
2051ea8dc4b6Seschrock 		return (error);
2052ea8dc4b6Seschrock 
2053e9dbad6fSeschrock 	error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst,
2054ea8dc4b6Seschrock 	    &count);
2055ea8dc4b6Seschrock 	if (error == 0)
2056e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = count;
2057ea8dc4b6Seschrock 	else
2058e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = spa_get_errlog_size(spa);
2059ea8dc4b6Seschrock 
2060ea8dc4b6Seschrock 	spa_close(spa, FTAG);
2061ea8dc4b6Seschrock 
2062ea8dc4b6Seschrock 	return (error);
2063ea8dc4b6Seschrock }
2064ea8dc4b6Seschrock 
2065ea8dc4b6Seschrock static int
2066ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc)
2067ea8dc4b6Seschrock {
2068ea8dc4b6Seschrock 	spa_t *spa;
2069ea8dc4b6Seschrock 	vdev_t *vd;
20703d7072f8Seschrock 	uint64_t txg;
2071bb8b5132Sek 	int error;
2072ea8dc4b6Seschrock 
2073ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
2074ea8dc4b6Seschrock 		return (error);
2075ea8dc4b6Seschrock 
20763d7072f8Seschrock 	txg = spa_vdev_enter(spa);
2077ea8dc4b6Seschrock 
2078e9dbad6fSeschrock 	if (zc->zc_guid == 0) {
2079ea8dc4b6Seschrock 		vd = NULL;
2080e9dbad6fSeschrock 	} else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) {
20813d7072f8Seschrock 		(void) spa_vdev_exit(spa, NULL, txg, ENODEV);
2082ea8dc4b6Seschrock 		spa_close(spa, FTAG);
2083ea8dc4b6Seschrock 		return (ENODEV);
2084ea8dc4b6Seschrock 	}
2085ea8dc4b6Seschrock 
2086ea8dc4b6Seschrock 	vdev_clear(spa, vd);
2087ea8dc4b6Seschrock 
20883d7072f8Seschrock 	(void) spa_vdev_exit(spa, NULL, txg, 0);
2089ea8dc4b6Seschrock 
2090ea8dc4b6Seschrock 	spa_close(spa, FTAG);
2091ea8dc4b6Seschrock 
2092ea8dc4b6Seschrock 	return (0);
2093ea8dc4b6Seschrock }
2094ea8dc4b6Seschrock 
209599653d4eSeschrock static int
209699653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc)
209799653d4eSeschrock {
20980b69c2f0Sahrens 	char *cp;
20990b69c2f0Sahrens 
21000b69c2f0Sahrens 	/*
21010b69c2f0Sahrens 	 * We don't need to unmount *all* the origin fs's snapshots, but
21020b69c2f0Sahrens 	 * it's easier.
21030b69c2f0Sahrens 	 */
2104e9dbad6fSeschrock 	cp = strchr(zc->zc_value, '@');
21050b69c2f0Sahrens 	if (cp)
21060b69c2f0Sahrens 		*cp = '\0';
2107e9dbad6fSeschrock 	(void) dmu_objset_find(zc->zc_value,
21080b69c2f0Sahrens 	    zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS);
210999653d4eSeschrock 	return (dsl_dataset_promote(zc->zc_name));
211099653d4eSeschrock }
211199653d4eSeschrock 
2112ecd6cf80Smarks /*
2113ecd6cf80Smarks  * We don't want to have a hard dependency
2114ecd6cf80Smarks  * against some special symbols in sharefs
2115ecd6cf80Smarks  * and nfs.  Determine them if needed when
2116ecd6cf80Smarks  * the first file system is shared.
2117ecd6cf80Smarks  * Neither sharefs or nfs are unloadable modules.
2118ecd6cf80Smarks  */
2119ecd6cf80Smarks int (*zexport_fs)(void *arg);
2120ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t);
2121ecd6cf80Smarks 
2122ecd6cf80Smarks int zfs_share_inited;
2123ecd6cf80Smarks ddi_modhandle_t nfs_mod;
2124ecd6cf80Smarks ddi_modhandle_t sharefs_mod;
2125ecd6cf80Smarks kmutex_t zfs_share_lock;
2126ecd6cf80Smarks 
2127ecd6cf80Smarks static int
2128ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc)
2129ecd6cf80Smarks {
2130ecd6cf80Smarks 	int error;
2131ecd6cf80Smarks 	int opcode;
2132ecd6cf80Smarks 
2133ecd6cf80Smarks 	if (zfs_share_inited == 0) {
2134ecd6cf80Smarks 		mutex_enter(&zfs_share_lock);
2135ecd6cf80Smarks 		nfs_mod = ddi_modopen("fs/nfs", KRTLD_MODE_FIRST, &error);
2136ecd6cf80Smarks 		sharefs_mod = ddi_modopen("fs/sharefs",
2137ecd6cf80Smarks 		    KRTLD_MODE_FIRST, &error);
2138ecd6cf80Smarks 		if (nfs_mod == NULL || sharefs_mod == NULL) {
2139ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2140ecd6cf80Smarks 			return (ENOSYS);
2141ecd6cf80Smarks 		}
2142ecd6cf80Smarks 		if (zexport_fs == NULL && ((zexport_fs = (int (*)(void *))
2143ecd6cf80Smarks 		    ddi_modsym(nfs_mod, "nfs_export", &error)) == NULL)) {
2144ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2145ecd6cf80Smarks 			return (ENOSYS);
2146ecd6cf80Smarks 		}
2147ecd6cf80Smarks 
2148ecd6cf80Smarks 		if (zshare_fs == NULL && ((zshare_fs =
2149ecd6cf80Smarks 		    (int (*)(enum sharefs_sys_op, share_t *, uint32_t))
2150ecd6cf80Smarks 		    ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) {
2151ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2152ecd6cf80Smarks 			return (ENOSYS);
2153ecd6cf80Smarks 		}
2154ecd6cf80Smarks 		zfs_share_inited = 1;
2155ecd6cf80Smarks 		mutex_exit(&zfs_share_lock);
2156ecd6cf80Smarks 	}
2157ecd6cf80Smarks 
2158ecd6cf80Smarks 	if (error = zexport_fs((void *)(uintptr_t)zc->zc_share.z_exportdata))
2159ecd6cf80Smarks 		return (error);
2160ecd6cf80Smarks 
2161ecd6cf80Smarks 	opcode = (zc->zc_share.z_sharetype == B_TRUE) ?
2162ecd6cf80Smarks 	    SHAREFS_ADD : SHAREFS_REMOVE;
2163ecd6cf80Smarks 
2164ecd6cf80Smarks 	error = zshare_fs(opcode,
2165ecd6cf80Smarks 	    (void *)(uintptr_t)zc->zc_share.z_sharedata,
2166ecd6cf80Smarks 	    zc->zc_share.z_sharemax);
2167ecd6cf80Smarks 
2168ecd6cf80Smarks 	return (error);
2169ecd6cf80Smarks 
2170ecd6cf80Smarks }
2171ecd6cf80Smarks 
2172ecd6cf80Smarks /*
21732a6b87f0Sek  * pool create, destroy, and export don't log the history as part of
21742a6b87f0Sek  * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export
21752a6b87f0Sek  * do the logging of those commands.
2176ecd6cf80Smarks  */
2177fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = {
2178228975ccSek 	{ zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2179e7437265Sahrens 	{ zfs_ioc_pool_destroy,	zfs_secpolicy_config, POOL_NAME, B_FALSE },
2180e7437265Sahrens 	{ zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2181e7437265Sahrens 	{ zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2182e7437265Sahrens 	{ zfs_ioc_pool_configs,	zfs_secpolicy_none, NO_NAME, B_FALSE },
2183e7437265Sahrens 	{ zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE },
2184e7437265Sahrens 	{ zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE },
2185e7437265Sahrens 	{ zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2186e7437265Sahrens 	{ zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE },
2187e7437265Sahrens 	{ zfs_ioc_pool_upgrade,	zfs_secpolicy_config, POOL_NAME, B_TRUE },
2188e7437265Sahrens 	{ zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2189e7437265Sahrens 	{ zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2190e7437265Sahrens 	{ zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2191e7437265Sahrens 	{ zfs_ioc_vdev_set_state, zfs_secpolicy_config,	POOL_NAME, B_TRUE },
2192e7437265Sahrens 	{ zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2193e7437265Sahrens 	{ zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2194e7437265Sahrens 	{ zfs_ioc_vdev_setpath,	zfs_secpolicy_config, POOL_NAME, B_FALSE },
2195e7437265Sahrens 	{ zfs_ioc_objset_stats,	zfs_secpolicy_read, DATASET_NAME, B_FALSE },
2196bd00f61bSrm 	{ zfs_ioc_objset_version, zfs_secpolicy_read, DATASET_NAME, B_FALSE },
2197ecd6cf80Smarks 	{ zfs_ioc_dataset_list_next, zfs_secpolicy_read,
2198e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2199ecd6cf80Smarks 	{ zfs_ioc_snapshot_list_next, zfs_secpolicy_read,
2200e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2201e7437265Sahrens 	{ zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE },
2202e7437265Sahrens 	{ zfs_ioc_create_minor,	zfs_secpolicy_minor, DATASET_NAME, B_FALSE },
2203e7437265Sahrens 	{ zfs_ioc_remove_minor,	zfs_secpolicy_minor, DATASET_NAME, B_FALSE },
2204e7437265Sahrens 	{ zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE },
2205e7437265Sahrens 	{ zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE },
2206e7437265Sahrens 	{ zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE },
2207e7437265Sahrens 	{ zfs_ioc_rename, zfs_secpolicy_rename,	DATASET_NAME, B_TRUE },
2208e7437265Sahrens 	{ zfs_ioc_recvbackup, zfs_secpolicy_receive, DATASET_NAME, B_TRUE },
2209e7437265Sahrens 	{ zfs_ioc_sendbackup, zfs_secpolicy_send, DATASET_NAME, B_TRUE },
2210e7437265Sahrens 	{ zfs_ioc_inject_fault,	zfs_secpolicy_inject, NO_NAME, B_FALSE },
2211e7437265Sahrens 	{ zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE },
2212e7437265Sahrens 	{ zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE },
2213e7437265Sahrens 	{ zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE },
2214e7437265Sahrens 	{ zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2215e7437265Sahrens 	{ zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE },
2216e7437265Sahrens 	{ zfs_ioc_destroy_snaps, zfs_secpolicy_destroy,	DATASET_NAME, B_TRUE },
2217e7437265Sahrens 	{ zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE },
2218e7437265Sahrens 	{ zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2219e7437265Sahrens 	{ zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE },
2220e7437265Sahrens 	{ zfs_ioc_pool_set_props, zfs_secpolicy_config,	POOL_NAME, B_TRUE },
2221e7437265Sahrens 	{ zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE },
2222e7437265Sahrens 	{ zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE },
2223e7437265Sahrens 	{ zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE },
2224ecd6cf80Smarks 	{ zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi,
2225e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2226e45ce728Sahrens 	{ zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE },
2227e45ce728Sahrens 	{ zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE },
2228fa9e4066Sahrens };
2229fa9e4066Sahrens 
2230fa9e4066Sahrens static int
2231fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
2232fa9e4066Sahrens {
2233fa9e4066Sahrens 	zfs_cmd_t *zc;
2234fa9e4066Sahrens 	uint_t vec;
22351d452cf5Sahrens 	int error, rc;
2236fa9e4066Sahrens 
2237fa9e4066Sahrens 	if (getminor(dev) != 0)
2238fa9e4066Sahrens 		return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp));
2239fa9e4066Sahrens 
2240fa9e4066Sahrens 	vec = cmd - ZFS_IOC;
224191ebeef5Sahrens 	ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip));
2242fa9e4066Sahrens 
2243fa9e4066Sahrens 	if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
2244fa9e4066Sahrens 		return (EINVAL);
2245fa9e4066Sahrens 
2246fa9e4066Sahrens 	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
2247fa9e4066Sahrens 
2248fa9e4066Sahrens 	error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t));
2249fa9e4066Sahrens 
225091ebeef5Sahrens 	if (error == 0)
2251ecd6cf80Smarks 		error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr);
2252fa9e4066Sahrens 
2253fa9e4066Sahrens 	/*
2254fa9e4066Sahrens 	 * Ensure that all pool/dataset names are valid before we pass down to
2255fa9e4066Sahrens 	 * the lower layers.
2256fa9e4066Sahrens 	 */
2257fa9e4066Sahrens 	if (error == 0) {
2258fa9e4066Sahrens 		zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
2259fa9e4066Sahrens 		switch (zfs_ioc_vec[vec].zvec_namecheck) {
2260e7437265Sahrens 		case POOL_NAME:
2261fa9e4066Sahrens 			if (pool_namecheck(zc->zc_name, NULL, NULL) != 0)
2262fa9e4066Sahrens 				error = EINVAL;
2263fa9e4066Sahrens 			break;
2264fa9e4066Sahrens 
2265e7437265Sahrens 		case DATASET_NAME:
2266fa9e4066Sahrens 			if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0)
2267fa9e4066Sahrens 				error = EINVAL;
2268fa9e4066Sahrens 			break;
22695ad82045Snd 
2270e7437265Sahrens 		case NO_NAME:
22715ad82045Snd 			break;
2272fa9e4066Sahrens 		}
2273fa9e4066Sahrens 	}
2274fa9e4066Sahrens 
2275fa9e4066Sahrens 	if (error == 0)
2276fa9e4066Sahrens 		error = zfs_ioc_vec[vec].zvec_func(zc);
2277fa9e4066Sahrens 
22781d452cf5Sahrens 	rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t));
2279ecd6cf80Smarks 	if (error == 0) {
22801d452cf5Sahrens 		error = rc;
2281ecd6cf80Smarks 		if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE)
2282ecd6cf80Smarks 			zfs_log_history(zc);
2283ecd6cf80Smarks 	}
2284fa9e4066Sahrens 
2285fa9e4066Sahrens 	kmem_free(zc, sizeof (zfs_cmd_t));
2286fa9e4066Sahrens 	return (error);
2287fa9e4066Sahrens }
2288fa9e4066Sahrens 
2289fa9e4066Sahrens static int
2290fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2291fa9e4066Sahrens {
2292fa9e4066Sahrens 	if (cmd != DDI_ATTACH)
2293fa9e4066Sahrens 		return (DDI_FAILURE);
2294fa9e4066Sahrens 
2295fa9e4066Sahrens 	if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0,
2296fa9e4066Sahrens 	    DDI_PSEUDO, 0) == DDI_FAILURE)
2297fa9e4066Sahrens 		return (DDI_FAILURE);
2298fa9e4066Sahrens 
2299fa9e4066Sahrens 	zfs_dip = dip;
2300fa9e4066Sahrens 
2301fa9e4066Sahrens 	ddi_report_dev(dip);
2302fa9e4066Sahrens 
2303fa9e4066Sahrens 	return (DDI_SUCCESS);
2304fa9e4066Sahrens }
2305fa9e4066Sahrens 
2306fa9e4066Sahrens static int
2307fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2308fa9e4066Sahrens {
2309fa9e4066Sahrens 	if (spa_busy() || zfs_busy() || zvol_busy())
2310fa9e4066Sahrens 		return (DDI_FAILURE);
2311fa9e4066Sahrens 
2312fa9e4066Sahrens 	if (cmd != DDI_DETACH)
2313fa9e4066Sahrens 		return (DDI_FAILURE);
2314fa9e4066Sahrens 
2315fa9e4066Sahrens 	zfs_dip = NULL;
2316fa9e4066Sahrens 
2317fa9e4066Sahrens 	ddi_prop_remove_all(dip);
2318fa9e4066Sahrens 	ddi_remove_minor_node(dip, NULL);
2319fa9e4066Sahrens 
2320fa9e4066Sahrens 	return (DDI_SUCCESS);
2321fa9e4066Sahrens }
2322fa9e4066Sahrens 
2323fa9e4066Sahrens /*ARGSUSED*/
2324fa9e4066Sahrens static int
2325fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2326fa9e4066Sahrens {
2327fa9e4066Sahrens 	switch (infocmd) {
2328fa9e4066Sahrens 	case DDI_INFO_DEVT2DEVINFO:
2329fa9e4066Sahrens 		*result = zfs_dip;
2330fa9e4066Sahrens 		return (DDI_SUCCESS);
2331fa9e4066Sahrens 
2332fa9e4066Sahrens 	case DDI_INFO_DEVT2INSTANCE:
2333a0965f35Sbonwick 		*result = (void *)0;
2334fa9e4066Sahrens 		return (DDI_SUCCESS);
2335fa9e4066Sahrens 	}
2336fa9e4066Sahrens 
2337fa9e4066Sahrens 	return (DDI_FAILURE);
2338fa9e4066Sahrens }
2339fa9e4066Sahrens 
2340fa9e4066Sahrens /*
2341fa9e4066Sahrens  * OK, so this is a little weird.
2342fa9e4066Sahrens  *
2343fa9e4066Sahrens  * /dev/zfs is the control node, i.e. minor 0.
2344fa9e4066Sahrens  * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0.
2345fa9e4066Sahrens  *
2346fa9e4066Sahrens  * /dev/zfs has basically nothing to do except serve up ioctls,
2347fa9e4066Sahrens  * so most of the standard driver entry points are in zvol.c.
2348fa9e4066Sahrens  */
2349fa9e4066Sahrens static struct cb_ops zfs_cb_ops = {
2350fa9e4066Sahrens 	zvol_open,	/* open */
2351fa9e4066Sahrens 	zvol_close,	/* close */
2352fa9e4066Sahrens 	zvol_strategy,	/* strategy */
2353fa9e4066Sahrens 	nodev,		/* print */
2354fa9e4066Sahrens 	nodev,		/* dump */
2355fa9e4066Sahrens 	zvol_read,	/* read */
2356fa9e4066Sahrens 	zvol_write,	/* write */
2357fa9e4066Sahrens 	zfsdev_ioctl,	/* ioctl */
2358fa9e4066Sahrens 	nodev,		/* devmap */
2359fa9e4066Sahrens 	nodev,		/* mmap */
2360fa9e4066Sahrens 	nodev,		/* segmap */
2361fa9e4066Sahrens 	nochpoll,	/* poll */
2362fa9e4066Sahrens 	ddi_prop_op,	/* prop_op */
2363fa9e4066Sahrens 	NULL,		/* streamtab */
2364fa9e4066Sahrens 	D_NEW | D_MP | D_64BIT,		/* Driver compatibility flag */
2365fa9e4066Sahrens 	CB_REV,		/* version */
2366feb08c6bSbillm 	nodev,		/* async read */
2367feb08c6bSbillm 	nodev,		/* async write */
2368fa9e4066Sahrens };
2369fa9e4066Sahrens 
2370fa9e4066Sahrens static struct dev_ops zfs_dev_ops = {
2371fa9e4066Sahrens 	DEVO_REV,	/* version */
2372fa9e4066Sahrens 	0,		/* refcnt */
2373fa9e4066Sahrens 	zfs_info,	/* info */
2374fa9e4066Sahrens 	nulldev,	/* identify */
2375fa9e4066Sahrens 	nulldev,	/* probe */
2376fa9e4066Sahrens 	zfs_attach,	/* attach */
2377fa9e4066Sahrens 	zfs_detach,	/* detach */
2378fa9e4066Sahrens 	nodev,		/* reset */
2379fa9e4066Sahrens 	&zfs_cb_ops,	/* driver operations */
2380fa9e4066Sahrens 	NULL		/* no bus operations */
2381fa9e4066Sahrens };
2382fa9e4066Sahrens 
2383fa9e4066Sahrens static struct modldrv zfs_modldrv = {
2384e7437265Sahrens 	&mod_driverops, "ZFS storage pool version " SPA_VERSION_STRING,
2385e9dbad6fSeschrock 	    &zfs_dev_ops
2386fa9e4066Sahrens };
2387fa9e4066Sahrens 
2388fa9e4066Sahrens static struct modlinkage modlinkage = {
2389fa9e4066Sahrens 	MODREV_1,
2390fa9e4066Sahrens 	(void *)&zfs_modlfs,
2391fa9e4066Sahrens 	(void *)&zfs_modldrv,
2392fa9e4066Sahrens 	NULL
2393fa9e4066Sahrens };
2394fa9e4066Sahrens 
2395ec533521Sfr 
2396ec533521Sfr uint_t zfs_fsyncer_key;
2397*f18faf3fSek extern uint_t rrw_tsd_key;
2398ec533521Sfr 
2399fa9e4066Sahrens int
2400fa9e4066Sahrens _init(void)
2401fa9e4066Sahrens {
2402fa9e4066Sahrens 	int error;
2403fa9e4066Sahrens 
2404a0965f35Sbonwick 	spa_init(FREAD | FWRITE);
2405a0965f35Sbonwick 	zfs_init();
2406a0965f35Sbonwick 	zvol_init();
2407a0965f35Sbonwick 
2408a0965f35Sbonwick 	if ((error = mod_install(&modlinkage)) != 0) {
2409a0965f35Sbonwick 		zvol_fini();
2410a0965f35Sbonwick 		zfs_fini();
2411a0965f35Sbonwick 		spa_fini();
2412fa9e4066Sahrens 		return (error);
2413a0965f35Sbonwick 	}
2414fa9e4066Sahrens 
2415ec533521Sfr 	tsd_create(&zfs_fsyncer_key, NULL);
2416*f18faf3fSek 	tsd_create(&rrw_tsd_key, NULL);
2417ec533521Sfr 
2418fa9e4066Sahrens 	error = ldi_ident_from_mod(&modlinkage, &zfs_li);
2419fa9e4066Sahrens 	ASSERT(error == 0);
2420ecd6cf80Smarks 	mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL);
2421fa9e4066Sahrens 
2422fa9e4066Sahrens 	return (0);
2423fa9e4066Sahrens }
2424fa9e4066Sahrens 
2425fa9e4066Sahrens int
2426fa9e4066Sahrens _fini(void)
2427fa9e4066Sahrens {
2428fa9e4066Sahrens 	int error;
2429fa9e4066Sahrens 
2430ea8dc4b6Seschrock 	if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled)
2431fa9e4066Sahrens 		return (EBUSY);
2432fa9e4066Sahrens 
2433fa9e4066Sahrens 	if ((error = mod_remove(&modlinkage)) != 0)
2434fa9e4066Sahrens 		return (error);
2435fa9e4066Sahrens 
2436fa9e4066Sahrens 	zvol_fini();
2437fa9e4066Sahrens 	zfs_fini();
2438fa9e4066Sahrens 	spa_fini();
2439ecd6cf80Smarks 	if (zfs_share_inited) {
2440ecd6cf80Smarks 		(void) ddi_modclose(nfs_mod);
2441ecd6cf80Smarks 		(void) ddi_modclose(sharefs_mod);
2442ecd6cf80Smarks 	}
2443fa9e4066Sahrens 
2444ec533521Sfr 	tsd_destroy(&zfs_fsyncer_key);
2445fa9e4066Sahrens 	ldi_ident_release(zfs_li);
2446fa9e4066Sahrens 	zfs_li = NULL;
2447ecd6cf80Smarks 	mutex_destroy(&zfs_share_lock);
2448fa9e4066Sahrens 
2449fa9e4066Sahrens 	return (error);
2450fa9e4066Sahrens }
2451fa9e4066Sahrens 
2452fa9e4066Sahrens int
2453fa9e4066Sahrens _info(struct modinfo *modinfop)
2454fa9e4066Sahrens {
2455fa9e4066Sahrens 	return (mod_info(&modlinkage, modinfop));
2456fa9e4066Sahrens }
2457