xref: /illumos-gate/usr/src/uts/common/fs/zfs/zfs_ioctl.c (revision ecd6cf800b63704be73fb264c3f5b6e0dafc068d)
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>
50*ecd6cf80Smarks #include <sys/dsl_deleg.h>
51*ecd6cf80Smarks #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>
64*ecd6cf80Smarks #include <sharefs/share.h>
65fa9e4066Sahrens 
66fa9e4066Sahrens #include "zfs_namecheck.h"
67e9dbad6fSeschrock #include "zfs_prop.h"
68*ecd6cf80Smarks #include "zfs_deleg.h"
69fa9e4066Sahrens 
70fa9e4066Sahrens extern struct modlfs zfs_modlfs;
71fa9e4066Sahrens 
72fa9e4066Sahrens extern void zfs_init(void);
73fa9e4066Sahrens extern void zfs_fini(void);
74fa9e4066Sahrens 
75fa9e4066Sahrens ldi_ident_t zfs_li = NULL;
76fa9e4066Sahrens dev_info_t *zfs_dip;
77fa9e4066Sahrens 
78fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *);
79*ecd6cf80Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *);
80fa9e4066Sahrens 
81fa9e4066Sahrens typedef struct zfs_ioc_vec {
82fa9e4066Sahrens 	zfs_ioc_func_t		*zvec_func;
83fa9e4066Sahrens 	zfs_secpolicy_func_t	*zvec_secpolicy;
84fa9e4066Sahrens 	enum {
85fa9e4066Sahrens 		no_name,
86fa9e4066Sahrens 		pool_name,
87fa9e4066Sahrens 		dataset_name
88*ecd6cf80Smarks 	} zvec_namecheck;
89*ecd6cf80Smarks 	boolean_t		zvec_his_log;
90fa9e4066Sahrens } zfs_ioc_vec_t;
91fa9e4066Sahrens 
92fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */
93fa9e4066Sahrens void
94fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
95fa9e4066Sahrens {
96fa9e4066Sahrens 	const char *newfile;
97fa9e4066Sahrens 	char buf[256];
98fa9e4066Sahrens 	va_list adx;
99fa9e4066Sahrens 
100fa9e4066Sahrens 	/*
101fa9e4066Sahrens 	 * Get rid of annoying "../common/" prefix to filename.
102fa9e4066Sahrens 	 */
103fa9e4066Sahrens 	newfile = strrchr(file, '/');
104fa9e4066Sahrens 	if (newfile != NULL) {
105fa9e4066Sahrens 		newfile = newfile + 1; /* Get rid of leading / */
106fa9e4066Sahrens 	} else {
107fa9e4066Sahrens 		newfile = file;
108fa9e4066Sahrens 	}
109fa9e4066Sahrens 
110fa9e4066Sahrens 	va_start(adx, fmt);
111fa9e4066Sahrens 	(void) vsnprintf(buf, sizeof (buf), fmt, adx);
112fa9e4066Sahrens 	va_end(adx);
113fa9e4066Sahrens 
114fa9e4066Sahrens 	/*
115fa9e4066Sahrens 	 * To get this data, use the zfs-dprintf probe as so:
116fa9e4066Sahrens 	 * dtrace -q -n 'zfs-dprintf \
117fa9e4066Sahrens 	 *	/stringof(arg0) == "dbuf.c"/ \
118fa9e4066Sahrens 	 *	{printf("%s: %s", stringof(arg1), stringof(arg3))}'
119fa9e4066Sahrens 	 * arg0 = file name
120fa9e4066Sahrens 	 * arg1 = function name
121fa9e4066Sahrens 	 * arg2 = line number
122fa9e4066Sahrens 	 * arg3 = message
123fa9e4066Sahrens 	 */
124fa9e4066Sahrens 	DTRACE_PROBE4(zfs__dprintf,
125fa9e4066Sahrens 	    char *, newfile, char *, func, int, line, char *, buf);
126fa9e4066Sahrens }
127fa9e4066Sahrens 
128*ecd6cf80Smarks static void
129*ecd6cf80Smarks zfs_log_history(zfs_cmd_t *zc)
130*ecd6cf80Smarks {
131*ecd6cf80Smarks 	spa_t *spa;
132*ecd6cf80Smarks 	char poolname[MAXNAMELEN];
133*ecd6cf80Smarks 	char *buf, *cp;
134*ecd6cf80Smarks 
135*ecd6cf80Smarks 	if (zc->zc_history == NULL)
136*ecd6cf80Smarks 		return;
137*ecd6cf80Smarks 
138*ecd6cf80Smarks 	buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP);
139*ecd6cf80Smarks 	if (copyinstr((void *)(uintptr_t)zc->zc_history,
140*ecd6cf80Smarks 	    buf, HIS_MAX_RECORD_LEN, NULL) != 0) {
141*ecd6cf80Smarks 		kmem_free(buf, HIS_MAX_RECORD_LEN);
142*ecd6cf80Smarks 		return;
143*ecd6cf80Smarks 	}
144*ecd6cf80Smarks 
145*ecd6cf80Smarks 	buf[HIS_MAX_RECORD_LEN -1] = '\0';
146*ecd6cf80Smarks 
147*ecd6cf80Smarks 	(void) strlcpy(poolname, zc->zc_name, sizeof (poolname));
148*ecd6cf80Smarks 	cp = strpbrk(poolname, "/@");
149*ecd6cf80Smarks 	if (cp != NULL)
150*ecd6cf80Smarks 		*cp = '\0';
151*ecd6cf80Smarks 
152*ecd6cf80Smarks 	if (spa_open(poolname, &spa, FTAG) != 0) {
153*ecd6cf80Smarks 		kmem_free(buf, HIS_MAX_RECORD_LEN);
154*ecd6cf80Smarks 		return;
155*ecd6cf80Smarks 	}
156*ecd6cf80Smarks 
157*ecd6cf80Smarks 	if (spa_version(spa) >= ZFS_VERSION_ZPOOL_HISTORY)
158*ecd6cf80Smarks 		(void) spa_history_log(spa, buf, zc->zc_history_offset);
159*ecd6cf80Smarks 
160*ecd6cf80Smarks 	spa_close(spa, FTAG);
161*ecd6cf80Smarks 	kmem_free(buf, HIS_MAX_RECORD_LEN);
162*ecd6cf80Smarks }
163*ecd6cf80Smarks 
164fa9e4066Sahrens /*
165fa9e4066Sahrens  * Policy for top-level read operations (list pools).  Requires no privileges,
166fa9e4066Sahrens  * and can be used in the local zone, as there is no associated dataset.
167fa9e4066Sahrens  */
168fa9e4066Sahrens /* ARGSUSED */
169fa9e4066Sahrens static int
170*ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr)
171fa9e4066Sahrens {
172fa9e4066Sahrens 	return (0);
173fa9e4066Sahrens }
174fa9e4066Sahrens 
175fa9e4066Sahrens /*
176fa9e4066Sahrens  * Policy for dataset read operations (list children, get statistics).  Requires
177fa9e4066Sahrens  * no privileges, but must be visible in the local zone.
178fa9e4066Sahrens  */
179fa9e4066Sahrens /* ARGSUSED */
180fa9e4066Sahrens static int
181*ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr)
182fa9e4066Sahrens {
183fa9e4066Sahrens 	if (INGLOBALZONE(curproc) ||
184*ecd6cf80Smarks 	    zone_dataset_visible(zc->zc_name, NULL))
185fa9e4066Sahrens 		return (0);
186fa9e4066Sahrens 
187fa9e4066Sahrens 	return (ENOENT);
188fa9e4066Sahrens }
189fa9e4066Sahrens 
190fa9e4066Sahrens static int
191fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr)
192fa9e4066Sahrens {
193fa9e4066Sahrens 	uint64_t zoned;
194fa9e4066Sahrens 	int writable = 1;
195fa9e4066Sahrens 
196fa9e4066Sahrens 	/*
197fa9e4066Sahrens 	 * The dataset must be visible by this zone -- check this first
198fa9e4066Sahrens 	 * so they don't see EPERM on something they shouldn't know about.
199fa9e4066Sahrens 	 */
200fa9e4066Sahrens 	if (!INGLOBALZONE(curproc) &&
201fa9e4066Sahrens 	    !zone_dataset_visible(dataset, &writable))
202fa9e4066Sahrens 		return (ENOENT);
203fa9e4066Sahrens 
204fa9e4066Sahrens 	if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL))
205fa9e4066Sahrens 		return (ENOENT);
206fa9e4066Sahrens 
207fa9e4066Sahrens 	if (INGLOBALZONE(curproc)) {
208fa9e4066Sahrens 		/*
209fa9e4066Sahrens 		 * If the fs is zoned, only root can access it from the
210fa9e4066Sahrens 		 * global zone.
211fa9e4066Sahrens 		 */
212fa9e4066Sahrens 		if (secpolicy_zfs(cr) && zoned)
213fa9e4066Sahrens 			return (EPERM);
214fa9e4066Sahrens 	} else {
215fa9e4066Sahrens 		/*
216fa9e4066Sahrens 		 * If we are in a local zone, the 'zoned' property must be set.
217fa9e4066Sahrens 		 */
218fa9e4066Sahrens 		if (!zoned)
219fa9e4066Sahrens 			return (EPERM);
220fa9e4066Sahrens 
221fa9e4066Sahrens 		/* must be writable by this zone */
222fa9e4066Sahrens 		if (!writable)
223fa9e4066Sahrens 			return (EPERM);
224fa9e4066Sahrens 	}
225fa9e4066Sahrens 	return (0);
226fa9e4066Sahrens }
227fa9e4066Sahrens 
228fa9e4066Sahrens int
229*ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr)
230fa9e4066Sahrens {
231fa9e4066Sahrens 	int error;
232fa9e4066Sahrens 
233*ecd6cf80Smarks 	error = zfs_dozonecheck(name, cr);
234*ecd6cf80Smarks 	if (error == 0) {
235*ecd6cf80Smarks 		error = secpolicy_zfs(cr);
236*ecd6cf80Smarks 		if (error) {
237*ecd6cf80Smarks 			error = dsl_deleg_access(name, perm, cr);
238*ecd6cf80Smarks 		}
239*ecd6cf80Smarks 	}
240*ecd6cf80Smarks 	return (error);
241*ecd6cf80Smarks }
242*ecd6cf80Smarks 
243*ecd6cf80Smarks static int
244*ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr)
245*ecd6cf80Smarks {
246*ecd6cf80Smarks 	int error = 0;
247*ecd6cf80Smarks 
248*ecd6cf80Smarks 	/*
249*ecd6cf80Smarks 	 * Check permissions for special properties.
250*ecd6cf80Smarks 	 */
251*ecd6cf80Smarks 	switch (prop) {
252*ecd6cf80Smarks 	case ZFS_PROP_ZONED:
253*ecd6cf80Smarks 		/*
254*ecd6cf80Smarks 		 * Disallow setting of 'zoned' from within a local zone.
255*ecd6cf80Smarks 		 */
256*ecd6cf80Smarks 		if (!INGLOBALZONE(curproc))
257*ecd6cf80Smarks 			return (EPERM);
258*ecd6cf80Smarks 		break;
259*ecd6cf80Smarks 
260*ecd6cf80Smarks 	case ZFS_PROP_QUOTA:
261*ecd6cf80Smarks 		if (error =
262*ecd6cf80Smarks 		    zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_QUOTA, cr))
263*ecd6cf80Smarks 			return (error);
264*ecd6cf80Smarks 
265*ecd6cf80Smarks 		if (!INGLOBALZONE(curproc)) {
266*ecd6cf80Smarks 			uint64_t zoned;
267*ecd6cf80Smarks 			char setpoint[MAXNAMELEN];
268*ecd6cf80Smarks 			int dslen;
269*ecd6cf80Smarks 			/*
270*ecd6cf80Smarks 			 * Unprivileged users are allowed to modify the
271*ecd6cf80Smarks 			 * quota on things *under* (ie. contained by)
272*ecd6cf80Smarks 			 * the thing they own.
273*ecd6cf80Smarks 			 */
274*ecd6cf80Smarks 			if (dsl_prop_get_integer(name, "zoned", &zoned,
275*ecd6cf80Smarks 			    setpoint))
276*ecd6cf80Smarks 				return (EPERM);
277*ecd6cf80Smarks 			if (!zoned) /* this shouldn't happen */
278*ecd6cf80Smarks 				return (EPERM);
279*ecd6cf80Smarks 			dslen = strlen(name);
280*ecd6cf80Smarks 			if (dslen <= strlen(setpoint))
281*ecd6cf80Smarks 				return (EPERM);
282*ecd6cf80Smarks 		}
283*ecd6cf80Smarks 	default:
284*ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(name,
285*ecd6cf80Smarks 		    zfs_prop_perm(prop), cr);
286*ecd6cf80Smarks 	}
287*ecd6cf80Smarks 
288*ecd6cf80Smarks 	return (error);
289*ecd6cf80Smarks }
290*ecd6cf80Smarks 
291*ecd6cf80Smarks int
292*ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr)
293*ecd6cf80Smarks {
294*ecd6cf80Smarks 	int error;
295*ecd6cf80Smarks 
296*ecd6cf80Smarks 	error = zfs_dozonecheck(zc->zc_name, cr);
297*ecd6cf80Smarks 	if (error)
298fa9e4066Sahrens 		return (error);
299fa9e4066Sahrens 
300*ecd6cf80Smarks 	/*
301*ecd6cf80Smarks 	 * permission to set permissions will be evaluated later in
302*ecd6cf80Smarks 	 * dsl_deleg_can_allow()
303*ecd6cf80Smarks 	 */
304*ecd6cf80Smarks 	return (0);
305*ecd6cf80Smarks }
306*ecd6cf80Smarks 
307*ecd6cf80Smarks int
308*ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr)
309*ecd6cf80Smarks {
310*ecd6cf80Smarks 	int error;
311*ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(zc->zc_name,
312*ecd6cf80Smarks 	    ZFS_DELEG_PERM_ROLLBACK, cr);
313*ecd6cf80Smarks 	if (error == 0)
314*ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(zc->zc_name,
315*ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr);
316*ecd6cf80Smarks 	return (error);
317*ecd6cf80Smarks }
318*ecd6cf80Smarks 
319*ecd6cf80Smarks int
320*ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr)
321*ecd6cf80Smarks {
322*ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(zc->zc_name,
323*ecd6cf80Smarks 	    ZFS_DELEG_PERM_SEND, cr));
324*ecd6cf80Smarks }
325*ecd6cf80Smarks 
326*ecd6cf80Smarks int
327*ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr)
328*ecd6cf80Smarks {
329*ecd6cf80Smarks 	if (!INGLOBALZONE(curproc))
330*ecd6cf80Smarks 		return (EPERM);
331*ecd6cf80Smarks 
332*ecd6cf80Smarks 	if (secpolicy_nfs(CRED()) == 0) {
333*ecd6cf80Smarks 		return (0);
334*ecd6cf80Smarks 	} else {
335*ecd6cf80Smarks 		vnode_t *vp;
336*ecd6cf80Smarks 		int error;
337*ecd6cf80Smarks 
338*ecd6cf80Smarks 		if ((error = lookupname(zc->zc_value, UIO_SYSSPACE,
339*ecd6cf80Smarks 		    NO_FOLLOW, NULL, &vp)) != 0)
340*ecd6cf80Smarks 			return (error);
341*ecd6cf80Smarks 
342*ecd6cf80Smarks 		/* Now make sure mntpnt and dataset are ZFS */
343*ecd6cf80Smarks 
344*ecd6cf80Smarks 		if (vp->v_vfsp->vfs_fstype != zfsfstype ||
345*ecd6cf80Smarks 		    (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource),
346*ecd6cf80Smarks 		    zc->zc_name) != 0)) {
347*ecd6cf80Smarks 			VN_RELE(vp);
348*ecd6cf80Smarks 			return (EPERM);
349*ecd6cf80Smarks 		}
350*ecd6cf80Smarks 
351*ecd6cf80Smarks 		VN_RELE(vp);
352*ecd6cf80Smarks 		return (dsl_deleg_access(zc->zc_name,
353*ecd6cf80Smarks 		    ZFS_DELEG_PERM_SHARE, cr));
354*ecd6cf80Smarks 	}
355fa9e4066Sahrens }
356fa9e4066Sahrens 
357fa9e4066Sahrens static int
358*ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize)
359fa9e4066Sahrens {
360fa9e4066Sahrens 	char *cp;
361fa9e4066Sahrens 
362fa9e4066Sahrens 	/*
363fa9e4066Sahrens 	 * Remove the @bla or /bla from the end of the name to get the parent.
364fa9e4066Sahrens 	 */
365*ecd6cf80Smarks 	(void) strncpy(parent, datasetname, parentsize);
366*ecd6cf80Smarks 	cp = strrchr(parent, '@');
367fa9e4066Sahrens 	if (cp != NULL) {
368fa9e4066Sahrens 		cp[0] = '\0';
369fa9e4066Sahrens 	} else {
370*ecd6cf80Smarks 		cp = strrchr(parent, '/');
371fa9e4066Sahrens 		if (cp == NULL)
372fa9e4066Sahrens 			return (ENOENT);
373fa9e4066Sahrens 		cp[0] = '\0';
374*ecd6cf80Smarks 	}
375*ecd6cf80Smarks 
376*ecd6cf80Smarks 	return (0);
377*ecd6cf80Smarks }
378*ecd6cf80Smarks 
379*ecd6cf80Smarks int
380*ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr)
381*ecd6cf80Smarks {
382*ecd6cf80Smarks 	int error;
383*ecd6cf80Smarks 
384*ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(name,
385*ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
386*ecd6cf80Smarks 		return (error);
387*ecd6cf80Smarks 
388*ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr));
389*ecd6cf80Smarks }
390*ecd6cf80Smarks 
391*ecd6cf80Smarks static int
392*ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr)
393*ecd6cf80Smarks {
394*ecd6cf80Smarks 	return (zfs_secpolicy_destroy_perms(zc->zc_name, cr));
395*ecd6cf80Smarks }
396*ecd6cf80Smarks 
397*ecd6cf80Smarks /*
398*ecd6cf80Smarks  * Must have sys_config privilege to check the iscsi permission
399*ecd6cf80Smarks  */
400*ecd6cf80Smarks /* ARGSUSED */
401*ecd6cf80Smarks static int
402*ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr)
403*ecd6cf80Smarks {
404*ecd6cf80Smarks 	return (secpolicy_zfs(cr));
405*ecd6cf80Smarks }
406*ecd6cf80Smarks 
407*ecd6cf80Smarks int
408*ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
409*ecd6cf80Smarks {
410*ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
411*ecd6cf80Smarks 	int	error;
412*ecd6cf80Smarks 
413*ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(from,
414*ecd6cf80Smarks 	    ZFS_DELEG_PERM_RENAME, cr)) != 0)
415*ecd6cf80Smarks 		return (error);
416*ecd6cf80Smarks 
417*ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(from,
418*ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
419*ecd6cf80Smarks 		return (error);
420*ecd6cf80Smarks 
421*ecd6cf80Smarks 	if ((error = zfs_get_parent(to, parentname,
422*ecd6cf80Smarks 	    sizeof (parentname))) != 0)
423*ecd6cf80Smarks 		return (error);
424*ecd6cf80Smarks 
425*ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
426*ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr)) != 0)
427*ecd6cf80Smarks 		return (error);
428*ecd6cf80Smarks 
429*ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
430*ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
431*ecd6cf80Smarks 		return (error);
432*ecd6cf80Smarks 
433*ecd6cf80Smarks 	return (error);
434*ecd6cf80Smarks }
435*ecd6cf80Smarks 
436*ecd6cf80Smarks static int
437*ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr)
438*ecd6cf80Smarks {
439*ecd6cf80Smarks 	return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr));
440*ecd6cf80Smarks }
441*ecd6cf80Smarks 
442*ecd6cf80Smarks static int
443*ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr)
444*ecd6cf80Smarks {
445*ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
446*ecd6cf80Smarks 	objset_t *clone;
447*ecd6cf80Smarks 	int error;
448*ecd6cf80Smarks 
449*ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(zc->zc_name,
450*ecd6cf80Smarks 	    ZFS_DELEG_PERM_PROMOTE, cr);
451*ecd6cf80Smarks 	if (error)
452*ecd6cf80Smarks 		return (error);
453*ecd6cf80Smarks 
454*ecd6cf80Smarks 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
455*ecd6cf80Smarks 	    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
456*ecd6cf80Smarks 
457*ecd6cf80Smarks 	if (error == 0) {
458*ecd6cf80Smarks 		dsl_dataset_t *pclone = NULL;
459*ecd6cf80Smarks 		dsl_dir_t *dd;
460*ecd6cf80Smarks 		dd = clone->os->os_dsl_dataset->ds_dir;
461*ecd6cf80Smarks 
462*ecd6cf80Smarks 		rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
463*ecd6cf80Smarks 		error = dsl_dataset_open_obj(dd->dd_pool,
464*ecd6cf80Smarks 		    dd->dd_phys->dd_clone_parent_obj, NULL,
465*ecd6cf80Smarks 		    DS_MODE_NONE, FTAG, &pclone);
466*ecd6cf80Smarks 		rw_exit(&dd->dd_pool->dp_config_rwlock);
467*ecd6cf80Smarks 		if (error) {
468*ecd6cf80Smarks 			dmu_objset_close(clone);
469*ecd6cf80Smarks 			return (error);
470*ecd6cf80Smarks 		}
471*ecd6cf80Smarks 
472*ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(zc->zc_name,
473*ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr);
474*ecd6cf80Smarks 
475*ecd6cf80Smarks 		dsl_dataset_name(pclone, parentname);
476*ecd6cf80Smarks 		dmu_objset_close(clone);
477*ecd6cf80Smarks 		dsl_dataset_close(pclone, DS_MODE_NONE, FTAG);
478*ecd6cf80Smarks 		if (error == 0)
479*ecd6cf80Smarks 			error = zfs_secpolicy_write_perms(parentname,
480*ecd6cf80Smarks 			    ZFS_DELEG_PERM_PROMOTE, cr);
481*ecd6cf80Smarks 	}
482*ecd6cf80Smarks 	return (error);
483*ecd6cf80Smarks }
484*ecd6cf80Smarks 
485*ecd6cf80Smarks static int
486*ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr)
487*ecd6cf80Smarks {
488*ecd6cf80Smarks 	int error;
489*ecd6cf80Smarks 
490*ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(zc->zc_name,
491*ecd6cf80Smarks 	    ZFS_DELEG_PERM_RECEIVE, cr)) != 0)
492*ecd6cf80Smarks 		return (error);
493*ecd6cf80Smarks 
494*ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(zc->zc_name,
495*ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
496*ecd6cf80Smarks 		return (error);
497*ecd6cf80Smarks 
498*ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(zc->zc_name,
499*ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr));
500*ecd6cf80Smarks }
501*ecd6cf80Smarks 
502*ecd6cf80Smarks int
503*ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
504*ecd6cf80Smarks {
505*ecd6cf80Smarks 	int error;
506*ecd6cf80Smarks 
507*ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(name,
508*ecd6cf80Smarks 	    ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0)
509*ecd6cf80Smarks 		return (error);
510*ecd6cf80Smarks 
511*ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(name,
512*ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr);
513*ecd6cf80Smarks 
514*ecd6cf80Smarks 	return (error);
515*ecd6cf80Smarks }
516*ecd6cf80Smarks 
517*ecd6cf80Smarks static int
518*ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr)
519*ecd6cf80Smarks {
520*ecd6cf80Smarks 
521*ecd6cf80Smarks 	return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr));
522*ecd6cf80Smarks }
523*ecd6cf80Smarks 
524*ecd6cf80Smarks 
525*ecd6cf80Smarks 
526*ecd6cf80Smarks static int
527*ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr)
528*ecd6cf80Smarks {
529*ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
530*ecd6cf80Smarks 	int 	error;
531*ecd6cf80Smarks 
532*ecd6cf80Smarks 	if ((error = zfs_get_parent(zc->zc_name, parentname,
533*ecd6cf80Smarks 	    sizeof (parentname))) != 0)
534*ecd6cf80Smarks 		return (error);
535fa9e4066Sahrens 
536*ecd6cf80Smarks 	if (zc->zc_value[0] != '\0') {
537*ecd6cf80Smarks 		if ((error = zfs_secpolicy_write_perms(zc->zc_value,
538*ecd6cf80Smarks 		    ZFS_DELEG_PERM_CLONE, cr)) != 0)
539*ecd6cf80Smarks 			return (error);
540fa9e4066Sahrens 	}
541fa9e4066Sahrens 
542*ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
543*ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr)) != 0)
544*ecd6cf80Smarks 		return (error);
545*ecd6cf80Smarks 
546*ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(parentname,
547*ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr);
548*ecd6cf80Smarks 
549*ecd6cf80Smarks 	return (error);
550*ecd6cf80Smarks }
551*ecd6cf80Smarks 
552*ecd6cf80Smarks static int
553*ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr)
554*ecd6cf80Smarks {
555*ecd6cf80Smarks 	int error;
556*ecd6cf80Smarks 
557*ecd6cf80Smarks 	error = secpolicy_fs_unmount(cr, NULL);
558*ecd6cf80Smarks 	if (error) {
559*ecd6cf80Smarks 		error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr);
560*ecd6cf80Smarks 	}
561*ecd6cf80Smarks 	return (error);
562fa9e4066Sahrens }
563fa9e4066Sahrens 
564fa9e4066Sahrens /*
565fa9e4066Sahrens  * Policy for pool operations - create/destroy pools, add vdevs, etc.  Requires
566fa9e4066Sahrens  * SYS_CONFIG privilege, which is not available in a local zone.
567fa9e4066Sahrens  */
568fa9e4066Sahrens /* ARGSUSED */
569fa9e4066Sahrens static int
570*ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr)
571fa9e4066Sahrens {
572fa9e4066Sahrens 	if (secpolicy_sys_config(cr, B_FALSE) != 0)
573fa9e4066Sahrens 		return (EPERM);
574fa9e4066Sahrens 
575fa9e4066Sahrens 	return (0);
576fa9e4066Sahrens }
577fa9e4066Sahrens 
578*ecd6cf80Smarks /*
579*ecd6cf80Smarks  * Just like zfs_secpolicy_config, except that we will check for
580*ecd6cf80Smarks  * mount permission on the dataset for permission to create/remove
581*ecd6cf80Smarks  * the minor nodes.
582*ecd6cf80Smarks  */
583*ecd6cf80Smarks static int
584*ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr)
585*ecd6cf80Smarks {
586*ecd6cf80Smarks 	if (secpolicy_sys_config(cr, B_FALSE) != 0) {
587*ecd6cf80Smarks 		return (dsl_deleg_access(zc->zc_name,
588*ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr));
589*ecd6cf80Smarks 	}
590*ecd6cf80Smarks 
591*ecd6cf80Smarks 	return (0);
592*ecd6cf80Smarks }
593*ecd6cf80Smarks 
594ea8dc4b6Seschrock /*
595ea8dc4b6Seschrock  * Policy for fault injection.  Requires all privileges.
596ea8dc4b6Seschrock  */
597ea8dc4b6Seschrock /* ARGSUSED */
598ea8dc4b6Seschrock static int
599*ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr)
600ea8dc4b6Seschrock {
601ea8dc4b6Seschrock 	return (secpolicy_zinject(cr));
602ea8dc4b6Seschrock }
603ea8dc4b6Seschrock 
604fa9e4066Sahrens /*
605fa9e4066Sahrens  * Returns the nvlist as specified by the user in the zfs_cmd_t.
606fa9e4066Sahrens  */
607fa9e4066Sahrens static int
608e9dbad6fSeschrock get_nvlist(zfs_cmd_t *zc, nvlist_t **nvp)
609fa9e4066Sahrens {
610fa9e4066Sahrens 	char *packed;
611fa9e4066Sahrens 	size_t size;
612fa9e4066Sahrens 	int error;
613fa9e4066Sahrens 	nvlist_t *config = NULL;
614fa9e4066Sahrens 
615fa9e4066Sahrens 	/*
616e9dbad6fSeschrock 	 * Read in and unpack the user-supplied nvlist.
617fa9e4066Sahrens 	 */
618e9dbad6fSeschrock 	if ((size = zc->zc_nvlist_src_size) == 0)
619fa9e4066Sahrens 		return (EINVAL);
620fa9e4066Sahrens 
621fa9e4066Sahrens 	packed = kmem_alloc(size, KM_SLEEP);
622fa9e4066Sahrens 
623e9dbad6fSeschrock 	if ((error = xcopyin((void *)(uintptr_t)zc->zc_nvlist_src, packed,
624fa9e4066Sahrens 	    size)) != 0) {
625fa9e4066Sahrens 		kmem_free(packed, size);
626fa9e4066Sahrens 		return (error);
627fa9e4066Sahrens 	}
628fa9e4066Sahrens 
629fa9e4066Sahrens 	if ((error = nvlist_unpack(packed, size, &config, 0)) != 0) {
630fa9e4066Sahrens 		kmem_free(packed, size);
631fa9e4066Sahrens 		return (error);
632fa9e4066Sahrens 	}
633fa9e4066Sahrens 
634fa9e4066Sahrens 	kmem_free(packed, size);
635fa9e4066Sahrens 
636fa9e4066Sahrens 	*nvp = config;
637fa9e4066Sahrens 	return (0);
638fa9e4066Sahrens }
639fa9e4066Sahrens 
640e9dbad6fSeschrock static int
641e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
642e9dbad6fSeschrock {
643e9dbad6fSeschrock 	char *packed = NULL;
644e9dbad6fSeschrock 	size_t size;
645e9dbad6fSeschrock 	int error;
646e9dbad6fSeschrock 
647e9dbad6fSeschrock 	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
648e9dbad6fSeschrock 
649e9dbad6fSeschrock 	if (size > zc->zc_nvlist_dst_size) {
650e9dbad6fSeschrock 		error = ENOMEM;
651e9dbad6fSeschrock 	} else {
652e9dbad6fSeschrock 		VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
653e9dbad6fSeschrock 		    KM_SLEEP) == 0);
654e9dbad6fSeschrock 		error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst,
655e9dbad6fSeschrock 		    size);
656e9dbad6fSeschrock 		kmem_free(packed, size);
657e9dbad6fSeschrock 	}
658e9dbad6fSeschrock 
659e9dbad6fSeschrock 	zc->zc_nvlist_dst_size = size;
660e9dbad6fSeschrock 	return (error);
661e9dbad6fSeschrock }
662e9dbad6fSeschrock 
663fa9e4066Sahrens static int
664fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc)
665fa9e4066Sahrens {
666fa9e4066Sahrens 	int error;
667fa9e4066Sahrens 	nvlist_t *config;
668fa9e4066Sahrens 
669e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) != 0)
670fa9e4066Sahrens 		return (error);
671fa9e4066Sahrens 
672e9dbad6fSeschrock 	error = spa_create(zc->zc_name, config, zc->zc_value[0] == '\0' ?
673e9dbad6fSeschrock 	    NULL : zc->zc_value);
674fa9e4066Sahrens 
675fa9e4066Sahrens 	nvlist_free(config);
676fa9e4066Sahrens 
677fa9e4066Sahrens 	return (error);
678fa9e4066Sahrens }
679fa9e4066Sahrens 
680fa9e4066Sahrens static int
681fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc)
682fa9e4066Sahrens {
683*ecd6cf80Smarks 	int error;
684*ecd6cf80Smarks 	zfs_log_history(zc);
685*ecd6cf80Smarks 	error = spa_destroy(zc->zc_name);
686*ecd6cf80Smarks 	return (error);
687fa9e4066Sahrens }
688fa9e4066Sahrens 
689fa9e4066Sahrens static int
690fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc)
691fa9e4066Sahrens {
692fa9e4066Sahrens 	int error;
693fa9e4066Sahrens 	nvlist_t *config;
694fa9e4066Sahrens 	uint64_t guid;
695fa9e4066Sahrens 
696e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) != 0)
697fa9e4066Sahrens 		return (error);
698fa9e4066Sahrens 
699fa9e4066Sahrens 	if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
700ea8dc4b6Seschrock 	    guid != zc->zc_guid)
701fa9e4066Sahrens 		error = EINVAL;
702fa9e4066Sahrens 	else
703fa9e4066Sahrens 		error = spa_import(zc->zc_name, config,
704e9dbad6fSeschrock 		    zc->zc_value[0] == '\0' ? NULL : zc->zc_value);
705fa9e4066Sahrens 
706fa9e4066Sahrens 	nvlist_free(config);
707fa9e4066Sahrens 
708fa9e4066Sahrens 	return (error);
709fa9e4066Sahrens }
710fa9e4066Sahrens 
711fa9e4066Sahrens static int
712fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc)
713fa9e4066Sahrens {
714*ecd6cf80Smarks 	int error;
715*ecd6cf80Smarks 	zfs_log_history(zc);
716*ecd6cf80Smarks 	error = spa_export(zc->zc_name, NULL);
717*ecd6cf80Smarks 	return (error);
718fa9e4066Sahrens }
719fa9e4066Sahrens 
720fa9e4066Sahrens static int
721fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc)
722fa9e4066Sahrens {
723fa9e4066Sahrens 	nvlist_t *configs;
724fa9e4066Sahrens 	int error;
725fa9e4066Sahrens 
726fa9e4066Sahrens 	if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
727fa9e4066Sahrens 		return (EEXIST);
728fa9e4066Sahrens 
729e9dbad6fSeschrock 	error = put_nvlist(zc, configs);
730fa9e4066Sahrens 
731fa9e4066Sahrens 	nvlist_free(configs);
732fa9e4066Sahrens 
733fa9e4066Sahrens 	return (error);
734fa9e4066Sahrens }
735fa9e4066Sahrens 
736fa9e4066Sahrens static int
737fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc)
738fa9e4066Sahrens {
739fa9e4066Sahrens 	nvlist_t *config;
740fa9e4066Sahrens 	int error;
741ea8dc4b6Seschrock 	int ret = 0;
742fa9e4066Sahrens 
743e9dbad6fSeschrock 	error = spa_get_stats(zc->zc_name, &config, zc->zc_value,
744e9dbad6fSeschrock 	    sizeof (zc->zc_value));
745fa9e4066Sahrens 
746fa9e4066Sahrens 	if (config != NULL) {
747e9dbad6fSeschrock 		ret = put_nvlist(zc, config);
748fa9e4066Sahrens 		nvlist_free(config);
749ea8dc4b6Seschrock 
750ea8dc4b6Seschrock 		/*
751ea8dc4b6Seschrock 		 * The config may be present even if 'error' is non-zero.
752ea8dc4b6Seschrock 		 * In this case we return success, and preserve the real errno
753ea8dc4b6Seschrock 		 * in 'zc_cookie'.
754ea8dc4b6Seschrock 		 */
755ea8dc4b6Seschrock 		zc->zc_cookie = error;
756fa9e4066Sahrens 	} else {
757ea8dc4b6Seschrock 		ret = error;
758fa9e4066Sahrens 	}
759fa9e4066Sahrens 
760ea8dc4b6Seschrock 	return (ret);
761fa9e4066Sahrens }
762fa9e4066Sahrens 
763fa9e4066Sahrens /*
764fa9e4066Sahrens  * Try to import the given pool, returning pool stats as appropriate so that
765fa9e4066Sahrens  * user land knows which devices are available and overall pool health.
766fa9e4066Sahrens  */
767fa9e4066Sahrens static int
768fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
769fa9e4066Sahrens {
770fa9e4066Sahrens 	nvlist_t *tryconfig, *config;
771fa9e4066Sahrens 	int error;
772fa9e4066Sahrens 
773e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &tryconfig)) != 0)
774fa9e4066Sahrens 		return (error);
775fa9e4066Sahrens 
776fa9e4066Sahrens 	config = spa_tryimport(tryconfig);
777fa9e4066Sahrens 
778fa9e4066Sahrens 	nvlist_free(tryconfig);
779fa9e4066Sahrens 
780fa9e4066Sahrens 	if (config == NULL)
781fa9e4066Sahrens 		return (EINVAL);
782fa9e4066Sahrens 
783e9dbad6fSeschrock 	error = put_nvlist(zc, config);
784fa9e4066Sahrens 	nvlist_free(config);
785fa9e4066Sahrens 
786fa9e4066Sahrens 	return (error);
787fa9e4066Sahrens }
788fa9e4066Sahrens 
789fa9e4066Sahrens static int
790fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc)
791fa9e4066Sahrens {
792fa9e4066Sahrens 	spa_t *spa;
793fa9e4066Sahrens 	int error;
794fa9e4066Sahrens 
79506eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
79606eeb2adSek 		return (error);
79706eeb2adSek 
7983d7072f8Seschrock 	spa_config_enter(spa, RW_READER, FTAG);
79906eeb2adSek 	error = spa_scrub(spa, zc->zc_cookie, B_FALSE);
8003d7072f8Seschrock 	spa_config_exit(spa, FTAG);
80106eeb2adSek 
80206eeb2adSek 	spa_close(spa, FTAG);
80306eeb2adSek 
804fa9e4066Sahrens 	return (error);
805fa9e4066Sahrens }
806fa9e4066Sahrens 
807fa9e4066Sahrens static int
808fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc)
809fa9e4066Sahrens {
810fa9e4066Sahrens 	spa_t *spa;
811fa9e4066Sahrens 	int error;
812fa9e4066Sahrens 
813fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
814fa9e4066Sahrens 	if (error == 0) {
815fa9e4066Sahrens 		spa_freeze(spa);
816fa9e4066Sahrens 		spa_close(spa, FTAG);
817fa9e4066Sahrens 	}
818fa9e4066Sahrens 	return (error);
819fa9e4066Sahrens }
820fa9e4066Sahrens 
821eaca9bbdSeschrock static int
822eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc)
823eaca9bbdSeschrock {
824eaca9bbdSeschrock 	spa_t *spa;
825eaca9bbdSeschrock 	int error;
826eaca9bbdSeschrock 
82706eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
82806eeb2adSek 		return (error);
82906eeb2adSek 
83006eeb2adSek 	spa_upgrade(spa);
83106eeb2adSek 	spa_close(spa, FTAG);
83206eeb2adSek 
83306eeb2adSek 	return (error);
83406eeb2adSek }
83506eeb2adSek 
83606eeb2adSek static int
83706eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc)
83806eeb2adSek {
83906eeb2adSek 	spa_t *spa;
84006eeb2adSek 	char *hist_buf;
84106eeb2adSek 	uint64_t size;
84206eeb2adSek 	int error;
84306eeb2adSek 
84406eeb2adSek 	if ((size = zc->zc_history_len) == 0)
84506eeb2adSek 		return (EINVAL);
84606eeb2adSek 
84706eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
84806eeb2adSek 		return (error);
84906eeb2adSek 
850d7306b64Sek 	if (spa_version(spa) < ZFS_VERSION_ZPOOL_HISTORY) {
851d7306b64Sek 		spa_close(spa, FTAG);
852d7306b64Sek 		return (ENOTSUP);
853d7306b64Sek 	}
854d7306b64Sek 
85506eeb2adSek 	hist_buf = kmem_alloc(size, KM_SLEEP);
85606eeb2adSek 	if ((error = spa_history_get(spa, &zc->zc_history_offset,
85706eeb2adSek 	    &zc->zc_history_len, hist_buf)) == 0) {
858*ecd6cf80Smarks 		error = xcopyout(hist_buf,
859*ecd6cf80Smarks 		    (char *)(uintptr_t)zc->zc_history,
86006eeb2adSek 		    zc->zc_history_len);
86106eeb2adSek 	}
86206eeb2adSek 
86306eeb2adSek 	spa_close(spa, FTAG);
86406eeb2adSek 	kmem_free(hist_buf, size);
86506eeb2adSek 	return (error);
86606eeb2adSek }
86706eeb2adSek 
86855434c77Sek static int
86955434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc)
87055434c77Sek {
87155434c77Sek 	int error;
87255434c77Sek 
873b1b8ab34Slling 	if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value))
87455434c77Sek 		return (error);
87555434c77Sek 
87655434c77Sek 	return (0);
87755434c77Sek }
87855434c77Sek 
87955434c77Sek static int
88055434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc)
88155434c77Sek {
88255434c77Sek 	objset_t *osp;
88355434c77Sek 	int error;
88455434c77Sek 
88555434c77Sek 	if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS,
88655434c77Sek 	    DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0)
88755434c77Sek 		return (error);
88855434c77Sek 
88955434c77Sek 	error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value,
89055434c77Sek 	    sizeof (zc->zc_value));
89155434c77Sek 	dmu_objset_close(osp);
89255434c77Sek 
89355434c77Sek 	return (error);
89455434c77Sek }
89555434c77Sek 
896fa9e4066Sahrens static int
897fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc)
898fa9e4066Sahrens {
899fa9e4066Sahrens 	spa_t *spa;
900fa9e4066Sahrens 	int error;
901fa9e4066Sahrens 	nvlist_t *config;
902fa9e4066Sahrens 
903fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
904fa9e4066Sahrens 	if (error != 0)
905fa9e4066Sahrens 		return (error);
906fa9e4066Sahrens 
907b1b8ab34Slling 	/*
908b1b8ab34Slling 	 * A root pool with concatenated devices is not supported.
909b1b8ab34Slling 	 * Thus, can not add a device to a root pool with one device.
910b1b8ab34Slling 	 */
911b1b8ab34Slling 	if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) {
912b1b8ab34Slling 		spa_close(spa, FTAG);
913b1b8ab34Slling 		return (EDOM);
914b1b8ab34Slling 	}
915b1b8ab34Slling 
916e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) == 0) {
917fa9e4066Sahrens 		error = spa_vdev_add(spa, config);
918fa9e4066Sahrens 		nvlist_free(config);
919fa9e4066Sahrens 	}
920fa9e4066Sahrens 	spa_close(spa, FTAG);
921fa9e4066Sahrens 	return (error);
922fa9e4066Sahrens }
923fa9e4066Sahrens 
924fa9e4066Sahrens static int
925fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc)
926fa9e4066Sahrens {
92799653d4eSeschrock 	spa_t *spa;
92899653d4eSeschrock 	int error;
92999653d4eSeschrock 
93099653d4eSeschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
93199653d4eSeschrock 	if (error != 0)
93299653d4eSeschrock 		return (error);
93399653d4eSeschrock 	error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE);
93499653d4eSeschrock 	spa_close(spa, FTAG);
93599653d4eSeschrock 	return (error);
936fa9e4066Sahrens }
937fa9e4066Sahrens 
938fa9e4066Sahrens static int
9393d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc)
940fa9e4066Sahrens {
941fa9e4066Sahrens 	spa_t *spa;
942fa9e4066Sahrens 	int error;
9433d7072f8Seschrock 	vdev_state_t newstate = VDEV_STATE_UNKNOWN;
944fa9e4066Sahrens 
94506eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
946fa9e4066Sahrens 		return (error);
9473d7072f8Seschrock 	switch (zc->zc_cookie) {
9483d7072f8Seschrock 	case VDEV_STATE_ONLINE:
9493d7072f8Seschrock 		error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate);
9503d7072f8Seschrock 		break;
951fa9e4066Sahrens 
9523d7072f8Seschrock 	case VDEV_STATE_OFFLINE:
9533d7072f8Seschrock 		error = vdev_offline(spa, zc->zc_guid, zc->zc_obj);
9543d7072f8Seschrock 		break;
955fa9e4066Sahrens 
9563d7072f8Seschrock 	case VDEV_STATE_FAULTED:
9573d7072f8Seschrock 		error = vdev_fault(spa, zc->zc_guid);
9583d7072f8Seschrock 		break;
9593d7072f8Seschrock 
9603d7072f8Seschrock 	case VDEV_STATE_DEGRADED:
9613d7072f8Seschrock 		error = vdev_degrade(spa, zc->zc_guid);
9623d7072f8Seschrock 		break;
9633d7072f8Seschrock 
9643d7072f8Seschrock 	default:
9653d7072f8Seschrock 		error = EINVAL;
9663d7072f8Seschrock 	}
9673d7072f8Seschrock 	zc->zc_cookie = newstate;
968fa9e4066Sahrens 	spa_close(spa, FTAG);
969fa9e4066Sahrens 	return (error);
970fa9e4066Sahrens }
971fa9e4066Sahrens 
972fa9e4066Sahrens static int
973fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc)
974fa9e4066Sahrens {
975fa9e4066Sahrens 	spa_t *spa;
976fa9e4066Sahrens 	int replacing = zc->zc_cookie;
977fa9e4066Sahrens 	nvlist_t *config;
978fa9e4066Sahrens 	int error;
979fa9e4066Sahrens 
98006eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
981fa9e4066Sahrens 		return (error);
982fa9e4066Sahrens 
983e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) == 0) {
984ea8dc4b6Seschrock 		error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
985fa9e4066Sahrens 		nvlist_free(config);
986fa9e4066Sahrens 	}
987fa9e4066Sahrens 
988fa9e4066Sahrens 	spa_close(spa, FTAG);
989fa9e4066Sahrens 	return (error);
990fa9e4066Sahrens }
991fa9e4066Sahrens 
992fa9e4066Sahrens static int
993fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc)
994fa9e4066Sahrens {
995fa9e4066Sahrens 	spa_t *spa;
996fa9e4066Sahrens 	int error;
997fa9e4066Sahrens 
99806eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
999fa9e4066Sahrens 		return (error);
1000fa9e4066Sahrens 
1001ea8dc4b6Seschrock 	error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE);
1002fa9e4066Sahrens 
1003fa9e4066Sahrens 	spa_close(spa, FTAG);
1004fa9e4066Sahrens 	return (error);
1005fa9e4066Sahrens }
1006fa9e4066Sahrens 
1007c67d9675Seschrock static int
1008c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
1009c67d9675Seschrock {
1010c67d9675Seschrock 	spa_t *spa;
1011e9dbad6fSeschrock 	char *path = zc->zc_value;
1012ea8dc4b6Seschrock 	uint64_t guid = zc->zc_guid;
1013c67d9675Seschrock 	int error;
1014c67d9675Seschrock 
1015c67d9675Seschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
1016c67d9675Seschrock 	if (error != 0)
1017c67d9675Seschrock 		return (error);
1018c67d9675Seschrock 
1019c67d9675Seschrock 	error = spa_vdev_setpath(spa, guid, path);
1020c67d9675Seschrock 	spa_close(spa, FTAG);
1021c67d9675Seschrock 	return (error);
1022c67d9675Seschrock }
1023c67d9675Seschrock 
1024fa9e4066Sahrens static int
1025fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc)
1026fa9e4066Sahrens {
1027fa9e4066Sahrens 	objset_t *os = NULL;
1028fa9e4066Sahrens 	int error;
10297f7322feSeschrock 	nvlist_t *nv;
1030fa9e4066Sahrens 
1031fa9e4066Sahrens retry:
1032fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1033fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
1034fa9e4066Sahrens 	if (error != 0) {
1035fa9e4066Sahrens 		/*
1036fa9e4066Sahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
1037fa9e4066Sahrens 		 * the objset is held exclusively. Fortunately this hold is
1038fa9e4066Sahrens 		 * only for a short while, so we retry here.
1039fa9e4066Sahrens 		 * This avoids user code having to handle EBUSY,
1040fa9e4066Sahrens 		 * for example for a "zfs list".
1041fa9e4066Sahrens 		 */
1042fa9e4066Sahrens 		if (error == EBUSY) {
1043fa9e4066Sahrens 			delay(1);
1044fa9e4066Sahrens 			goto retry;
1045fa9e4066Sahrens 		}
1046fa9e4066Sahrens 		return (error);
1047fa9e4066Sahrens 	}
1048fa9e4066Sahrens 
1049a2eea2e1Sahrens 	dmu_objset_fast_stat(os, &zc->zc_objset_stats);
1050fa9e4066Sahrens 
10515ad82045Snd 	if (zc->zc_nvlist_dst != 0 &&
10527f7322feSeschrock 	    (error = dsl_prop_get_all(os, &nv)) == 0) {
1053a2eea2e1Sahrens 		dmu_objset_stats(os, nv);
1054432f72fdSahrens 		/*
1055432f72fdSahrens 		 * NB: zvol_get_stats() will read the objset contents,
1056432f72fdSahrens 		 * which we aren't supposed to do with a
1057432f72fdSahrens 		 * DS_MODE_STANDARD open, because it could be
1058432f72fdSahrens 		 * inconsistent.  So this is a bit of a workaround...
1059432f72fdSahrens 		 */
1060432f72fdSahrens 		if (!zc->zc_objset_stats.dds_inconsistent &&
1061432f72fdSahrens 		    dmu_objset_type(os) == DMU_OST_ZVOL)
1062a2eea2e1Sahrens 			VERIFY(zvol_get_stats(os, nv) == 0);
1063e9dbad6fSeschrock 		error = put_nvlist(zc, nv);
10647f7322feSeschrock 		nvlist_free(nv);
10657f7322feSeschrock 	}
1066fa9e4066Sahrens 
1067e9dbad6fSeschrock 	spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value));
1068ea8dc4b6Seschrock 
1069fa9e4066Sahrens 	dmu_objset_close(os);
1070fa9e4066Sahrens 	return (error);
1071fa9e4066Sahrens }
1072fa9e4066Sahrens 
1073fa9e4066Sahrens static int
1074fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc)
1075fa9e4066Sahrens {
107687e5029aSahrens 	objset_t *os;
1077fa9e4066Sahrens 	int error;
1078fa9e4066Sahrens 	char *p;
1079fa9e4066Sahrens 
108087e5029aSahrens retry:
108187e5029aSahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
108287e5029aSahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
108387e5029aSahrens 	if (error != 0) {
108487e5029aSahrens 		/*
108587e5029aSahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
108687e5029aSahrens 		 * the objset is held exclusively. Fortunately this hold is
108787e5029aSahrens 		 * only for a short while, so we retry here.
108887e5029aSahrens 		 * This avoids user code having to handle EBUSY,
108987e5029aSahrens 		 * for example for a "zfs list".
109087e5029aSahrens 		 */
109187e5029aSahrens 		if (error == EBUSY) {
109287e5029aSahrens 			delay(1);
109387e5029aSahrens 			goto retry;
109487e5029aSahrens 		}
109587e5029aSahrens 		if (error == ENOENT)
109687e5029aSahrens 			error = ESRCH;
109787e5029aSahrens 		return (error);
1098fa9e4066Sahrens 	}
1099fa9e4066Sahrens 
1100fa9e4066Sahrens 	p = strrchr(zc->zc_name, '/');
1101fa9e4066Sahrens 	if (p == NULL || p[1] != '\0')
1102fa9e4066Sahrens 		(void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name));
1103fa9e4066Sahrens 	p = zc->zc_name + strlen(zc->zc_name);
1104fa9e4066Sahrens 
1105fa9e4066Sahrens 	do {
110687e5029aSahrens 		error = dmu_dir_list_next(os,
110787e5029aSahrens 		    sizeof (zc->zc_name) - (p - zc->zc_name), p,
110887e5029aSahrens 		    NULL, &zc->zc_cookie);
1109fa9e4066Sahrens 		if (error == ENOENT)
1110fa9e4066Sahrens 			error = ESRCH;
111187e5029aSahrens 	} while (error == 0 && !INGLOBALZONE(curproc) &&
1112fa9e4066Sahrens 	    !zone_dataset_visible(zc->zc_name, NULL));
1113fa9e4066Sahrens 
1114fa9e4066Sahrens 	/*
111587e5029aSahrens 	 * If it's a hidden dataset (ie. with a '$' in its name), don't
111687e5029aSahrens 	 * try to get stats for it.  Userland will skip over it.
1117fa9e4066Sahrens 	 */
111887e5029aSahrens 	if (error == 0 && strchr(zc->zc_name, '$') == NULL)
111987e5029aSahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
1120fa9e4066Sahrens 
112187e5029aSahrens 	dmu_objset_close(os);
1122fa9e4066Sahrens 	return (error);
1123fa9e4066Sahrens }
1124fa9e4066Sahrens 
1125fa9e4066Sahrens static int
1126fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
1127fa9e4066Sahrens {
112887e5029aSahrens 	objset_t *os;
1129fa9e4066Sahrens 	int error;
1130fa9e4066Sahrens 
1131fa9e4066Sahrens retry:
113287e5029aSahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
113387e5029aSahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
113487e5029aSahrens 	if (error != 0) {
1135fa9e4066Sahrens 		/*
113687e5029aSahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
1137fa9e4066Sahrens 		 * the objset is held exclusively. Fortunately this hold is
1138fa9e4066Sahrens 		 * only for a short while, so we retry here.
1139fa9e4066Sahrens 		 * This avoids user code having to handle EBUSY,
114087e5029aSahrens 		 * for example for a "zfs list".
1141fa9e4066Sahrens 		 */
1142fa9e4066Sahrens 		if (error == EBUSY) {
1143fa9e4066Sahrens 			delay(1);
1144fa9e4066Sahrens 			goto retry;
1145fa9e4066Sahrens 		}
1146fa9e4066Sahrens 		if (error == ENOENT)
114787e5029aSahrens 			error = ESRCH;
1148fa9e4066Sahrens 		return (error);
1149fa9e4066Sahrens 	}
1150fa9e4066Sahrens 
1151b81d61a6Slling 	/*
1152b81d61a6Slling 	 * A dataset name of maximum length cannot have any snapshots,
1153b81d61a6Slling 	 * so exit immediately.
1154b81d61a6Slling 	 */
1155b81d61a6Slling 	if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) {
115687e5029aSahrens 		dmu_objset_close(os);
1157b81d61a6Slling 		return (ESRCH);
1158fa9e4066Sahrens 	}
1159fa9e4066Sahrens 
116087e5029aSahrens 	error = dmu_snapshot_list_next(os,
116187e5029aSahrens 	    sizeof (zc->zc_name) - strlen(zc->zc_name),
116287e5029aSahrens 	    zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie);
116387e5029aSahrens 	if (error == ENOENT)
116487e5029aSahrens 		error = ESRCH;
1165fa9e4066Sahrens 
116687e5029aSahrens 	if (error == 0)
116787e5029aSahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
1168fa9e4066Sahrens 
116987e5029aSahrens 	dmu_objset_close(os);
1170fa9e4066Sahrens 	return (error);
1171fa9e4066Sahrens }
1172fa9e4066Sahrens 
1173fa9e4066Sahrens static int
1174e9dbad6fSeschrock zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl)
1175fa9e4066Sahrens {
1176e9dbad6fSeschrock 	nvpair_t *elem;
1177e9dbad6fSeschrock 	int error;
1178e9dbad6fSeschrock 	const char *propname;
1179e9dbad6fSeschrock 	zfs_prop_t prop;
1180e9dbad6fSeschrock 	uint64_t intval;
1181e9dbad6fSeschrock 	char *strval;
1182e9dbad6fSeschrock 
1183*ecd6cf80Smarks 	/*
1184*ecd6cf80Smarks 	 * First validate permission to set all of the properties
1185*ecd6cf80Smarks 	 */
1186e9dbad6fSeschrock 	elem = NULL;
1187e9dbad6fSeschrock 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1188e9dbad6fSeschrock 		propname = nvpair_name(elem);
1189e9dbad6fSeschrock 
1190e9dbad6fSeschrock 		if ((prop = zfs_name_to_prop(propname)) ==
1191e9dbad6fSeschrock 		    ZFS_PROP_INVAL) {
1192e9dbad6fSeschrock 			/*
1193e9dbad6fSeschrock 			 * If this is a user-defined property, it must be a
1194e9dbad6fSeschrock 			 * string, and there is no further validation to do.
1195e9dbad6fSeschrock 			 */
1196e9dbad6fSeschrock 			if (!zfs_prop_user(propname) ||
1197e9dbad6fSeschrock 			    nvpair_type(elem) != DATA_TYPE_STRING)
1198e9dbad6fSeschrock 				return (EINVAL);
1199e9dbad6fSeschrock 
1200*ecd6cf80Smarks 			error = zfs_secpolicy_write_perms(name,
1201*ecd6cf80Smarks 			    ZFS_DELEG_PERM_USERPROP, cr);
1202*ecd6cf80Smarks 			if (error) {
1203*ecd6cf80Smarks 				return (EPERM);
1204*ecd6cf80Smarks 			}
1205*ecd6cf80Smarks 			continue;
1206e9dbad6fSeschrock 		}
1207fa9e4066Sahrens 
1208e9dbad6fSeschrock 		/*
1209*ecd6cf80Smarks 		 * Check permissions for special properties
1210e9dbad6fSeschrock 		 */
1211*ecd6cf80Smarks 
1212e9dbad6fSeschrock 		switch (prop) {
1213e9dbad6fSeschrock 		case ZFS_PROP_ZONED:
1214e9dbad6fSeschrock 			/*
1215e9dbad6fSeschrock 			 * Disallow setting of 'zoned' from within a local zone.
1216e9dbad6fSeschrock 			 */
1217e9dbad6fSeschrock 			if (!INGLOBALZONE(curproc))
1218e9dbad6fSeschrock 				return (EPERM);
1219e9dbad6fSeschrock 			break;
1220fa9e4066Sahrens 
1221e9dbad6fSeschrock 		case ZFS_PROP_QUOTA:
1222e9dbad6fSeschrock 			if (error = zfs_dozonecheck(name, cr))
1223e9dbad6fSeschrock 				return (error);
1224fa9e4066Sahrens 
1225e9dbad6fSeschrock 			if (!INGLOBALZONE(curproc)) {
1226e9dbad6fSeschrock 				uint64_t zoned;
1227e9dbad6fSeschrock 				char setpoint[MAXNAMELEN];
1228e9dbad6fSeschrock 				int dslen;
1229e9dbad6fSeschrock 				/*
1230e9dbad6fSeschrock 				 * Unprivileged users are allowed to modify the
1231e9dbad6fSeschrock 				 * quota on things *under* (ie. contained by)
1232e9dbad6fSeschrock 				 * the thing they own.
1233e9dbad6fSeschrock 				 */
1234e9dbad6fSeschrock 				if (dsl_prop_get_integer(name, "zoned", &zoned,
1235e9dbad6fSeschrock 				    setpoint))
1236e9dbad6fSeschrock 					return (EPERM);
1237e9dbad6fSeschrock 				if (!zoned) /* this shouldn't happen */
1238e9dbad6fSeschrock 					return (EPERM);
1239e9dbad6fSeschrock 				dslen = strlen(name);
1240e9dbad6fSeschrock 				if (dslen <= strlen(setpoint))
1241e9dbad6fSeschrock 					return (EPERM);
1242e9dbad6fSeschrock 			}
1243c9431fa1Sahl 			break;
1244c9431fa1Sahl 
1245c9431fa1Sahl 		case ZFS_PROP_COMPRESSION:
1246c9431fa1Sahl 			/*
1247c9431fa1Sahl 			 * If the user specified gzip compression, make sure
1248c9431fa1Sahl 			 * the SPA supports it. We ignore any errors here since
1249c9431fa1Sahl 			 * we'll catch them later.
1250c9431fa1Sahl 			 */
1251c9431fa1Sahl 			if (nvpair_type(elem) == DATA_TYPE_UINT64 &&
1252c9431fa1Sahl 			    nvpair_value_uint64(elem, &intval) == 0 &&
1253c9431fa1Sahl 			    intval >= ZIO_COMPRESS_GZIP_1 &&
1254c9431fa1Sahl 			    intval <= ZIO_COMPRESS_GZIP_9) {
1255*ecd6cf80Smarks 				char buf[MAXNAMELEN];
1256*ecd6cf80Smarks 				spa_t *spa;
1257*ecd6cf80Smarks 				const char *p;
1258*ecd6cf80Smarks 
1259c9431fa1Sahl 				if ((p = strchr(name, '/')) == NULL) {
1260c9431fa1Sahl 					p = name;
1261c9431fa1Sahl 				} else {
1262c9431fa1Sahl 					bcopy(name, buf, p - name);
1263c9431fa1Sahl 					buf[p - name] = '\0';
1264c9431fa1Sahl 					p = buf;
1265c9431fa1Sahl 				}
1266c9431fa1Sahl 
1267c9431fa1Sahl 				if (spa_open(p, &spa, FTAG) == 0) {
1268c9431fa1Sahl 					if (spa_version(spa) <
1269c9431fa1Sahl 					    ZFS_VERSION_GZIP_COMPRESSION) {
1270c9431fa1Sahl 						spa_close(spa, FTAG);
1271c9431fa1Sahl 						return (ENOTSUP);
1272c9431fa1Sahl 					}
1273c9431fa1Sahl 
1274c9431fa1Sahl 					spa_close(spa, FTAG);
1275c9431fa1Sahl 				}
1276c9431fa1Sahl 			}
1277c9431fa1Sahl 			break;
1278e9dbad6fSeschrock 		}
1279*ecd6cf80Smarks 		if ((error = zfs_secpolicy_setprop(name, prop, cr)) != 0)
1280*ecd6cf80Smarks 			return (error);
1281*ecd6cf80Smarks 	}
1282*ecd6cf80Smarks 
1283*ecd6cf80Smarks 	elem = NULL;
1284*ecd6cf80Smarks 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1285*ecd6cf80Smarks 		propname = nvpair_name(elem);
1286*ecd6cf80Smarks 
1287*ecd6cf80Smarks 		if ((prop = zfs_name_to_prop(propname)) ==
1288*ecd6cf80Smarks 		    ZFS_PROP_INVAL) {
1289*ecd6cf80Smarks 
1290*ecd6cf80Smarks 			VERIFY(nvpair_value_string(elem, &strval) == 0);
1291*ecd6cf80Smarks 			error = dsl_prop_set(name, propname, 1,
1292*ecd6cf80Smarks 			    strlen(strval) + 1, strval);
1293*ecd6cf80Smarks 			if (error == 0)
1294*ecd6cf80Smarks 				continue;
1295*ecd6cf80Smarks 			else
1296*ecd6cf80Smarks 				return (error);
1297*ecd6cf80Smarks 		}
1298e9dbad6fSeschrock 
1299e9dbad6fSeschrock 		switch (prop) {
1300e9dbad6fSeschrock 		case ZFS_PROP_QUOTA:
1301e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1302e9dbad6fSeschrock 			    (error = dsl_dir_set_quota(name,
1303e9dbad6fSeschrock 			    intval)) != 0)
1304e9dbad6fSeschrock 				return (error);
1305e9dbad6fSeschrock 			break;
1306e9dbad6fSeschrock 
1307e9dbad6fSeschrock 		case ZFS_PROP_RESERVATION:
1308e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1309e9dbad6fSeschrock 			    (error = dsl_dir_set_reservation(name,
1310e9dbad6fSeschrock 			    intval)) != 0)
1311e9dbad6fSeschrock 				return (error);
1312e9dbad6fSeschrock 			break;
1313e9dbad6fSeschrock 
1314e9dbad6fSeschrock 		case ZFS_PROP_VOLSIZE:
1315e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1316e9dbad6fSeschrock 			    (error = zvol_set_volsize(name, dev,
1317e9dbad6fSeschrock 			    intval)) != 0)
1318e9dbad6fSeschrock 				return (error);
1319e9dbad6fSeschrock 			break;
1320e9dbad6fSeschrock 
1321e9dbad6fSeschrock 		case ZFS_PROP_VOLBLOCKSIZE:
1322e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1323e9dbad6fSeschrock 			    (error = zvol_set_volblocksize(name,
1324e9dbad6fSeschrock 			    intval)) != 0)
1325e9dbad6fSeschrock 				return (error);
1326e9dbad6fSeschrock 			break;
1327e9dbad6fSeschrock 
1328e9dbad6fSeschrock 		default:
1329e9dbad6fSeschrock 			if (nvpair_type(elem) == DATA_TYPE_STRING) {
1330e9dbad6fSeschrock 				if (zfs_prop_get_type(prop) !=
1331e9dbad6fSeschrock 				    prop_type_string)
1332e9dbad6fSeschrock 					return (EINVAL);
1333acd76fe5Seschrock 				VERIFY(nvpair_value_string(elem, &strval) == 0);
1334acd76fe5Seschrock 				if ((error = dsl_prop_set(name,
1335e9dbad6fSeschrock 				    nvpair_name(elem), 1, strlen(strval) + 1,
1336acd76fe5Seschrock 				    strval)) != 0)
1337acd76fe5Seschrock 					return (error);
1338e9dbad6fSeschrock 			} else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
1339a2eea2e1Sahrens 				const char *unused;
1340a2eea2e1Sahrens 
1341acd76fe5Seschrock 				VERIFY(nvpair_value_uint64(elem, &intval) == 0);
1342e9dbad6fSeschrock 
1343e9dbad6fSeschrock 				switch (zfs_prop_get_type(prop)) {
1344e9dbad6fSeschrock 				case prop_type_number:
1345e9dbad6fSeschrock 					break;
1346e9dbad6fSeschrock 				case prop_type_boolean:
1347e9dbad6fSeschrock 					if (intval > 1)
1348acd76fe5Seschrock 						return (EINVAL);
1349e9dbad6fSeschrock 					break;
1350e9dbad6fSeschrock 				case prop_type_string:
1351acd76fe5Seschrock 					return (EINVAL);
1352e9dbad6fSeschrock 				case prop_type_index:
1353acd76fe5Seschrock 					if (zfs_prop_index_to_string(prop,
1354acd76fe5Seschrock 					    intval, &unused) != 0)
1355acd76fe5Seschrock 						return (EINVAL);
1356e9dbad6fSeschrock 					break;
1357e9dbad6fSeschrock 				default:
1358e9dbad6fSeschrock 					cmn_err(CE_PANIC, "unknown property "
1359e9dbad6fSeschrock 					    "type");
1360e9dbad6fSeschrock 					break;
1361e9dbad6fSeschrock 				}
1362e9dbad6fSeschrock 
1363acd76fe5Seschrock 				if ((error = dsl_prop_set(name, propname,
1364acd76fe5Seschrock 				    8, 1, &intval)) != 0)
1365acd76fe5Seschrock 					return (error);
1366e9dbad6fSeschrock 			} else {
1367e9dbad6fSeschrock 				return (EINVAL);
1368e9dbad6fSeschrock 			}
1369e9dbad6fSeschrock 			break;
1370e9dbad6fSeschrock 		}
1371e9dbad6fSeschrock 	}
1372e9dbad6fSeschrock 
1373e9dbad6fSeschrock 	return (0);
1374fa9e4066Sahrens }
1375fa9e4066Sahrens 
1376fa9e4066Sahrens static int
1377e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc)
1378fa9e4066Sahrens {
1379e9dbad6fSeschrock 	nvlist_t *nvl;
1380e9dbad6fSeschrock 	int error;
1381e9dbad6fSeschrock 	zfs_prop_t prop;
1382e9dbad6fSeschrock 
1383e9dbad6fSeschrock 	/*
1384e9dbad6fSeschrock 	 * If zc_value is set, then this is an attempt to inherit a value.
1385e9dbad6fSeschrock 	 * Otherwise, zc_nvlist refers to a list of properties to set.
1386e9dbad6fSeschrock 	 */
1387e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1388e9dbad6fSeschrock 		if (!zfs_prop_user(zc->zc_value) &&
1389e9dbad6fSeschrock 		    ((prop = zfs_name_to_prop(zc->zc_value)) ==
1390e9dbad6fSeschrock 		    ZFS_PROP_INVAL ||
1391e9dbad6fSeschrock 		    !zfs_prop_inheritable(prop)))
1392e9dbad6fSeschrock 			return (EINVAL);
1393e9dbad6fSeschrock 
1394e9dbad6fSeschrock 		return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL));
1395e9dbad6fSeschrock 	}
1396e9dbad6fSeschrock 
1397e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &nvl)) != 0)
1398e9dbad6fSeschrock 		return (error);
1399e9dbad6fSeschrock 
1400e9dbad6fSeschrock 	error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev,
1401e9dbad6fSeschrock 	    (cred_t *)(uintptr_t)zc->zc_cred, nvl);
1402*ecd6cf80Smarks 
1403e9dbad6fSeschrock 	nvlist_free(nvl);
1404e9dbad6fSeschrock 	return (error);
1405fa9e4066Sahrens }
1406fa9e4066Sahrens 
1407b1b8ab34Slling static int
140811a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc)
1409b1b8ab34Slling {
1410b1b8ab34Slling 	nvlist_t *nvl;
1411b1b8ab34Slling 	int error, reset_bootfs = 0;
1412b1b8ab34Slling 	uint64_t objnum;
1413*ecd6cf80Smarks 	uint64_t intval;
1414b1b8ab34Slling 	zpool_prop_t prop;
1415b1b8ab34Slling 	nvpair_t *elem;
1416b1b8ab34Slling 	char *propname, *strval;
1417b1b8ab34Slling 	spa_t *spa;
1418b1b8ab34Slling 	vdev_t *rvdev;
1419b1b8ab34Slling 	char *vdev_type;
1420b1b8ab34Slling 	objset_t *os;
1421b1b8ab34Slling 
1422b1b8ab34Slling 	if ((error = get_nvlist(zc, &nvl)) != 0)
1423b1b8ab34Slling 		return (error);
1424b1b8ab34Slling 
1425b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) {
1426b1b8ab34Slling 		nvlist_free(nvl);
1427b1b8ab34Slling 		return (error);
1428b1b8ab34Slling 	}
1429b1b8ab34Slling 
1430b1b8ab34Slling 	if (spa_version(spa) < ZFS_VERSION_BOOTFS) {
1431b1b8ab34Slling 		nvlist_free(nvl);
1432b1b8ab34Slling 		spa_close(spa, FTAG);
1433b1b8ab34Slling 		return (ENOTSUP);
1434b1b8ab34Slling 	}
1435b1b8ab34Slling 
1436b1b8ab34Slling 	elem = NULL;
1437b1b8ab34Slling 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1438b1b8ab34Slling 
1439b1b8ab34Slling 		propname = nvpair_name(elem);
1440b1b8ab34Slling 
1441b1b8ab34Slling 		if ((prop = zpool_name_to_prop(propname)) ==
1442b1b8ab34Slling 		    ZFS_PROP_INVAL) {
1443b1b8ab34Slling 			nvlist_free(nvl);
1444b1b8ab34Slling 			spa_close(spa, FTAG);
1445b1b8ab34Slling 			return (EINVAL);
1446b1b8ab34Slling 		}
1447b1b8ab34Slling 
1448b1b8ab34Slling 		switch (prop) {
1449*ecd6cf80Smarks 		case ZPOOL_PROP_DELEGATION:
1450*ecd6cf80Smarks 			VERIFY(nvpair_value_uint64(elem, &intval) == 0);
1451*ecd6cf80Smarks 			if (intval > 1)
1452*ecd6cf80Smarks 				error = EINVAL;
1453*ecd6cf80Smarks 			break;
14543d7072f8Seschrock 		case ZPOOL_PROP_BOOTFS:
1455b1b8ab34Slling 			/*
1456b1b8ab34Slling 			 * A bootable filesystem can not be on a RAIDZ pool
1457b1b8ab34Slling 			 * nor a striped pool with more than 1 device.
1458b1b8ab34Slling 			 */
1459b1b8ab34Slling 			rvdev = spa->spa_root_vdev;
1460b1b8ab34Slling 			vdev_type =
1461b1b8ab34Slling 			    rvdev->vdev_child[0]->vdev_ops->vdev_op_type;
1462b1b8ab34Slling 			if (strcmp(vdev_type, VDEV_TYPE_RAIDZ) == 0 ||
1463b1b8ab34Slling 			    (strcmp(vdev_type, VDEV_TYPE_MIRROR) != 0 &&
1464b1b8ab34Slling 			    rvdev->vdev_children > 1)) {
1465b1b8ab34Slling 				error = ENOTSUP;
1466b1b8ab34Slling 				break;
1467b1b8ab34Slling 			}
1468b1b8ab34Slling 
1469b1b8ab34Slling 			reset_bootfs = 1;
1470b1b8ab34Slling 
1471b1b8ab34Slling 			VERIFY(nvpair_value_string(elem, &strval) == 0);
1472b1b8ab34Slling 			if (strval == NULL || strval[0] == '\0') {
14733d7072f8Seschrock 				objnum = zpool_prop_default_numeric(
14743d7072f8Seschrock 				    ZPOOL_PROP_BOOTFS);
1475b1b8ab34Slling 				break;
1476b1b8ab34Slling 			}
1477b1b8ab34Slling 
1478b1b8ab34Slling 			if (error = dmu_objset_open(strval, DMU_OST_ZFS,
1479b1b8ab34Slling 			    DS_MODE_STANDARD | DS_MODE_READONLY, &os))
1480b1b8ab34Slling 				break;
1481b1b8ab34Slling 			objnum = dmu_objset_id(os);
1482b1b8ab34Slling 			dmu_objset_close(os);
1483b1b8ab34Slling 			break;
1484b1b8ab34Slling 		}
1485b1b8ab34Slling 
1486b1b8ab34Slling 		if (error)
1487b1b8ab34Slling 			break;
1488b1b8ab34Slling 	}
1489b1b8ab34Slling 	if (error == 0) {
1490b1b8ab34Slling 		if (reset_bootfs) {
1491b1b8ab34Slling 			VERIFY(nvlist_remove(nvl,
14923d7072f8Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_BOOTFS),
1493b1b8ab34Slling 			    DATA_TYPE_STRING) == 0);
1494b1b8ab34Slling 			VERIFY(nvlist_add_uint64(nvl,
14953d7072f8Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_BOOTFS),
14963d7072f8Seschrock 			    objnum) == 0);
1497b1b8ab34Slling 		}
1498b1b8ab34Slling 		error = spa_set_props(spa, nvl);
1499b1b8ab34Slling 	}
1500b1b8ab34Slling 
1501b1b8ab34Slling 	nvlist_free(nvl);
1502b1b8ab34Slling 	spa_close(spa, FTAG);
1503b1b8ab34Slling 
1504b1b8ab34Slling 	return (error);
1505b1b8ab34Slling }
1506b1b8ab34Slling 
1507b1b8ab34Slling static int
150811a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc)
1509b1b8ab34Slling {
1510b1b8ab34Slling 	spa_t *spa;
1511b1b8ab34Slling 	int error;
1512b1b8ab34Slling 	nvlist_t *nvp = NULL;
1513b1b8ab34Slling 
1514b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1515b1b8ab34Slling 		return (error);
1516b1b8ab34Slling 
1517b1b8ab34Slling 	error = spa_get_props(spa, &nvp);
1518b1b8ab34Slling 
1519b1b8ab34Slling 	if (error == 0 && zc->zc_nvlist_dst != NULL)
1520b1b8ab34Slling 		error = put_nvlist(zc, nvp);
1521b1b8ab34Slling 	else
1522b1b8ab34Slling 		error = EFAULT;
1523b1b8ab34Slling 
1524b1b8ab34Slling 	spa_close(spa, FTAG);
1525b1b8ab34Slling 
1526b1b8ab34Slling 	if (nvp)
1527b1b8ab34Slling 		nvlist_free(nvp);
1528b1b8ab34Slling 	return (error);
1529b1b8ab34Slling }
1530b1b8ab34Slling 
1531*ecd6cf80Smarks static int
1532*ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc)
1533*ecd6cf80Smarks {
1534*ecd6cf80Smarks 	nvlist_t *nvp;
1535*ecd6cf80Smarks 	int error;
1536*ecd6cf80Smarks 	uint32_t uid;
1537*ecd6cf80Smarks 	uint32_t gid;
1538*ecd6cf80Smarks 	uint32_t *groups;
1539*ecd6cf80Smarks 	uint_t group_cnt;
1540*ecd6cf80Smarks 	cred_t	*usercred;
1541*ecd6cf80Smarks 
1542*ecd6cf80Smarks 	if ((error = get_nvlist(zc, &nvp)) != 0) {
1543*ecd6cf80Smarks 		return (error);
1544*ecd6cf80Smarks 	}
1545*ecd6cf80Smarks 
1546*ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32(nvp,
1547*ecd6cf80Smarks 	    ZFS_DELEG_PERM_UID, &uid)) != 0) {
1548*ecd6cf80Smarks 		nvlist_free(nvp);
1549*ecd6cf80Smarks 		return (EPERM);
1550*ecd6cf80Smarks 	}
1551*ecd6cf80Smarks 
1552*ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32(nvp,
1553*ecd6cf80Smarks 	    ZFS_DELEG_PERM_GID, &gid)) != 0) {
1554*ecd6cf80Smarks 		nvlist_free(nvp);
1555*ecd6cf80Smarks 		return (EPERM);
1556*ecd6cf80Smarks 	}
1557*ecd6cf80Smarks 
1558*ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS,
1559*ecd6cf80Smarks 	    &groups, &group_cnt)) != 0) {
1560*ecd6cf80Smarks 		nvlist_free(nvp);
1561*ecd6cf80Smarks 		return (EPERM);
1562*ecd6cf80Smarks 	}
1563*ecd6cf80Smarks 	usercred = cralloc();
1564*ecd6cf80Smarks 	if ((crsetugid(usercred, uid, gid) != 0) ||
1565*ecd6cf80Smarks 	    (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) {
1566*ecd6cf80Smarks 		nvlist_free(nvp);
1567*ecd6cf80Smarks 		crfree(usercred);
1568*ecd6cf80Smarks 		return (EPERM);
1569*ecd6cf80Smarks 	}
1570*ecd6cf80Smarks 	nvlist_free(nvp);
1571*ecd6cf80Smarks 	error = dsl_deleg_access(zc->zc_name,
1572*ecd6cf80Smarks 	    ZFS_DELEG_PERM_SHAREISCSI, usercred);
1573*ecd6cf80Smarks 	crfree(usercred);
1574*ecd6cf80Smarks 	return (error);
1575*ecd6cf80Smarks }
1576*ecd6cf80Smarks 
1577*ecd6cf80Smarks static int
1578*ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc)
1579*ecd6cf80Smarks {
1580*ecd6cf80Smarks 	int error;
1581*ecd6cf80Smarks 	nvlist_t *fsaclnv = NULL;
1582*ecd6cf80Smarks 	cred_t *cr;
1583*ecd6cf80Smarks 
1584*ecd6cf80Smarks 	if ((error = get_nvlist(zc, &fsaclnv)) != 0)
1585*ecd6cf80Smarks 		return (error);
1586*ecd6cf80Smarks 
1587*ecd6cf80Smarks 	/*
1588*ecd6cf80Smarks 	 * Verify nvlist is constructed correctly
1589*ecd6cf80Smarks 	 */
1590*ecd6cf80Smarks 	if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) {
1591*ecd6cf80Smarks 		nvlist_free(fsaclnv);
1592*ecd6cf80Smarks 		return (EINVAL);
1593*ecd6cf80Smarks 	}
1594*ecd6cf80Smarks 
1595*ecd6cf80Smarks 	/*
1596*ecd6cf80Smarks 	 * If we don't have PRIV_SYS_MOUNT, then validate
1597*ecd6cf80Smarks 	 * that user is allowed to hand out each permission in
1598*ecd6cf80Smarks 	 * the nvlist(s)
1599*ecd6cf80Smarks 	 */
1600*ecd6cf80Smarks 
1601*ecd6cf80Smarks 	cr = (cred_t *)(uintptr_t)zc->zc_cred;
1602*ecd6cf80Smarks 	error = secpolicy_zfs(cr);
1603*ecd6cf80Smarks 	if (error) {
1604*ecd6cf80Smarks 		if (zc->zc_perm_action == B_FALSE)
1605*ecd6cf80Smarks 			error = dsl_deleg_can_allow(zc->zc_name, fsaclnv, cr);
1606*ecd6cf80Smarks 		else
1607*ecd6cf80Smarks 			error = dsl_deleg_can_unallow(zc->zc_name, fsaclnv, cr);
1608*ecd6cf80Smarks 	}
1609*ecd6cf80Smarks 
1610*ecd6cf80Smarks 	if (error == 0)
1611*ecd6cf80Smarks 		error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action);
1612*ecd6cf80Smarks 
1613*ecd6cf80Smarks 	nvlist_free(fsaclnv);
1614*ecd6cf80Smarks 	return (error);
1615*ecd6cf80Smarks }
1616*ecd6cf80Smarks 
1617*ecd6cf80Smarks static int
1618*ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc)
1619*ecd6cf80Smarks {
1620*ecd6cf80Smarks 	nvlist_t *nvp;
1621*ecd6cf80Smarks 	int error;
1622*ecd6cf80Smarks 
1623*ecd6cf80Smarks 	if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) {
1624*ecd6cf80Smarks 		error = put_nvlist(zc, nvp);
1625*ecd6cf80Smarks 		nvlist_free(nvp);
1626*ecd6cf80Smarks 	}
1627*ecd6cf80Smarks 
1628*ecd6cf80Smarks 	return (error);
1629*ecd6cf80Smarks }
1630*ecd6cf80Smarks 
1631fa9e4066Sahrens static int
1632fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc)
1633fa9e4066Sahrens {
1634e9dbad6fSeschrock 	return (zvol_create_minor(zc->zc_name, zc->zc_dev));
1635fa9e4066Sahrens }
1636fa9e4066Sahrens 
1637fa9e4066Sahrens static int
1638fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc)
1639fa9e4066Sahrens {
1640e9dbad6fSeschrock 	return (zvol_remove_minor(zc->zc_name));
1641fa9e4066Sahrens }
1642fa9e4066Sahrens 
1643fa9e4066Sahrens /*
1644fa9e4066Sahrens  * Search the vfs list for a specified resource.  Returns a pointer to it
1645fa9e4066Sahrens  * or NULL if no suitable entry is found. The caller of this routine
1646fa9e4066Sahrens  * is responsible for releasing the returned vfs pointer.
1647fa9e4066Sahrens  */
1648fa9e4066Sahrens static vfs_t *
1649fa9e4066Sahrens zfs_get_vfs(const char *resource)
1650fa9e4066Sahrens {
1651fa9e4066Sahrens 	struct vfs *vfsp;
1652fa9e4066Sahrens 	struct vfs *vfs_found = NULL;
1653fa9e4066Sahrens 
1654fa9e4066Sahrens 	vfs_list_read_lock();
1655fa9e4066Sahrens 	vfsp = rootvfs;
1656fa9e4066Sahrens 	do {
1657fa9e4066Sahrens 		if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) {
1658fa9e4066Sahrens 			VFS_HOLD(vfsp);
1659fa9e4066Sahrens 			vfs_found = vfsp;
1660fa9e4066Sahrens 			break;
1661fa9e4066Sahrens 		}
1662fa9e4066Sahrens 		vfsp = vfsp->vfs_next;
1663fa9e4066Sahrens 	} while (vfsp != rootvfs);
1664fa9e4066Sahrens 	vfs_list_unlock();
1665fa9e4066Sahrens 	return (vfs_found);
1666fa9e4066Sahrens }
1667fa9e4066Sahrens 
1668*ecd6cf80Smarks /* ARGSUSED */
1669fa9e4066Sahrens static void
1670*ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
1671fa9e4066Sahrens {
1672*ecd6cf80Smarks 	zfs_create_fs(os, cr, tx);
1673fa9e4066Sahrens }
1674fa9e4066Sahrens 
1675fa9e4066Sahrens static int
1676fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc)
1677fa9e4066Sahrens {
1678fa9e4066Sahrens 	objset_t *clone;
1679fa9e4066Sahrens 	int error = 0;
1680*ecd6cf80Smarks 	nvlist_t *nvprops = NULL;
1681*ecd6cf80Smarks 	void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
1682fa9e4066Sahrens 	dmu_objset_type_t type = zc->zc_objset_type;
1683fa9e4066Sahrens 
1684fa9e4066Sahrens 	switch (type) {
1685fa9e4066Sahrens 
1686fa9e4066Sahrens 	case DMU_OST_ZFS:
1687fa9e4066Sahrens 		cbfunc = zfs_create_cb;
1688fa9e4066Sahrens 		break;
1689fa9e4066Sahrens 
1690fa9e4066Sahrens 	case DMU_OST_ZVOL:
1691fa9e4066Sahrens 		cbfunc = zvol_create_cb;
1692fa9e4066Sahrens 		break;
1693fa9e4066Sahrens 
1694fa9e4066Sahrens 	default:
16951d452cf5Sahrens 		cbfunc = NULL;
1696fa9e4066Sahrens 	}
16971d452cf5Sahrens 	if (strchr(zc->zc_name, '@'))
16981d452cf5Sahrens 		return (EINVAL);
1699fa9e4066Sahrens 
1700e9dbad6fSeschrock 	if (zc->zc_nvlist_src != NULL &&
1701*ecd6cf80Smarks 	    (error = get_nvlist(zc, &nvprops)) != 0)
1702e9dbad6fSeschrock 		return (error);
1703e9dbad6fSeschrock 
1704e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1705fa9e4066Sahrens 		/*
1706fa9e4066Sahrens 		 * We're creating a clone of an existing snapshot.
1707fa9e4066Sahrens 		 */
1708e9dbad6fSeschrock 		zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
1709e9dbad6fSeschrock 		if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) {
1710*ecd6cf80Smarks 			nvlist_free(nvprops);
1711fa9e4066Sahrens 			return (EINVAL);
1712e9dbad6fSeschrock 		}
1713fa9e4066Sahrens 
1714e9dbad6fSeschrock 		error = dmu_objset_open(zc->zc_value, type,
1715fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
1716e9dbad6fSeschrock 		if (error) {
1717*ecd6cf80Smarks 			nvlist_free(nvprops);
1718fa9e4066Sahrens 			return (error);
1719e9dbad6fSeschrock 		}
1720fa9e4066Sahrens 		error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL);
1721fa9e4066Sahrens 		dmu_objset_close(clone);
1722fa9e4066Sahrens 	} else {
1723e9dbad6fSeschrock 		if (cbfunc == NULL) {
1724*ecd6cf80Smarks 			nvlist_free(nvprops);
17251d452cf5Sahrens 			return (EINVAL);
1726e9dbad6fSeschrock 		}
17275c5460e9Seschrock 
1728e9dbad6fSeschrock 		if (type == DMU_OST_ZVOL) {
1729e9dbad6fSeschrock 			uint64_t volsize, volblocksize;
1730e9dbad6fSeschrock 
1731*ecd6cf80Smarks 			if (nvprops == NULL ||
1732*ecd6cf80Smarks 			    nvlist_lookup_uint64(nvprops,
1733e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1734e9dbad6fSeschrock 			    &volsize) != 0) {
1735*ecd6cf80Smarks 				nvlist_free(nvprops);
1736e9dbad6fSeschrock 				return (EINVAL);
1737e9dbad6fSeschrock 			}
1738e9dbad6fSeschrock 
1739*ecd6cf80Smarks 			if ((error = nvlist_lookup_uint64(nvprops,
1740e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1741e9dbad6fSeschrock 			    &volblocksize)) != 0 && error != ENOENT) {
1742*ecd6cf80Smarks 				nvlist_free(nvprops);
1743e9dbad6fSeschrock 				return (EINVAL);
1744e9dbad6fSeschrock 			}
1745e9dbad6fSeschrock 
1746e9dbad6fSeschrock 			if (error != 0)
1747e9dbad6fSeschrock 				volblocksize = zfs_prop_default_numeric(
1748e9dbad6fSeschrock 				    ZFS_PROP_VOLBLOCKSIZE);
1749e9dbad6fSeschrock 
1750e9dbad6fSeschrock 			if ((error = zvol_check_volblocksize(
1751e9dbad6fSeschrock 			    volblocksize)) != 0 ||
1752e9dbad6fSeschrock 			    (error = zvol_check_volsize(volsize,
1753e9dbad6fSeschrock 			    volblocksize)) != 0) {
1754*ecd6cf80Smarks 				nvlist_free(nvprops);
17555c5460e9Seschrock 				return (error);
1756e9dbad6fSeschrock 			}
1757fa9e4066Sahrens 		}
1758e9dbad6fSeschrock 
1759e9dbad6fSeschrock 		error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc,
1760*ecd6cf80Smarks 		    nvprops);
1761fa9e4066Sahrens 	}
1762e9dbad6fSeschrock 
1763e9dbad6fSeschrock 	/*
1764e9dbad6fSeschrock 	 * It would be nice to do this atomically.
1765e9dbad6fSeschrock 	 */
1766e9dbad6fSeschrock 	if (error == 0) {
1767e9dbad6fSeschrock 		if ((error = zfs_set_prop_nvlist(zc->zc_name,
1768e9dbad6fSeschrock 		    zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred,
1769*ecd6cf80Smarks 		    nvprops)) != 0)
1770e9dbad6fSeschrock 			(void) dmu_objset_destroy(zc->zc_name);
1771e9dbad6fSeschrock 	}
1772e9dbad6fSeschrock 
1773*ecd6cf80Smarks 	nvlist_free(nvprops);
1774fa9e4066Sahrens 	return (error);
1775fa9e4066Sahrens }
1776fa9e4066Sahrens 
1777fa9e4066Sahrens static int
17781d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc)
1779fa9e4066Sahrens {
1780e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
17811d452cf5Sahrens 		return (EINVAL);
17821d452cf5Sahrens 	return (dmu_objset_snapshot(zc->zc_name,
1783e9dbad6fSeschrock 	    zc->zc_value, zc->zc_cookie));
17841d452cf5Sahrens }
1785fa9e4066Sahrens 
1786cdf5b4caSmmusante int
17871d452cf5Sahrens zfs_unmount_snap(char *name, void *arg)
17881d452cf5Sahrens {
17891d452cf5Sahrens 	char *snapname = arg;
17901d452cf5Sahrens 	char *cp;
17910b69c2f0Sahrens 	vfs_t *vfsp = NULL;
17921d452cf5Sahrens 
17931d452cf5Sahrens 	/*
17941d452cf5Sahrens 	 * Snapshots (which are under .zfs control) must be unmounted
17951d452cf5Sahrens 	 * before they can be destroyed.
17961d452cf5Sahrens 	 */
17971d452cf5Sahrens 
17981d452cf5Sahrens 	if (snapname) {
17991d452cf5Sahrens 		(void) strcat(name, "@");
18001d452cf5Sahrens 		(void) strcat(name, snapname);
18011d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
18021d452cf5Sahrens 		cp = strchr(name, '@');
18031d452cf5Sahrens 		*cp = '\0';
18040b69c2f0Sahrens 	} else if (strchr(name, '@')) {
18051d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
18061d452cf5Sahrens 	}
18071d452cf5Sahrens 
18081d452cf5Sahrens 	if (vfsp) {
1809fa9e4066Sahrens 		/*
18101d452cf5Sahrens 		 * Always force the unmount for snapshots.
1811fa9e4066Sahrens 		 */
18121d452cf5Sahrens 		int flag = MS_FORCE;
18131d452cf5Sahrens 		int err;
18141d452cf5Sahrens 
18151d452cf5Sahrens 		if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) {
1816fa9e4066Sahrens 			VFS_RELE(vfsp);
18171d452cf5Sahrens 			return (err);
1818fa9e4066Sahrens 		}
18191d452cf5Sahrens 		VFS_RELE(vfsp);
18201d452cf5Sahrens 		if ((err = dounmount(vfsp, flag, kcred)) != 0)
18211d452cf5Sahrens 			return (err);
18221d452cf5Sahrens 	}
18231d452cf5Sahrens 	return (0);
18241d452cf5Sahrens }
18251d452cf5Sahrens 
18261d452cf5Sahrens static int
18271d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc)
18281d452cf5Sahrens {
18291d452cf5Sahrens 	int err;
18301d452cf5Sahrens 
1831e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
18321d452cf5Sahrens 		return (EINVAL);
18331d452cf5Sahrens 	err = dmu_objset_find(zc->zc_name,
1834e9dbad6fSeschrock 	    zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN);
18351d452cf5Sahrens 	if (err)
18361d452cf5Sahrens 		return (err);
1837e9dbad6fSeschrock 	return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value));
18381d452cf5Sahrens }
18391d452cf5Sahrens 
18401d452cf5Sahrens static int
18411d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc)
18421d452cf5Sahrens {
18431d452cf5Sahrens 	if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) {
18441d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
18451d452cf5Sahrens 		if (err)
18461d452cf5Sahrens 			return (err);
1847fa9e4066Sahrens 	}
1848fa9e4066Sahrens 
1849fa9e4066Sahrens 	return (dmu_objset_destroy(zc->zc_name));
1850fa9e4066Sahrens }
1851fa9e4066Sahrens 
1852fa9e4066Sahrens static int
1853fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc)
1854fa9e4066Sahrens {
1855fa9e4066Sahrens 	return (dmu_objset_rollback(zc->zc_name));
1856fa9e4066Sahrens }
1857fa9e4066Sahrens 
1858fa9e4066Sahrens static int
1859fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc)
1860fa9e4066Sahrens {
18617f1f55eaSvb 	boolean_t recursive = zc->zc_cookie & 1;
1862cdf5b4caSmmusante 
1863e9dbad6fSeschrock 	zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
1864e9dbad6fSeschrock 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0)
1865fa9e4066Sahrens 		return (EINVAL);
1866fa9e4066Sahrens 
1867cdf5b4caSmmusante 	/*
1868cdf5b4caSmmusante 	 * Unmount snapshot unless we're doing a recursive rename,
1869cdf5b4caSmmusante 	 * in which case the dataset code figures out which snapshots
1870cdf5b4caSmmusante 	 * to unmount.
1871cdf5b4caSmmusante 	 */
1872cdf5b4caSmmusante 	if (!recursive && strchr(zc->zc_name, '@') != NULL &&
1873fa9e4066Sahrens 	    zc->zc_objset_type == DMU_OST_ZFS) {
18741d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
18751d452cf5Sahrens 		if (err)
18761d452cf5Sahrens 			return (err);
1877fa9e4066Sahrens 	}
1878fa9e4066Sahrens 
1879cdf5b4caSmmusante 	return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive));
1880fa9e4066Sahrens }
1881fa9e4066Sahrens 
1882fa9e4066Sahrens static int
1883fa9e4066Sahrens zfs_ioc_recvbackup(zfs_cmd_t *zc)
1884fa9e4066Sahrens {
1885fa9e4066Sahrens 	file_t *fp;
1886fa9e4066Sahrens 	int error, fd;
1887a2eea2e1Sahrens 	offset_t new_off;
1888fa9e4066Sahrens 
18893ccfa83cSahrens 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
18903ccfa83cSahrens 	    strchr(zc->zc_value, '@') == NULL)
18913ccfa83cSahrens 		return (EINVAL);
18923ccfa83cSahrens 
1893fa9e4066Sahrens 	fd = zc->zc_cookie;
1894fa9e4066Sahrens 	fp = getf(fd);
1895fa9e4066Sahrens 	if (fp == NULL)
1896fa9e4066Sahrens 		return (EBADF);
1897e9dbad6fSeschrock 	error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record,
1898e9dbad6fSeschrock 	    &zc->zc_cookie, (boolean_t)zc->zc_guid, fp->f_vnode,
189998579b20Snd 	    fp->f_offset);
1900a2eea2e1Sahrens 
1901a2eea2e1Sahrens 	new_off = fp->f_offset + zc->zc_cookie;
1902a2eea2e1Sahrens 	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off) == 0)
1903a2eea2e1Sahrens 		fp->f_offset = new_off;
1904a2eea2e1Sahrens 
1905fa9e4066Sahrens 	releasef(fd);
1906fa9e4066Sahrens 	return (error);
1907fa9e4066Sahrens }
1908fa9e4066Sahrens 
1909fa9e4066Sahrens static int
1910fa9e4066Sahrens zfs_ioc_sendbackup(zfs_cmd_t *zc)
1911fa9e4066Sahrens {
1912fa9e4066Sahrens 	objset_t *fromsnap = NULL;
1913fa9e4066Sahrens 	objset_t *tosnap;
1914fa9e4066Sahrens 	file_t *fp;
1915fa9e4066Sahrens 	int error;
1916fa9e4066Sahrens 
1917fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1918fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap);
1919fa9e4066Sahrens 	if (error)
1920fa9e4066Sahrens 		return (error);
1921fa9e4066Sahrens 
1922e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1923a2eea2e1Sahrens 		char buf[MAXPATHLEN];
1924a2eea2e1Sahrens 		char *cp;
1925a2eea2e1Sahrens 
1926a2eea2e1Sahrens 		(void) strncpy(buf, zc->zc_name, sizeof (buf));
1927a2eea2e1Sahrens 		cp = strchr(buf, '@');
1928a2eea2e1Sahrens 		if (cp)
1929a2eea2e1Sahrens 			*(cp+1) = 0;
1930a2eea2e1Sahrens 		(void) strncat(buf, zc->zc_value, sizeof (buf));
1931a2eea2e1Sahrens 		error = dmu_objset_open(buf, DMU_OST_ANY,
1932fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap);
1933fa9e4066Sahrens 		if (error) {
1934fa9e4066Sahrens 			dmu_objset_close(tosnap);
1935fa9e4066Sahrens 			return (error);
1936fa9e4066Sahrens 		}
1937fa9e4066Sahrens 	}
1938fa9e4066Sahrens 
1939fa9e4066Sahrens 	fp = getf(zc->zc_cookie);
1940fa9e4066Sahrens 	if (fp == NULL) {
1941fa9e4066Sahrens 		dmu_objset_close(tosnap);
1942fa9e4066Sahrens 		if (fromsnap)
1943fa9e4066Sahrens 			dmu_objset_close(fromsnap);
1944fa9e4066Sahrens 		return (EBADF);
1945fa9e4066Sahrens 	}
1946fa9e4066Sahrens 
1947fa9e4066Sahrens 	error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode);
1948fa9e4066Sahrens 
1949fa9e4066Sahrens 	releasef(zc->zc_cookie);
1950fa9e4066Sahrens 	if (fromsnap)
1951fa9e4066Sahrens 		dmu_objset_close(fromsnap);
1952fa9e4066Sahrens 	dmu_objset_close(tosnap);
1953fa9e4066Sahrens 	return (error);
1954fa9e4066Sahrens }
1955fa9e4066Sahrens 
1956ea8dc4b6Seschrock static int
1957ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc)
1958ea8dc4b6Seschrock {
1959ea8dc4b6Seschrock 	int id, error;
1960ea8dc4b6Seschrock 
1961ea8dc4b6Seschrock 	error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id,
1962ea8dc4b6Seschrock 	    &zc->zc_inject_record);
1963ea8dc4b6Seschrock 
1964ea8dc4b6Seschrock 	if (error == 0)
1965ea8dc4b6Seschrock 		zc->zc_guid = (uint64_t)id;
1966ea8dc4b6Seschrock 
1967ea8dc4b6Seschrock 	return (error);
1968ea8dc4b6Seschrock }
1969ea8dc4b6Seschrock 
1970ea8dc4b6Seschrock static int
1971ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc)
1972ea8dc4b6Seschrock {
1973ea8dc4b6Seschrock 	return (zio_clear_fault((int)zc->zc_guid));
1974ea8dc4b6Seschrock }
1975ea8dc4b6Seschrock 
1976ea8dc4b6Seschrock static int
1977ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc)
1978ea8dc4b6Seschrock {
1979ea8dc4b6Seschrock 	int id = (int)zc->zc_guid;
1980ea8dc4b6Seschrock 	int error;
1981ea8dc4b6Seschrock 
1982ea8dc4b6Seschrock 	error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name),
1983ea8dc4b6Seschrock 	    &zc->zc_inject_record);
1984ea8dc4b6Seschrock 
1985ea8dc4b6Seschrock 	zc->zc_guid = id;
1986ea8dc4b6Seschrock 
1987ea8dc4b6Seschrock 	return (error);
1988ea8dc4b6Seschrock }
1989ea8dc4b6Seschrock 
1990ea8dc4b6Seschrock static int
1991ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc)
1992ea8dc4b6Seschrock {
1993ea8dc4b6Seschrock 	spa_t *spa;
1994ea8dc4b6Seschrock 	int error;
1995e9dbad6fSeschrock 	size_t count = (size_t)zc->zc_nvlist_dst_size;
1996ea8dc4b6Seschrock 
1997ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1998ea8dc4b6Seschrock 		return (error);
1999ea8dc4b6Seschrock 
2000e9dbad6fSeschrock 	error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst,
2001ea8dc4b6Seschrock 	    &count);
2002ea8dc4b6Seschrock 	if (error == 0)
2003e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = count;
2004ea8dc4b6Seschrock 	else
2005e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = spa_get_errlog_size(spa);
2006ea8dc4b6Seschrock 
2007ea8dc4b6Seschrock 	spa_close(spa, FTAG);
2008ea8dc4b6Seschrock 
2009ea8dc4b6Seschrock 	return (error);
2010ea8dc4b6Seschrock }
2011ea8dc4b6Seschrock 
2012ea8dc4b6Seschrock static int
2013ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc)
2014ea8dc4b6Seschrock {
2015ea8dc4b6Seschrock 	spa_t *spa;
2016ea8dc4b6Seschrock 	vdev_t *vd;
2017ea8dc4b6Seschrock 	int error;
20183d7072f8Seschrock 	uint64_t txg;
2019ea8dc4b6Seschrock 
2020ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
2021ea8dc4b6Seschrock 		return (error);
2022ea8dc4b6Seschrock 
20233d7072f8Seschrock 	txg = spa_vdev_enter(spa);
2024ea8dc4b6Seschrock 
2025e9dbad6fSeschrock 	if (zc->zc_guid == 0) {
2026ea8dc4b6Seschrock 		vd = NULL;
2027e9dbad6fSeschrock 	} else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) {
20283d7072f8Seschrock 		(void) spa_vdev_exit(spa, NULL, txg, ENODEV);
2029ea8dc4b6Seschrock 		spa_close(spa, FTAG);
2030ea8dc4b6Seschrock 		return (ENODEV);
2031ea8dc4b6Seschrock 	}
2032ea8dc4b6Seschrock 
2033ea8dc4b6Seschrock 	vdev_clear(spa, vd);
2034ea8dc4b6Seschrock 
20353d7072f8Seschrock 	(void) spa_vdev_exit(spa, NULL, txg, 0);
2036ea8dc4b6Seschrock 
2037ea8dc4b6Seschrock 	spa_close(spa, FTAG);
2038ea8dc4b6Seschrock 
2039ea8dc4b6Seschrock 	return (0);
2040ea8dc4b6Seschrock }
2041ea8dc4b6Seschrock 
204299653d4eSeschrock static int
204399653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc)
204499653d4eSeschrock {
20450b69c2f0Sahrens 	char *cp;
20460b69c2f0Sahrens 
20470b69c2f0Sahrens 	/*
20480b69c2f0Sahrens 	 * We don't need to unmount *all* the origin fs's snapshots, but
20490b69c2f0Sahrens 	 * it's easier.
20500b69c2f0Sahrens 	 */
2051e9dbad6fSeschrock 	cp = strchr(zc->zc_value, '@');
20520b69c2f0Sahrens 	if (cp)
20530b69c2f0Sahrens 		*cp = '\0';
2054e9dbad6fSeschrock 	(void) dmu_objset_find(zc->zc_value,
20550b69c2f0Sahrens 	    zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS);
205699653d4eSeschrock 	return (dsl_dataset_promote(zc->zc_name));
205799653d4eSeschrock }
205899653d4eSeschrock 
2059*ecd6cf80Smarks /*
2060*ecd6cf80Smarks  * We don't want to have a hard dependency
2061*ecd6cf80Smarks  * against some special symbols in sharefs
2062*ecd6cf80Smarks  * and nfs.  Determine them if needed when
2063*ecd6cf80Smarks  * the first file system is shared.
2064*ecd6cf80Smarks  * Neither sharefs or nfs are unloadable modules.
2065*ecd6cf80Smarks  */
2066*ecd6cf80Smarks int (*zexport_fs)(void *arg);
2067*ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t);
2068*ecd6cf80Smarks 
2069*ecd6cf80Smarks int zfs_share_inited;
2070*ecd6cf80Smarks ddi_modhandle_t nfs_mod;
2071*ecd6cf80Smarks ddi_modhandle_t sharefs_mod;
2072*ecd6cf80Smarks kmutex_t zfs_share_lock;
2073*ecd6cf80Smarks 
2074*ecd6cf80Smarks static int
2075*ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc)
2076*ecd6cf80Smarks {
2077*ecd6cf80Smarks 	int error;
2078*ecd6cf80Smarks 	int opcode;
2079*ecd6cf80Smarks 
2080*ecd6cf80Smarks 	if (zfs_share_inited == 0) {
2081*ecd6cf80Smarks 		mutex_enter(&zfs_share_lock);
2082*ecd6cf80Smarks 		nfs_mod = ddi_modopen("fs/nfs", KRTLD_MODE_FIRST, &error);
2083*ecd6cf80Smarks 		sharefs_mod = ddi_modopen("fs/sharefs",
2084*ecd6cf80Smarks 		    KRTLD_MODE_FIRST, &error);
2085*ecd6cf80Smarks 		if (nfs_mod == NULL || sharefs_mod == NULL) {
2086*ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2087*ecd6cf80Smarks 			return (ENOSYS);
2088*ecd6cf80Smarks 		}
2089*ecd6cf80Smarks 		if (zexport_fs == NULL && ((zexport_fs = (int (*)(void *))
2090*ecd6cf80Smarks 		    ddi_modsym(nfs_mod, "nfs_export", &error)) == NULL)) {
2091*ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2092*ecd6cf80Smarks 			return (ENOSYS);
2093*ecd6cf80Smarks 		}
2094*ecd6cf80Smarks 
2095*ecd6cf80Smarks 		if (zshare_fs == NULL && ((zshare_fs =
2096*ecd6cf80Smarks 		    (int (*)(enum sharefs_sys_op, share_t *, uint32_t))
2097*ecd6cf80Smarks 		    ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) {
2098*ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2099*ecd6cf80Smarks 			return (ENOSYS);
2100*ecd6cf80Smarks 		}
2101*ecd6cf80Smarks 		zfs_share_inited = 1;
2102*ecd6cf80Smarks 		mutex_exit(&zfs_share_lock);
2103*ecd6cf80Smarks 	}
2104*ecd6cf80Smarks 
2105*ecd6cf80Smarks 	if (error = zexport_fs((void *)(uintptr_t)zc->zc_share.z_exportdata))
2106*ecd6cf80Smarks 		return (error);
2107*ecd6cf80Smarks 
2108*ecd6cf80Smarks 	opcode = (zc->zc_share.z_sharetype == B_TRUE) ?
2109*ecd6cf80Smarks 	    SHAREFS_ADD : SHAREFS_REMOVE;
2110*ecd6cf80Smarks 
2111*ecd6cf80Smarks 	error = zshare_fs(opcode,
2112*ecd6cf80Smarks 	    (void *)(uintptr_t)zc->zc_share.z_sharedata,
2113*ecd6cf80Smarks 	    zc->zc_share.z_sharemax);
2114*ecd6cf80Smarks 
2115*ecd6cf80Smarks 	return (error);
2116*ecd6cf80Smarks 
2117*ecd6cf80Smarks }
2118*ecd6cf80Smarks 
2119*ecd6cf80Smarks /*
2120*ecd6cf80Smarks  * pool destroy and pool export don't log the history as part of zfsdev_ioctl,
2121*ecd6cf80Smarks  * but rather zfs_ioc_pool_create, and zfs_ioc_pool_export do the loggin
2122*ecd6cf80Smarks  * of those commands.
2123*ecd6cf80Smarks  */
2124fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = {
2125*ecd6cf80Smarks 	{ zfs_ioc_pool_create, zfs_secpolicy_config, pool_name, B_TRUE },
2126*ecd6cf80Smarks 	{ zfs_ioc_pool_destroy,	zfs_secpolicy_config, pool_name, B_FALSE },
2127*ecd6cf80Smarks 	{ zfs_ioc_pool_import, zfs_secpolicy_config, pool_name, B_TRUE },
2128*ecd6cf80Smarks 	{ zfs_ioc_pool_export, zfs_secpolicy_config, pool_name, B_FALSE },
2129*ecd6cf80Smarks 	{ zfs_ioc_pool_configs,	zfs_secpolicy_none, no_name, B_FALSE },
2130*ecd6cf80Smarks 	{ zfs_ioc_pool_stats, zfs_secpolicy_read, pool_name, B_FALSE },
2131*ecd6cf80Smarks 	{ zfs_ioc_pool_tryimport, zfs_secpolicy_config, no_name, B_FALSE },
2132*ecd6cf80Smarks 	{ zfs_ioc_pool_scrub, zfs_secpolicy_config, pool_name, B_TRUE },
2133*ecd6cf80Smarks 	{ zfs_ioc_pool_freeze, zfs_secpolicy_config, no_name, B_FALSE },
2134*ecd6cf80Smarks 	{ zfs_ioc_pool_upgrade,	zfs_secpolicy_config, pool_name, B_TRUE },
2135*ecd6cf80Smarks 	{ zfs_ioc_pool_get_history, zfs_secpolicy_config, pool_name, B_FALSE },
2136*ecd6cf80Smarks 	{ zfs_ioc_vdev_add, zfs_secpolicy_config, pool_name, B_TRUE },
2137*ecd6cf80Smarks 	{ zfs_ioc_vdev_remove, zfs_secpolicy_config, pool_name, B_TRUE },
2138*ecd6cf80Smarks 	{ zfs_ioc_vdev_set_state, zfs_secpolicy_config,	pool_name, B_TRUE },
2139*ecd6cf80Smarks 	{ zfs_ioc_vdev_attach, zfs_secpolicy_config, pool_name, B_TRUE },
2140*ecd6cf80Smarks 	{ zfs_ioc_vdev_detach, zfs_secpolicy_config, pool_name, B_TRUE },
2141*ecd6cf80Smarks 	{ zfs_ioc_vdev_setpath,	zfs_secpolicy_config, pool_name, B_FALSE },
2142*ecd6cf80Smarks 	{ zfs_ioc_objset_stats,	zfs_secpolicy_read, dataset_name, B_FALSE },
2143*ecd6cf80Smarks 	{ zfs_ioc_dataset_list_next, zfs_secpolicy_read,
2144*ecd6cf80Smarks 	    dataset_name, B_FALSE },
2145*ecd6cf80Smarks 	{ zfs_ioc_snapshot_list_next, zfs_secpolicy_read,
2146*ecd6cf80Smarks 	    dataset_name, B_FALSE },
2147*ecd6cf80Smarks 	{ zfs_ioc_set_prop, zfs_secpolicy_none, dataset_name, B_TRUE },
2148*ecd6cf80Smarks 	{ zfs_ioc_create_minor,	zfs_secpolicy_minor, dataset_name, B_FALSE },
2149*ecd6cf80Smarks 	{ zfs_ioc_remove_minor,	zfs_secpolicy_minor, dataset_name, B_FALSE },
2150*ecd6cf80Smarks 	{ zfs_ioc_create, zfs_secpolicy_create, dataset_name, B_TRUE },
2151*ecd6cf80Smarks 	{ zfs_ioc_destroy, zfs_secpolicy_destroy, dataset_name, B_TRUE },
2152*ecd6cf80Smarks 	{ zfs_ioc_rollback, zfs_secpolicy_rollback, dataset_name, B_TRUE },
2153*ecd6cf80Smarks 	{ zfs_ioc_rename, zfs_secpolicy_rename,	dataset_name, B_TRUE },
2154*ecd6cf80Smarks 	{ zfs_ioc_recvbackup, zfs_secpolicy_receive, dataset_name, B_TRUE },
2155*ecd6cf80Smarks 	{ zfs_ioc_sendbackup, zfs_secpolicy_send, dataset_name, B_TRUE },
2156*ecd6cf80Smarks 	{ zfs_ioc_inject_fault,	zfs_secpolicy_inject, no_name, B_FALSE },
2157*ecd6cf80Smarks 	{ zfs_ioc_clear_fault, zfs_secpolicy_inject, no_name, B_FALSE },
2158*ecd6cf80Smarks 	{ zfs_ioc_inject_list_next, zfs_secpolicy_inject, no_name, B_FALSE },
2159*ecd6cf80Smarks 	{ zfs_ioc_error_log, zfs_secpolicy_inject, pool_name, B_FALSE },
2160*ecd6cf80Smarks 	{ zfs_ioc_clear, zfs_secpolicy_config, pool_name, B_TRUE },
2161*ecd6cf80Smarks 	{ zfs_ioc_promote, zfs_secpolicy_promote, dataset_name, B_TRUE },
2162*ecd6cf80Smarks 	{ zfs_ioc_destroy_snaps, zfs_secpolicy_destroy,	dataset_name, B_TRUE },
2163*ecd6cf80Smarks 	{ zfs_ioc_snapshot, zfs_secpolicy_snapshot, dataset_name, B_TRUE },
2164*ecd6cf80Smarks 	{ zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, pool_name, B_FALSE },
2165*ecd6cf80Smarks 	{ zfs_ioc_obj_to_path, zfs_secpolicy_config, no_name, B_FALSE },
2166*ecd6cf80Smarks 	{ zfs_ioc_pool_set_props, zfs_secpolicy_config,	pool_name, B_TRUE },
2167*ecd6cf80Smarks 	{ zfs_ioc_pool_get_props, zfs_secpolicy_read, pool_name, B_FALSE },
2168*ecd6cf80Smarks 	{ zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, dataset_name, B_TRUE },
2169*ecd6cf80Smarks 	{ zfs_ioc_get_fsacl, zfs_secpolicy_read, dataset_name, B_FALSE },
2170*ecd6cf80Smarks 	{ zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi,
2171*ecd6cf80Smarks 	    dataset_name, B_FALSE },
2172*ecd6cf80Smarks 	{ zfs_ioc_share, zfs_secpolicy_share, dataset_name, B_FALSE }
2173fa9e4066Sahrens };
2174fa9e4066Sahrens 
2175fa9e4066Sahrens static int
2176fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
2177fa9e4066Sahrens {
2178fa9e4066Sahrens 	zfs_cmd_t *zc;
2179fa9e4066Sahrens 	uint_t vec;
21801d452cf5Sahrens 	int error, rc;
2181fa9e4066Sahrens 
2182fa9e4066Sahrens 	if (getminor(dev) != 0)
2183fa9e4066Sahrens 		return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp));
2184fa9e4066Sahrens 
2185fa9e4066Sahrens 	vec = cmd - ZFS_IOC;
2186fa9e4066Sahrens 
2187fa9e4066Sahrens 	if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
2188fa9e4066Sahrens 		return (EINVAL);
2189fa9e4066Sahrens 
2190fa9e4066Sahrens 	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
2191fa9e4066Sahrens 
2192fa9e4066Sahrens 	error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t));
2193fa9e4066Sahrens 
2194fa9e4066Sahrens 	if (error == 0) {
2195fa9e4066Sahrens 		zc->zc_cred = (uintptr_t)cr;
2196fa9e4066Sahrens 		zc->zc_dev = dev;
2197*ecd6cf80Smarks 		error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr);
2198fa9e4066Sahrens 	}
2199fa9e4066Sahrens 
2200fa9e4066Sahrens 	/*
2201fa9e4066Sahrens 	 * Ensure that all pool/dataset names are valid before we pass down to
2202fa9e4066Sahrens 	 * the lower layers.
2203fa9e4066Sahrens 	 */
2204fa9e4066Sahrens 	if (error == 0) {
2205fa9e4066Sahrens 		zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
2206fa9e4066Sahrens 		switch (zfs_ioc_vec[vec].zvec_namecheck) {
2207fa9e4066Sahrens 		case pool_name:
2208fa9e4066Sahrens 			if (pool_namecheck(zc->zc_name, NULL, NULL) != 0)
2209fa9e4066Sahrens 				error = EINVAL;
2210fa9e4066Sahrens 			break;
2211fa9e4066Sahrens 
2212fa9e4066Sahrens 		case dataset_name:
2213fa9e4066Sahrens 			if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0)
2214fa9e4066Sahrens 				error = EINVAL;
2215fa9e4066Sahrens 			break;
22165ad82045Snd 
22175ad82045Snd 		case no_name:
22185ad82045Snd 			break;
2219fa9e4066Sahrens 		}
2220fa9e4066Sahrens 	}
2221fa9e4066Sahrens 
2222fa9e4066Sahrens 	if (error == 0)
2223fa9e4066Sahrens 		error = zfs_ioc_vec[vec].zvec_func(zc);
2224fa9e4066Sahrens 
22251d452cf5Sahrens 	rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t));
2226*ecd6cf80Smarks 	if (error == 0) {
22271d452cf5Sahrens 		error = rc;
2228*ecd6cf80Smarks 		if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE)
2229*ecd6cf80Smarks 			zfs_log_history(zc);
2230*ecd6cf80Smarks 	}
2231fa9e4066Sahrens 
2232fa9e4066Sahrens 	kmem_free(zc, sizeof (zfs_cmd_t));
2233fa9e4066Sahrens 	return (error);
2234fa9e4066Sahrens }
2235fa9e4066Sahrens 
2236fa9e4066Sahrens static int
2237fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2238fa9e4066Sahrens {
2239fa9e4066Sahrens 	if (cmd != DDI_ATTACH)
2240fa9e4066Sahrens 		return (DDI_FAILURE);
2241fa9e4066Sahrens 
2242fa9e4066Sahrens 	if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0,
2243fa9e4066Sahrens 	    DDI_PSEUDO, 0) == DDI_FAILURE)
2244fa9e4066Sahrens 		return (DDI_FAILURE);
2245fa9e4066Sahrens 
2246fa9e4066Sahrens 	zfs_dip = dip;
2247fa9e4066Sahrens 
2248fa9e4066Sahrens 	ddi_report_dev(dip);
2249fa9e4066Sahrens 
2250fa9e4066Sahrens 	return (DDI_SUCCESS);
2251fa9e4066Sahrens }
2252fa9e4066Sahrens 
2253fa9e4066Sahrens static int
2254fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2255fa9e4066Sahrens {
2256fa9e4066Sahrens 	if (spa_busy() || zfs_busy() || zvol_busy())
2257fa9e4066Sahrens 		return (DDI_FAILURE);
2258fa9e4066Sahrens 
2259fa9e4066Sahrens 	if (cmd != DDI_DETACH)
2260fa9e4066Sahrens 		return (DDI_FAILURE);
2261fa9e4066Sahrens 
2262fa9e4066Sahrens 	zfs_dip = NULL;
2263fa9e4066Sahrens 
2264fa9e4066Sahrens 	ddi_prop_remove_all(dip);
2265fa9e4066Sahrens 	ddi_remove_minor_node(dip, NULL);
2266fa9e4066Sahrens 
2267fa9e4066Sahrens 	return (DDI_SUCCESS);
2268fa9e4066Sahrens }
2269fa9e4066Sahrens 
2270fa9e4066Sahrens /*ARGSUSED*/
2271fa9e4066Sahrens static int
2272fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2273fa9e4066Sahrens {
2274fa9e4066Sahrens 	switch (infocmd) {
2275fa9e4066Sahrens 	case DDI_INFO_DEVT2DEVINFO:
2276fa9e4066Sahrens 		*result = zfs_dip;
2277fa9e4066Sahrens 		return (DDI_SUCCESS);
2278fa9e4066Sahrens 
2279fa9e4066Sahrens 	case DDI_INFO_DEVT2INSTANCE:
2280a0965f35Sbonwick 		*result = (void *)0;
2281fa9e4066Sahrens 		return (DDI_SUCCESS);
2282fa9e4066Sahrens 	}
2283fa9e4066Sahrens 
2284fa9e4066Sahrens 	return (DDI_FAILURE);
2285fa9e4066Sahrens }
2286fa9e4066Sahrens 
2287fa9e4066Sahrens /*
2288fa9e4066Sahrens  * OK, so this is a little weird.
2289fa9e4066Sahrens  *
2290fa9e4066Sahrens  * /dev/zfs is the control node, i.e. minor 0.
2291fa9e4066Sahrens  * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0.
2292fa9e4066Sahrens  *
2293fa9e4066Sahrens  * /dev/zfs has basically nothing to do except serve up ioctls,
2294fa9e4066Sahrens  * so most of the standard driver entry points are in zvol.c.
2295fa9e4066Sahrens  */
2296fa9e4066Sahrens static struct cb_ops zfs_cb_ops = {
2297fa9e4066Sahrens 	zvol_open,	/* open */
2298fa9e4066Sahrens 	zvol_close,	/* close */
2299fa9e4066Sahrens 	zvol_strategy,	/* strategy */
2300fa9e4066Sahrens 	nodev,		/* print */
2301fa9e4066Sahrens 	nodev,		/* dump */
2302fa9e4066Sahrens 	zvol_read,	/* read */
2303fa9e4066Sahrens 	zvol_write,	/* write */
2304fa9e4066Sahrens 	zfsdev_ioctl,	/* ioctl */
2305fa9e4066Sahrens 	nodev,		/* devmap */
2306fa9e4066Sahrens 	nodev,		/* mmap */
2307fa9e4066Sahrens 	nodev,		/* segmap */
2308fa9e4066Sahrens 	nochpoll,	/* poll */
2309fa9e4066Sahrens 	ddi_prop_op,	/* prop_op */
2310fa9e4066Sahrens 	NULL,		/* streamtab */
2311fa9e4066Sahrens 	D_NEW | D_MP | D_64BIT,		/* Driver compatibility flag */
2312fa9e4066Sahrens 	CB_REV,		/* version */
2313feb08c6bSbillm 	nodev,		/* async read */
2314feb08c6bSbillm 	nodev,		/* async write */
2315fa9e4066Sahrens };
2316fa9e4066Sahrens 
2317fa9e4066Sahrens static struct dev_ops zfs_dev_ops = {
2318fa9e4066Sahrens 	DEVO_REV,	/* version */
2319fa9e4066Sahrens 	0,		/* refcnt */
2320fa9e4066Sahrens 	zfs_info,	/* info */
2321fa9e4066Sahrens 	nulldev,	/* identify */
2322fa9e4066Sahrens 	nulldev,	/* probe */
2323fa9e4066Sahrens 	zfs_attach,	/* attach */
2324fa9e4066Sahrens 	zfs_detach,	/* detach */
2325fa9e4066Sahrens 	nodev,		/* reset */
2326fa9e4066Sahrens 	&zfs_cb_ops,	/* driver operations */
2327fa9e4066Sahrens 	NULL		/* no bus operations */
2328fa9e4066Sahrens };
2329fa9e4066Sahrens 
2330fa9e4066Sahrens static struct modldrv zfs_modldrv = {
2331e9dbad6fSeschrock 	&mod_driverops, "ZFS storage pool version " ZFS_VERSION_STRING,
2332e9dbad6fSeschrock 	    &zfs_dev_ops
2333fa9e4066Sahrens };
2334fa9e4066Sahrens 
2335fa9e4066Sahrens static struct modlinkage modlinkage = {
2336fa9e4066Sahrens 	MODREV_1,
2337fa9e4066Sahrens 	(void *)&zfs_modlfs,
2338fa9e4066Sahrens 	(void *)&zfs_modldrv,
2339fa9e4066Sahrens 	NULL
2340fa9e4066Sahrens };
2341fa9e4066Sahrens 
2342fa9e4066Sahrens int
2343fa9e4066Sahrens _init(void)
2344fa9e4066Sahrens {
2345fa9e4066Sahrens 	int error;
2346fa9e4066Sahrens 
2347a0965f35Sbonwick 	spa_init(FREAD | FWRITE);
2348a0965f35Sbonwick 	zfs_init();
2349a0965f35Sbonwick 	zvol_init();
2350a0965f35Sbonwick 
2351a0965f35Sbonwick 	if ((error = mod_install(&modlinkage)) != 0) {
2352a0965f35Sbonwick 		zvol_fini();
2353a0965f35Sbonwick 		zfs_fini();
2354a0965f35Sbonwick 		spa_fini();
2355fa9e4066Sahrens 		return (error);
2356a0965f35Sbonwick 	}
2357fa9e4066Sahrens 
2358fa9e4066Sahrens 	error = ldi_ident_from_mod(&modlinkage, &zfs_li);
2359fa9e4066Sahrens 	ASSERT(error == 0);
2360*ecd6cf80Smarks 	mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL);
2361fa9e4066Sahrens 
2362fa9e4066Sahrens 	return (0);
2363fa9e4066Sahrens }
2364fa9e4066Sahrens 
2365fa9e4066Sahrens int
2366fa9e4066Sahrens _fini(void)
2367fa9e4066Sahrens {
2368fa9e4066Sahrens 	int error;
2369fa9e4066Sahrens 
2370ea8dc4b6Seschrock 	if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled)
2371fa9e4066Sahrens 		return (EBUSY);
2372fa9e4066Sahrens 
2373fa9e4066Sahrens 	if ((error = mod_remove(&modlinkage)) != 0)
2374fa9e4066Sahrens 		return (error);
2375fa9e4066Sahrens 
2376fa9e4066Sahrens 	zvol_fini();
2377fa9e4066Sahrens 	zfs_fini();
2378fa9e4066Sahrens 	spa_fini();
2379*ecd6cf80Smarks 	if (zfs_share_inited) {
2380*ecd6cf80Smarks 		(void) ddi_modclose(nfs_mod);
2381*ecd6cf80Smarks 		(void) ddi_modclose(sharefs_mod);
2382*ecd6cf80Smarks 	}
2383fa9e4066Sahrens 
2384fa9e4066Sahrens 	ldi_ident_release(zfs_li);
2385fa9e4066Sahrens 	zfs_li = NULL;
2386*ecd6cf80Smarks 	mutex_destroy(&zfs_share_lock);
2387fa9e4066Sahrens 
2388fa9e4066Sahrens 	return (error);
2389fa9e4066Sahrens }
2390fa9e4066Sahrens 
2391fa9e4066Sahrens int
2392fa9e4066Sahrens _info(struct modinfo *modinfop)
2393fa9e4066Sahrens {
2394fa9e4066Sahrens 	return (mod_info(&modlinkage, modinfop));
2395fa9e4066Sahrens }
2396