xref: /illumos-gate/usr/src/uts/common/fs/zfs/zfs_ioctl.c (revision 40feaa914945406e86e193599d115ea71a171d18)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5441d80aaSlling  * Common Development and Distribution License (the "License").
6441d80aaSlling  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
21fa9e4066Sahrens /*
2255434c77Sek  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23fa9e4066Sahrens  * Use is subject to license terms.
24fa9e4066Sahrens  */
25fa9e4066Sahrens 
26fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
27fa9e4066Sahrens 
28fa9e4066Sahrens #include <sys/types.h>
29fa9e4066Sahrens #include <sys/param.h>
30fa9e4066Sahrens #include <sys/errno.h>
31fa9e4066Sahrens #include <sys/uio.h>
32fa9e4066Sahrens #include <sys/buf.h>
33fa9e4066Sahrens #include <sys/modctl.h>
34fa9e4066Sahrens #include <sys/open.h>
35fa9e4066Sahrens #include <sys/file.h>
36fa9e4066Sahrens #include <sys/kmem.h>
37fa9e4066Sahrens #include <sys/conf.h>
38fa9e4066Sahrens #include <sys/cmn_err.h>
39fa9e4066Sahrens #include <sys/stat.h>
40fa9e4066Sahrens #include <sys/zfs_ioctl.h>
41fa9e4066Sahrens #include <sys/zap.h>
42fa9e4066Sahrens #include <sys/spa.h>
43b1b8ab34Slling #include <sys/spa_impl.h>
44fa9e4066Sahrens #include <sys/vdev.h>
45b1b8ab34Slling #include <sys/vdev_impl.h>
46fa9e4066Sahrens #include <sys/dmu.h>
47fa9e4066Sahrens #include <sys/dsl_dir.h>
48fa9e4066Sahrens #include <sys/dsl_dataset.h>
49fa9e4066Sahrens #include <sys/dsl_prop.h>
50ecd6cf80Smarks #include <sys/dsl_deleg.h>
51ecd6cf80Smarks #include <sys/dmu_objset.h>
52fa9e4066Sahrens #include <sys/ddi.h>
53fa9e4066Sahrens #include <sys/sunddi.h>
54fa9e4066Sahrens #include <sys/sunldi.h>
55fa9e4066Sahrens #include <sys/policy.h>
56fa9e4066Sahrens #include <sys/zone.h>
57fa9e4066Sahrens #include <sys/nvpair.h>
58fa9e4066Sahrens #include <sys/pathname.h>
59fa9e4066Sahrens #include <sys/mount.h>
60fa9e4066Sahrens #include <sys/sdt.h>
61fa9e4066Sahrens #include <sys/fs/zfs.h>
62fa9e4066Sahrens #include <sys/zfs_ctldir.h>
63a2eea2e1Sahrens #include <sys/zvol.h>
64ecd6cf80Smarks #include <sharefs/share.h>
65e7437265Sahrens #include <sys/zfs_znode.h>
66fa9e4066Sahrens 
67fa9e4066Sahrens #include "zfs_namecheck.h"
68e9dbad6fSeschrock #include "zfs_prop.h"
69ecd6cf80Smarks #include "zfs_deleg.h"
70fa9e4066Sahrens 
71fa9e4066Sahrens extern struct modlfs zfs_modlfs;
72fa9e4066Sahrens 
73fa9e4066Sahrens extern void zfs_init(void);
74fa9e4066Sahrens extern void zfs_fini(void);
75fa9e4066Sahrens 
76fa9e4066Sahrens ldi_ident_t zfs_li = NULL;
77fa9e4066Sahrens dev_info_t *zfs_dip;
78fa9e4066Sahrens 
79fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *);
80ecd6cf80Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *);
81fa9e4066Sahrens 
82fa9e4066Sahrens typedef struct zfs_ioc_vec {
83fa9e4066Sahrens 	zfs_ioc_func_t		*zvec_func;
84fa9e4066Sahrens 	zfs_secpolicy_func_t	*zvec_secpolicy;
85fa9e4066Sahrens 	enum {
86e7437265Sahrens 		NO_NAME,
87e7437265Sahrens 		POOL_NAME,
88e7437265Sahrens 		DATASET_NAME
89ecd6cf80Smarks 	} zvec_namecheck;
90ecd6cf80Smarks 	boolean_t		zvec_his_log;
91fa9e4066Sahrens } zfs_ioc_vec_t;
92fa9e4066Sahrens 
93fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */
94fa9e4066Sahrens void
95fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
96fa9e4066Sahrens {
97fa9e4066Sahrens 	const char *newfile;
98fa9e4066Sahrens 	char buf[256];
99fa9e4066Sahrens 	va_list adx;
100fa9e4066Sahrens 
101fa9e4066Sahrens 	/*
102fa9e4066Sahrens 	 * Get rid of annoying "../common/" prefix to filename.
103fa9e4066Sahrens 	 */
104fa9e4066Sahrens 	newfile = strrchr(file, '/');
105fa9e4066Sahrens 	if (newfile != NULL) {
106fa9e4066Sahrens 		newfile = newfile + 1; /* Get rid of leading / */
107fa9e4066Sahrens 	} else {
108fa9e4066Sahrens 		newfile = file;
109fa9e4066Sahrens 	}
110fa9e4066Sahrens 
111fa9e4066Sahrens 	va_start(adx, fmt);
112fa9e4066Sahrens 	(void) vsnprintf(buf, sizeof (buf), fmt, adx);
113fa9e4066Sahrens 	va_end(adx);
114fa9e4066Sahrens 
115fa9e4066Sahrens 	/*
116fa9e4066Sahrens 	 * To get this data, use the zfs-dprintf probe as so:
117fa9e4066Sahrens 	 * dtrace -q -n 'zfs-dprintf \
118fa9e4066Sahrens 	 *	/stringof(arg0) == "dbuf.c"/ \
119fa9e4066Sahrens 	 *	{printf("%s: %s", stringof(arg1), stringof(arg3))}'
120fa9e4066Sahrens 	 * arg0 = file name
121fa9e4066Sahrens 	 * arg1 = function name
122fa9e4066Sahrens 	 * arg2 = line number
123fa9e4066Sahrens 	 * arg3 = message
124fa9e4066Sahrens 	 */
125fa9e4066Sahrens 	DTRACE_PROBE4(zfs__dprintf,
126fa9e4066Sahrens 	    char *, newfile, char *, func, int, line, char *, buf);
127fa9e4066Sahrens }
128fa9e4066Sahrens 
129ecd6cf80Smarks static void
130ecd6cf80Smarks zfs_log_history(zfs_cmd_t *zc)
131ecd6cf80Smarks {
132ecd6cf80Smarks 	spa_t *spa;
133*40feaa91Sahrens 	char *buf;
134ecd6cf80Smarks 
135ecd6cf80Smarks 	if (zc->zc_history == NULL)
136ecd6cf80Smarks 		return;
137ecd6cf80Smarks 
138e7437265Sahrens 	if (zc->zc_history_offset != LOG_CMD_POOL_CREATE &&
139e7437265Sahrens 	    zc->zc_history_offset != LOG_CMD_NORMAL)
140e7437265Sahrens 		return;
141e7437265Sahrens 
142ecd6cf80Smarks 	buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP);
143ecd6cf80Smarks 	if (copyinstr((void *)(uintptr_t)zc->zc_history,
144ecd6cf80Smarks 	    buf, HIS_MAX_RECORD_LEN, NULL) != 0) {
145ecd6cf80Smarks 		kmem_free(buf, HIS_MAX_RECORD_LEN);
146ecd6cf80Smarks 		return;
147ecd6cf80Smarks 	}
148ecd6cf80Smarks 
149ecd6cf80Smarks 	buf[HIS_MAX_RECORD_LEN -1] = '\0';
150ecd6cf80Smarks 
151*40feaa91Sahrens 	if (spa_open(zc->zc_name, &spa, FTAG) != 0) {
152ecd6cf80Smarks 		kmem_free(buf, HIS_MAX_RECORD_LEN);
153ecd6cf80Smarks 		return;
154ecd6cf80Smarks 	}
155ecd6cf80Smarks 
156e7437265Sahrens 	if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY)
157ecd6cf80Smarks 		(void) spa_history_log(spa, buf, zc->zc_history_offset);
158ecd6cf80Smarks 
159ecd6cf80Smarks 	spa_close(spa, FTAG);
160ecd6cf80Smarks 	kmem_free(buf, HIS_MAX_RECORD_LEN);
161ecd6cf80Smarks }
162ecd6cf80Smarks 
163fa9e4066Sahrens /*
164fa9e4066Sahrens  * Policy for top-level read operations (list pools).  Requires no privileges,
165fa9e4066Sahrens  * and can be used in the local zone, as there is no associated dataset.
166fa9e4066Sahrens  */
167fa9e4066Sahrens /* ARGSUSED */
168fa9e4066Sahrens static int
169ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr)
170fa9e4066Sahrens {
171fa9e4066Sahrens 	return (0);
172fa9e4066Sahrens }
173fa9e4066Sahrens 
174fa9e4066Sahrens /*
175fa9e4066Sahrens  * Policy for dataset read operations (list children, get statistics).  Requires
176fa9e4066Sahrens  * no privileges, but must be visible in the local zone.
177fa9e4066Sahrens  */
178fa9e4066Sahrens /* ARGSUSED */
179fa9e4066Sahrens static int
180ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr)
181fa9e4066Sahrens {
182fa9e4066Sahrens 	if (INGLOBALZONE(curproc) ||
183ecd6cf80Smarks 	    zone_dataset_visible(zc->zc_name, NULL))
184fa9e4066Sahrens 		return (0);
185fa9e4066Sahrens 
186fa9e4066Sahrens 	return (ENOENT);
187fa9e4066Sahrens }
188fa9e4066Sahrens 
189fa9e4066Sahrens static int
190fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr)
191fa9e4066Sahrens {
192fa9e4066Sahrens 	uint64_t zoned;
193fa9e4066Sahrens 	int writable = 1;
194fa9e4066Sahrens 
195fa9e4066Sahrens 	/*
196fa9e4066Sahrens 	 * The dataset must be visible by this zone -- check this first
197fa9e4066Sahrens 	 * so they don't see EPERM on something they shouldn't know about.
198fa9e4066Sahrens 	 */
199fa9e4066Sahrens 	if (!INGLOBALZONE(curproc) &&
200fa9e4066Sahrens 	    !zone_dataset_visible(dataset, &writable))
201fa9e4066Sahrens 		return (ENOENT);
202fa9e4066Sahrens 
203fa9e4066Sahrens 	if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL))
204fa9e4066Sahrens 		return (ENOENT);
205fa9e4066Sahrens 
206fa9e4066Sahrens 	if (INGLOBALZONE(curproc)) {
207fa9e4066Sahrens 		/*
208fa9e4066Sahrens 		 * If the fs is zoned, only root can access it from the
209fa9e4066Sahrens 		 * global zone.
210fa9e4066Sahrens 		 */
211fa9e4066Sahrens 		if (secpolicy_zfs(cr) && zoned)
212fa9e4066Sahrens 			return (EPERM);
213fa9e4066Sahrens 	} else {
214fa9e4066Sahrens 		/*
215fa9e4066Sahrens 		 * If we are in a local zone, the 'zoned' property must be set.
216fa9e4066Sahrens 		 */
217fa9e4066Sahrens 		if (!zoned)
218fa9e4066Sahrens 			return (EPERM);
219fa9e4066Sahrens 
220fa9e4066Sahrens 		/* must be writable by this zone */
221fa9e4066Sahrens 		if (!writable)
222fa9e4066Sahrens 			return (EPERM);
223fa9e4066Sahrens 	}
224fa9e4066Sahrens 	return (0);
225fa9e4066Sahrens }
226fa9e4066Sahrens 
227fa9e4066Sahrens int
228ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr)
229fa9e4066Sahrens {
230fa9e4066Sahrens 	int error;
231fa9e4066Sahrens 
232ecd6cf80Smarks 	error = zfs_dozonecheck(name, cr);
233ecd6cf80Smarks 	if (error == 0) {
234ecd6cf80Smarks 		error = secpolicy_zfs(cr);
235ecd6cf80Smarks 		if (error) {
236ecd6cf80Smarks 			error = dsl_deleg_access(name, perm, cr);
237ecd6cf80Smarks 		}
238ecd6cf80Smarks 	}
239ecd6cf80Smarks 	return (error);
240ecd6cf80Smarks }
241ecd6cf80Smarks 
242ecd6cf80Smarks static int
243ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr)
244ecd6cf80Smarks {
245ecd6cf80Smarks 	int error = 0;
246ecd6cf80Smarks 
247ecd6cf80Smarks 	/*
248ecd6cf80Smarks 	 * Check permissions for special properties.
249ecd6cf80Smarks 	 */
250ecd6cf80Smarks 	switch (prop) {
251ecd6cf80Smarks 	case ZFS_PROP_ZONED:
252ecd6cf80Smarks 		/*
253ecd6cf80Smarks 		 * Disallow setting of 'zoned' from within a local zone.
254ecd6cf80Smarks 		 */
255ecd6cf80Smarks 		if (!INGLOBALZONE(curproc))
256ecd6cf80Smarks 			return (EPERM);
257ecd6cf80Smarks 		break;
258ecd6cf80Smarks 
259ecd6cf80Smarks 	case ZFS_PROP_QUOTA:
260ecd6cf80Smarks 		if (error =
261ecd6cf80Smarks 		    zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_QUOTA, cr))
262ecd6cf80Smarks 			return (error);
263ecd6cf80Smarks 
264ecd6cf80Smarks 		if (!INGLOBALZONE(curproc)) {
265ecd6cf80Smarks 			uint64_t zoned;
266ecd6cf80Smarks 			char setpoint[MAXNAMELEN];
267ecd6cf80Smarks 			int dslen;
268ecd6cf80Smarks 			/*
269ecd6cf80Smarks 			 * Unprivileged users are allowed to modify the
270ecd6cf80Smarks 			 * quota on things *under* (ie. contained by)
271ecd6cf80Smarks 			 * the thing they own.
272ecd6cf80Smarks 			 */
273ecd6cf80Smarks 			if (dsl_prop_get_integer(name, "zoned", &zoned,
274ecd6cf80Smarks 			    setpoint))
275ecd6cf80Smarks 				return (EPERM);
276ecd6cf80Smarks 			if (!zoned) /* this shouldn't happen */
277ecd6cf80Smarks 				return (EPERM);
278ecd6cf80Smarks 			dslen = strlen(name);
279ecd6cf80Smarks 			if (dslen <= strlen(setpoint))
280ecd6cf80Smarks 				return (EPERM);
281ecd6cf80Smarks 		}
282ecd6cf80Smarks 	default:
283ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(name,
284ecd6cf80Smarks 		    zfs_prop_perm(prop), cr);
285ecd6cf80Smarks 	}
286ecd6cf80Smarks 
287ecd6cf80Smarks 	return (error);
288ecd6cf80Smarks }
289ecd6cf80Smarks 
290ecd6cf80Smarks int
291ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr)
292ecd6cf80Smarks {
293ecd6cf80Smarks 	int error;
294ecd6cf80Smarks 
295ecd6cf80Smarks 	error = zfs_dozonecheck(zc->zc_name, cr);
296ecd6cf80Smarks 	if (error)
297fa9e4066Sahrens 		return (error);
298fa9e4066Sahrens 
299ecd6cf80Smarks 	/*
300ecd6cf80Smarks 	 * permission to set permissions will be evaluated later in
301ecd6cf80Smarks 	 * dsl_deleg_can_allow()
302ecd6cf80Smarks 	 */
303ecd6cf80Smarks 	return (0);
304ecd6cf80Smarks }
305ecd6cf80Smarks 
306ecd6cf80Smarks int
307ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr)
308ecd6cf80Smarks {
309ecd6cf80Smarks 	int error;
310ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(zc->zc_name,
311ecd6cf80Smarks 	    ZFS_DELEG_PERM_ROLLBACK, cr);
312ecd6cf80Smarks 	if (error == 0)
313ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(zc->zc_name,
314ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr);
315ecd6cf80Smarks 	return (error);
316ecd6cf80Smarks }
317ecd6cf80Smarks 
318ecd6cf80Smarks int
319ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr)
320ecd6cf80Smarks {
321ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(zc->zc_name,
322ecd6cf80Smarks 	    ZFS_DELEG_PERM_SEND, cr));
323ecd6cf80Smarks }
324ecd6cf80Smarks 
325ecd6cf80Smarks int
326ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr)
327ecd6cf80Smarks {
328ecd6cf80Smarks 	if (!INGLOBALZONE(curproc))
329ecd6cf80Smarks 		return (EPERM);
330ecd6cf80Smarks 
331ecd6cf80Smarks 	if (secpolicy_nfs(CRED()) == 0) {
332ecd6cf80Smarks 		return (0);
333ecd6cf80Smarks 	} else {
334ecd6cf80Smarks 		vnode_t *vp;
335ecd6cf80Smarks 		int error;
336ecd6cf80Smarks 
337ecd6cf80Smarks 		if ((error = lookupname(zc->zc_value, UIO_SYSSPACE,
338ecd6cf80Smarks 		    NO_FOLLOW, NULL, &vp)) != 0)
339ecd6cf80Smarks 			return (error);
340ecd6cf80Smarks 
341ecd6cf80Smarks 		/* Now make sure mntpnt and dataset are ZFS */
342ecd6cf80Smarks 
343ecd6cf80Smarks 		if (vp->v_vfsp->vfs_fstype != zfsfstype ||
344ecd6cf80Smarks 		    (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource),
345ecd6cf80Smarks 		    zc->zc_name) != 0)) {
346ecd6cf80Smarks 			VN_RELE(vp);
347ecd6cf80Smarks 			return (EPERM);
348ecd6cf80Smarks 		}
349ecd6cf80Smarks 
350ecd6cf80Smarks 		VN_RELE(vp);
351ecd6cf80Smarks 		return (dsl_deleg_access(zc->zc_name,
352ecd6cf80Smarks 		    ZFS_DELEG_PERM_SHARE, cr));
353ecd6cf80Smarks 	}
354fa9e4066Sahrens }
355fa9e4066Sahrens 
356fa9e4066Sahrens static int
357ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize)
358fa9e4066Sahrens {
359fa9e4066Sahrens 	char *cp;
360fa9e4066Sahrens 
361fa9e4066Sahrens 	/*
362fa9e4066Sahrens 	 * Remove the @bla or /bla from the end of the name to get the parent.
363fa9e4066Sahrens 	 */
364ecd6cf80Smarks 	(void) strncpy(parent, datasetname, parentsize);
365ecd6cf80Smarks 	cp = strrchr(parent, '@');
366fa9e4066Sahrens 	if (cp != NULL) {
367fa9e4066Sahrens 		cp[0] = '\0';
368fa9e4066Sahrens 	} else {
369ecd6cf80Smarks 		cp = strrchr(parent, '/');
370fa9e4066Sahrens 		if (cp == NULL)
371fa9e4066Sahrens 			return (ENOENT);
372fa9e4066Sahrens 		cp[0] = '\0';
373ecd6cf80Smarks 	}
374ecd6cf80Smarks 
375ecd6cf80Smarks 	return (0);
376ecd6cf80Smarks }
377ecd6cf80Smarks 
378ecd6cf80Smarks int
379ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr)
380ecd6cf80Smarks {
381ecd6cf80Smarks 	int error;
382ecd6cf80Smarks 
383ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(name,
384ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
385ecd6cf80Smarks 		return (error);
386ecd6cf80Smarks 
387ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr));
388ecd6cf80Smarks }
389ecd6cf80Smarks 
390ecd6cf80Smarks static int
391ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr)
392ecd6cf80Smarks {
393ecd6cf80Smarks 	return (zfs_secpolicy_destroy_perms(zc->zc_name, cr));
394ecd6cf80Smarks }
395ecd6cf80Smarks 
396ecd6cf80Smarks /*
397ecd6cf80Smarks  * Must have sys_config privilege to check the iscsi permission
398ecd6cf80Smarks  */
399ecd6cf80Smarks /* ARGSUSED */
400ecd6cf80Smarks static int
401ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr)
402ecd6cf80Smarks {
403ecd6cf80Smarks 	return (secpolicy_zfs(cr));
404ecd6cf80Smarks }
405ecd6cf80Smarks 
406ecd6cf80Smarks int
407ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
408ecd6cf80Smarks {
409ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
410ecd6cf80Smarks 	int	error;
411ecd6cf80Smarks 
412ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(from,
413ecd6cf80Smarks 	    ZFS_DELEG_PERM_RENAME, cr)) != 0)
414ecd6cf80Smarks 		return (error);
415ecd6cf80Smarks 
416ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(from,
417ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
418ecd6cf80Smarks 		return (error);
419ecd6cf80Smarks 
420ecd6cf80Smarks 	if ((error = zfs_get_parent(to, parentname,
421ecd6cf80Smarks 	    sizeof (parentname))) != 0)
422ecd6cf80Smarks 		return (error);
423ecd6cf80Smarks 
424ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
425ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr)) != 0)
426ecd6cf80Smarks 		return (error);
427ecd6cf80Smarks 
428ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
429ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
430ecd6cf80Smarks 		return (error);
431ecd6cf80Smarks 
432ecd6cf80Smarks 	return (error);
433ecd6cf80Smarks }
434ecd6cf80Smarks 
435ecd6cf80Smarks static int
436ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr)
437ecd6cf80Smarks {
438ecd6cf80Smarks 	return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr));
439ecd6cf80Smarks }
440ecd6cf80Smarks 
441ecd6cf80Smarks static int
442ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr)
443ecd6cf80Smarks {
444ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
445ecd6cf80Smarks 	objset_t *clone;
446ecd6cf80Smarks 	int error;
447ecd6cf80Smarks 
448ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(zc->zc_name,
449ecd6cf80Smarks 	    ZFS_DELEG_PERM_PROMOTE, cr);
450ecd6cf80Smarks 	if (error)
451ecd6cf80Smarks 		return (error);
452ecd6cf80Smarks 
453ecd6cf80Smarks 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
454ecd6cf80Smarks 	    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
455ecd6cf80Smarks 
456ecd6cf80Smarks 	if (error == 0) {
457ecd6cf80Smarks 		dsl_dataset_t *pclone = NULL;
458ecd6cf80Smarks 		dsl_dir_t *dd;
459ecd6cf80Smarks 		dd = clone->os->os_dsl_dataset->ds_dir;
460ecd6cf80Smarks 
461ecd6cf80Smarks 		rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
462ecd6cf80Smarks 		error = dsl_dataset_open_obj(dd->dd_pool,
463ecd6cf80Smarks 		    dd->dd_phys->dd_clone_parent_obj, NULL,
464ecd6cf80Smarks 		    DS_MODE_NONE, FTAG, &pclone);
465ecd6cf80Smarks 		rw_exit(&dd->dd_pool->dp_config_rwlock);
466ecd6cf80Smarks 		if (error) {
467ecd6cf80Smarks 			dmu_objset_close(clone);
468ecd6cf80Smarks 			return (error);
469ecd6cf80Smarks 		}
470ecd6cf80Smarks 
471ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(zc->zc_name,
472ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr);
473ecd6cf80Smarks 
474ecd6cf80Smarks 		dsl_dataset_name(pclone, parentname);
475ecd6cf80Smarks 		dmu_objset_close(clone);
476ecd6cf80Smarks 		dsl_dataset_close(pclone, DS_MODE_NONE, FTAG);
477ecd6cf80Smarks 		if (error == 0)
478ecd6cf80Smarks 			error = zfs_secpolicy_write_perms(parentname,
479ecd6cf80Smarks 			    ZFS_DELEG_PERM_PROMOTE, cr);
480ecd6cf80Smarks 	}
481ecd6cf80Smarks 	return (error);
482ecd6cf80Smarks }
483ecd6cf80Smarks 
484ecd6cf80Smarks static int
485ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr)
486ecd6cf80Smarks {
487ecd6cf80Smarks 	int error;
488ecd6cf80Smarks 
489ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(zc->zc_name,
490ecd6cf80Smarks 	    ZFS_DELEG_PERM_RECEIVE, cr)) != 0)
491ecd6cf80Smarks 		return (error);
492ecd6cf80Smarks 
493ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(zc->zc_name,
494ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
495ecd6cf80Smarks 		return (error);
496ecd6cf80Smarks 
497ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(zc->zc_name,
498ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr));
499ecd6cf80Smarks }
500ecd6cf80Smarks 
501ecd6cf80Smarks int
502ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
503ecd6cf80Smarks {
504ecd6cf80Smarks 	int error;
505ecd6cf80Smarks 
506ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(name,
507ecd6cf80Smarks 	    ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0)
508ecd6cf80Smarks 		return (error);
509ecd6cf80Smarks 
510ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(name,
511ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr);
512ecd6cf80Smarks 
513ecd6cf80Smarks 	return (error);
514ecd6cf80Smarks }
515ecd6cf80Smarks 
516ecd6cf80Smarks static int
517ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr)
518ecd6cf80Smarks {
519ecd6cf80Smarks 
520ecd6cf80Smarks 	return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr));
521ecd6cf80Smarks }
522ecd6cf80Smarks 
523ecd6cf80Smarks static int
524ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr)
525ecd6cf80Smarks {
526ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
527ecd6cf80Smarks 	int 	error;
528ecd6cf80Smarks 
529ecd6cf80Smarks 	if ((error = zfs_get_parent(zc->zc_name, parentname,
530ecd6cf80Smarks 	    sizeof (parentname))) != 0)
531ecd6cf80Smarks 		return (error);
532fa9e4066Sahrens 
533ecd6cf80Smarks 	if (zc->zc_value[0] != '\0') {
534ecd6cf80Smarks 		if ((error = zfs_secpolicy_write_perms(zc->zc_value,
535ecd6cf80Smarks 		    ZFS_DELEG_PERM_CLONE, cr)) != 0)
536ecd6cf80Smarks 			return (error);
537fa9e4066Sahrens 	}
538fa9e4066Sahrens 
539ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
540ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr)) != 0)
541ecd6cf80Smarks 		return (error);
542ecd6cf80Smarks 
543ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(parentname,
544ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr);
545ecd6cf80Smarks 
546ecd6cf80Smarks 	return (error);
547ecd6cf80Smarks }
548ecd6cf80Smarks 
549ecd6cf80Smarks static int
550ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr)
551ecd6cf80Smarks {
552ecd6cf80Smarks 	int error;
553ecd6cf80Smarks 
554ecd6cf80Smarks 	error = secpolicy_fs_unmount(cr, NULL);
555ecd6cf80Smarks 	if (error) {
556ecd6cf80Smarks 		error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr);
557ecd6cf80Smarks 	}
558ecd6cf80Smarks 	return (error);
559fa9e4066Sahrens }
560fa9e4066Sahrens 
561fa9e4066Sahrens /*
562fa9e4066Sahrens  * Policy for pool operations - create/destroy pools, add vdevs, etc.  Requires
563fa9e4066Sahrens  * SYS_CONFIG privilege, which is not available in a local zone.
564fa9e4066Sahrens  */
565fa9e4066Sahrens /* ARGSUSED */
566fa9e4066Sahrens static int
567ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr)
568fa9e4066Sahrens {
569fa9e4066Sahrens 	if (secpolicy_sys_config(cr, B_FALSE) != 0)
570fa9e4066Sahrens 		return (EPERM);
571fa9e4066Sahrens 
572fa9e4066Sahrens 	return (0);
573fa9e4066Sahrens }
574fa9e4066Sahrens 
575ecd6cf80Smarks /*
576ecd6cf80Smarks  * Just like zfs_secpolicy_config, except that we will check for
577ecd6cf80Smarks  * mount permission on the dataset for permission to create/remove
578ecd6cf80Smarks  * the minor nodes.
579ecd6cf80Smarks  */
580ecd6cf80Smarks static int
581ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr)
582ecd6cf80Smarks {
583ecd6cf80Smarks 	if (secpolicy_sys_config(cr, B_FALSE) != 0) {
584ecd6cf80Smarks 		return (dsl_deleg_access(zc->zc_name,
585ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr));
586ecd6cf80Smarks 	}
587ecd6cf80Smarks 
588ecd6cf80Smarks 	return (0);
589ecd6cf80Smarks }
590ecd6cf80Smarks 
591ea8dc4b6Seschrock /*
592ea8dc4b6Seschrock  * Policy for fault injection.  Requires all privileges.
593ea8dc4b6Seschrock  */
594ea8dc4b6Seschrock /* ARGSUSED */
595ea8dc4b6Seschrock static int
596ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr)
597ea8dc4b6Seschrock {
598ea8dc4b6Seschrock 	return (secpolicy_zinject(cr));
599ea8dc4b6Seschrock }
600ea8dc4b6Seschrock 
601fa9e4066Sahrens /*
602fa9e4066Sahrens  * Returns the nvlist as specified by the user in the zfs_cmd_t.
603fa9e4066Sahrens  */
604fa9e4066Sahrens static int
605e9dbad6fSeschrock get_nvlist(zfs_cmd_t *zc, nvlist_t **nvp)
606fa9e4066Sahrens {
607fa9e4066Sahrens 	char *packed;
608fa9e4066Sahrens 	size_t size;
609fa9e4066Sahrens 	int error;
610fa9e4066Sahrens 	nvlist_t *config = NULL;
611fa9e4066Sahrens 
612fa9e4066Sahrens 	/*
613e9dbad6fSeschrock 	 * Read in and unpack the user-supplied nvlist.
614fa9e4066Sahrens 	 */
615e9dbad6fSeschrock 	if ((size = zc->zc_nvlist_src_size) == 0)
616fa9e4066Sahrens 		return (EINVAL);
617fa9e4066Sahrens 
618fa9e4066Sahrens 	packed = kmem_alloc(size, KM_SLEEP);
619fa9e4066Sahrens 
620e9dbad6fSeschrock 	if ((error = xcopyin((void *)(uintptr_t)zc->zc_nvlist_src, packed,
621fa9e4066Sahrens 	    size)) != 0) {
622fa9e4066Sahrens 		kmem_free(packed, size);
623fa9e4066Sahrens 		return (error);
624fa9e4066Sahrens 	}
625fa9e4066Sahrens 
626fa9e4066Sahrens 	if ((error = nvlist_unpack(packed, size, &config, 0)) != 0) {
627fa9e4066Sahrens 		kmem_free(packed, size);
628fa9e4066Sahrens 		return (error);
629fa9e4066Sahrens 	}
630fa9e4066Sahrens 
631fa9e4066Sahrens 	kmem_free(packed, size);
632fa9e4066Sahrens 
633fa9e4066Sahrens 	*nvp = config;
634fa9e4066Sahrens 	return (0);
635fa9e4066Sahrens }
636fa9e4066Sahrens 
637e9dbad6fSeschrock static int
638e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
639e9dbad6fSeschrock {
640e9dbad6fSeschrock 	char *packed = NULL;
641e9dbad6fSeschrock 	size_t size;
642e9dbad6fSeschrock 	int error;
643e9dbad6fSeschrock 
644e9dbad6fSeschrock 	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
645e9dbad6fSeschrock 
646e9dbad6fSeschrock 	if (size > zc->zc_nvlist_dst_size) {
647e9dbad6fSeschrock 		error = ENOMEM;
648e9dbad6fSeschrock 	} else {
649e9dbad6fSeschrock 		VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
650e9dbad6fSeschrock 		    KM_SLEEP) == 0);
651e9dbad6fSeschrock 		error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst,
652e9dbad6fSeschrock 		    size);
653e9dbad6fSeschrock 		kmem_free(packed, size);
654e9dbad6fSeschrock 	}
655e9dbad6fSeschrock 
656e9dbad6fSeschrock 	zc->zc_nvlist_dst_size = size;
657e9dbad6fSeschrock 	return (error);
658e9dbad6fSeschrock }
659e9dbad6fSeschrock 
660fa9e4066Sahrens static int
661fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc)
662fa9e4066Sahrens {
663fa9e4066Sahrens 	int error;
664fa9e4066Sahrens 	nvlist_t *config;
665fa9e4066Sahrens 
666e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) != 0)
667fa9e4066Sahrens 		return (error);
668fa9e4066Sahrens 
669e9dbad6fSeschrock 	error = spa_create(zc->zc_name, config, zc->zc_value[0] == '\0' ?
670e9dbad6fSeschrock 	    NULL : zc->zc_value);
671fa9e4066Sahrens 
672fa9e4066Sahrens 	nvlist_free(config);
673fa9e4066Sahrens 
674fa9e4066Sahrens 	return (error);
675fa9e4066Sahrens }
676fa9e4066Sahrens 
677fa9e4066Sahrens static int
678fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc)
679fa9e4066Sahrens {
680ecd6cf80Smarks 	int error;
681ecd6cf80Smarks 	zfs_log_history(zc);
682ecd6cf80Smarks 	error = spa_destroy(zc->zc_name);
683ecd6cf80Smarks 	return (error);
684fa9e4066Sahrens }
685fa9e4066Sahrens 
686fa9e4066Sahrens static int
687fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc)
688fa9e4066Sahrens {
689fa9e4066Sahrens 	int error;
690fa9e4066Sahrens 	nvlist_t *config;
691fa9e4066Sahrens 	uint64_t guid;
692fa9e4066Sahrens 
693e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) != 0)
694fa9e4066Sahrens 		return (error);
695fa9e4066Sahrens 
696fa9e4066Sahrens 	if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
697ea8dc4b6Seschrock 	    guid != zc->zc_guid)
698fa9e4066Sahrens 		error = EINVAL;
699fa9e4066Sahrens 	else
700fa9e4066Sahrens 		error = spa_import(zc->zc_name, config,
701e9dbad6fSeschrock 		    zc->zc_value[0] == '\0' ? NULL : zc->zc_value);
702fa9e4066Sahrens 
703fa9e4066Sahrens 	nvlist_free(config);
704fa9e4066Sahrens 
705fa9e4066Sahrens 	return (error);
706fa9e4066Sahrens }
707fa9e4066Sahrens 
708fa9e4066Sahrens static int
709fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc)
710fa9e4066Sahrens {
711ecd6cf80Smarks 	int error;
712ecd6cf80Smarks 	zfs_log_history(zc);
713ecd6cf80Smarks 	error = spa_export(zc->zc_name, NULL);
714ecd6cf80Smarks 	return (error);
715fa9e4066Sahrens }
716fa9e4066Sahrens 
717fa9e4066Sahrens static int
718fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc)
719fa9e4066Sahrens {
720fa9e4066Sahrens 	nvlist_t *configs;
721fa9e4066Sahrens 	int error;
722fa9e4066Sahrens 
723fa9e4066Sahrens 	if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
724fa9e4066Sahrens 		return (EEXIST);
725fa9e4066Sahrens 
726e9dbad6fSeschrock 	error = put_nvlist(zc, configs);
727fa9e4066Sahrens 
728fa9e4066Sahrens 	nvlist_free(configs);
729fa9e4066Sahrens 
730fa9e4066Sahrens 	return (error);
731fa9e4066Sahrens }
732fa9e4066Sahrens 
733fa9e4066Sahrens static int
734fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc)
735fa9e4066Sahrens {
736fa9e4066Sahrens 	nvlist_t *config;
737fa9e4066Sahrens 	int error;
738ea8dc4b6Seschrock 	int ret = 0;
739fa9e4066Sahrens 
740e9dbad6fSeschrock 	error = spa_get_stats(zc->zc_name, &config, zc->zc_value,
741e9dbad6fSeschrock 	    sizeof (zc->zc_value));
742fa9e4066Sahrens 
743fa9e4066Sahrens 	if (config != NULL) {
744e9dbad6fSeschrock 		ret = put_nvlist(zc, config);
745fa9e4066Sahrens 		nvlist_free(config);
746ea8dc4b6Seschrock 
747ea8dc4b6Seschrock 		/*
748ea8dc4b6Seschrock 		 * The config may be present even if 'error' is non-zero.
749ea8dc4b6Seschrock 		 * In this case we return success, and preserve the real errno
750ea8dc4b6Seschrock 		 * in 'zc_cookie'.
751ea8dc4b6Seschrock 		 */
752ea8dc4b6Seschrock 		zc->zc_cookie = error;
753fa9e4066Sahrens 	} else {
754ea8dc4b6Seschrock 		ret = error;
755fa9e4066Sahrens 	}
756fa9e4066Sahrens 
757ea8dc4b6Seschrock 	return (ret);
758fa9e4066Sahrens }
759fa9e4066Sahrens 
760fa9e4066Sahrens /*
761fa9e4066Sahrens  * Try to import the given pool, returning pool stats as appropriate so that
762fa9e4066Sahrens  * user land knows which devices are available and overall pool health.
763fa9e4066Sahrens  */
764fa9e4066Sahrens static int
765fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
766fa9e4066Sahrens {
767fa9e4066Sahrens 	nvlist_t *tryconfig, *config;
768fa9e4066Sahrens 	int error;
769fa9e4066Sahrens 
770e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &tryconfig)) != 0)
771fa9e4066Sahrens 		return (error);
772fa9e4066Sahrens 
773fa9e4066Sahrens 	config = spa_tryimport(tryconfig);
774fa9e4066Sahrens 
775fa9e4066Sahrens 	nvlist_free(tryconfig);
776fa9e4066Sahrens 
777fa9e4066Sahrens 	if (config == NULL)
778fa9e4066Sahrens 		return (EINVAL);
779fa9e4066Sahrens 
780e9dbad6fSeschrock 	error = put_nvlist(zc, config);
781fa9e4066Sahrens 	nvlist_free(config);
782fa9e4066Sahrens 
783fa9e4066Sahrens 	return (error);
784fa9e4066Sahrens }
785fa9e4066Sahrens 
786fa9e4066Sahrens static int
787fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc)
788fa9e4066Sahrens {
789fa9e4066Sahrens 	spa_t *spa;
790fa9e4066Sahrens 	int error;
791fa9e4066Sahrens 
79206eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
79306eeb2adSek 		return (error);
79406eeb2adSek 
7953d7072f8Seschrock 	spa_config_enter(spa, RW_READER, FTAG);
79606eeb2adSek 	error = spa_scrub(spa, zc->zc_cookie, B_FALSE);
7973d7072f8Seschrock 	spa_config_exit(spa, FTAG);
79806eeb2adSek 
79906eeb2adSek 	spa_close(spa, FTAG);
80006eeb2adSek 
801fa9e4066Sahrens 	return (error);
802fa9e4066Sahrens }
803fa9e4066Sahrens 
804fa9e4066Sahrens static int
805fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc)
806fa9e4066Sahrens {
807fa9e4066Sahrens 	spa_t *spa;
808fa9e4066Sahrens 	int error;
809fa9e4066Sahrens 
810fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
811fa9e4066Sahrens 	if (error == 0) {
812fa9e4066Sahrens 		spa_freeze(spa);
813fa9e4066Sahrens 		spa_close(spa, FTAG);
814fa9e4066Sahrens 	}
815fa9e4066Sahrens 	return (error);
816fa9e4066Sahrens }
817fa9e4066Sahrens 
818eaca9bbdSeschrock static int
819eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc)
820eaca9bbdSeschrock {
821eaca9bbdSeschrock 	spa_t *spa;
822eaca9bbdSeschrock 	int error;
823eaca9bbdSeschrock 
82406eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
82506eeb2adSek 		return (error);
82606eeb2adSek 
82706eeb2adSek 	spa_upgrade(spa);
82806eeb2adSek 	spa_close(spa, FTAG);
82906eeb2adSek 
83006eeb2adSek 	return (error);
83106eeb2adSek }
83206eeb2adSek 
83306eeb2adSek static int
83406eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc)
83506eeb2adSek {
83606eeb2adSek 	spa_t *spa;
83706eeb2adSek 	char *hist_buf;
83806eeb2adSek 	uint64_t size;
83906eeb2adSek 	int error;
84006eeb2adSek 
84106eeb2adSek 	if ((size = zc->zc_history_len) == 0)
84206eeb2adSek 		return (EINVAL);
84306eeb2adSek 
84406eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
84506eeb2adSek 		return (error);
84606eeb2adSek 
847e7437265Sahrens 	if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) {
848d7306b64Sek 		spa_close(spa, FTAG);
849d7306b64Sek 		return (ENOTSUP);
850d7306b64Sek 	}
851d7306b64Sek 
85206eeb2adSek 	hist_buf = kmem_alloc(size, KM_SLEEP);
85306eeb2adSek 	if ((error = spa_history_get(spa, &zc->zc_history_offset,
85406eeb2adSek 	    &zc->zc_history_len, hist_buf)) == 0) {
855ecd6cf80Smarks 		error = xcopyout(hist_buf,
856ecd6cf80Smarks 		    (char *)(uintptr_t)zc->zc_history,
85706eeb2adSek 		    zc->zc_history_len);
85806eeb2adSek 	}
85906eeb2adSek 
86006eeb2adSek 	spa_close(spa, FTAG);
86106eeb2adSek 	kmem_free(hist_buf, size);
86206eeb2adSek 	return (error);
86306eeb2adSek }
86406eeb2adSek 
86555434c77Sek static int
86655434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc)
86755434c77Sek {
86855434c77Sek 	int error;
86955434c77Sek 
870b1b8ab34Slling 	if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value))
87155434c77Sek 		return (error);
87255434c77Sek 
87355434c77Sek 	return (0);
87455434c77Sek }
87555434c77Sek 
87655434c77Sek static int
87755434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc)
87855434c77Sek {
87955434c77Sek 	objset_t *osp;
88055434c77Sek 	int error;
88155434c77Sek 
88255434c77Sek 	if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS,
88355434c77Sek 	    DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0)
88455434c77Sek 		return (error);
88555434c77Sek 
88655434c77Sek 	error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value,
88755434c77Sek 	    sizeof (zc->zc_value));
88855434c77Sek 	dmu_objset_close(osp);
88955434c77Sek 
89055434c77Sek 	return (error);
89155434c77Sek }
89255434c77Sek 
893fa9e4066Sahrens static int
894fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc)
895fa9e4066Sahrens {
896fa9e4066Sahrens 	spa_t *spa;
897fa9e4066Sahrens 	int error;
898fa9e4066Sahrens 	nvlist_t *config;
899fa9e4066Sahrens 
900fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
901fa9e4066Sahrens 	if (error != 0)
902fa9e4066Sahrens 		return (error);
903fa9e4066Sahrens 
904b1b8ab34Slling 	/*
905b1b8ab34Slling 	 * A root pool with concatenated devices is not supported.
906b1b8ab34Slling 	 * Thus, can not add a device to a root pool with one device.
907b1b8ab34Slling 	 */
908b1b8ab34Slling 	if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) {
909b1b8ab34Slling 		spa_close(spa, FTAG);
910b1b8ab34Slling 		return (EDOM);
911b1b8ab34Slling 	}
912b1b8ab34Slling 
913e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) == 0) {
914fa9e4066Sahrens 		error = spa_vdev_add(spa, config);
915fa9e4066Sahrens 		nvlist_free(config);
916fa9e4066Sahrens 	}
917fa9e4066Sahrens 	spa_close(spa, FTAG);
918fa9e4066Sahrens 	return (error);
919fa9e4066Sahrens }
920fa9e4066Sahrens 
921fa9e4066Sahrens static int
922fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc)
923fa9e4066Sahrens {
92499653d4eSeschrock 	spa_t *spa;
92599653d4eSeschrock 	int error;
92699653d4eSeschrock 
92799653d4eSeschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
92899653d4eSeschrock 	if (error != 0)
92999653d4eSeschrock 		return (error);
93099653d4eSeschrock 	error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE);
93199653d4eSeschrock 	spa_close(spa, FTAG);
93299653d4eSeschrock 	return (error);
933fa9e4066Sahrens }
934fa9e4066Sahrens 
935fa9e4066Sahrens static int
9363d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc)
937fa9e4066Sahrens {
938fa9e4066Sahrens 	spa_t *spa;
939fa9e4066Sahrens 	int error;
9403d7072f8Seschrock 	vdev_state_t newstate = VDEV_STATE_UNKNOWN;
941fa9e4066Sahrens 
94206eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
943fa9e4066Sahrens 		return (error);
9443d7072f8Seschrock 	switch (zc->zc_cookie) {
9453d7072f8Seschrock 	case VDEV_STATE_ONLINE:
9463d7072f8Seschrock 		error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate);
9473d7072f8Seschrock 		break;
948fa9e4066Sahrens 
9493d7072f8Seschrock 	case VDEV_STATE_OFFLINE:
9503d7072f8Seschrock 		error = vdev_offline(spa, zc->zc_guid, zc->zc_obj);
9513d7072f8Seschrock 		break;
952fa9e4066Sahrens 
9533d7072f8Seschrock 	case VDEV_STATE_FAULTED:
9543d7072f8Seschrock 		error = vdev_fault(spa, zc->zc_guid);
9553d7072f8Seschrock 		break;
9563d7072f8Seschrock 
9573d7072f8Seschrock 	case VDEV_STATE_DEGRADED:
9583d7072f8Seschrock 		error = vdev_degrade(spa, zc->zc_guid);
9593d7072f8Seschrock 		break;
9603d7072f8Seschrock 
9613d7072f8Seschrock 	default:
9623d7072f8Seschrock 		error = EINVAL;
9633d7072f8Seschrock 	}
9643d7072f8Seschrock 	zc->zc_cookie = newstate;
965fa9e4066Sahrens 	spa_close(spa, FTAG);
966fa9e4066Sahrens 	return (error);
967fa9e4066Sahrens }
968fa9e4066Sahrens 
969fa9e4066Sahrens static int
970fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc)
971fa9e4066Sahrens {
972fa9e4066Sahrens 	spa_t *spa;
973fa9e4066Sahrens 	int replacing = zc->zc_cookie;
974fa9e4066Sahrens 	nvlist_t *config;
975fa9e4066Sahrens 	int error;
976fa9e4066Sahrens 
97706eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
978fa9e4066Sahrens 		return (error);
979fa9e4066Sahrens 
980e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &config)) == 0) {
981ea8dc4b6Seschrock 		error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
982fa9e4066Sahrens 		nvlist_free(config);
983fa9e4066Sahrens 	}
984fa9e4066Sahrens 
985fa9e4066Sahrens 	spa_close(spa, FTAG);
986fa9e4066Sahrens 	return (error);
987fa9e4066Sahrens }
988fa9e4066Sahrens 
989fa9e4066Sahrens static int
990fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc)
991fa9e4066Sahrens {
992fa9e4066Sahrens 	spa_t *spa;
993fa9e4066Sahrens 	int error;
994fa9e4066Sahrens 
99506eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
996fa9e4066Sahrens 		return (error);
997fa9e4066Sahrens 
998ea8dc4b6Seschrock 	error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE);
999fa9e4066Sahrens 
1000fa9e4066Sahrens 	spa_close(spa, FTAG);
1001fa9e4066Sahrens 	return (error);
1002fa9e4066Sahrens }
1003fa9e4066Sahrens 
1004c67d9675Seschrock static int
1005c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
1006c67d9675Seschrock {
1007c67d9675Seschrock 	spa_t *spa;
1008e9dbad6fSeschrock 	char *path = zc->zc_value;
1009ea8dc4b6Seschrock 	uint64_t guid = zc->zc_guid;
1010c67d9675Seschrock 	int error;
1011c67d9675Seschrock 
1012c67d9675Seschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
1013c67d9675Seschrock 	if (error != 0)
1014c67d9675Seschrock 		return (error);
1015c67d9675Seschrock 
1016c67d9675Seschrock 	error = spa_vdev_setpath(spa, guid, path);
1017c67d9675Seschrock 	spa_close(spa, FTAG);
1018c67d9675Seschrock 	return (error);
1019c67d9675Seschrock }
1020c67d9675Seschrock 
1021fa9e4066Sahrens static int
1022fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc)
1023fa9e4066Sahrens {
1024fa9e4066Sahrens 	objset_t *os = NULL;
1025fa9e4066Sahrens 	int error;
10267f7322feSeschrock 	nvlist_t *nv;
1027fa9e4066Sahrens 
1028fa9e4066Sahrens retry:
1029fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1030fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
1031fa9e4066Sahrens 	if (error != 0) {
1032fa9e4066Sahrens 		/*
1033fa9e4066Sahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
1034fa9e4066Sahrens 		 * the objset is held exclusively. Fortunately this hold is
1035fa9e4066Sahrens 		 * only for a short while, so we retry here.
1036fa9e4066Sahrens 		 * This avoids user code having to handle EBUSY,
1037fa9e4066Sahrens 		 * for example for a "zfs list".
1038fa9e4066Sahrens 		 */
1039fa9e4066Sahrens 		if (error == EBUSY) {
1040fa9e4066Sahrens 			delay(1);
1041fa9e4066Sahrens 			goto retry;
1042fa9e4066Sahrens 		}
1043fa9e4066Sahrens 		return (error);
1044fa9e4066Sahrens 	}
1045fa9e4066Sahrens 
1046a2eea2e1Sahrens 	dmu_objset_fast_stat(os, &zc->zc_objset_stats);
1047fa9e4066Sahrens 
10485ad82045Snd 	if (zc->zc_nvlist_dst != 0 &&
10497f7322feSeschrock 	    (error = dsl_prop_get_all(os, &nv)) == 0) {
1050a2eea2e1Sahrens 		dmu_objset_stats(os, nv);
1051432f72fdSahrens 		/*
1052e7437265Sahrens 		 * NB: {zpl,zvol}_get_stats() will read the objset contents,
1053432f72fdSahrens 		 * which we aren't supposed to do with a
1054432f72fdSahrens 		 * DS_MODE_STANDARD open, because it could be
1055432f72fdSahrens 		 * inconsistent.  So this is a bit of a workaround...
1056432f72fdSahrens 		 */
1057e7437265Sahrens 		if (!zc->zc_objset_stats.dds_inconsistent) {
1058e7437265Sahrens 			if (dmu_objset_type(os) == DMU_OST_ZVOL)
1059e7437265Sahrens 				VERIFY(zvol_get_stats(os, nv) == 0);
1060e7437265Sahrens 			else if (dmu_objset_type(os) == DMU_OST_ZFS)
1061e7437265Sahrens 				(void) zfs_get_stats(os, nv);
1062e7437265Sahrens 		}
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 
1183ecd6cf80Smarks 	/*
1184ecd6cf80Smarks 	 * First validate permission to set all of the properties
1185ecd6cf80Smarks 	 */
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 
1200ecd6cf80Smarks 			error = zfs_secpolicy_write_perms(name,
1201ecd6cf80Smarks 			    ZFS_DELEG_PERM_USERPROP, cr);
1202ecd6cf80Smarks 			if (error) {
1203ecd6cf80Smarks 				return (EPERM);
1204ecd6cf80Smarks 			}
1205ecd6cf80Smarks 			continue;
1206e9dbad6fSeschrock 		}
1207fa9e4066Sahrens 
1208e9dbad6fSeschrock 		/*
1209ecd6cf80Smarks 		 * Check permissions for special properties
1210e9dbad6fSeschrock 		 */
1211ecd6cf80Smarks 
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) {
1255ecd6cf80Smarks 				spa_t *spa;
1256c9431fa1Sahl 
1257*40feaa91Sahrens 				if (spa_open(name, &spa, FTAG) == 0) {
1258c9431fa1Sahl 					if (spa_version(spa) <
1259e7437265Sahrens 					    SPA_VERSION_GZIP_COMPRESSION) {
1260c9431fa1Sahl 						spa_close(spa, FTAG);
1261c9431fa1Sahl 						return (ENOTSUP);
1262c9431fa1Sahl 					}
1263c9431fa1Sahl 
1264c9431fa1Sahl 					spa_close(spa, FTAG);
1265c9431fa1Sahl 				}
1266c9431fa1Sahl 			}
1267c9431fa1Sahl 			break;
1268*40feaa91Sahrens 
1269*40feaa91Sahrens 		case ZFS_PROP_COPIES:
1270*40feaa91Sahrens 		{
1271*40feaa91Sahrens 			spa_t *spa;
1272*40feaa91Sahrens 
1273*40feaa91Sahrens 			if (spa_open(name, &spa, FTAG) == 0) {
1274*40feaa91Sahrens 				if (spa_version(spa) <
1275*40feaa91Sahrens 				    SPA_VERSION_DITTO_BLOCKS) {
1276*40feaa91Sahrens 					spa_close(spa, FTAG);
1277*40feaa91Sahrens 					return (ENOTSUP);
1278*40feaa91Sahrens 				}
1279*40feaa91Sahrens 				spa_close(spa, FTAG);
1280*40feaa91Sahrens 			}
1281*40feaa91Sahrens 			break;
1282*40feaa91Sahrens 		}
1283e9dbad6fSeschrock 		}
1284ecd6cf80Smarks 		if ((error = zfs_secpolicy_setprop(name, prop, cr)) != 0)
1285ecd6cf80Smarks 			return (error);
1286ecd6cf80Smarks 	}
1287ecd6cf80Smarks 
1288ecd6cf80Smarks 	elem = NULL;
1289ecd6cf80Smarks 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1290ecd6cf80Smarks 		propname = nvpair_name(elem);
1291ecd6cf80Smarks 
1292ecd6cf80Smarks 		if ((prop = zfs_name_to_prop(propname)) ==
1293ecd6cf80Smarks 		    ZFS_PROP_INVAL) {
1294ecd6cf80Smarks 
1295ecd6cf80Smarks 			VERIFY(nvpair_value_string(elem, &strval) == 0);
1296ecd6cf80Smarks 			error = dsl_prop_set(name, propname, 1,
1297ecd6cf80Smarks 			    strlen(strval) + 1, strval);
1298ecd6cf80Smarks 			if (error == 0)
1299ecd6cf80Smarks 				continue;
1300ecd6cf80Smarks 			else
1301ecd6cf80Smarks 				return (error);
1302ecd6cf80Smarks 		}
1303e9dbad6fSeschrock 
1304e9dbad6fSeschrock 		switch (prop) {
1305e9dbad6fSeschrock 		case ZFS_PROP_QUOTA:
1306e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1307e7437265Sahrens 			    (error = dsl_dir_set_quota(name, intval)) != 0)
1308e9dbad6fSeschrock 				return (error);
1309e9dbad6fSeschrock 			break;
1310e9dbad6fSeschrock 
1311e9dbad6fSeschrock 		case ZFS_PROP_RESERVATION:
1312e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1313e9dbad6fSeschrock 			    (error = dsl_dir_set_reservation(name,
1314e9dbad6fSeschrock 			    intval)) != 0)
1315e9dbad6fSeschrock 				return (error);
1316e9dbad6fSeschrock 			break;
1317e9dbad6fSeschrock 
1318e9dbad6fSeschrock 		case ZFS_PROP_VOLSIZE:
1319e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1320e7437265Sahrens 			    (error = zvol_set_volsize(name, dev, intval)) != 0)
1321e9dbad6fSeschrock 				return (error);
1322e9dbad6fSeschrock 			break;
1323e9dbad6fSeschrock 
1324e9dbad6fSeschrock 		case ZFS_PROP_VOLBLOCKSIZE:
1325e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1326e7437265Sahrens 			    (error = zvol_set_volblocksize(name, intval)) != 0)
1327e7437265Sahrens 				return (error);
1328e7437265Sahrens 			break;
1329e7437265Sahrens 
1330e7437265Sahrens 		case ZFS_PROP_VERSION:
1331e7437265Sahrens 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1332e7437265Sahrens 			    (error = zfs_set_version(name, intval)) != 0)
1333e9dbad6fSeschrock 				return (error);
1334e9dbad6fSeschrock 			break;
1335e9dbad6fSeschrock 
1336e9dbad6fSeschrock 		default:
1337e9dbad6fSeschrock 			if (nvpair_type(elem) == DATA_TYPE_STRING) {
1338e9dbad6fSeschrock 				if (zfs_prop_get_type(prop) !=
1339e9dbad6fSeschrock 				    prop_type_string)
1340e9dbad6fSeschrock 					return (EINVAL);
1341acd76fe5Seschrock 				VERIFY(nvpair_value_string(elem, &strval) == 0);
1342acd76fe5Seschrock 				if ((error = dsl_prop_set(name,
1343e9dbad6fSeschrock 				    nvpair_name(elem), 1, strlen(strval) + 1,
1344acd76fe5Seschrock 				    strval)) != 0)
1345acd76fe5Seschrock 					return (error);
1346e9dbad6fSeschrock 			} else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
1347a2eea2e1Sahrens 				const char *unused;
1348a2eea2e1Sahrens 
1349acd76fe5Seschrock 				VERIFY(nvpair_value_uint64(elem, &intval) == 0);
1350e9dbad6fSeschrock 
1351e9dbad6fSeschrock 				switch (zfs_prop_get_type(prop)) {
1352e9dbad6fSeschrock 				case prop_type_number:
1353e9dbad6fSeschrock 					break;
1354e9dbad6fSeschrock 				case prop_type_boolean:
1355e9dbad6fSeschrock 					if (intval > 1)
1356acd76fe5Seschrock 						return (EINVAL);
1357e9dbad6fSeschrock 					break;
1358e9dbad6fSeschrock 				case prop_type_string:
1359acd76fe5Seschrock 					return (EINVAL);
1360e9dbad6fSeschrock 				case prop_type_index:
1361acd76fe5Seschrock 					if (zfs_prop_index_to_string(prop,
1362acd76fe5Seschrock 					    intval, &unused) != 0)
1363acd76fe5Seschrock 						return (EINVAL);
1364e9dbad6fSeschrock 					break;
1365e9dbad6fSeschrock 				default:
1366e7437265Sahrens 					cmn_err(CE_PANIC,
1367e7437265Sahrens 					    "unknown property type");
1368e9dbad6fSeschrock 					break;
1369e9dbad6fSeschrock 				}
1370e9dbad6fSeschrock 
1371acd76fe5Seschrock 				if ((error = dsl_prop_set(name, propname,
1372acd76fe5Seschrock 				    8, 1, &intval)) != 0)
1373acd76fe5Seschrock 					return (error);
1374e9dbad6fSeschrock 			} else {
1375e9dbad6fSeschrock 				return (EINVAL);
1376e9dbad6fSeschrock 			}
1377e9dbad6fSeschrock 			break;
1378e9dbad6fSeschrock 		}
1379e9dbad6fSeschrock 	}
1380e9dbad6fSeschrock 
1381e9dbad6fSeschrock 	return (0);
1382fa9e4066Sahrens }
1383fa9e4066Sahrens 
1384fa9e4066Sahrens static int
1385e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc)
1386fa9e4066Sahrens {
1387e9dbad6fSeschrock 	nvlist_t *nvl;
1388e9dbad6fSeschrock 	int error;
1389e9dbad6fSeschrock 	zfs_prop_t prop;
1390e9dbad6fSeschrock 
1391e9dbad6fSeschrock 	/*
1392e9dbad6fSeschrock 	 * If zc_value is set, then this is an attempt to inherit a value.
1393e9dbad6fSeschrock 	 * Otherwise, zc_nvlist refers to a list of properties to set.
1394e9dbad6fSeschrock 	 */
1395e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1396e9dbad6fSeschrock 		if (!zfs_prop_user(zc->zc_value) &&
1397e9dbad6fSeschrock 		    ((prop = zfs_name_to_prop(zc->zc_value)) ==
1398e9dbad6fSeschrock 		    ZFS_PROP_INVAL ||
1399e9dbad6fSeschrock 		    !zfs_prop_inheritable(prop)))
1400e9dbad6fSeschrock 			return (EINVAL);
1401e9dbad6fSeschrock 
1402e9dbad6fSeschrock 		return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL));
1403e9dbad6fSeschrock 	}
1404e9dbad6fSeschrock 
1405e9dbad6fSeschrock 	if ((error = get_nvlist(zc, &nvl)) != 0)
1406e9dbad6fSeschrock 		return (error);
1407e9dbad6fSeschrock 
1408e9dbad6fSeschrock 	error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev,
1409e9dbad6fSeschrock 	    (cred_t *)(uintptr_t)zc->zc_cred, nvl);
1410ecd6cf80Smarks 
1411e9dbad6fSeschrock 	nvlist_free(nvl);
1412e9dbad6fSeschrock 	return (error);
1413fa9e4066Sahrens }
1414fa9e4066Sahrens 
1415b1b8ab34Slling static int
141611a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc)
1417b1b8ab34Slling {
1418b1b8ab34Slling 	nvlist_t *nvl;
1419b1b8ab34Slling 	int error, reset_bootfs = 0;
1420b1b8ab34Slling 	uint64_t objnum;
1421ecd6cf80Smarks 	uint64_t intval;
1422b1b8ab34Slling 	zpool_prop_t prop;
1423b1b8ab34Slling 	nvpair_t *elem;
1424b1b8ab34Slling 	char *propname, *strval;
1425b1b8ab34Slling 	spa_t *spa;
1426b1b8ab34Slling 	vdev_t *rvdev;
1427b1b8ab34Slling 	char *vdev_type;
1428b1b8ab34Slling 	objset_t *os;
1429b1b8ab34Slling 
1430b1b8ab34Slling 	if ((error = get_nvlist(zc, &nvl)) != 0)
1431b1b8ab34Slling 		return (error);
1432b1b8ab34Slling 
1433b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) {
1434b1b8ab34Slling 		nvlist_free(nvl);
1435b1b8ab34Slling 		return (error);
1436b1b8ab34Slling 	}
1437b1b8ab34Slling 
1438e7437265Sahrens 	if (spa_version(spa) < SPA_VERSION_BOOTFS) {
1439b1b8ab34Slling 		nvlist_free(nvl);
1440b1b8ab34Slling 		spa_close(spa, FTAG);
1441b1b8ab34Slling 		return (ENOTSUP);
1442b1b8ab34Slling 	}
1443b1b8ab34Slling 
1444b1b8ab34Slling 	elem = NULL;
1445b1b8ab34Slling 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1446b1b8ab34Slling 
1447b1b8ab34Slling 		propname = nvpair_name(elem);
1448b1b8ab34Slling 
1449b1b8ab34Slling 		if ((prop = zpool_name_to_prop(propname)) ==
1450b1b8ab34Slling 		    ZFS_PROP_INVAL) {
1451b1b8ab34Slling 			nvlist_free(nvl);
1452b1b8ab34Slling 			spa_close(spa, FTAG);
1453b1b8ab34Slling 			return (EINVAL);
1454b1b8ab34Slling 		}
1455b1b8ab34Slling 
1456b1b8ab34Slling 		switch (prop) {
1457ecd6cf80Smarks 		case ZPOOL_PROP_DELEGATION:
1458ecd6cf80Smarks 			VERIFY(nvpair_value_uint64(elem, &intval) == 0);
1459ecd6cf80Smarks 			if (intval > 1)
1460ecd6cf80Smarks 				error = EINVAL;
1461ecd6cf80Smarks 			break;
14623d7072f8Seschrock 		case ZPOOL_PROP_BOOTFS:
1463b1b8ab34Slling 			/*
1464b1b8ab34Slling 			 * A bootable filesystem can not be on a RAIDZ pool
1465b1b8ab34Slling 			 * nor a striped pool with more than 1 device.
1466b1b8ab34Slling 			 */
1467b1b8ab34Slling 			rvdev = spa->spa_root_vdev;
1468b1b8ab34Slling 			vdev_type =
1469b1b8ab34Slling 			    rvdev->vdev_child[0]->vdev_ops->vdev_op_type;
1470b1b8ab34Slling 			if (strcmp(vdev_type, VDEV_TYPE_RAIDZ) == 0 ||
1471b1b8ab34Slling 			    (strcmp(vdev_type, VDEV_TYPE_MIRROR) != 0 &&
1472b1b8ab34Slling 			    rvdev->vdev_children > 1)) {
1473b1b8ab34Slling 				error = ENOTSUP;
1474b1b8ab34Slling 				break;
1475b1b8ab34Slling 			}
1476b1b8ab34Slling 
1477b1b8ab34Slling 			reset_bootfs = 1;
1478b1b8ab34Slling 
1479b1b8ab34Slling 			VERIFY(nvpair_value_string(elem, &strval) == 0);
1480b1b8ab34Slling 			if (strval == NULL || strval[0] == '\0') {
14813d7072f8Seschrock 				objnum = zpool_prop_default_numeric(
14823d7072f8Seschrock 				    ZPOOL_PROP_BOOTFS);
1483b1b8ab34Slling 				break;
1484b1b8ab34Slling 			}
1485b1b8ab34Slling 
1486b1b8ab34Slling 			if (error = dmu_objset_open(strval, DMU_OST_ZFS,
1487b1b8ab34Slling 			    DS_MODE_STANDARD | DS_MODE_READONLY, &os))
1488b1b8ab34Slling 				break;
1489b1b8ab34Slling 			objnum = dmu_objset_id(os);
1490b1b8ab34Slling 			dmu_objset_close(os);
1491b1b8ab34Slling 			break;
1492b1b8ab34Slling 		}
1493b1b8ab34Slling 
1494b1b8ab34Slling 		if (error)
1495b1b8ab34Slling 			break;
1496b1b8ab34Slling 	}
1497b1b8ab34Slling 	if (error == 0) {
1498b1b8ab34Slling 		if (reset_bootfs) {
1499b1b8ab34Slling 			VERIFY(nvlist_remove(nvl,
15003d7072f8Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_BOOTFS),
1501b1b8ab34Slling 			    DATA_TYPE_STRING) == 0);
1502b1b8ab34Slling 			VERIFY(nvlist_add_uint64(nvl,
15033d7072f8Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_BOOTFS),
15043d7072f8Seschrock 			    objnum) == 0);
1505b1b8ab34Slling 		}
1506b1b8ab34Slling 		error = spa_set_props(spa, nvl);
1507b1b8ab34Slling 	}
1508b1b8ab34Slling 
1509b1b8ab34Slling 	nvlist_free(nvl);
1510b1b8ab34Slling 	spa_close(spa, FTAG);
1511b1b8ab34Slling 
1512b1b8ab34Slling 	return (error);
1513b1b8ab34Slling }
1514b1b8ab34Slling 
1515b1b8ab34Slling static int
151611a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc)
1517b1b8ab34Slling {
1518b1b8ab34Slling 	spa_t *spa;
1519b1b8ab34Slling 	int error;
1520b1b8ab34Slling 	nvlist_t *nvp = NULL;
1521b1b8ab34Slling 
1522b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1523b1b8ab34Slling 		return (error);
1524b1b8ab34Slling 
1525b1b8ab34Slling 	error = spa_get_props(spa, &nvp);
1526b1b8ab34Slling 
1527b1b8ab34Slling 	if (error == 0 && zc->zc_nvlist_dst != NULL)
1528b1b8ab34Slling 		error = put_nvlist(zc, nvp);
1529b1b8ab34Slling 	else
1530b1b8ab34Slling 		error = EFAULT;
1531b1b8ab34Slling 
1532b1b8ab34Slling 	spa_close(spa, FTAG);
1533b1b8ab34Slling 
1534b1b8ab34Slling 	if (nvp)
1535b1b8ab34Slling 		nvlist_free(nvp);
1536b1b8ab34Slling 	return (error);
1537b1b8ab34Slling }
1538b1b8ab34Slling 
1539ecd6cf80Smarks static int
1540ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc)
1541ecd6cf80Smarks {
1542ecd6cf80Smarks 	nvlist_t *nvp;
1543ecd6cf80Smarks 	int error;
1544ecd6cf80Smarks 	uint32_t uid;
1545ecd6cf80Smarks 	uint32_t gid;
1546ecd6cf80Smarks 	uint32_t *groups;
1547ecd6cf80Smarks 	uint_t group_cnt;
1548ecd6cf80Smarks 	cred_t	*usercred;
1549ecd6cf80Smarks 
1550ecd6cf80Smarks 	if ((error = get_nvlist(zc, &nvp)) != 0) {
1551ecd6cf80Smarks 		return (error);
1552ecd6cf80Smarks 	}
1553ecd6cf80Smarks 
1554ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32(nvp,
1555ecd6cf80Smarks 	    ZFS_DELEG_PERM_UID, &uid)) != 0) {
1556ecd6cf80Smarks 		nvlist_free(nvp);
1557ecd6cf80Smarks 		return (EPERM);
1558ecd6cf80Smarks 	}
1559ecd6cf80Smarks 
1560ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32(nvp,
1561ecd6cf80Smarks 	    ZFS_DELEG_PERM_GID, &gid)) != 0) {
1562ecd6cf80Smarks 		nvlist_free(nvp);
1563ecd6cf80Smarks 		return (EPERM);
1564ecd6cf80Smarks 	}
1565ecd6cf80Smarks 
1566ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS,
1567ecd6cf80Smarks 	    &groups, &group_cnt)) != 0) {
1568ecd6cf80Smarks 		nvlist_free(nvp);
1569ecd6cf80Smarks 		return (EPERM);
1570ecd6cf80Smarks 	}
1571ecd6cf80Smarks 	usercred = cralloc();
1572ecd6cf80Smarks 	if ((crsetugid(usercred, uid, gid) != 0) ||
1573ecd6cf80Smarks 	    (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) {
1574ecd6cf80Smarks 		nvlist_free(nvp);
1575ecd6cf80Smarks 		crfree(usercred);
1576ecd6cf80Smarks 		return (EPERM);
1577ecd6cf80Smarks 	}
1578ecd6cf80Smarks 	nvlist_free(nvp);
1579ecd6cf80Smarks 	error = dsl_deleg_access(zc->zc_name,
1580ecd6cf80Smarks 	    ZFS_DELEG_PERM_SHAREISCSI, usercred);
1581ecd6cf80Smarks 	crfree(usercred);
1582ecd6cf80Smarks 	return (error);
1583ecd6cf80Smarks }
1584ecd6cf80Smarks 
1585ecd6cf80Smarks static int
1586ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc)
1587ecd6cf80Smarks {
1588ecd6cf80Smarks 	int error;
1589ecd6cf80Smarks 	nvlist_t *fsaclnv = NULL;
1590ecd6cf80Smarks 	cred_t *cr;
1591ecd6cf80Smarks 
1592ecd6cf80Smarks 	if ((error = get_nvlist(zc, &fsaclnv)) != 0)
1593ecd6cf80Smarks 		return (error);
1594ecd6cf80Smarks 
1595ecd6cf80Smarks 	/*
1596ecd6cf80Smarks 	 * Verify nvlist is constructed correctly
1597ecd6cf80Smarks 	 */
1598ecd6cf80Smarks 	if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) {
1599ecd6cf80Smarks 		nvlist_free(fsaclnv);
1600ecd6cf80Smarks 		return (EINVAL);
1601ecd6cf80Smarks 	}
1602ecd6cf80Smarks 
1603ecd6cf80Smarks 	/*
1604ecd6cf80Smarks 	 * If we don't have PRIV_SYS_MOUNT, then validate
1605ecd6cf80Smarks 	 * that user is allowed to hand out each permission in
1606ecd6cf80Smarks 	 * the nvlist(s)
1607ecd6cf80Smarks 	 */
1608ecd6cf80Smarks 
1609ecd6cf80Smarks 	cr = (cred_t *)(uintptr_t)zc->zc_cred;
1610ecd6cf80Smarks 	error = secpolicy_zfs(cr);
1611ecd6cf80Smarks 	if (error) {
1612ecd6cf80Smarks 		if (zc->zc_perm_action == B_FALSE)
1613ecd6cf80Smarks 			error = dsl_deleg_can_allow(zc->zc_name, fsaclnv, cr);
1614ecd6cf80Smarks 		else
1615ecd6cf80Smarks 			error = dsl_deleg_can_unallow(zc->zc_name, fsaclnv, cr);
1616ecd6cf80Smarks 	}
1617ecd6cf80Smarks 
1618ecd6cf80Smarks 	if (error == 0)
1619ecd6cf80Smarks 		error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action);
1620ecd6cf80Smarks 
1621ecd6cf80Smarks 	nvlist_free(fsaclnv);
1622ecd6cf80Smarks 	return (error);
1623ecd6cf80Smarks }
1624ecd6cf80Smarks 
1625ecd6cf80Smarks static int
1626ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc)
1627ecd6cf80Smarks {
1628ecd6cf80Smarks 	nvlist_t *nvp;
1629ecd6cf80Smarks 	int error;
1630ecd6cf80Smarks 
1631ecd6cf80Smarks 	if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) {
1632ecd6cf80Smarks 		error = put_nvlist(zc, nvp);
1633ecd6cf80Smarks 		nvlist_free(nvp);
1634ecd6cf80Smarks 	}
1635ecd6cf80Smarks 
1636ecd6cf80Smarks 	return (error);
1637ecd6cf80Smarks }
1638ecd6cf80Smarks 
1639fa9e4066Sahrens static int
1640fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc)
1641fa9e4066Sahrens {
1642e9dbad6fSeschrock 	return (zvol_create_minor(zc->zc_name, zc->zc_dev));
1643fa9e4066Sahrens }
1644fa9e4066Sahrens 
1645fa9e4066Sahrens static int
1646fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc)
1647fa9e4066Sahrens {
1648e9dbad6fSeschrock 	return (zvol_remove_minor(zc->zc_name));
1649fa9e4066Sahrens }
1650fa9e4066Sahrens 
1651fa9e4066Sahrens /*
1652fa9e4066Sahrens  * Search the vfs list for a specified resource.  Returns a pointer to it
1653fa9e4066Sahrens  * or NULL if no suitable entry is found. The caller of this routine
1654fa9e4066Sahrens  * is responsible for releasing the returned vfs pointer.
1655fa9e4066Sahrens  */
1656fa9e4066Sahrens static vfs_t *
1657fa9e4066Sahrens zfs_get_vfs(const char *resource)
1658fa9e4066Sahrens {
1659fa9e4066Sahrens 	struct vfs *vfsp;
1660fa9e4066Sahrens 	struct vfs *vfs_found = NULL;
1661fa9e4066Sahrens 
1662fa9e4066Sahrens 	vfs_list_read_lock();
1663fa9e4066Sahrens 	vfsp = rootvfs;
1664fa9e4066Sahrens 	do {
1665fa9e4066Sahrens 		if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) {
1666fa9e4066Sahrens 			VFS_HOLD(vfsp);
1667fa9e4066Sahrens 			vfs_found = vfsp;
1668fa9e4066Sahrens 			break;
1669fa9e4066Sahrens 		}
1670fa9e4066Sahrens 		vfsp = vfsp->vfs_next;
1671fa9e4066Sahrens 	} while (vfsp != rootvfs);
1672fa9e4066Sahrens 	vfs_list_unlock();
1673fa9e4066Sahrens 	return (vfs_found);
1674fa9e4066Sahrens }
1675fa9e4066Sahrens 
1676ecd6cf80Smarks /* ARGSUSED */
1677fa9e4066Sahrens static void
1678ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
1679fa9e4066Sahrens {
1680e7437265Sahrens 	nvlist_t *nvprops = arg;
1681e7437265Sahrens 	uint64_t version = ZPL_VERSION;
1682e7437265Sahrens 
1683e7437265Sahrens 	(void) nvlist_lookup_uint64(nvprops,
1684e7437265Sahrens 	    zfs_prop_to_name(ZFS_PROP_VERSION), &version);
1685e7437265Sahrens 
1686e7437265Sahrens 	zfs_create_fs(os, cr, version, tx);
1687fa9e4066Sahrens }
1688fa9e4066Sahrens 
1689fa9e4066Sahrens static int
1690fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc)
1691fa9e4066Sahrens {
1692fa9e4066Sahrens 	objset_t *clone;
1693fa9e4066Sahrens 	int error = 0;
1694ecd6cf80Smarks 	nvlist_t *nvprops = NULL;
1695ecd6cf80Smarks 	void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
1696fa9e4066Sahrens 	dmu_objset_type_t type = zc->zc_objset_type;
1697fa9e4066Sahrens 
1698fa9e4066Sahrens 	switch (type) {
1699fa9e4066Sahrens 
1700fa9e4066Sahrens 	case DMU_OST_ZFS:
1701fa9e4066Sahrens 		cbfunc = zfs_create_cb;
1702fa9e4066Sahrens 		break;
1703fa9e4066Sahrens 
1704fa9e4066Sahrens 	case DMU_OST_ZVOL:
1705fa9e4066Sahrens 		cbfunc = zvol_create_cb;
1706fa9e4066Sahrens 		break;
1707fa9e4066Sahrens 
1708fa9e4066Sahrens 	default:
17091d452cf5Sahrens 		cbfunc = NULL;
1710fa9e4066Sahrens 	}
17111d452cf5Sahrens 	if (strchr(zc->zc_name, '@'))
17121d452cf5Sahrens 		return (EINVAL);
1713fa9e4066Sahrens 
1714e9dbad6fSeschrock 	if (zc->zc_nvlist_src != NULL &&
1715ecd6cf80Smarks 	    (error = get_nvlist(zc, &nvprops)) != 0)
1716e9dbad6fSeschrock 		return (error);
1717e9dbad6fSeschrock 
1718e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1719fa9e4066Sahrens 		/*
1720fa9e4066Sahrens 		 * We're creating a clone of an existing snapshot.
1721fa9e4066Sahrens 		 */
1722e9dbad6fSeschrock 		zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
1723e9dbad6fSeschrock 		if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) {
1724ecd6cf80Smarks 			nvlist_free(nvprops);
1725fa9e4066Sahrens 			return (EINVAL);
1726e9dbad6fSeschrock 		}
1727fa9e4066Sahrens 
1728e9dbad6fSeschrock 		error = dmu_objset_open(zc->zc_value, type,
1729fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
1730e9dbad6fSeschrock 		if (error) {
1731ecd6cf80Smarks 			nvlist_free(nvprops);
1732fa9e4066Sahrens 			return (error);
1733e9dbad6fSeschrock 		}
1734fa9e4066Sahrens 		error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL);
1735fa9e4066Sahrens 		dmu_objset_close(clone);
1736fa9e4066Sahrens 	} else {
1737e9dbad6fSeschrock 		if (cbfunc == NULL) {
1738ecd6cf80Smarks 			nvlist_free(nvprops);
17391d452cf5Sahrens 			return (EINVAL);
1740e9dbad6fSeschrock 		}
17415c5460e9Seschrock 
1742e9dbad6fSeschrock 		if (type == DMU_OST_ZVOL) {
1743e9dbad6fSeschrock 			uint64_t volsize, volblocksize;
1744e9dbad6fSeschrock 
1745ecd6cf80Smarks 			if (nvprops == NULL ||
1746ecd6cf80Smarks 			    nvlist_lookup_uint64(nvprops,
1747e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1748e9dbad6fSeschrock 			    &volsize) != 0) {
1749ecd6cf80Smarks 				nvlist_free(nvprops);
1750e9dbad6fSeschrock 				return (EINVAL);
1751e9dbad6fSeschrock 			}
1752e9dbad6fSeschrock 
1753ecd6cf80Smarks 			if ((error = nvlist_lookup_uint64(nvprops,
1754e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1755e9dbad6fSeschrock 			    &volblocksize)) != 0 && error != ENOENT) {
1756ecd6cf80Smarks 				nvlist_free(nvprops);
1757e9dbad6fSeschrock 				return (EINVAL);
1758e9dbad6fSeschrock 			}
1759e9dbad6fSeschrock 
1760e9dbad6fSeschrock 			if (error != 0)
1761e9dbad6fSeschrock 				volblocksize = zfs_prop_default_numeric(
1762e9dbad6fSeschrock 				    ZFS_PROP_VOLBLOCKSIZE);
1763e9dbad6fSeschrock 
1764e9dbad6fSeschrock 			if ((error = zvol_check_volblocksize(
1765e9dbad6fSeschrock 			    volblocksize)) != 0 ||
1766e9dbad6fSeschrock 			    (error = zvol_check_volsize(volsize,
1767e9dbad6fSeschrock 			    volblocksize)) != 0) {
1768ecd6cf80Smarks 				nvlist_free(nvprops);
17695c5460e9Seschrock 				return (error);
1770e9dbad6fSeschrock 			}
1771e7437265Sahrens 		} else if (type == DMU_OST_ZFS) {
1772e7437265Sahrens 			uint64_t version;
1773e7437265Sahrens 
1774e7437265Sahrens 			if (0 == nvlist_lookup_uint64(nvprops,
1775e7437265Sahrens 			    zfs_prop_to_name(ZFS_PROP_VERSION), &version) &&
1776e7437265Sahrens 			    (version < ZPL_VERSION_INITIAL ||
1777e7437265Sahrens 			    version > ZPL_VERSION)) {
1778e7437265Sahrens 				nvlist_free(nvprops);
1779e7437265Sahrens 				return (EINVAL);
1780e7437265Sahrens 			}
1781fa9e4066Sahrens 		}
1782e9dbad6fSeschrock 
1783e9dbad6fSeschrock 		error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc,
1784ecd6cf80Smarks 		    nvprops);
1785fa9e4066Sahrens 	}
1786e9dbad6fSeschrock 
1787e9dbad6fSeschrock 	/*
1788e9dbad6fSeschrock 	 * It would be nice to do this atomically.
1789e9dbad6fSeschrock 	 */
1790e9dbad6fSeschrock 	if (error == 0) {
1791e9dbad6fSeschrock 		if ((error = zfs_set_prop_nvlist(zc->zc_name,
1792e9dbad6fSeschrock 		    zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred,
1793ecd6cf80Smarks 		    nvprops)) != 0)
1794e9dbad6fSeschrock 			(void) dmu_objset_destroy(zc->zc_name);
1795e9dbad6fSeschrock 	}
1796e9dbad6fSeschrock 
1797ecd6cf80Smarks 	nvlist_free(nvprops);
1798fa9e4066Sahrens 	return (error);
1799fa9e4066Sahrens }
1800fa9e4066Sahrens 
1801fa9e4066Sahrens static int
18021d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc)
1803fa9e4066Sahrens {
1804e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
18051d452cf5Sahrens 		return (EINVAL);
18061d452cf5Sahrens 	return (dmu_objset_snapshot(zc->zc_name,
1807e9dbad6fSeschrock 	    zc->zc_value, zc->zc_cookie));
18081d452cf5Sahrens }
1809fa9e4066Sahrens 
1810cdf5b4caSmmusante int
18111d452cf5Sahrens zfs_unmount_snap(char *name, void *arg)
18121d452cf5Sahrens {
18131d452cf5Sahrens 	char *snapname = arg;
18141d452cf5Sahrens 	char *cp;
18150b69c2f0Sahrens 	vfs_t *vfsp = NULL;
18161d452cf5Sahrens 
18171d452cf5Sahrens 	/*
18181d452cf5Sahrens 	 * Snapshots (which are under .zfs control) must be unmounted
18191d452cf5Sahrens 	 * before they can be destroyed.
18201d452cf5Sahrens 	 */
18211d452cf5Sahrens 
18221d452cf5Sahrens 	if (snapname) {
18231d452cf5Sahrens 		(void) strcat(name, "@");
18241d452cf5Sahrens 		(void) strcat(name, snapname);
18251d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
18261d452cf5Sahrens 		cp = strchr(name, '@');
18271d452cf5Sahrens 		*cp = '\0';
18280b69c2f0Sahrens 	} else if (strchr(name, '@')) {
18291d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
18301d452cf5Sahrens 	}
18311d452cf5Sahrens 
18321d452cf5Sahrens 	if (vfsp) {
1833fa9e4066Sahrens 		/*
18341d452cf5Sahrens 		 * Always force the unmount for snapshots.
1835fa9e4066Sahrens 		 */
18361d452cf5Sahrens 		int flag = MS_FORCE;
18371d452cf5Sahrens 		int err;
18381d452cf5Sahrens 
18391d452cf5Sahrens 		if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) {
1840fa9e4066Sahrens 			VFS_RELE(vfsp);
18411d452cf5Sahrens 			return (err);
1842fa9e4066Sahrens 		}
18431d452cf5Sahrens 		VFS_RELE(vfsp);
18441d452cf5Sahrens 		if ((err = dounmount(vfsp, flag, kcred)) != 0)
18451d452cf5Sahrens 			return (err);
18461d452cf5Sahrens 	}
18471d452cf5Sahrens 	return (0);
18481d452cf5Sahrens }
18491d452cf5Sahrens 
18501d452cf5Sahrens static int
18511d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc)
18521d452cf5Sahrens {
18531d452cf5Sahrens 	int err;
18541d452cf5Sahrens 
1855e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
18561d452cf5Sahrens 		return (EINVAL);
18571d452cf5Sahrens 	err = dmu_objset_find(zc->zc_name,
1858e9dbad6fSeschrock 	    zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN);
18591d452cf5Sahrens 	if (err)
18601d452cf5Sahrens 		return (err);
1861e9dbad6fSeschrock 	return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value));
18621d452cf5Sahrens }
18631d452cf5Sahrens 
18641d452cf5Sahrens static int
18651d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc)
18661d452cf5Sahrens {
18671d452cf5Sahrens 	if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) {
18681d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
18691d452cf5Sahrens 		if (err)
18701d452cf5Sahrens 			return (err);
1871fa9e4066Sahrens 	}
1872fa9e4066Sahrens 
1873fa9e4066Sahrens 	return (dmu_objset_destroy(zc->zc_name));
1874fa9e4066Sahrens }
1875fa9e4066Sahrens 
1876fa9e4066Sahrens static int
1877fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc)
1878fa9e4066Sahrens {
1879fa9e4066Sahrens 	return (dmu_objset_rollback(zc->zc_name));
1880fa9e4066Sahrens }
1881fa9e4066Sahrens 
1882fa9e4066Sahrens static int
1883fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc)
1884fa9e4066Sahrens {
18857f1f55eaSvb 	boolean_t recursive = zc->zc_cookie & 1;
1886cdf5b4caSmmusante 
1887e9dbad6fSeschrock 	zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
1888e9dbad6fSeschrock 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0)
1889fa9e4066Sahrens 		return (EINVAL);
1890fa9e4066Sahrens 
1891cdf5b4caSmmusante 	/*
1892cdf5b4caSmmusante 	 * Unmount snapshot unless we're doing a recursive rename,
1893cdf5b4caSmmusante 	 * in which case the dataset code figures out which snapshots
1894cdf5b4caSmmusante 	 * to unmount.
1895cdf5b4caSmmusante 	 */
1896cdf5b4caSmmusante 	if (!recursive && strchr(zc->zc_name, '@') != NULL &&
1897fa9e4066Sahrens 	    zc->zc_objset_type == DMU_OST_ZFS) {
18981d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
18991d452cf5Sahrens 		if (err)
19001d452cf5Sahrens 			return (err);
1901fa9e4066Sahrens 	}
1902fa9e4066Sahrens 
1903cdf5b4caSmmusante 	return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive));
1904fa9e4066Sahrens }
1905fa9e4066Sahrens 
1906fa9e4066Sahrens static int
1907fa9e4066Sahrens zfs_ioc_recvbackup(zfs_cmd_t *zc)
1908fa9e4066Sahrens {
1909fa9e4066Sahrens 	file_t *fp;
1910fa9e4066Sahrens 	int error, fd;
1911a2eea2e1Sahrens 	offset_t new_off;
1912fa9e4066Sahrens 
19133ccfa83cSahrens 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
19143ccfa83cSahrens 	    strchr(zc->zc_value, '@') == NULL)
19153ccfa83cSahrens 		return (EINVAL);
19163ccfa83cSahrens 
1917fa9e4066Sahrens 	fd = zc->zc_cookie;
1918fa9e4066Sahrens 	fp = getf(fd);
1919fa9e4066Sahrens 	if (fp == NULL)
1920fa9e4066Sahrens 		return (EBADF);
1921e9dbad6fSeschrock 	error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record,
1922e9dbad6fSeschrock 	    &zc->zc_cookie, (boolean_t)zc->zc_guid, fp->f_vnode,
192398579b20Snd 	    fp->f_offset);
1924a2eea2e1Sahrens 
1925a2eea2e1Sahrens 	new_off = fp->f_offset + zc->zc_cookie;
1926a2eea2e1Sahrens 	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off) == 0)
1927a2eea2e1Sahrens 		fp->f_offset = new_off;
1928a2eea2e1Sahrens 
1929fa9e4066Sahrens 	releasef(fd);
1930fa9e4066Sahrens 	return (error);
1931fa9e4066Sahrens }
1932fa9e4066Sahrens 
1933fa9e4066Sahrens static int
1934fa9e4066Sahrens zfs_ioc_sendbackup(zfs_cmd_t *zc)
1935fa9e4066Sahrens {
1936fa9e4066Sahrens 	objset_t *fromsnap = NULL;
1937fa9e4066Sahrens 	objset_t *tosnap;
1938fa9e4066Sahrens 	file_t *fp;
1939fa9e4066Sahrens 	int error;
1940fa9e4066Sahrens 
1941fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1942fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap);
1943fa9e4066Sahrens 	if (error)
1944fa9e4066Sahrens 		return (error);
1945fa9e4066Sahrens 
1946e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1947a2eea2e1Sahrens 		char buf[MAXPATHLEN];
1948a2eea2e1Sahrens 		char *cp;
1949a2eea2e1Sahrens 
1950a2eea2e1Sahrens 		(void) strncpy(buf, zc->zc_name, sizeof (buf));
1951a2eea2e1Sahrens 		cp = strchr(buf, '@');
1952a2eea2e1Sahrens 		if (cp)
1953a2eea2e1Sahrens 			*(cp+1) = 0;
1954a2eea2e1Sahrens 		(void) strncat(buf, zc->zc_value, sizeof (buf));
1955a2eea2e1Sahrens 		error = dmu_objset_open(buf, DMU_OST_ANY,
1956fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap);
1957fa9e4066Sahrens 		if (error) {
1958fa9e4066Sahrens 			dmu_objset_close(tosnap);
1959fa9e4066Sahrens 			return (error);
1960fa9e4066Sahrens 		}
1961fa9e4066Sahrens 	}
1962fa9e4066Sahrens 
1963fa9e4066Sahrens 	fp = getf(zc->zc_cookie);
1964fa9e4066Sahrens 	if (fp == NULL) {
1965fa9e4066Sahrens 		dmu_objset_close(tosnap);
1966fa9e4066Sahrens 		if (fromsnap)
1967fa9e4066Sahrens 			dmu_objset_close(fromsnap);
1968fa9e4066Sahrens 		return (EBADF);
1969fa9e4066Sahrens 	}
1970fa9e4066Sahrens 
1971fa9e4066Sahrens 	error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode);
1972fa9e4066Sahrens 
1973fa9e4066Sahrens 	releasef(zc->zc_cookie);
1974fa9e4066Sahrens 	if (fromsnap)
1975fa9e4066Sahrens 		dmu_objset_close(fromsnap);
1976fa9e4066Sahrens 	dmu_objset_close(tosnap);
1977fa9e4066Sahrens 	return (error);
1978fa9e4066Sahrens }
1979fa9e4066Sahrens 
1980ea8dc4b6Seschrock static int
1981ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc)
1982ea8dc4b6Seschrock {
1983ea8dc4b6Seschrock 	int id, error;
1984ea8dc4b6Seschrock 
1985ea8dc4b6Seschrock 	error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id,
1986ea8dc4b6Seschrock 	    &zc->zc_inject_record);
1987ea8dc4b6Seschrock 
1988ea8dc4b6Seschrock 	if (error == 0)
1989ea8dc4b6Seschrock 		zc->zc_guid = (uint64_t)id;
1990ea8dc4b6Seschrock 
1991ea8dc4b6Seschrock 	return (error);
1992ea8dc4b6Seschrock }
1993ea8dc4b6Seschrock 
1994ea8dc4b6Seschrock static int
1995ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc)
1996ea8dc4b6Seschrock {
1997ea8dc4b6Seschrock 	return (zio_clear_fault((int)zc->zc_guid));
1998ea8dc4b6Seschrock }
1999ea8dc4b6Seschrock 
2000ea8dc4b6Seschrock static int
2001ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc)
2002ea8dc4b6Seschrock {
2003ea8dc4b6Seschrock 	int id = (int)zc->zc_guid;
2004ea8dc4b6Seschrock 	int error;
2005ea8dc4b6Seschrock 
2006ea8dc4b6Seschrock 	error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name),
2007ea8dc4b6Seschrock 	    &zc->zc_inject_record);
2008ea8dc4b6Seschrock 
2009ea8dc4b6Seschrock 	zc->zc_guid = id;
2010ea8dc4b6Seschrock 
2011ea8dc4b6Seschrock 	return (error);
2012ea8dc4b6Seschrock }
2013ea8dc4b6Seschrock 
2014ea8dc4b6Seschrock static int
2015ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc)
2016ea8dc4b6Seschrock {
2017ea8dc4b6Seschrock 	spa_t *spa;
2018ea8dc4b6Seschrock 	int error;
2019e9dbad6fSeschrock 	size_t count = (size_t)zc->zc_nvlist_dst_size;
2020ea8dc4b6Seschrock 
2021ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
2022ea8dc4b6Seschrock 		return (error);
2023ea8dc4b6Seschrock 
2024e9dbad6fSeschrock 	error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst,
2025ea8dc4b6Seschrock 	    &count);
2026ea8dc4b6Seschrock 	if (error == 0)
2027e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = count;
2028ea8dc4b6Seschrock 	else
2029e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = spa_get_errlog_size(spa);
2030ea8dc4b6Seschrock 
2031ea8dc4b6Seschrock 	spa_close(spa, FTAG);
2032ea8dc4b6Seschrock 
2033ea8dc4b6Seschrock 	return (error);
2034ea8dc4b6Seschrock }
2035ea8dc4b6Seschrock 
2036ea8dc4b6Seschrock static int
2037ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc)
2038ea8dc4b6Seschrock {
2039ea8dc4b6Seschrock 	spa_t *spa;
2040ea8dc4b6Seschrock 	vdev_t *vd;
2041ea8dc4b6Seschrock 	int error;
20423d7072f8Seschrock 	uint64_t txg;
2043ea8dc4b6Seschrock 
2044ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
2045ea8dc4b6Seschrock 		return (error);
2046ea8dc4b6Seschrock 
20473d7072f8Seschrock 	txg = spa_vdev_enter(spa);
2048ea8dc4b6Seschrock 
2049e9dbad6fSeschrock 	if (zc->zc_guid == 0) {
2050ea8dc4b6Seschrock 		vd = NULL;
2051e9dbad6fSeschrock 	} else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) {
20523d7072f8Seschrock 		(void) spa_vdev_exit(spa, NULL, txg, ENODEV);
2053ea8dc4b6Seschrock 		spa_close(spa, FTAG);
2054ea8dc4b6Seschrock 		return (ENODEV);
2055ea8dc4b6Seschrock 	}
2056ea8dc4b6Seschrock 
2057ea8dc4b6Seschrock 	vdev_clear(spa, vd);
2058ea8dc4b6Seschrock 
20593d7072f8Seschrock 	(void) spa_vdev_exit(spa, NULL, txg, 0);
2060ea8dc4b6Seschrock 
2061ea8dc4b6Seschrock 	spa_close(spa, FTAG);
2062ea8dc4b6Seschrock 
2063ea8dc4b6Seschrock 	return (0);
2064ea8dc4b6Seschrock }
2065ea8dc4b6Seschrock 
206699653d4eSeschrock static int
206799653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc)
206899653d4eSeschrock {
20690b69c2f0Sahrens 	char *cp;
20700b69c2f0Sahrens 
20710b69c2f0Sahrens 	/*
20720b69c2f0Sahrens 	 * We don't need to unmount *all* the origin fs's snapshots, but
20730b69c2f0Sahrens 	 * it's easier.
20740b69c2f0Sahrens 	 */
2075e9dbad6fSeschrock 	cp = strchr(zc->zc_value, '@');
20760b69c2f0Sahrens 	if (cp)
20770b69c2f0Sahrens 		*cp = '\0';
2078e9dbad6fSeschrock 	(void) dmu_objset_find(zc->zc_value,
20790b69c2f0Sahrens 	    zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS);
208099653d4eSeschrock 	return (dsl_dataset_promote(zc->zc_name));
208199653d4eSeschrock }
208299653d4eSeschrock 
2083ecd6cf80Smarks /*
2084ecd6cf80Smarks  * We don't want to have a hard dependency
2085ecd6cf80Smarks  * against some special symbols in sharefs
2086ecd6cf80Smarks  * and nfs.  Determine them if needed when
2087ecd6cf80Smarks  * the first file system is shared.
2088ecd6cf80Smarks  * Neither sharefs or nfs are unloadable modules.
2089ecd6cf80Smarks  */
2090ecd6cf80Smarks int (*zexport_fs)(void *arg);
2091ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t);
2092ecd6cf80Smarks 
2093ecd6cf80Smarks int zfs_share_inited;
2094ecd6cf80Smarks ddi_modhandle_t nfs_mod;
2095ecd6cf80Smarks ddi_modhandle_t sharefs_mod;
2096ecd6cf80Smarks kmutex_t zfs_share_lock;
2097ecd6cf80Smarks 
2098ecd6cf80Smarks static int
2099ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc)
2100ecd6cf80Smarks {
2101ecd6cf80Smarks 	int error;
2102ecd6cf80Smarks 	int opcode;
2103ecd6cf80Smarks 
2104ecd6cf80Smarks 	if (zfs_share_inited == 0) {
2105ecd6cf80Smarks 		mutex_enter(&zfs_share_lock);
2106ecd6cf80Smarks 		nfs_mod = ddi_modopen("fs/nfs", KRTLD_MODE_FIRST, &error);
2107ecd6cf80Smarks 		sharefs_mod = ddi_modopen("fs/sharefs",
2108ecd6cf80Smarks 		    KRTLD_MODE_FIRST, &error);
2109ecd6cf80Smarks 		if (nfs_mod == NULL || sharefs_mod == NULL) {
2110ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2111ecd6cf80Smarks 			return (ENOSYS);
2112ecd6cf80Smarks 		}
2113ecd6cf80Smarks 		if (zexport_fs == NULL && ((zexport_fs = (int (*)(void *))
2114ecd6cf80Smarks 		    ddi_modsym(nfs_mod, "nfs_export", &error)) == NULL)) {
2115ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2116ecd6cf80Smarks 			return (ENOSYS);
2117ecd6cf80Smarks 		}
2118ecd6cf80Smarks 
2119ecd6cf80Smarks 		if (zshare_fs == NULL && ((zshare_fs =
2120ecd6cf80Smarks 		    (int (*)(enum sharefs_sys_op, share_t *, uint32_t))
2121ecd6cf80Smarks 		    ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) {
2122ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2123ecd6cf80Smarks 			return (ENOSYS);
2124ecd6cf80Smarks 		}
2125ecd6cf80Smarks 		zfs_share_inited = 1;
2126ecd6cf80Smarks 		mutex_exit(&zfs_share_lock);
2127ecd6cf80Smarks 	}
2128ecd6cf80Smarks 
2129ecd6cf80Smarks 	if (error = zexport_fs((void *)(uintptr_t)zc->zc_share.z_exportdata))
2130ecd6cf80Smarks 		return (error);
2131ecd6cf80Smarks 
2132ecd6cf80Smarks 	opcode = (zc->zc_share.z_sharetype == B_TRUE) ?
2133ecd6cf80Smarks 	    SHAREFS_ADD : SHAREFS_REMOVE;
2134ecd6cf80Smarks 
2135ecd6cf80Smarks 	error = zshare_fs(opcode,
2136ecd6cf80Smarks 	    (void *)(uintptr_t)zc->zc_share.z_sharedata,
2137ecd6cf80Smarks 	    zc->zc_share.z_sharemax);
2138ecd6cf80Smarks 
2139ecd6cf80Smarks 	return (error);
2140ecd6cf80Smarks 
2141ecd6cf80Smarks }
2142ecd6cf80Smarks 
2143ecd6cf80Smarks /*
2144ecd6cf80Smarks  * pool destroy and pool export don't log the history as part of zfsdev_ioctl,
2145ecd6cf80Smarks  * but rather zfs_ioc_pool_create, and zfs_ioc_pool_export do the loggin
2146ecd6cf80Smarks  * of those commands.
2147ecd6cf80Smarks  */
2148fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = {
2149e7437265Sahrens 	{ zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2150e7437265Sahrens 	{ zfs_ioc_pool_destroy,	zfs_secpolicy_config, POOL_NAME, B_FALSE },
2151e7437265Sahrens 	{ zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2152e7437265Sahrens 	{ zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2153e7437265Sahrens 	{ zfs_ioc_pool_configs,	zfs_secpolicy_none, NO_NAME, B_FALSE },
2154e7437265Sahrens 	{ zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE },
2155e7437265Sahrens 	{ zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE },
2156e7437265Sahrens 	{ zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2157e7437265Sahrens 	{ zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE },
2158e7437265Sahrens 	{ zfs_ioc_pool_upgrade,	zfs_secpolicy_config, POOL_NAME, B_TRUE },
2159e7437265Sahrens 	{ zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2160e7437265Sahrens 	{ zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2161e7437265Sahrens 	{ zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2162e7437265Sahrens 	{ zfs_ioc_vdev_set_state, zfs_secpolicy_config,	POOL_NAME, B_TRUE },
2163e7437265Sahrens 	{ zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2164e7437265Sahrens 	{ zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2165e7437265Sahrens 	{ zfs_ioc_vdev_setpath,	zfs_secpolicy_config, POOL_NAME, B_FALSE },
2166e7437265Sahrens 	{ zfs_ioc_objset_stats,	zfs_secpolicy_read, DATASET_NAME, B_FALSE },
2167ecd6cf80Smarks 	{ zfs_ioc_dataset_list_next, zfs_secpolicy_read,
2168e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2169ecd6cf80Smarks 	{ zfs_ioc_snapshot_list_next, zfs_secpolicy_read,
2170e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2171e7437265Sahrens 	{ zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE },
2172e7437265Sahrens 	{ zfs_ioc_create_minor,	zfs_secpolicy_minor, DATASET_NAME, B_FALSE },
2173e7437265Sahrens 	{ zfs_ioc_remove_minor,	zfs_secpolicy_minor, DATASET_NAME, B_FALSE },
2174e7437265Sahrens 	{ zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE },
2175e7437265Sahrens 	{ zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE },
2176e7437265Sahrens 	{ zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE },
2177e7437265Sahrens 	{ zfs_ioc_rename, zfs_secpolicy_rename,	DATASET_NAME, B_TRUE },
2178e7437265Sahrens 	{ zfs_ioc_recvbackup, zfs_secpolicy_receive, DATASET_NAME, B_TRUE },
2179e7437265Sahrens 	{ zfs_ioc_sendbackup, zfs_secpolicy_send, DATASET_NAME, B_TRUE },
2180e7437265Sahrens 	{ zfs_ioc_inject_fault,	zfs_secpolicy_inject, NO_NAME, B_FALSE },
2181e7437265Sahrens 	{ zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE },
2182e7437265Sahrens 	{ zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE },
2183e7437265Sahrens 	{ zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE },
2184e7437265Sahrens 	{ zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2185e7437265Sahrens 	{ zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE },
2186e7437265Sahrens 	{ zfs_ioc_destroy_snaps, zfs_secpolicy_destroy,	DATASET_NAME, B_TRUE },
2187e7437265Sahrens 	{ zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE },
2188e7437265Sahrens 	{ zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2189e7437265Sahrens 	{ zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE },
2190e7437265Sahrens 	{ zfs_ioc_pool_set_props, zfs_secpolicy_config,	POOL_NAME, B_TRUE },
2191e7437265Sahrens 	{ zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE },
2192e7437265Sahrens 	{ zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE },
2193e7437265Sahrens 	{ zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE },
2194ecd6cf80Smarks 	{ zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi,
2195e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2196e7437265Sahrens 	{ zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE }
2197fa9e4066Sahrens };
2198fa9e4066Sahrens 
2199fa9e4066Sahrens static int
2200fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
2201fa9e4066Sahrens {
2202fa9e4066Sahrens 	zfs_cmd_t *zc;
2203fa9e4066Sahrens 	uint_t vec;
22041d452cf5Sahrens 	int error, rc;
2205fa9e4066Sahrens 
2206fa9e4066Sahrens 	if (getminor(dev) != 0)
2207fa9e4066Sahrens 		return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp));
2208fa9e4066Sahrens 
2209fa9e4066Sahrens 	vec = cmd - ZFS_IOC;
2210fa9e4066Sahrens 
2211fa9e4066Sahrens 	if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
2212fa9e4066Sahrens 		return (EINVAL);
2213fa9e4066Sahrens 
2214fa9e4066Sahrens 	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
2215fa9e4066Sahrens 
2216fa9e4066Sahrens 	error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t));
2217fa9e4066Sahrens 
2218fa9e4066Sahrens 	if (error == 0) {
2219fa9e4066Sahrens 		zc->zc_cred = (uintptr_t)cr;
2220fa9e4066Sahrens 		zc->zc_dev = dev;
2221ecd6cf80Smarks 		error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr);
2222fa9e4066Sahrens 	}
2223fa9e4066Sahrens 
2224fa9e4066Sahrens 	/*
2225fa9e4066Sahrens 	 * Ensure that all pool/dataset names are valid before we pass down to
2226fa9e4066Sahrens 	 * the lower layers.
2227fa9e4066Sahrens 	 */
2228fa9e4066Sahrens 	if (error == 0) {
2229fa9e4066Sahrens 		zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
2230fa9e4066Sahrens 		switch (zfs_ioc_vec[vec].zvec_namecheck) {
2231e7437265Sahrens 		case POOL_NAME:
2232fa9e4066Sahrens 			if (pool_namecheck(zc->zc_name, NULL, NULL) != 0)
2233fa9e4066Sahrens 				error = EINVAL;
2234fa9e4066Sahrens 			break;
2235fa9e4066Sahrens 
2236e7437265Sahrens 		case DATASET_NAME:
2237fa9e4066Sahrens 			if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0)
2238fa9e4066Sahrens 				error = EINVAL;
2239fa9e4066Sahrens 			break;
22405ad82045Snd 
2241e7437265Sahrens 		case NO_NAME:
22425ad82045Snd 			break;
2243fa9e4066Sahrens 		}
2244fa9e4066Sahrens 	}
2245fa9e4066Sahrens 
2246fa9e4066Sahrens 	if (error == 0)
2247fa9e4066Sahrens 		error = zfs_ioc_vec[vec].zvec_func(zc);
2248fa9e4066Sahrens 
22491d452cf5Sahrens 	rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t));
2250ecd6cf80Smarks 	if (error == 0) {
22511d452cf5Sahrens 		error = rc;
2252ecd6cf80Smarks 		if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE)
2253ecd6cf80Smarks 			zfs_log_history(zc);
2254ecd6cf80Smarks 	}
2255fa9e4066Sahrens 
2256fa9e4066Sahrens 	kmem_free(zc, sizeof (zfs_cmd_t));
2257fa9e4066Sahrens 	return (error);
2258fa9e4066Sahrens }
2259fa9e4066Sahrens 
2260fa9e4066Sahrens static int
2261fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2262fa9e4066Sahrens {
2263fa9e4066Sahrens 	if (cmd != DDI_ATTACH)
2264fa9e4066Sahrens 		return (DDI_FAILURE);
2265fa9e4066Sahrens 
2266fa9e4066Sahrens 	if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0,
2267fa9e4066Sahrens 	    DDI_PSEUDO, 0) == DDI_FAILURE)
2268fa9e4066Sahrens 		return (DDI_FAILURE);
2269fa9e4066Sahrens 
2270fa9e4066Sahrens 	zfs_dip = dip;
2271fa9e4066Sahrens 
2272fa9e4066Sahrens 	ddi_report_dev(dip);
2273fa9e4066Sahrens 
2274fa9e4066Sahrens 	return (DDI_SUCCESS);
2275fa9e4066Sahrens }
2276fa9e4066Sahrens 
2277fa9e4066Sahrens static int
2278fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2279fa9e4066Sahrens {
2280fa9e4066Sahrens 	if (spa_busy() || zfs_busy() || zvol_busy())
2281fa9e4066Sahrens 		return (DDI_FAILURE);
2282fa9e4066Sahrens 
2283fa9e4066Sahrens 	if (cmd != DDI_DETACH)
2284fa9e4066Sahrens 		return (DDI_FAILURE);
2285fa9e4066Sahrens 
2286fa9e4066Sahrens 	zfs_dip = NULL;
2287fa9e4066Sahrens 
2288fa9e4066Sahrens 	ddi_prop_remove_all(dip);
2289fa9e4066Sahrens 	ddi_remove_minor_node(dip, NULL);
2290fa9e4066Sahrens 
2291fa9e4066Sahrens 	return (DDI_SUCCESS);
2292fa9e4066Sahrens }
2293fa9e4066Sahrens 
2294fa9e4066Sahrens /*ARGSUSED*/
2295fa9e4066Sahrens static int
2296fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2297fa9e4066Sahrens {
2298fa9e4066Sahrens 	switch (infocmd) {
2299fa9e4066Sahrens 	case DDI_INFO_DEVT2DEVINFO:
2300fa9e4066Sahrens 		*result = zfs_dip;
2301fa9e4066Sahrens 		return (DDI_SUCCESS);
2302fa9e4066Sahrens 
2303fa9e4066Sahrens 	case DDI_INFO_DEVT2INSTANCE:
2304a0965f35Sbonwick 		*result = (void *)0;
2305fa9e4066Sahrens 		return (DDI_SUCCESS);
2306fa9e4066Sahrens 	}
2307fa9e4066Sahrens 
2308fa9e4066Sahrens 	return (DDI_FAILURE);
2309fa9e4066Sahrens }
2310fa9e4066Sahrens 
2311fa9e4066Sahrens /*
2312fa9e4066Sahrens  * OK, so this is a little weird.
2313fa9e4066Sahrens  *
2314fa9e4066Sahrens  * /dev/zfs is the control node, i.e. minor 0.
2315fa9e4066Sahrens  * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0.
2316fa9e4066Sahrens  *
2317fa9e4066Sahrens  * /dev/zfs has basically nothing to do except serve up ioctls,
2318fa9e4066Sahrens  * so most of the standard driver entry points are in zvol.c.
2319fa9e4066Sahrens  */
2320fa9e4066Sahrens static struct cb_ops zfs_cb_ops = {
2321fa9e4066Sahrens 	zvol_open,	/* open */
2322fa9e4066Sahrens 	zvol_close,	/* close */
2323fa9e4066Sahrens 	zvol_strategy,	/* strategy */
2324fa9e4066Sahrens 	nodev,		/* print */
2325fa9e4066Sahrens 	nodev,		/* dump */
2326fa9e4066Sahrens 	zvol_read,	/* read */
2327fa9e4066Sahrens 	zvol_write,	/* write */
2328fa9e4066Sahrens 	zfsdev_ioctl,	/* ioctl */
2329fa9e4066Sahrens 	nodev,		/* devmap */
2330fa9e4066Sahrens 	nodev,		/* mmap */
2331fa9e4066Sahrens 	nodev,		/* segmap */
2332fa9e4066Sahrens 	nochpoll,	/* poll */
2333fa9e4066Sahrens 	ddi_prop_op,	/* prop_op */
2334fa9e4066Sahrens 	NULL,		/* streamtab */
2335fa9e4066Sahrens 	D_NEW | D_MP | D_64BIT,		/* Driver compatibility flag */
2336fa9e4066Sahrens 	CB_REV,		/* version */
2337feb08c6bSbillm 	nodev,		/* async read */
2338feb08c6bSbillm 	nodev,		/* async write */
2339fa9e4066Sahrens };
2340fa9e4066Sahrens 
2341fa9e4066Sahrens static struct dev_ops zfs_dev_ops = {
2342fa9e4066Sahrens 	DEVO_REV,	/* version */
2343fa9e4066Sahrens 	0,		/* refcnt */
2344fa9e4066Sahrens 	zfs_info,	/* info */
2345fa9e4066Sahrens 	nulldev,	/* identify */
2346fa9e4066Sahrens 	nulldev,	/* probe */
2347fa9e4066Sahrens 	zfs_attach,	/* attach */
2348fa9e4066Sahrens 	zfs_detach,	/* detach */
2349fa9e4066Sahrens 	nodev,		/* reset */
2350fa9e4066Sahrens 	&zfs_cb_ops,	/* driver operations */
2351fa9e4066Sahrens 	NULL		/* no bus operations */
2352fa9e4066Sahrens };
2353fa9e4066Sahrens 
2354fa9e4066Sahrens static struct modldrv zfs_modldrv = {
2355e7437265Sahrens 	&mod_driverops, "ZFS storage pool version " SPA_VERSION_STRING,
2356e9dbad6fSeschrock 	    &zfs_dev_ops
2357fa9e4066Sahrens };
2358fa9e4066Sahrens 
2359fa9e4066Sahrens static struct modlinkage modlinkage = {
2360fa9e4066Sahrens 	MODREV_1,
2361fa9e4066Sahrens 	(void *)&zfs_modlfs,
2362fa9e4066Sahrens 	(void *)&zfs_modldrv,
2363fa9e4066Sahrens 	NULL
2364fa9e4066Sahrens };
2365fa9e4066Sahrens 
2366fa9e4066Sahrens int
2367fa9e4066Sahrens _init(void)
2368fa9e4066Sahrens {
2369fa9e4066Sahrens 	int error;
2370fa9e4066Sahrens 
2371a0965f35Sbonwick 	spa_init(FREAD | FWRITE);
2372a0965f35Sbonwick 	zfs_init();
2373a0965f35Sbonwick 	zvol_init();
2374a0965f35Sbonwick 
2375a0965f35Sbonwick 	if ((error = mod_install(&modlinkage)) != 0) {
2376a0965f35Sbonwick 		zvol_fini();
2377a0965f35Sbonwick 		zfs_fini();
2378a0965f35Sbonwick 		spa_fini();
2379fa9e4066Sahrens 		return (error);
2380a0965f35Sbonwick 	}
2381fa9e4066Sahrens 
2382fa9e4066Sahrens 	error = ldi_ident_from_mod(&modlinkage, &zfs_li);
2383fa9e4066Sahrens 	ASSERT(error == 0);
2384ecd6cf80Smarks 	mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL);
2385fa9e4066Sahrens 
2386fa9e4066Sahrens 	return (0);
2387fa9e4066Sahrens }
2388fa9e4066Sahrens 
2389fa9e4066Sahrens int
2390fa9e4066Sahrens _fini(void)
2391fa9e4066Sahrens {
2392fa9e4066Sahrens 	int error;
2393fa9e4066Sahrens 
2394ea8dc4b6Seschrock 	if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled)
2395fa9e4066Sahrens 		return (EBUSY);
2396fa9e4066Sahrens 
2397fa9e4066Sahrens 	if ((error = mod_remove(&modlinkage)) != 0)
2398fa9e4066Sahrens 		return (error);
2399fa9e4066Sahrens 
2400fa9e4066Sahrens 	zvol_fini();
2401fa9e4066Sahrens 	zfs_fini();
2402fa9e4066Sahrens 	spa_fini();
2403ecd6cf80Smarks 	if (zfs_share_inited) {
2404ecd6cf80Smarks 		(void) ddi_modclose(nfs_mod);
2405ecd6cf80Smarks 		(void) ddi_modclose(sharefs_mod);
2406ecd6cf80Smarks 	}
2407fa9e4066Sahrens 
2408fa9e4066Sahrens 	ldi_ident_release(zfs_li);
2409fa9e4066Sahrens 	zfs_li = NULL;
2410ecd6cf80Smarks 	mutex_destroy(&zfs_share_lock);
2411fa9e4066Sahrens 
2412fa9e4066Sahrens 	return (error);
2413fa9e4066Sahrens }
2414fa9e4066Sahrens 
2415fa9e4066Sahrens int
2416fa9e4066Sahrens _info(struct modinfo *modinfop)
2417fa9e4066Sahrens {
2418fa9e4066Sahrens 	return (mod_info(&modlinkage, modinfop));
2419fa9e4066Sahrens }
2420