xref: /illumos-gate/usr/src/uts/common/fs/zfs/zfs_ioctl.c (revision c2a93d44)
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>
41da6c28aaSamw #include <sys/zfs_i18n.h>
42da6c28aaSamw #include <sys/zfs_znode.h>
43fa9e4066Sahrens #include <sys/zap.h>
44fa9e4066Sahrens #include <sys/spa.h>
45b1b8ab34Slling #include <sys/spa_impl.h>
46fa9e4066Sahrens #include <sys/vdev.h>
47b1b8ab34Slling #include <sys/vdev_impl.h>
48fa9e4066Sahrens #include <sys/dmu.h>
49fa9e4066Sahrens #include <sys/dsl_dir.h>
50fa9e4066Sahrens #include <sys/dsl_dataset.h>
51fa9e4066Sahrens #include <sys/dsl_prop.h>
52ecd6cf80Smarks #include <sys/dsl_deleg.h>
53ecd6cf80Smarks #include <sys/dmu_objset.h>
54fa9e4066Sahrens #include <sys/ddi.h>
55fa9e4066Sahrens #include <sys/sunddi.h>
56fa9e4066Sahrens #include <sys/sunldi.h>
57fa9e4066Sahrens #include <sys/policy.h>
58fa9e4066Sahrens #include <sys/zone.h>
59fa9e4066Sahrens #include <sys/nvpair.h>
60fa9e4066Sahrens #include <sys/pathname.h>
61fa9e4066Sahrens #include <sys/mount.h>
62fa9e4066Sahrens #include <sys/sdt.h>
63fa9e4066Sahrens #include <sys/fs/zfs.h>
64fa9e4066Sahrens #include <sys/zfs_ctldir.h>
65da6c28aaSamw #include <sys/zfs_dir.h>
66a2eea2e1Sahrens #include <sys/zvol.h>
67ecd6cf80Smarks #include <sharefs/share.h>
68e7437265Sahrens #include <sys/zfs_znode.h>
69f18faf3fSek #include <sys/zfs_vfsops.h>
70f18faf3fSek #include <sys/dmu_objset.h>
71fa9e4066Sahrens 
72fa9e4066Sahrens #include "zfs_namecheck.h"
73e9dbad6fSeschrock #include "zfs_prop.h"
74ecd6cf80Smarks #include "zfs_deleg.h"
75fa9e4066Sahrens 
76fa9e4066Sahrens extern struct modlfs zfs_modlfs;
77fa9e4066Sahrens 
78fa9e4066Sahrens extern void zfs_init(void);
79fa9e4066Sahrens extern void zfs_fini(void);
80fa9e4066Sahrens 
81fa9e4066Sahrens ldi_ident_t zfs_li = NULL;
82fa9e4066Sahrens dev_info_t *zfs_dip;
83fa9e4066Sahrens 
84fa9e4066Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *);
85ecd6cf80Smarks typedef int zfs_secpolicy_func_t(zfs_cmd_t *, cred_t *);
86fa9e4066Sahrens 
87fa9e4066Sahrens typedef struct zfs_ioc_vec {
88fa9e4066Sahrens 	zfs_ioc_func_t		*zvec_func;
89fa9e4066Sahrens 	zfs_secpolicy_func_t	*zvec_secpolicy;
90fa9e4066Sahrens 	enum {
91e7437265Sahrens 		NO_NAME,
92e7437265Sahrens 		POOL_NAME,
93e7437265Sahrens 		DATASET_NAME
94ecd6cf80Smarks 	} zvec_namecheck;
95ecd6cf80Smarks 	boolean_t		zvec_his_log;
96fa9e4066Sahrens } zfs_ioc_vec_t;
97fa9e4066Sahrens 
98fa9e4066Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */
99fa9e4066Sahrens void
100fa9e4066Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
101fa9e4066Sahrens {
102fa9e4066Sahrens 	const char *newfile;
103fa9e4066Sahrens 	char buf[256];
104fa9e4066Sahrens 	va_list adx;
105fa9e4066Sahrens 
106fa9e4066Sahrens 	/*
107fa9e4066Sahrens 	 * Get rid of annoying "../common/" prefix to filename.
108fa9e4066Sahrens 	 */
109fa9e4066Sahrens 	newfile = strrchr(file, '/');
110fa9e4066Sahrens 	if (newfile != NULL) {
111fa9e4066Sahrens 		newfile = newfile + 1; /* Get rid of leading / */
112fa9e4066Sahrens 	} else {
113fa9e4066Sahrens 		newfile = file;
114fa9e4066Sahrens 	}
115fa9e4066Sahrens 
116fa9e4066Sahrens 	va_start(adx, fmt);
117fa9e4066Sahrens 	(void) vsnprintf(buf, sizeof (buf), fmt, adx);
118fa9e4066Sahrens 	va_end(adx);
119fa9e4066Sahrens 
120fa9e4066Sahrens 	/*
121fa9e4066Sahrens 	 * To get this data, use the zfs-dprintf probe as so:
122fa9e4066Sahrens 	 * dtrace -q -n 'zfs-dprintf \
123fa9e4066Sahrens 	 *	/stringof(arg0) == "dbuf.c"/ \
124fa9e4066Sahrens 	 *	{printf("%s: %s", stringof(arg1), stringof(arg3))}'
125fa9e4066Sahrens 	 * arg0 = file name
126fa9e4066Sahrens 	 * arg1 = function name
127fa9e4066Sahrens 	 * arg2 = line number
128fa9e4066Sahrens 	 * arg3 = message
129fa9e4066Sahrens 	 */
130fa9e4066Sahrens 	DTRACE_PROBE4(zfs__dprintf,
131fa9e4066Sahrens 	    char *, newfile, char *, func, int, line, char *, buf);
132fa9e4066Sahrens }
133fa9e4066Sahrens 
134ecd6cf80Smarks static void
135228975ccSek history_str_free(char *buf)
136228975ccSek {
137228975ccSek 	kmem_free(buf, HIS_MAX_RECORD_LEN);
138228975ccSek }
139228975ccSek 
140228975ccSek static char *
141228975ccSek history_str_get(zfs_cmd_t *zc)
142ecd6cf80Smarks {
14340feaa91Sahrens 	char *buf;
144ecd6cf80Smarks 
145ecd6cf80Smarks 	if (zc->zc_history == NULL)
146228975ccSek 		return (NULL);
147e7437265Sahrens 
148ecd6cf80Smarks 	buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP);
149ecd6cf80Smarks 	if (copyinstr((void *)(uintptr_t)zc->zc_history,
150ecd6cf80Smarks 	    buf, HIS_MAX_RECORD_LEN, NULL) != 0) {
151228975ccSek 		history_str_free(buf);
152228975ccSek 		return (NULL);
153ecd6cf80Smarks 	}
154ecd6cf80Smarks 
155ecd6cf80Smarks 	buf[HIS_MAX_RECORD_LEN -1] = '\0';
156ecd6cf80Smarks 
157228975ccSek 	return (buf);
158228975ccSek }
159ecd6cf80Smarks 
160*c2a93d44Stimh /*
161*c2a93d44Stimh  * zfs_check_version
162*c2a93d44Stimh  *
163*c2a93d44Stimh  *	Return non-zero if the spa version is less than requested version.
164*c2a93d44Stimh  */
165da6c28aaSamw static int
166da6c28aaSamw zfs_check_version(const char *name, int version)
167da6c28aaSamw {
168da6c28aaSamw 
169da6c28aaSamw 	spa_t *spa;
170da6c28aaSamw 
171da6c28aaSamw 	if (spa_open(name, &spa, FTAG) == 0) {
172da6c28aaSamw 		if (spa_version(spa) < version) {
173da6c28aaSamw 			spa_close(spa, FTAG);
174da6c28aaSamw 			return (1);
175da6c28aaSamw 		}
176da6c28aaSamw 		spa_close(spa, FTAG);
177da6c28aaSamw 	}
178da6c28aaSamw 	return (0);
179da6c28aaSamw }
180da6c28aaSamw 
181228975ccSek static void
182228975ccSek zfs_log_history(zfs_cmd_t *zc)
183228975ccSek {
184228975ccSek 	spa_t *spa;
185228975ccSek 	char *buf;
186ecd6cf80Smarks 
187228975ccSek 	if ((buf = history_str_get(zc)) == NULL)
188228975ccSek 		return;
189228975ccSek 
190228975ccSek 	if (spa_open(zc->zc_name, &spa, FTAG) == 0) {
191228975ccSek 		if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY)
192228975ccSek 			(void) spa_history_log(spa, buf, LOG_CMD_NORMAL);
193228975ccSek 		spa_close(spa, FTAG);
194228975ccSek 	}
195228975ccSek 	history_str_free(buf);
196ecd6cf80Smarks }
197ecd6cf80Smarks 
198fa9e4066Sahrens /*
199fa9e4066Sahrens  * Policy for top-level read operations (list pools).  Requires no privileges,
200fa9e4066Sahrens  * and can be used in the local zone, as there is no associated dataset.
201fa9e4066Sahrens  */
202fa9e4066Sahrens /* ARGSUSED */
203fa9e4066Sahrens static int
204ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr)
205fa9e4066Sahrens {
206fa9e4066Sahrens 	return (0);
207fa9e4066Sahrens }
208fa9e4066Sahrens 
209fa9e4066Sahrens /*
210fa9e4066Sahrens  * Policy for dataset read operations (list children, get statistics).  Requires
211fa9e4066Sahrens  * no privileges, but must be visible in the local zone.
212fa9e4066Sahrens  */
213fa9e4066Sahrens /* ARGSUSED */
214fa9e4066Sahrens static int
215ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr)
216fa9e4066Sahrens {
217fa9e4066Sahrens 	if (INGLOBALZONE(curproc) ||
218ecd6cf80Smarks 	    zone_dataset_visible(zc->zc_name, NULL))
219fa9e4066Sahrens 		return (0);
220fa9e4066Sahrens 
221fa9e4066Sahrens 	return (ENOENT);
222fa9e4066Sahrens }
223fa9e4066Sahrens 
224fa9e4066Sahrens static int
225fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr)
226fa9e4066Sahrens {
227fa9e4066Sahrens 	uint64_t zoned;
228fa9e4066Sahrens 	int writable = 1;
229fa9e4066Sahrens 
230fa9e4066Sahrens 	/*
231fa9e4066Sahrens 	 * The dataset must be visible by this zone -- check this first
232fa9e4066Sahrens 	 * so they don't see EPERM on something they shouldn't know about.
233fa9e4066Sahrens 	 */
234fa9e4066Sahrens 	if (!INGLOBALZONE(curproc) &&
235fa9e4066Sahrens 	    !zone_dataset_visible(dataset, &writable))
236fa9e4066Sahrens 		return (ENOENT);
237fa9e4066Sahrens 
238fa9e4066Sahrens 	if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL))
239fa9e4066Sahrens 		return (ENOENT);
240fa9e4066Sahrens 
241fa9e4066Sahrens 	if (INGLOBALZONE(curproc)) {
242fa9e4066Sahrens 		/*
243fa9e4066Sahrens 		 * If the fs is zoned, only root can access it from the
244fa9e4066Sahrens 		 * global zone.
245fa9e4066Sahrens 		 */
246fa9e4066Sahrens 		if (secpolicy_zfs(cr) && zoned)
247fa9e4066Sahrens 			return (EPERM);
248fa9e4066Sahrens 	} else {
249fa9e4066Sahrens 		/*
250fa9e4066Sahrens 		 * If we are in a local zone, the 'zoned' property must be set.
251fa9e4066Sahrens 		 */
252fa9e4066Sahrens 		if (!zoned)
253fa9e4066Sahrens 			return (EPERM);
254fa9e4066Sahrens 
255fa9e4066Sahrens 		/* must be writable by this zone */
256fa9e4066Sahrens 		if (!writable)
257fa9e4066Sahrens 			return (EPERM);
258fa9e4066Sahrens 	}
259fa9e4066Sahrens 	return (0);
260fa9e4066Sahrens }
261fa9e4066Sahrens 
262fa9e4066Sahrens int
263ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr)
264fa9e4066Sahrens {
265fa9e4066Sahrens 	int error;
266fa9e4066Sahrens 
267ecd6cf80Smarks 	error = zfs_dozonecheck(name, cr);
268ecd6cf80Smarks 	if (error == 0) {
269ecd6cf80Smarks 		error = secpolicy_zfs(cr);
270db870a07Sahrens 		if (error)
271ecd6cf80Smarks 			error = dsl_deleg_access(name, perm, cr);
272ecd6cf80Smarks 	}
273ecd6cf80Smarks 	return (error);
274ecd6cf80Smarks }
275ecd6cf80Smarks 
276ecd6cf80Smarks static int
277ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr)
278ecd6cf80Smarks {
279ecd6cf80Smarks 	/*
280ecd6cf80Smarks 	 * Check permissions for special properties.
281ecd6cf80Smarks 	 */
282ecd6cf80Smarks 	switch (prop) {
283ecd6cf80Smarks 	case ZFS_PROP_ZONED:
284ecd6cf80Smarks 		/*
285ecd6cf80Smarks 		 * Disallow setting of 'zoned' from within a local zone.
286ecd6cf80Smarks 		 */
287ecd6cf80Smarks 		if (!INGLOBALZONE(curproc))
288ecd6cf80Smarks 			return (EPERM);
289ecd6cf80Smarks 		break;
290ecd6cf80Smarks 
291ecd6cf80Smarks 	case ZFS_PROP_QUOTA:
292ecd6cf80Smarks 		if (!INGLOBALZONE(curproc)) {
293ecd6cf80Smarks 			uint64_t zoned;
294ecd6cf80Smarks 			char setpoint[MAXNAMELEN];
295ecd6cf80Smarks 			/*
296ecd6cf80Smarks 			 * Unprivileged users are allowed to modify the
297ecd6cf80Smarks 			 * quota on things *under* (ie. contained by)
298ecd6cf80Smarks 			 * the thing they own.
299ecd6cf80Smarks 			 */
300ecd6cf80Smarks 			if (dsl_prop_get_integer(name, "zoned", &zoned,
301ecd6cf80Smarks 			    setpoint))
302ecd6cf80Smarks 				return (EPERM);
303db870a07Sahrens 			if (!zoned || strlen(name) <= strlen(setpoint))
304ecd6cf80Smarks 				return (EPERM);
305ecd6cf80Smarks 		}
306db870a07Sahrens 		break;
307ecd6cf80Smarks 	}
308ecd6cf80Smarks 
30991ebeef5Sahrens 	return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr));
310ecd6cf80Smarks }
311ecd6cf80Smarks 
312ecd6cf80Smarks int
313ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr)
314ecd6cf80Smarks {
315ecd6cf80Smarks 	int error;
316ecd6cf80Smarks 
317ecd6cf80Smarks 	error = zfs_dozonecheck(zc->zc_name, cr);
318ecd6cf80Smarks 	if (error)
319fa9e4066Sahrens 		return (error);
320fa9e4066Sahrens 
321ecd6cf80Smarks 	/*
322ecd6cf80Smarks 	 * permission to set permissions will be evaluated later in
323ecd6cf80Smarks 	 * dsl_deleg_can_allow()
324ecd6cf80Smarks 	 */
325ecd6cf80Smarks 	return (0);
326ecd6cf80Smarks }
327ecd6cf80Smarks 
328ecd6cf80Smarks int
329ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr)
330ecd6cf80Smarks {
331ecd6cf80Smarks 	int error;
332ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(zc->zc_name,
333ecd6cf80Smarks 	    ZFS_DELEG_PERM_ROLLBACK, cr);
334ecd6cf80Smarks 	if (error == 0)
335ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(zc->zc_name,
336ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr);
337ecd6cf80Smarks 	return (error);
338ecd6cf80Smarks }
339ecd6cf80Smarks 
340ecd6cf80Smarks int
341ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr)
342ecd6cf80Smarks {
343ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(zc->zc_name,
344ecd6cf80Smarks 	    ZFS_DELEG_PERM_SEND, cr));
345ecd6cf80Smarks }
346ecd6cf80Smarks 
347ecd6cf80Smarks int
348ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr)
349ecd6cf80Smarks {
350ecd6cf80Smarks 	if (!INGLOBALZONE(curproc))
351ecd6cf80Smarks 		return (EPERM);
352ecd6cf80Smarks 
3533cb34c60Sahrens 	if (secpolicy_nfs(cr) == 0) {
354ecd6cf80Smarks 		return (0);
355ecd6cf80Smarks 	} else {
356ecd6cf80Smarks 		vnode_t *vp;
357ecd6cf80Smarks 		int error;
358ecd6cf80Smarks 
359ecd6cf80Smarks 		if ((error = lookupname(zc->zc_value, UIO_SYSSPACE,
360ecd6cf80Smarks 		    NO_FOLLOW, NULL, &vp)) != 0)
361ecd6cf80Smarks 			return (error);
362ecd6cf80Smarks 
363ecd6cf80Smarks 		/* Now make sure mntpnt and dataset are ZFS */
364ecd6cf80Smarks 
365ecd6cf80Smarks 		if (vp->v_vfsp->vfs_fstype != zfsfstype ||
366ecd6cf80Smarks 		    (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource),
367ecd6cf80Smarks 		    zc->zc_name) != 0)) {
368ecd6cf80Smarks 			VN_RELE(vp);
369ecd6cf80Smarks 			return (EPERM);
370ecd6cf80Smarks 		}
371ecd6cf80Smarks 
372ecd6cf80Smarks 		VN_RELE(vp);
373ecd6cf80Smarks 		return (dsl_deleg_access(zc->zc_name,
374ecd6cf80Smarks 		    ZFS_DELEG_PERM_SHARE, cr));
375ecd6cf80Smarks 	}
376fa9e4066Sahrens }
377fa9e4066Sahrens 
378fa9e4066Sahrens static int
379ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize)
380fa9e4066Sahrens {
381fa9e4066Sahrens 	char *cp;
382fa9e4066Sahrens 
383fa9e4066Sahrens 	/*
384fa9e4066Sahrens 	 * Remove the @bla or /bla from the end of the name to get the parent.
385fa9e4066Sahrens 	 */
386ecd6cf80Smarks 	(void) strncpy(parent, datasetname, parentsize);
387ecd6cf80Smarks 	cp = strrchr(parent, '@');
388fa9e4066Sahrens 	if (cp != NULL) {
389fa9e4066Sahrens 		cp[0] = '\0';
390fa9e4066Sahrens 	} else {
391ecd6cf80Smarks 		cp = strrchr(parent, '/');
392fa9e4066Sahrens 		if (cp == NULL)
393fa9e4066Sahrens 			return (ENOENT);
394fa9e4066Sahrens 		cp[0] = '\0';
395ecd6cf80Smarks 	}
396ecd6cf80Smarks 
397ecd6cf80Smarks 	return (0);
398ecd6cf80Smarks }
399ecd6cf80Smarks 
400ecd6cf80Smarks int
401ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr)
402ecd6cf80Smarks {
403ecd6cf80Smarks 	int error;
404ecd6cf80Smarks 
405ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(name,
406ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
407ecd6cf80Smarks 		return (error);
408ecd6cf80Smarks 
409ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr));
410ecd6cf80Smarks }
411ecd6cf80Smarks 
412ecd6cf80Smarks static int
413ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr)
414ecd6cf80Smarks {
415ecd6cf80Smarks 	return (zfs_secpolicy_destroy_perms(zc->zc_name, cr));
416ecd6cf80Smarks }
417ecd6cf80Smarks 
418ecd6cf80Smarks /*
419ecd6cf80Smarks  * Must have sys_config privilege to check the iscsi permission
420ecd6cf80Smarks  */
421ecd6cf80Smarks /* ARGSUSED */
422ecd6cf80Smarks static int
423ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr)
424ecd6cf80Smarks {
425ecd6cf80Smarks 	return (secpolicy_zfs(cr));
426ecd6cf80Smarks }
427ecd6cf80Smarks 
428ecd6cf80Smarks int
429ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
430ecd6cf80Smarks {
431ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
432ecd6cf80Smarks 	int	error;
433ecd6cf80Smarks 
434ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(from,
435ecd6cf80Smarks 	    ZFS_DELEG_PERM_RENAME, cr)) != 0)
436ecd6cf80Smarks 		return (error);
437ecd6cf80Smarks 
438ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(from,
439ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
440ecd6cf80Smarks 		return (error);
441ecd6cf80Smarks 
442ecd6cf80Smarks 	if ((error = zfs_get_parent(to, parentname,
443ecd6cf80Smarks 	    sizeof (parentname))) != 0)
444ecd6cf80Smarks 		return (error);
445ecd6cf80Smarks 
446ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
447ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr)) != 0)
448ecd6cf80Smarks 		return (error);
449ecd6cf80Smarks 
450ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
451ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
452ecd6cf80Smarks 		return (error);
453ecd6cf80Smarks 
454ecd6cf80Smarks 	return (error);
455ecd6cf80Smarks }
456ecd6cf80Smarks 
457ecd6cf80Smarks static int
458ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr)
459ecd6cf80Smarks {
460ecd6cf80Smarks 	return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr));
461ecd6cf80Smarks }
462ecd6cf80Smarks 
463ecd6cf80Smarks static int
464ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr)
465ecd6cf80Smarks {
466ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
467ecd6cf80Smarks 	objset_t *clone;
468ecd6cf80Smarks 	int error;
469ecd6cf80Smarks 
470ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(zc->zc_name,
471ecd6cf80Smarks 	    ZFS_DELEG_PERM_PROMOTE, cr);
472ecd6cf80Smarks 	if (error)
473ecd6cf80Smarks 		return (error);
474ecd6cf80Smarks 
475ecd6cf80Smarks 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
476ecd6cf80Smarks 	    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
477ecd6cf80Smarks 
478ecd6cf80Smarks 	if (error == 0) {
479ecd6cf80Smarks 		dsl_dataset_t *pclone = NULL;
480ecd6cf80Smarks 		dsl_dir_t *dd;
481ecd6cf80Smarks 		dd = clone->os->os_dsl_dataset->ds_dir;
482ecd6cf80Smarks 
483ecd6cf80Smarks 		rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
484ecd6cf80Smarks 		error = dsl_dataset_open_obj(dd->dd_pool,
4853cb34c60Sahrens 		    dd->dd_phys->dd_origin_obj, NULL,
486ecd6cf80Smarks 		    DS_MODE_NONE, FTAG, &pclone);
487ecd6cf80Smarks 		rw_exit(&dd->dd_pool->dp_config_rwlock);
488ecd6cf80Smarks 		if (error) {
489ecd6cf80Smarks 			dmu_objset_close(clone);
490ecd6cf80Smarks 			return (error);
491ecd6cf80Smarks 		}
492ecd6cf80Smarks 
493ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(zc->zc_name,
494ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr);
495ecd6cf80Smarks 
496ecd6cf80Smarks 		dsl_dataset_name(pclone, parentname);
497ecd6cf80Smarks 		dmu_objset_close(clone);
498ecd6cf80Smarks 		dsl_dataset_close(pclone, DS_MODE_NONE, FTAG);
499ecd6cf80Smarks 		if (error == 0)
500ecd6cf80Smarks 			error = zfs_secpolicy_write_perms(parentname,
501ecd6cf80Smarks 			    ZFS_DELEG_PERM_PROMOTE, cr);
502ecd6cf80Smarks 	}
503ecd6cf80Smarks 	return (error);
504ecd6cf80Smarks }
505ecd6cf80Smarks 
506ecd6cf80Smarks static int
507ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr)
508ecd6cf80Smarks {
509ecd6cf80Smarks 	int error;
510ecd6cf80Smarks 
511ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(zc->zc_name,
512ecd6cf80Smarks 	    ZFS_DELEG_PERM_RECEIVE, cr)) != 0)
513ecd6cf80Smarks 		return (error);
514ecd6cf80Smarks 
515ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(zc->zc_name,
516ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
517ecd6cf80Smarks 		return (error);
518ecd6cf80Smarks 
519ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(zc->zc_name,
520ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr));
521ecd6cf80Smarks }
522ecd6cf80Smarks 
523ecd6cf80Smarks int
524ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
525ecd6cf80Smarks {
526ecd6cf80Smarks 	int error;
527ecd6cf80Smarks 
528ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(name,
529ecd6cf80Smarks 	    ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0)
530ecd6cf80Smarks 		return (error);
531ecd6cf80Smarks 
532ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(name,
533ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr);
534ecd6cf80Smarks 
535ecd6cf80Smarks 	return (error);
536ecd6cf80Smarks }
537ecd6cf80Smarks 
538ecd6cf80Smarks static int
539ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr)
540ecd6cf80Smarks {
541ecd6cf80Smarks 
542ecd6cf80Smarks 	return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr));
543ecd6cf80Smarks }
544ecd6cf80Smarks 
545ecd6cf80Smarks static int
546ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr)
547ecd6cf80Smarks {
548ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
549ecd6cf80Smarks 	int 	error;
550ecd6cf80Smarks 
551ecd6cf80Smarks 	if ((error = zfs_get_parent(zc->zc_name, parentname,
552ecd6cf80Smarks 	    sizeof (parentname))) != 0)
553ecd6cf80Smarks 		return (error);
554fa9e4066Sahrens 
555ecd6cf80Smarks 	if (zc->zc_value[0] != '\0') {
556ecd6cf80Smarks 		if ((error = zfs_secpolicy_write_perms(zc->zc_value,
557ecd6cf80Smarks 		    ZFS_DELEG_PERM_CLONE, cr)) != 0)
558ecd6cf80Smarks 			return (error);
559fa9e4066Sahrens 	}
560fa9e4066Sahrens 
561ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
562ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr)) != 0)
563ecd6cf80Smarks 		return (error);
564ecd6cf80Smarks 
565ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(parentname,
566ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr);
567ecd6cf80Smarks 
568ecd6cf80Smarks 	return (error);
569ecd6cf80Smarks }
570ecd6cf80Smarks 
571ecd6cf80Smarks static int
572ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr)
573ecd6cf80Smarks {
574ecd6cf80Smarks 	int error;
575ecd6cf80Smarks 
576ecd6cf80Smarks 	error = secpolicy_fs_unmount(cr, NULL);
577ecd6cf80Smarks 	if (error) {
578ecd6cf80Smarks 		error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr);
579ecd6cf80Smarks 	}
580ecd6cf80Smarks 	return (error);
581fa9e4066Sahrens }
582fa9e4066Sahrens 
583fa9e4066Sahrens /*
584fa9e4066Sahrens  * Policy for pool operations - create/destroy pools, add vdevs, etc.  Requires
585fa9e4066Sahrens  * SYS_CONFIG privilege, which is not available in a local zone.
586fa9e4066Sahrens  */
587fa9e4066Sahrens /* ARGSUSED */
588fa9e4066Sahrens static int
589ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr)
590fa9e4066Sahrens {
591fa9e4066Sahrens 	if (secpolicy_sys_config(cr, B_FALSE) != 0)
592fa9e4066Sahrens 		return (EPERM);
593fa9e4066Sahrens 
594fa9e4066Sahrens 	return (0);
595fa9e4066Sahrens }
596fa9e4066Sahrens 
597ecd6cf80Smarks /*
598ecd6cf80Smarks  * Just like zfs_secpolicy_config, except that we will check for
599ecd6cf80Smarks  * mount permission on the dataset for permission to create/remove
600ecd6cf80Smarks  * the minor nodes.
601ecd6cf80Smarks  */
602ecd6cf80Smarks static int
603ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr)
604ecd6cf80Smarks {
605ecd6cf80Smarks 	if (secpolicy_sys_config(cr, B_FALSE) != 0) {
606ecd6cf80Smarks 		return (dsl_deleg_access(zc->zc_name,
607ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr));
608ecd6cf80Smarks 	}
609ecd6cf80Smarks 
610ecd6cf80Smarks 	return (0);
611ecd6cf80Smarks }
612ecd6cf80Smarks 
613ea8dc4b6Seschrock /*
614ea8dc4b6Seschrock  * Policy for fault injection.  Requires all privileges.
615ea8dc4b6Seschrock  */
616ea8dc4b6Seschrock /* ARGSUSED */
617ea8dc4b6Seschrock static int
618ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr)
619ea8dc4b6Seschrock {
620ea8dc4b6Seschrock 	return (secpolicy_zinject(cr));
621ea8dc4b6Seschrock }
622ea8dc4b6Seschrock 
623e45ce728Sahrens static int
624e45ce728Sahrens zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr)
625e45ce728Sahrens {
626e45ce728Sahrens 	zfs_prop_t prop = zfs_name_to_prop(zc->zc_value);
627e45ce728Sahrens 
628990b4856Slling 	if (prop == ZPROP_INVAL) {
629e45ce728Sahrens 		if (!zfs_prop_user(zc->zc_value))
630e45ce728Sahrens 			return (EINVAL);
631e45ce728Sahrens 		return (zfs_secpolicy_write_perms(zc->zc_name,
632e45ce728Sahrens 		    ZFS_DELEG_PERM_USERPROP, cr));
633e45ce728Sahrens 	} else {
634e45ce728Sahrens 		if (!zfs_prop_inheritable(prop))
635e45ce728Sahrens 			return (EINVAL);
636e45ce728Sahrens 		return (zfs_secpolicy_setprop(zc->zc_name, prop, cr));
637e45ce728Sahrens 	}
638e45ce728Sahrens }
639e45ce728Sahrens 
640fa9e4066Sahrens /*
641fa9e4066Sahrens  * Returns the nvlist as specified by the user in the zfs_cmd_t.
642fa9e4066Sahrens  */
643fa9e4066Sahrens static int
644990b4856Slling get_nvlist(uint64_t nvl, uint64_t size, nvlist_t **nvp)
645fa9e4066Sahrens {
646fa9e4066Sahrens 	char *packed;
647fa9e4066Sahrens 	int error;
648990b4856Slling 	nvlist_t *list = NULL;
649fa9e4066Sahrens 
650fa9e4066Sahrens 	/*
651e9dbad6fSeschrock 	 * Read in and unpack the user-supplied nvlist.
652fa9e4066Sahrens 	 */
653990b4856Slling 	if (size == 0)
654fa9e4066Sahrens 		return (EINVAL);
655fa9e4066Sahrens 
656fa9e4066Sahrens 	packed = kmem_alloc(size, KM_SLEEP);
657fa9e4066Sahrens 
658990b4856Slling 	if ((error = xcopyin((void *)(uintptr_t)nvl, packed, size)) != 0) {
659fa9e4066Sahrens 		kmem_free(packed, size);
660fa9e4066Sahrens 		return (error);
661fa9e4066Sahrens 	}
662fa9e4066Sahrens 
663990b4856Slling 	if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) {
664fa9e4066Sahrens 		kmem_free(packed, size);
665fa9e4066Sahrens 		return (error);
666fa9e4066Sahrens 	}
667fa9e4066Sahrens 
668fa9e4066Sahrens 	kmem_free(packed, size);
669fa9e4066Sahrens 
670990b4856Slling 	*nvp = list;
671fa9e4066Sahrens 	return (0);
672fa9e4066Sahrens }
673fa9e4066Sahrens 
674e9dbad6fSeschrock static int
675e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
676e9dbad6fSeschrock {
677e9dbad6fSeschrock 	char *packed = NULL;
678e9dbad6fSeschrock 	size_t size;
679e9dbad6fSeschrock 	int error;
680e9dbad6fSeschrock 
681e9dbad6fSeschrock 	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
682e9dbad6fSeschrock 
683e9dbad6fSeschrock 	if (size > zc->zc_nvlist_dst_size) {
684e9dbad6fSeschrock 		error = ENOMEM;
685e9dbad6fSeschrock 	} else {
686da165920Smarks 		packed = kmem_alloc(size, KM_SLEEP);
687e9dbad6fSeschrock 		VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
688e9dbad6fSeschrock 		    KM_SLEEP) == 0);
689e9dbad6fSeschrock 		error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst,
690e9dbad6fSeschrock 		    size);
691e9dbad6fSeschrock 		kmem_free(packed, size);
692e9dbad6fSeschrock 	}
693e9dbad6fSeschrock 
694e9dbad6fSeschrock 	zc->zc_nvlist_dst_size = size;
695e9dbad6fSeschrock 	return (error);
696e9dbad6fSeschrock }
697e9dbad6fSeschrock 
698fa9e4066Sahrens static int
699fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc)
700fa9e4066Sahrens {
701fa9e4066Sahrens 	int error;
702990b4856Slling 	nvlist_t *config, *props = NULL;
703228975ccSek 	char *buf;
704fa9e4066Sahrens 
705990b4856Slling 	if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
706990b4856Slling 	    &config))
707fa9e4066Sahrens 		return (error);
7082a6b87f0Sek 
709990b4856Slling 	if (zc->zc_nvlist_src_size != 0 && (error =
710990b4856Slling 	    get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) {
711990b4856Slling 		nvlist_free(config);
712990b4856Slling 		return (error);
713990b4856Slling 	}
714990b4856Slling 
7152a6b87f0Sek 	buf = history_str_get(zc);
716fa9e4066Sahrens 
717990b4856Slling 	error = spa_create(zc->zc_name, config, props, buf);
718fa9e4066Sahrens 
7192a6b87f0Sek 	if (buf != NULL)
7202a6b87f0Sek 		history_str_free(buf);
721990b4856Slling 
722fa9e4066Sahrens 	nvlist_free(config);
723fa9e4066Sahrens 
724990b4856Slling 	if (props)
725990b4856Slling 		nvlist_free(props);
726990b4856Slling 
727fa9e4066Sahrens 	return (error);
728fa9e4066Sahrens }
729fa9e4066Sahrens 
730fa9e4066Sahrens static int
731fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc)
732fa9e4066Sahrens {
733ecd6cf80Smarks 	int error;
734ecd6cf80Smarks 	zfs_log_history(zc);
735ecd6cf80Smarks 	error = spa_destroy(zc->zc_name);
736ecd6cf80Smarks 	return (error);
737fa9e4066Sahrens }
738fa9e4066Sahrens 
739fa9e4066Sahrens static int
740fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc)
741fa9e4066Sahrens {
742fa9e4066Sahrens 	int error;
743990b4856Slling 	nvlist_t *config, *props = NULL;
744fa9e4066Sahrens 	uint64_t guid;
745fa9e4066Sahrens 
746990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
747990b4856Slling 	    &config)) != 0)
748990b4856Slling 		return (error);
749990b4856Slling 
750990b4856Slling 	if (zc->zc_nvlist_src_size != 0 && (error =
751990b4856Slling 	    get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) {
752990b4856Slling 		nvlist_free(config);
753fa9e4066Sahrens 		return (error);
754990b4856Slling 	}
755fa9e4066Sahrens 
756fa9e4066Sahrens 	if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
757ea8dc4b6Seschrock 	    guid != zc->zc_guid)
758fa9e4066Sahrens 		error = EINVAL;
759fa9e4066Sahrens 	else
760990b4856Slling 		error = spa_import(zc->zc_name, config, props);
761fa9e4066Sahrens 
762fa9e4066Sahrens 	nvlist_free(config);
763fa9e4066Sahrens 
764990b4856Slling 	if (props)
765990b4856Slling 		nvlist_free(props);
766990b4856Slling 
767fa9e4066Sahrens 	return (error);
768fa9e4066Sahrens }
769fa9e4066Sahrens 
770fa9e4066Sahrens static int
771fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc)
772fa9e4066Sahrens {
773ecd6cf80Smarks 	int error;
774ecd6cf80Smarks 	zfs_log_history(zc);
775ecd6cf80Smarks 	error = spa_export(zc->zc_name, NULL);
776ecd6cf80Smarks 	return (error);
777fa9e4066Sahrens }
778fa9e4066Sahrens 
779fa9e4066Sahrens static int
780fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc)
781fa9e4066Sahrens {
782fa9e4066Sahrens 	nvlist_t *configs;
783fa9e4066Sahrens 	int error;
784fa9e4066Sahrens 
785fa9e4066Sahrens 	if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
786fa9e4066Sahrens 		return (EEXIST);
787fa9e4066Sahrens 
788e9dbad6fSeschrock 	error = put_nvlist(zc, configs);
789fa9e4066Sahrens 
790fa9e4066Sahrens 	nvlist_free(configs);
791fa9e4066Sahrens 
792fa9e4066Sahrens 	return (error);
793fa9e4066Sahrens }
794fa9e4066Sahrens 
795fa9e4066Sahrens static int
796fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc)
797fa9e4066Sahrens {
798fa9e4066Sahrens 	nvlist_t *config;
799fa9e4066Sahrens 	int error;
800ea8dc4b6Seschrock 	int ret = 0;
801fa9e4066Sahrens 
802e9dbad6fSeschrock 	error = spa_get_stats(zc->zc_name, &config, zc->zc_value,
803e9dbad6fSeschrock 	    sizeof (zc->zc_value));
804fa9e4066Sahrens 
805fa9e4066Sahrens 	if (config != NULL) {
806e9dbad6fSeschrock 		ret = put_nvlist(zc, config);
807fa9e4066Sahrens 		nvlist_free(config);
808ea8dc4b6Seschrock 
809ea8dc4b6Seschrock 		/*
810ea8dc4b6Seschrock 		 * The config may be present even if 'error' is non-zero.
811ea8dc4b6Seschrock 		 * In this case we return success, and preserve the real errno
812ea8dc4b6Seschrock 		 * in 'zc_cookie'.
813ea8dc4b6Seschrock 		 */
814ea8dc4b6Seschrock 		zc->zc_cookie = error;
815fa9e4066Sahrens 	} else {
816ea8dc4b6Seschrock 		ret = error;
817fa9e4066Sahrens 	}
818fa9e4066Sahrens 
819ea8dc4b6Seschrock 	return (ret);
820fa9e4066Sahrens }
821fa9e4066Sahrens 
822fa9e4066Sahrens /*
823fa9e4066Sahrens  * Try to import the given pool, returning pool stats as appropriate so that
824fa9e4066Sahrens  * user land knows which devices are available and overall pool health.
825fa9e4066Sahrens  */
826fa9e4066Sahrens static int
827fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
828fa9e4066Sahrens {
829fa9e4066Sahrens 	nvlist_t *tryconfig, *config;
830fa9e4066Sahrens 	int error;
831fa9e4066Sahrens 
832990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
833990b4856Slling 	    &tryconfig)) != 0)
834fa9e4066Sahrens 		return (error);
835fa9e4066Sahrens 
836fa9e4066Sahrens 	config = spa_tryimport(tryconfig);
837fa9e4066Sahrens 
838fa9e4066Sahrens 	nvlist_free(tryconfig);
839fa9e4066Sahrens 
840fa9e4066Sahrens 	if (config == NULL)
841fa9e4066Sahrens 		return (EINVAL);
842fa9e4066Sahrens 
843e9dbad6fSeschrock 	error = put_nvlist(zc, config);
844fa9e4066Sahrens 	nvlist_free(config);
845fa9e4066Sahrens 
846fa9e4066Sahrens 	return (error);
847fa9e4066Sahrens }
848fa9e4066Sahrens 
849fa9e4066Sahrens static int
850fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc)
851fa9e4066Sahrens {
852fa9e4066Sahrens 	spa_t *spa;
853fa9e4066Sahrens 	int error;
854fa9e4066Sahrens 
85506eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
85606eeb2adSek 		return (error);
85706eeb2adSek 
858bb8b5132Sek 	mutex_enter(&spa_namespace_lock);
85906eeb2adSek 	error = spa_scrub(spa, zc->zc_cookie, B_FALSE);
860bb8b5132Sek 	mutex_exit(&spa_namespace_lock);
86106eeb2adSek 
86206eeb2adSek 	spa_close(spa, FTAG);
86306eeb2adSek 
864fa9e4066Sahrens 	return (error);
865fa9e4066Sahrens }
866fa9e4066Sahrens 
867fa9e4066Sahrens static int
868fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc)
869fa9e4066Sahrens {
870fa9e4066Sahrens 	spa_t *spa;
871fa9e4066Sahrens 	int error;
872fa9e4066Sahrens 
873fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
874fa9e4066Sahrens 	if (error == 0) {
875fa9e4066Sahrens 		spa_freeze(spa);
876fa9e4066Sahrens 		spa_close(spa, FTAG);
877fa9e4066Sahrens 	}
878fa9e4066Sahrens 	return (error);
879fa9e4066Sahrens }
880fa9e4066Sahrens 
881eaca9bbdSeschrock static int
882eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc)
883eaca9bbdSeschrock {
884eaca9bbdSeschrock 	spa_t *spa;
885eaca9bbdSeschrock 	int error;
886eaca9bbdSeschrock 
88706eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
88806eeb2adSek 		return (error);
88906eeb2adSek 
890558d2d50Slling 	if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) {
891558d2d50Slling 		spa_close(spa, FTAG);
892558d2d50Slling 		return (EINVAL);
893558d2d50Slling 	}
894558d2d50Slling 
895990b4856Slling 	spa_upgrade(spa, zc->zc_cookie);
89606eeb2adSek 	spa_close(spa, FTAG);
89706eeb2adSek 
89806eeb2adSek 	return (error);
89906eeb2adSek }
90006eeb2adSek 
90106eeb2adSek static int
90206eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc)
90306eeb2adSek {
90406eeb2adSek 	spa_t *spa;
90506eeb2adSek 	char *hist_buf;
90606eeb2adSek 	uint64_t size;
90706eeb2adSek 	int error;
90806eeb2adSek 
90906eeb2adSek 	if ((size = zc->zc_history_len) == 0)
91006eeb2adSek 		return (EINVAL);
91106eeb2adSek 
91206eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
91306eeb2adSek 		return (error);
91406eeb2adSek 
915e7437265Sahrens 	if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) {
916d7306b64Sek 		spa_close(spa, FTAG);
917d7306b64Sek 		return (ENOTSUP);
918d7306b64Sek 	}
919d7306b64Sek 
92006eeb2adSek 	hist_buf = kmem_alloc(size, KM_SLEEP);
92106eeb2adSek 	if ((error = spa_history_get(spa, &zc->zc_history_offset,
92206eeb2adSek 	    &zc->zc_history_len, hist_buf)) == 0) {
923ecd6cf80Smarks 		error = xcopyout(hist_buf,
924ecd6cf80Smarks 		    (char *)(uintptr_t)zc->zc_history,
92506eeb2adSek 		    zc->zc_history_len);
92606eeb2adSek 	}
92706eeb2adSek 
92806eeb2adSek 	spa_close(spa, FTAG);
92906eeb2adSek 	kmem_free(hist_buf, size);
93006eeb2adSek 	return (error);
93106eeb2adSek }
93206eeb2adSek 
93355434c77Sek static int
93455434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc)
93555434c77Sek {
93655434c77Sek 	int error;
93755434c77Sek 
938b1b8ab34Slling 	if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value))
93955434c77Sek 		return (error);
94055434c77Sek 
94155434c77Sek 	return (0);
94255434c77Sek }
94355434c77Sek 
94455434c77Sek static int
94555434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc)
94655434c77Sek {
94755434c77Sek 	objset_t *osp;
94855434c77Sek 	int error;
94955434c77Sek 
95055434c77Sek 	if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS,
95155434c77Sek 	    DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0)
95255434c77Sek 		return (error);
95355434c77Sek 
95455434c77Sek 	error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value,
95555434c77Sek 	    sizeof (zc->zc_value));
95655434c77Sek 	dmu_objset_close(osp);
95755434c77Sek 
95855434c77Sek 	return (error);
95955434c77Sek }
96055434c77Sek 
961fa9e4066Sahrens static int
962fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc)
963fa9e4066Sahrens {
964fa9e4066Sahrens 	spa_t *spa;
965fa9e4066Sahrens 	int error;
966fa9e4066Sahrens 	nvlist_t *config;
967fa9e4066Sahrens 
968fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
969fa9e4066Sahrens 	if (error != 0)
970fa9e4066Sahrens 		return (error);
971fa9e4066Sahrens 
972b1b8ab34Slling 	/*
973b1b8ab34Slling 	 * A root pool with concatenated devices is not supported.
974b1b8ab34Slling 	 * Thus, can not add a device to a root pool with one device.
975b1b8ab34Slling 	 */
976b1b8ab34Slling 	if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) {
977b1b8ab34Slling 		spa_close(spa, FTAG);
978b1b8ab34Slling 		return (EDOM);
979b1b8ab34Slling 	}
980b1b8ab34Slling 
981990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
982990b4856Slling 	    &config)) == 0) {
983fa9e4066Sahrens 		error = spa_vdev_add(spa, config);
984fa9e4066Sahrens 		nvlist_free(config);
985fa9e4066Sahrens 	}
986fa9e4066Sahrens 	spa_close(spa, FTAG);
987fa9e4066Sahrens 	return (error);
988fa9e4066Sahrens }
989fa9e4066Sahrens 
990fa9e4066Sahrens static int
991fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc)
992fa9e4066Sahrens {
99399653d4eSeschrock 	spa_t *spa;
99499653d4eSeschrock 	int error;
99599653d4eSeschrock 
99699653d4eSeschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
99799653d4eSeschrock 	if (error != 0)
99899653d4eSeschrock 		return (error);
99999653d4eSeschrock 	error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE);
100099653d4eSeschrock 	spa_close(spa, FTAG);
100199653d4eSeschrock 	return (error);
1002fa9e4066Sahrens }
1003fa9e4066Sahrens 
1004fa9e4066Sahrens static int
10053d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc)
1006fa9e4066Sahrens {
1007fa9e4066Sahrens 	spa_t *spa;
1008fa9e4066Sahrens 	int error;
10093d7072f8Seschrock 	vdev_state_t newstate = VDEV_STATE_UNKNOWN;
1010fa9e4066Sahrens 
101106eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1012fa9e4066Sahrens 		return (error);
10133d7072f8Seschrock 	switch (zc->zc_cookie) {
10143d7072f8Seschrock 	case VDEV_STATE_ONLINE:
10153d7072f8Seschrock 		error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate);
10163d7072f8Seschrock 		break;
1017fa9e4066Sahrens 
10183d7072f8Seschrock 	case VDEV_STATE_OFFLINE:
10193d7072f8Seschrock 		error = vdev_offline(spa, zc->zc_guid, zc->zc_obj);
10203d7072f8Seschrock 		break;
1021fa9e4066Sahrens 
10223d7072f8Seschrock 	case VDEV_STATE_FAULTED:
10233d7072f8Seschrock 		error = vdev_fault(spa, zc->zc_guid);
10243d7072f8Seschrock 		break;
10253d7072f8Seschrock 
10263d7072f8Seschrock 	case VDEV_STATE_DEGRADED:
10273d7072f8Seschrock 		error = vdev_degrade(spa, zc->zc_guid);
10283d7072f8Seschrock 		break;
10293d7072f8Seschrock 
10303d7072f8Seschrock 	default:
10313d7072f8Seschrock 		error = EINVAL;
10323d7072f8Seschrock 	}
10333d7072f8Seschrock 	zc->zc_cookie = newstate;
1034fa9e4066Sahrens 	spa_close(spa, FTAG);
1035fa9e4066Sahrens 	return (error);
1036fa9e4066Sahrens }
1037fa9e4066Sahrens 
1038fa9e4066Sahrens static int
1039fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc)
1040fa9e4066Sahrens {
1041fa9e4066Sahrens 	spa_t *spa;
1042fa9e4066Sahrens 	int replacing = zc->zc_cookie;
1043fa9e4066Sahrens 	nvlist_t *config;
1044fa9e4066Sahrens 	int error;
1045fa9e4066Sahrens 
104606eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1047fa9e4066Sahrens 		return (error);
1048fa9e4066Sahrens 
1049990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
1050990b4856Slling 	    &config)) == 0) {
1051ea8dc4b6Seschrock 		error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
1052fa9e4066Sahrens 		nvlist_free(config);
1053fa9e4066Sahrens 	}
1054fa9e4066Sahrens 
1055fa9e4066Sahrens 	spa_close(spa, FTAG);
1056fa9e4066Sahrens 	return (error);
1057fa9e4066Sahrens }
1058fa9e4066Sahrens 
1059fa9e4066Sahrens static int
1060fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc)
1061fa9e4066Sahrens {
1062fa9e4066Sahrens 	spa_t *spa;
1063fa9e4066Sahrens 	int error;
1064fa9e4066Sahrens 
106506eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1066fa9e4066Sahrens 		return (error);
1067fa9e4066Sahrens 
1068ea8dc4b6Seschrock 	error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE);
1069fa9e4066Sahrens 
1070fa9e4066Sahrens 	spa_close(spa, FTAG);
1071fa9e4066Sahrens 	return (error);
1072fa9e4066Sahrens }
1073fa9e4066Sahrens 
1074c67d9675Seschrock static int
1075c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
1076c67d9675Seschrock {
1077c67d9675Seschrock 	spa_t *spa;
1078e9dbad6fSeschrock 	char *path = zc->zc_value;
1079ea8dc4b6Seschrock 	uint64_t guid = zc->zc_guid;
1080c67d9675Seschrock 	int error;
1081c67d9675Seschrock 
1082c67d9675Seschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
1083c67d9675Seschrock 	if (error != 0)
1084c67d9675Seschrock 		return (error);
1085c67d9675Seschrock 
1086c67d9675Seschrock 	error = spa_vdev_setpath(spa, guid, path);
1087c67d9675Seschrock 	spa_close(spa, FTAG);
1088c67d9675Seschrock 	return (error);
1089c67d9675Seschrock }
1090c67d9675Seschrock 
10913cb34c60Sahrens /*
10923cb34c60Sahrens  * inputs:
10933cb34c60Sahrens  * zc_name		name of filesystem
10943cb34c60Sahrens  * zc_nvlist_dst_size	size of buffer for property nvlist
10953cb34c60Sahrens  *
10963cb34c60Sahrens  * outputs:
10973cb34c60Sahrens  * zc_objset_stats	stats
10983cb34c60Sahrens  * zc_nvlist_dst	property nvlist
10993cb34c60Sahrens  * zc_nvlist_dst_size	size of property nvlist
11003cb34c60Sahrens  * zc_value		alternate root
11013cb34c60Sahrens  */
1102fa9e4066Sahrens static int
1103fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc)
1104fa9e4066Sahrens {
1105fa9e4066Sahrens 	objset_t *os = NULL;
1106fa9e4066Sahrens 	int error;
11077f7322feSeschrock 	nvlist_t *nv;
1108fa9e4066Sahrens 
1109fa9e4066Sahrens retry:
1110fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1111fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
1112fa9e4066Sahrens 	if (error != 0) {
1113fa9e4066Sahrens 		/*
1114fa9e4066Sahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
1115fa9e4066Sahrens 		 * the objset is held exclusively. Fortunately this hold is
1116fa9e4066Sahrens 		 * only for a short while, so we retry here.
1117fa9e4066Sahrens 		 * This avoids user code having to handle EBUSY,
1118fa9e4066Sahrens 		 * for example for a "zfs list".
1119fa9e4066Sahrens 		 */
1120fa9e4066Sahrens 		if (error == EBUSY) {
1121fa9e4066Sahrens 			delay(1);
1122fa9e4066Sahrens 			goto retry;
1123fa9e4066Sahrens 		}
1124fa9e4066Sahrens 		return (error);
1125fa9e4066Sahrens 	}
1126fa9e4066Sahrens 
1127a2eea2e1Sahrens 	dmu_objset_fast_stat(os, &zc->zc_objset_stats);
1128fa9e4066Sahrens 
11295ad82045Snd 	if (zc->zc_nvlist_dst != 0 &&
11307f7322feSeschrock 	    (error = dsl_prop_get_all(os, &nv)) == 0) {
1131a2eea2e1Sahrens 		dmu_objset_stats(os, nv);
1132432f72fdSahrens 		/*
1133bd00f61bSrm 		 * NB: zvol_get_stats() will read the objset contents,
1134432f72fdSahrens 		 * which we aren't supposed to do with a
1135432f72fdSahrens 		 * DS_MODE_STANDARD open, because it could be
1136432f72fdSahrens 		 * inconsistent.  So this is a bit of a workaround...
1137432f72fdSahrens 		 */
1138e7437265Sahrens 		if (!zc->zc_objset_stats.dds_inconsistent) {
1139e7437265Sahrens 			if (dmu_objset_type(os) == DMU_OST_ZVOL)
1140e7437265Sahrens 				VERIFY(zvol_get_stats(os, nv) == 0);
1141e7437265Sahrens 		}
1142e9dbad6fSeschrock 		error = put_nvlist(zc, nv);
11437f7322feSeschrock 		nvlist_free(nv);
11447f7322feSeschrock 	}
1145fa9e4066Sahrens 
1146e9dbad6fSeschrock 	spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value));
1147ea8dc4b6Seschrock 
1148fa9e4066Sahrens 	dmu_objset_close(os);
1149fa9e4066Sahrens 	return (error);
1150fa9e4066Sahrens }
1151fa9e4066Sahrens 
11523cb34c60Sahrens /*
11533cb34c60Sahrens  * inputs:
11543cb34c60Sahrens  * zc_name		name of filesystem
11553cb34c60Sahrens  * zc_cookie		zap cursor
11563cb34c60Sahrens  * zc_nvlist_dst_size	size of buffer for property nvlist
11573cb34c60Sahrens  *
11583cb34c60Sahrens  * outputs:
11593cb34c60Sahrens  * zc_name		name of next filesystem
11603cb34c60Sahrens  * zc_objset_stats	stats
11613cb34c60Sahrens  * zc_nvlist_dst	property nvlist
11623cb34c60Sahrens  * zc_nvlist_dst_size	size of property nvlist
11633cb34c60Sahrens  * zc_value		alternate root
11643cb34c60Sahrens  */
1165bd00f61bSrm static int
1166bd00f61bSrm zfs_ioc_objset_version(zfs_cmd_t *zc)
1167bd00f61bSrm {
1168bd00f61bSrm 	objset_t *os = NULL;
1169bd00f61bSrm 	int error;
1170bd00f61bSrm 
1171bd00f61bSrm retry:
1172bd00f61bSrm 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1173bd00f61bSrm 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
1174bd00f61bSrm 	if (error != 0) {
1175bd00f61bSrm 		/*
1176bd00f61bSrm 		 * This is ugly: dmu_objset_open() can return EBUSY if
1177bd00f61bSrm 		 * the objset is held exclusively. Fortunately this hold is
1178bd00f61bSrm 		 * only for a short while, so we retry here.
1179bd00f61bSrm 		 * This avoids user code having to handle EBUSY,
1180bd00f61bSrm 		 * for example for a "zfs list".
1181bd00f61bSrm 		 */
1182bd00f61bSrm 		if (error == EBUSY) {
1183bd00f61bSrm 			delay(1);
1184bd00f61bSrm 			goto retry;
1185bd00f61bSrm 		}
1186bd00f61bSrm 		return (error);
1187bd00f61bSrm 	}
1188bd00f61bSrm 
1189bd00f61bSrm 	dmu_objset_fast_stat(os, &zc->zc_objset_stats);
1190bd00f61bSrm 
1191bd00f61bSrm 	/*
1192bd00f61bSrm 	 * NB: zfs_get_version() will read the objset contents,
1193bd00f61bSrm 	 * which we aren't supposed to do with a
1194bd00f61bSrm 	 * DS_MODE_STANDARD open, because it could be
1195bd00f61bSrm 	 * inconsistent.  So this is a bit of a workaround...
1196bd00f61bSrm 	 */
1197bd00f61bSrm 	zc->zc_cookie = 0;
1198bd00f61bSrm 	if (!zc->zc_objset_stats.dds_inconsistent)
1199bd00f61bSrm 		if (dmu_objset_type(os) == DMU_OST_ZFS)
1200bd00f61bSrm 			(void) zfs_get_version(os, &zc->zc_cookie);
1201bd00f61bSrm 
1202bd00f61bSrm 	dmu_objset_close(os);
1203bd00f61bSrm 	return (0);
1204bd00f61bSrm }
1205bd00f61bSrm 
1206fa9e4066Sahrens static int
1207fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc)
1208fa9e4066Sahrens {
120987e5029aSahrens 	objset_t *os;
1210fa9e4066Sahrens 	int error;
1211fa9e4066Sahrens 	char *p;
1212fa9e4066Sahrens 
121387e5029aSahrens retry:
121487e5029aSahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
121587e5029aSahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
121687e5029aSahrens 	if (error != 0) {
121787e5029aSahrens 		/*
121887e5029aSahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
121987e5029aSahrens 		 * the objset is held exclusively. Fortunately this hold is
122087e5029aSahrens 		 * only for a short while, so we retry here.
122187e5029aSahrens 		 * This avoids user code having to handle EBUSY,
122287e5029aSahrens 		 * for example for a "zfs list".
122387e5029aSahrens 		 */
122487e5029aSahrens 		if (error == EBUSY) {
122587e5029aSahrens 			delay(1);
122687e5029aSahrens 			goto retry;
122787e5029aSahrens 		}
122887e5029aSahrens 		if (error == ENOENT)
122987e5029aSahrens 			error = ESRCH;
123087e5029aSahrens 		return (error);
1231fa9e4066Sahrens 	}
1232fa9e4066Sahrens 
1233fa9e4066Sahrens 	p = strrchr(zc->zc_name, '/');
1234fa9e4066Sahrens 	if (p == NULL || p[1] != '\0')
1235fa9e4066Sahrens 		(void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name));
1236fa9e4066Sahrens 	p = zc->zc_name + strlen(zc->zc_name);
1237fa9e4066Sahrens 
1238fa9e4066Sahrens 	do {
123987e5029aSahrens 		error = dmu_dir_list_next(os,
124087e5029aSahrens 		    sizeof (zc->zc_name) - (p - zc->zc_name), p,
124187e5029aSahrens 		    NULL, &zc->zc_cookie);
1242fa9e4066Sahrens 		if (error == ENOENT)
1243fa9e4066Sahrens 			error = ESRCH;
124487e5029aSahrens 	} while (error == 0 && !INGLOBALZONE(curproc) &&
1245fa9e4066Sahrens 	    !zone_dataset_visible(zc->zc_name, NULL));
1246fa9e4066Sahrens 
1247fa9e4066Sahrens 	/*
124887e5029aSahrens 	 * If it's a hidden dataset (ie. with a '$' in its name), don't
124987e5029aSahrens 	 * try to get stats for it.  Userland will skip over it.
1250fa9e4066Sahrens 	 */
125187e5029aSahrens 	if (error == 0 && strchr(zc->zc_name, '$') == NULL)
125287e5029aSahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
1253fa9e4066Sahrens 
125487e5029aSahrens 	dmu_objset_close(os);
1255fa9e4066Sahrens 	return (error);
1256fa9e4066Sahrens }
1257fa9e4066Sahrens 
12583cb34c60Sahrens /*
12593cb34c60Sahrens  * inputs:
12603cb34c60Sahrens  * zc_name		name of filesystem
12613cb34c60Sahrens  * zc_cookie		zap cursor
12623cb34c60Sahrens  * zc_nvlist_dst_size	size of buffer for property nvlist
12633cb34c60Sahrens  *
12643cb34c60Sahrens  * outputs:
12653cb34c60Sahrens  * zc_name		name of next snapshot
12663cb34c60Sahrens  * zc_objset_stats	stats
12673cb34c60Sahrens  * zc_nvlist_dst	property nvlist
12683cb34c60Sahrens  * zc_nvlist_dst_size	size of property nvlist
12693cb34c60Sahrens  * zc_value		alternate root
12703cb34c60Sahrens  */
1271fa9e4066Sahrens static int
1272fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
1273fa9e4066Sahrens {
127487e5029aSahrens 	objset_t *os;
1275fa9e4066Sahrens 	int error;
1276fa9e4066Sahrens 
1277fa9e4066Sahrens retry:
127887e5029aSahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
127987e5029aSahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
128087e5029aSahrens 	if (error != 0) {
1281fa9e4066Sahrens 		/*
128287e5029aSahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
1283fa9e4066Sahrens 		 * the objset is held exclusively. Fortunately this hold is
1284fa9e4066Sahrens 		 * only for a short while, so we retry here.
1285fa9e4066Sahrens 		 * This avoids user code having to handle EBUSY,
128687e5029aSahrens 		 * for example for a "zfs list".
1287fa9e4066Sahrens 		 */
1288fa9e4066Sahrens 		if (error == EBUSY) {
1289fa9e4066Sahrens 			delay(1);
1290fa9e4066Sahrens 			goto retry;
1291fa9e4066Sahrens 		}
1292fa9e4066Sahrens 		if (error == ENOENT)
129387e5029aSahrens 			error = ESRCH;
1294fa9e4066Sahrens 		return (error);
1295fa9e4066Sahrens 	}
1296fa9e4066Sahrens 
1297b81d61a6Slling 	/*
1298b81d61a6Slling 	 * A dataset name of maximum length cannot have any snapshots,
1299b81d61a6Slling 	 * so exit immediately.
1300b81d61a6Slling 	 */
1301b81d61a6Slling 	if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) {
130287e5029aSahrens 		dmu_objset_close(os);
1303b81d61a6Slling 		return (ESRCH);
1304fa9e4066Sahrens 	}
1305fa9e4066Sahrens 
130687e5029aSahrens 	error = dmu_snapshot_list_next(os,
130787e5029aSahrens 	    sizeof (zc->zc_name) - strlen(zc->zc_name),
130887e5029aSahrens 	    zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie);
130987e5029aSahrens 	if (error == ENOENT)
131087e5029aSahrens 		error = ESRCH;
1311fa9e4066Sahrens 
131287e5029aSahrens 	if (error == 0)
131387e5029aSahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
1314fa9e4066Sahrens 
13153cb34c60Sahrens 	/* if we failed, undo the @ that we tacked on to zc_name */
13163cb34c60Sahrens 	if (error != 0)
13173cb34c60Sahrens 		*strchr(zc->zc_name, '@') = '\0';
13183cb34c60Sahrens 
131987e5029aSahrens 	dmu_objset_close(os);
1320fa9e4066Sahrens 	return (error);
1321fa9e4066Sahrens }
1322fa9e4066Sahrens 
1323fa9e4066Sahrens static int
132491ebeef5Sahrens zfs_set_prop_nvlist(const char *name, nvlist_t *nvl)
1325fa9e4066Sahrens {
1326e9dbad6fSeschrock 	nvpair_t *elem;
1327e9dbad6fSeschrock 	int error;
1328e9dbad6fSeschrock 	uint64_t intval;
1329e9dbad6fSeschrock 	char *strval;
1330e9dbad6fSeschrock 
1331ecd6cf80Smarks 	/*
1332ecd6cf80Smarks 	 * First validate permission to set all of the properties
1333ecd6cf80Smarks 	 */
1334e9dbad6fSeschrock 	elem = NULL;
1335e9dbad6fSeschrock 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1336db870a07Sahrens 		const char *propname = nvpair_name(elem);
1337db870a07Sahrens 		zfs_prop_t prop = zfs_name_to_prop(propname);
1338e9dbad6fSeschrock 
1339990b4856Slling 		if (prop == ZPROP_INVAL) {
1340e9dbad6fSeschrock 			/*
1341e9dbad6fSeschrock 			 * If this is a user-defined property, it must be a
1342e9dbad6fSeschrock 			 * string, and there is no further validation to do.
1343e9dbad6fSeschrock 			 */
1344e9dbad6fSeschrock 			if (!zfs_prop_user(propname) ||
1345e9dbad6fSeschrock 			    nvpair_type(elem) != DATA_TYPE_STRING)
1346e9dbad6fSeschrock 				return (EINVAL);
1347e9dbad6fSeschrock 
1348da6c28aaSamw 			if (error = zfs_secpolicy_write_perms(name,
1349da6c28aaSamw 			    ZFS_DELEG_PERM_USERPROP, CRED()))
1350db870a07Sahrens 				return (error);
1351ecd6cf80Smarks 			continue;
1352e9dbad6fSeschrock 		}
1353fa9e4066Sahrens 
135491ebeef5Sahrens 		if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0)
1355db870a07Sahrens 			return (error);
1356db870a07Sahrens 
1357e9dbad6fSeschrock 		/*
1358db870a07Sahrens 		 * Check that this value is valid for this pool version
1359e9dbad6fSeschrock 		 */
1360e9dbad6fSeschrock 		switch (prop) {
1361c9431fa1Sahl 		case ZFS_PROP_COMPRESSION:
1362c9431fa1Sahl 			/*
1363c9431fa1Sahl 			 * If the user specified gzip compression, make sure
1364c9431fa1Sahl 			 * the SPA supports it. We ignore any errors here since
1365c9431fa1Sahl 			 * we'll catch them later.
1366c9431fa1Sahl 			 */
1367c9431fa1Sahl 			if (nvpair_type(elem) == DATA_TYPE_UINT64 &&
1368c9431fa1Sahl 			    nvpair_value_uint64(elem, &intval) == 0 &&
1369c9431fa1Sahl 			    intval >= ZIO_COMPRESS_GZIP_1 &&
1370c9431fa1Sahl 			    intval <= ZIO_COMPRESS_GZIP_9) {
1371da6c28aaSamw 				if (zfs_check_version(name,
1372da6c28aaSamw 				    SPA_VERSION_GZIP_COMPRESSION))
1373da6c28aaSamw 					return (ENOTSUP);
1374c9431fa1Sahl 			}
1375c9431fa1Sahl 			break;
137640feaa91Sahrens 
137740feaa91Sahrens 		case ZFS_PROP_COPIES:
1378da6c28aaSamw 			if (zfs_check_version(name, SPA_VERSION_DITTO_BLOCKS))
1379da6c28aaSamw 				return (ENOTSUP);
138040feaa91Sahrens 			break;
1381da6c28aaSamw 		case ZFS_PROP_NORMALIZE:
1382da6c28aaSamw 		case ZFS_PROP_UTF8ONLY:
1383da6c28aaSamw 		case ZFS_PROP_CASE:
1384da6c28aaSamw 			if (zfs_check_version(name, SPA_VERSION_NORMALIZATION))
1385da6c28aaSamw 				return (ENOTSUP);
1386da6c28aaSamw 
138740feaa91Sahrens 		}
1388da6c28aaSamw 		if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0)
1389da6c28aaSamw 			return (error);
1390ecd6cf80Smarks 	}
1391ecd6cf80Smarks 
1392ecd6cf80Smarks 	elem = NULL;
1393ecd6cf80Smarks 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1394db870a07Sahrens 		const char *propname = nvpair_name(elem);
1395db870a07Sahrens 		zfs_prop_t prop = zfs_name_to_prop(propname);
1396ecd6cf80Smarks 
1397990b4856Slling 		if (prop == ZPROP_INVAL) {
1398ecd6cf80Smarks 			VERIFY(nvpair_value_string(elem, &strval) == 0);
1399ecd6cf80Smarks 			error = dsl_prop_set(name, propname, 1,
1400ecd6cf80Smarks 			    strlen(strval) + 1, strval);
1401ecd6cf80Smarks 			if (error == 0)
1402ecd6cf80Smarks 				continue;
1403ecd6cf80Smarks 			else
1404ecd6cf80Smarks 				return (error);
1405ecd6cf80Smarks 		}
1406e9dbad6fSeschrock 
1407e9dbad6fSeschrock 		switch (prop) {
1408e9dbad6fSeschrock 		case ZFS_PROP_QUOTA:
1409e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1410e7437265Sahrens 			    (error = dsl_dir_set_quota(name, intval)) != 0)
1411e9dbad6fSeschrock 				return (error);
1412e9dbad6fSeschrock 			break;
1413e9dbad6fSeschrock 
1414e9dbad6fSeschrock 		case ZFS_PROP_RESERVATION:
1415e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1416e9dbad6fSeschrock 			    (error = dsl_dir_set_reservation(name,
1417e9dbad6fSeschrock 			    intval)) != 0)
1418e9dbad6fSeschrock 				return (error);
1419e9dbad6fSeschrock 			break;
1420e9dbad6fSeschrock 
1421e9dbad6fSeschrock 		case ZFS_PROP_VOLSIZE:
1422e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
142391ebeef5Sahrens 			    (error = zvol_set_volsize(name,
142491ebeef5Sahrens 			    ddi_driver_major(zfs_dip), intval)) != 0)
1425e9dbad6fSeschrock 				return (error);
1426e9dbad6fSeschrock 			break;
1427e9dbad6fSeschrock 
1428e9dbad6fSeschrock 		case ZFS_PROP_VOLBLOCKSIZE:
1429e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1430e7437265Sahrens 			    (error = zvol_set_volblocksize(name, intval)) != 0)
1431e7437265Sahrens 				return (error);
1432e7437265Sahrens 			break;
1433e7437265Sahrens 
1434e7437265Sahrens 		case ZFS_PROP_VERSION:
1435e7437265Sahrens 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1436e7437265Sahrens 			    (error = zfs_set_version(name, intval)) != 0)
1437e9dbad6fSeschrock 				return (error);
1438e9dbad6fSeschrock 			break;
1439e9dbad6fSeschrock 
1440e9dbad6fSeschrock 		default:
1441e9dbad6fSeschrock 			if (nvpair_type(elem) == DATA_TYPE_STRING) {
1442e9dbad6fSeschrock 				if (zfs_prop_get_type(prop) !=
144391ebeef5Sahrens 				    PROP_TYPE_STRING)
1444e9dbad6fSeschrock 					return (EINVAL);
1445acd76fe5Seschrock 				VERIFY(nvpair_value_string(elem, &strval) == 0);
1446acd76fe5Seschrock 				if ((error = dsl_prop_set(name,
1447e9dbad6fSeschrock 				    nvpair_name(elem), 1, strlen(strval) + 1,
1448acd76fe5Seschrock 				    strval)) != 0)
1449acd76fe5Seschrock 					return (error);
1450e9dbad6fSeschrock 			} else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
1451a2eea2e1Sahrens 				const char *unused;
1452a2eea2e1Sahrens 
1453acd76fe5Seschrock 				VERIFY(nvpair_value_uint64(elem, &intval) == 0);
1454e9dbad6fSeschrock 
1455e9dbad6fSeschrock 				switch (zfs_prop_get_type(prop)) {
145691ebeef5Sahrens 				case PROP_TYPE_NUMBER:
1457e9dbad6fSeschrock 					break;
145891ebeef5Sahrens 				case PROP_TYPE_STRING:
1459acd76fe5Seschrock 					return (EINVAL);
146091ebeef5Sahrens 				case PROP_TYPE_INDEX:
1461acd76fe5Seschrock 					if (zfs_prop_index_to_string(prop,
1462acd76fe5Seschrock 					    intval, &unused) != 0)
1463acd76fe5Seschrock 						return (EINVAL);
1464e9dbad6fSeschrock 					break;
1465e9dbad6fSeschrock 				default:
1466e7437265Sahrens 					cmn_err(CE_PANIC,
1467e7437265Sahrens 					    "unknown property type");
1468e9dbad6fSeschrock 					break;
1469e9dbad6fSeschrock 				}
1470e9dbad6fSeschrock 
1471acd76fe5Seschrock 				if ((error = dsl_prop_set(name, propname,
1472acd76fe5Seschrock 				    8, 1, &intval)) != 0)
1473acd76fe5Seschrock 					return (error);
1474e9dbad6fSeschrock 			} else {
1475e9dbad6fSeschrock 				return (EINVAL);
1476e9dbad6fSeschrock 			}
1477e9dbad6fSeschrock 			break;
1478e9dbad6fSeschrock 		}
1479e9dbad6fSeschrock 	}
1480e9dbad6fSeschrock 
1481e9dbad6fSeschrock 	return (0);
1482fa9e4066Sahrens }
1483fa9e4066Sahrens 
14843cb34c60Sahrens /*
14853cb34c60Sahrens  * inputs:
14863cb34c60Sahrens  * zc_name		name of filesystem
14873cb34c60Sahrens  * zc_value		name of property to inherit
14883cb34c60Sahrens  * zc_nvlist_src{_size}	nvlist of properties to apply
14893cb34c60Sahrens  *
14903cb34c60Sahrens  * outputs:		none
14913cb34c60Sahrens  */
1492fa9e4066Sahrens static int
1493e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc)
1494fa9e4066Sahrens {
1495e9dbad6fSeschrock 	nvlist_t *nvl;
1496e9dbad6fSeschrock 	int error;
1497e9dbad6fSeschrock 
1498990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1499990b4856Slling 	    &nvl)) != 0)
1500e9dbad6fSeschrock 		return (error);
1501e9dbad6fSeschrock 
150291ebeef5Sahrens 	error = zfs_set_prop_nvlist(zc->zc_name, nvl);
1503ecd6cf80Smarks 
1504e9dbad6fSeschrock 	nvlist_free(nvl);
1505e9dbad6fSeschrock 	return (error);
1506fa9e4066Sahrens }
1507fa9e4066Sahrens 
15083cb34c60Sahrens /*
15093cb34c60Sahrens  * inputs:
15103cb34c60Sahrens  * zc_name		name of filesystem
15113cb34c60Sahrens  * zc_value		name of property to inherit
15123cb34c60Sahrens  *
15133cb34c60Sahrens  * outputs:		none
15143cb34c60Sahrens  */
1515e45ce728Sahrens static int
1516e45ce728Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc)
1517e45ce728Sahrens {
1518e45ce728Sahrens 	/* the property name has been validated by zfs_secpolicy_inherit() */
1519e45ce728Sahrens 	return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL));
1520e45ce728Sahrens }
1521e45ce728Sahrens 
1522b1b8ab34Slling static int
152311a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc)
1524b1b8ab34Slling {
1525990b4856Slling 	nvlist_t *props;
1526b1b8ab34Slling 	spa_t *spa;
1527990b4856Slling 	int error;
1528b1b8ab34Slling 
1529990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1530990b4856Slling 	    &props)))
1531b1b8ab34Slling 		return (error);
1532b1b8ab34Slling 
1533b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) {
1534990b4856Slling 		nvlist_free(props);
1535b1b8ab34Slling 		return (error);
1536b1b8ab34Slling 	}
1537b1b8ab34Slling 
1538990b4856Slling 	error = spa_prop_set(spa, props);
1539b1b8ab34Slling 
1540990b4856Slling 	nvlist_free(props);
1541b1b8ab34Slling 	spa_close(spa, FTAG);
1542b1b8ab34Slling 
1543b1b8ab34Slling 	return (error);
1544b1b8ab34Slling }
1545b1b8ab34Slling 
1546b1b8ab34Slling static int
154711a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc)
1548b1b8ab34Slling {
1549b1b8ab34Slling 	spa_t *spa;
1550b1b8ab34Slling 	int error;
1551b1b8ab34Slling 	nvlist_t *nvp = NULL;
1552b1b8ab34Slling 
1553b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1554b1b8ab34Slling 		return (error);
1555b1b8ab34Slling 
1556990b4856Slling 	error = spa_prop_get(spa, &nvp);
1557b1b8ab34Slling 
1558b1b8ab34Slling 	if (error == 0 && zc->zc_nvlist_dst != NULL)
1559b1b8ab34Slling 		error = put_nvlist(zc, nvp);
1560b1b8ab34Slling 	else
1561b1b8ab34Slling 		error = EFAULT;
1562b1b8ab34Slling 
1563b1b8ab34Slling 	spa_close(spa, FTAG);
1564b1b8ab34Slling 
1565b1b8ab34Slling 	if (nvp)
1566b1b8ab34Slling 		nvlist_free(nvp);
1567b1b8ab34Slling 	return (error);
1568b1b8ab34Slling }
1569b1b8ab34Slling 
1570ecd6cf80Smarks static int
1571ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc)
1572ecd6cf80Smarks {
1573ecd6cf80Smarks 	nvlist_t *nvp;
1574ecd6cf80Smarks 	int error;
1575ecd6cf80Smarks 	uint32_t uid;
1576ecd6cf80Smarks 	uint32_t gid;
1577ecd6cf80Smarks 	uint32_t *groups;
1578ecd6cf80Smarks 	uint_t group_cnt;
1579ecd6cf80Smarks 	cred_t	*usercred;
1580ecd6cf80Smarks 
1581990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1582990b4856Slling 	    &nvp)) != 0) {
1583ecd6cf80Smarks 		return (error);
1584ecd6cf80Smarks 	}
1585ecd6cf80Smarks 
1586ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32(nvp,
1587ecd6cf80Smarks 	    ZFS_DELEG_PERM_UID, &uid)) != 0) {
1588ecd6cf80Smarks 		nvlist_free(nvp);
1589ecd6cf80Smarks 		return (EPERM);
1590ecd6cf80Smarks 	}
1591ecd6cf80Smarks 
1592ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32(nvp,
1593ecd6cf80Smarks 	    ZFS_DELEG_PERM_GID, &gid)) != 0) {
1594ecd6cf80Smarks 		nvlist_free(nvp);
1595ecd6cf80Smarks 		return (EPERM);
1596ecd6cf80Smarks 	}
1597ecd6cf80Smarks 
1598ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS,
1599ecd6cf80Smarks 	    &groups, &group_cnt)) != 0) {
1600ecd6cf80Smarks 		nvlist_free(nvp);
1601ecd6cf80Smarks 		return (EPERM);
1602ecd6cf80Smarks 	}
1603ecd6cf80Smarks 	usercred = cralloc();
1604ecd6cf80Smarks 	if ((crsetugid(usercred, uid, gid) != 0) ||
1605ecd6cf80Smarks 	    (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) {
1606ecd6cf80Smarks 		nvlist_free(nvp);
1607ecd6cf80Smarks 		crfree(usercred);
1608ecd6cf80Smarks 		return (EPERM);
1609ecd6cf80Smarks 	}
1610ecd6cf80Smarks 	nvlist_free(nvp);
1611ecd6cf80Smarks 	error = dsl_deleg_access(zc->zc_name,
161291ebeef5Sahrens 	    zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred);
1613ecd6cf80Smarks 	crfree(usercred);
1614ecd6cf80Smarks 	return (error);
1615ecd6cf80Smarks }
1616ecd6cf80Smarks 
16173cb34c60Sahrens /*
16183cb34c60Sahrens  * inputs:
16193cb34c60Sahrens  * zc_name		name of filesystem
16203cb34c60Sahrens  * zc_nvlist_src{_size}	nvlist of delegated permissions
16213cb34c60Sahrens  * zc_perm_action	allow/unallow flag
16223cb34c60Sahrens  *
16233cb34c60Sahrens  * outputs:		none
16243cb34c60Sahrens  */
1625ecd6cf80Smarks static int
1626ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc)
1627ecd6cf80Smarks {
1628ecd6cf80Smarks 	int error;
1629ecd6cf80Smarks 	nvlist_t *fsaclnv = NULL;
1630ecd6cf80Smarks 
1631990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1632990b4856Slling 	    &fsaclnv)) != 0)
1633ecd6cf80Smarks 		return (error);
1634ecd6cf80Smarks 
1635ecd6cf80Smarks 	/*
1636ecd6cf80Smarks 	 * Verify nvlist is constructed correctly
1637ecd6cf80Smarks 	 */
1638ecd6cf80Smarks 	if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) {
1639ecd6cf80Smarks 		nvlist_free(fsaclnv);
1640ecd6cf80Smarks 		return (EINVAL);
1641ecd6cf80Smarks 	}
1642ecd6cf80Smarks 
1643ecd6cf80Smarks 	/*
1644ecd6cf80Smarks 	 * If we don't have PRIV_SYS_MOUNT, then validate
1645ecd6cf80Smarks 	 * that user is allowed to hand out each permission in
1646ecd6cf80Smarks 	 * the nvlist(s)
1647ecd6cf80Smarks 	 */
1648ecd6cf80Smarks 
164991ebeef5Sahrens 	error = secpolicy_zfs(CRED());
1650ecd6cf80Smarks 	if (error) {
165191ebeef5Sahrens 		if (zc->zc_perm_action == B_FALSE) {
165291ebeef5Sahrens 			error = dsl_deleg_can_allow(zc->zc_name,
165391ebeef5Sahrens 			    fsaclnv, CRED());
165491ebeef5Sahrens 		} else {
165591ebeef5Sahrens 			error = dsl_deleg_can_unallow(zc->zc_name,
165691ebeef5Sahrens 			    fsaclnv, CRED());
165791ebeef5Sahrens 		}
1658ecd6cf80Smarks 	}
1659ecd6cf80Smarks 
1660ecd6cf80Smarks 	if (error == 0)
1661ecd6cf80Smarks 		error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action);
1662ecd6cf80Smarks 
1663ecd6cf80Smarks 	nvlist_free(fsaclnv);
1664ecd6cf80Smarks 	return (error);
1665ecd6cf80Smarks }
1666ecd6cf80Smarks 
16673cb34c60Sahrens /*
16683cb34c60Sahrens  * inputs:
16693cb34c60Sahrens  * zc_name		name of filesystem
16703cb34c60Sahrens  *
16713cb34c60Sahrens  * outputs:
16723cb34c60Sahrens  * zc_nvlist_src{_size}	nvlist of delegated permissions
16733cb34c60Sahrens  */
1674ecd6cf80Smarks static int
1675ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc)
1676ecd6cf80Smarks {
1677ecd6cf80Smarks 	nvlist_t *nvp;
1678ecd6cf80Smarks 	int error;
1679ecd6cf80Smarks 
1680ecd6cf80Smarks 	if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) {
1681ecd6cf80Smarks 		error = put_nvlist(zc, nvp);
1682ecd6cf80Smarks 		nvlist_free(nvp);
1683ecd6cf80Smarks 	}
1684ecd6cf80Smarks 
1685ecd6cf80Smarks 	return (error);
1686ecd6cf80Smarks }
1687ecd6cf80Smarks 
16883cb34c60Sahrens /*
16893cb34c60Sahrens  * inputs:
16903cb34c60Sahrens  * zc_name		name of volume
16913cb34c60Sahrens  *
16923cb34c60Sahrens  * outputs:		none
16933cb34c60Sahrens  */
1694fa9e4066Sahrens static int
1695fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc)
1696fa9e4066Sahrens {
169791ebeef5Sahrens 	return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip)));
1698fa9e4066Sahrens }
1699fa9e4066Sahrens 
17003cb34c60Sahrens /*
17013cb34c60Sahrens  * inputs:
17023cb34c60Sahrens  * zc_name		name of volume
17033cb34c60Sahrens  *
17043cb34c60Sahrens  * outputs:		none
17053cb34c60Sahrens  */
1706fa9e4066Sahrens static int
1707fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc)
1708fa9e4066Sahrens {
1709e9dbad6fSeschrock 	return (zvol_remove_minor(zc->zc_name));
1710fa9e4066Sahrens }
1711fa9e4066Sahrens 
1712fa9e4066Sahrens /*
1713fa9e4066Sahrens  * Search the vfs list for a specified resource.  Returns a pointer to it
1714fa9e4066Sahrens  * or NULL if no suitable entry is found. The caller of this routine
1715fa9e4066Sahrens  * is responsible for releasing the returned vfs pointer.
1716fa9e4066Sahrens  */
1717fa9e4066Sahrens static vfs_t *
1718fa9e4066Sahrens zfs_get_vfs(const char *resource)
1719fa9e4066Sahrens {
1720fa9e4066Sahrens 	struct vfs *vfsp;
1721fa9e4066Sahrens 	struct vfs *vfs_found = NULL;
1722fa9e4066Sahrens 
1723fa9e4066Sahrens 	vfs_list_read_lock();
1724fa9e4066Sahrens 	vfsp = rootvfs;
1725fa9e4066Sahrens 	do {
1726fa9e4066Sahrens 		if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) {
1727fa9e4066Sahrens 			VFS_HOLD(vfsp);
1728fa9e4066Sahrens 			vfs_found = vfsp;
1729fa9e4066Sahrens 			break;
1730fa9e4066Sahrens 		}
1731fa9e4066Sahrens 		vfsp = vfsp->vfs_next;
1732fa9e4066Sahrens 	} while (vfsp != rootvfs);
1733fa9e4066Sahrens 	vfs_list_unlock();
1734fa9e4066Sahrens 	return (vfs_found);
1735fa9e4066Sahrens }
1736fa9e4066Sahrens 
1737ecd6cf80Smarks /* ARGSUSED */
1738fa9e4066Sahrens static void
1739ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
1740fa9e4066Sahrens {
1741da6c28aaSamw 	zfs_creat_t *zct = arg;
1742da6c28aaSamw 	uint64_t version;
1743da6c28aaSamw 
1744da6c28aaSamw 	if (spa_version(dmu_objset_spa(os)) >= SPA_VERSION_FUID)
1745da6c28aaSamw 		version = ZPL_VERSION;
1746da6c28aaSamw 	else
1747da6c28aaSamw 		version = ZPL_VERSION_FUID - 1;
1748e7437265Sahrens 
1749da6c28aaSamw 	(void) nvlist_lookup_uint64(zct->zct_props,
1750e7437265Sahrens 	    zfs_prop_to_name(ZFS_PROP_VERSION), &version);
1751e7437265Sahrens 
1752da6c28aaSamw 	zfs_create_fs(os, cr, version, zct->zct_norm, tx);
1753da6c28aaSamw }
1754da6c28aaSamw 
1755da6c28aaSamw /*
1756da6c28aaSamw  * zfs_prop_lookup()
1757da6c28aaSamw  *
1758da6c28aaSamw  * Look for the property first in the existing property nvlist.  If
1759da6c28aaSamw  * it's already present, you're done.  If it's not there, attempt to
1760da6c28aaSamw  * find the property value from a parent dataset.  If that fails, fall
1761da6c28aaSamw  * back to the property's default value.  In either of these two
1762da6c28aaSamw  * cases, if update is TRUE, add a value for the property to the
1763da6c28aaSamw  * property nvlist.
1764da6c28aaSamw  *
1765da6c28aaSamw  * If the rval pointer is non-NULL, copy the discovered value to rval.
1766da6c28aaSamw  *
1767da6c28aaSamw  * If we get any unexpected errors, bail and return the error number
1768da6c28aaSamw  * to the caller.
1769da6c28aaSamw  *
1770da6c28aaSamw  * If we succeed, return 0.
1771da6c28aaSamw  */
1772da6c28aaSamw static int
1773da6c28aaSamw zfs_prop_lookup(const char *parentname, zfs_prop_t propnum,
1774da6c28aaSamw     nvlist_t *proplist, uint64_t *rval, boolean_t update)
1775da6c28aaSamw {
1776da6c28aaSamw 	const char *propname;
1777da6c28aaSamw 	uint64_t value;
1778da6c28aaSamw 	int error = ENOENT;
1779da6c28aaSamw 
1780da6c28aaSamw 	propname = zfs_prop_to_name(propnum);
1781da6c28aaSamw 	if (proplist != NULL)
1782da6c28aaSamw 		error = nvlist_lookup_uint64(proplist, propname, &value);
1783da6c28aaSamw 	if (error == ENOENT) {
1784da6c28aaSamw 		error = dsl_prop_get_integer(parentname, propname,
1785da6c28aaSamw 		    &value, NULL);
1786da6c28aaSamw 		if (error == ENOENT)
1787da6c28aaSamw 			value = zfs_prop_default_numeric(propnum);
1788da6c28aaSamw 		else if (error != 0)
1789da6c28aaSamw 			return (error);
1790da6c28aaSamw 		if (update) {
1791da6c28aaSamw 			ASSERT(proplist != NULL);
1792da6c28aaSamw 			error = nvlist_add_uint64(proplist, propname, value);
1793da6c28aaSamw 		}
1794da6c28aaSamw 	}
1795da6c28aaSamw 	if (error == 0 && rval)
1796da6c28aaSamw 		*rval = value;
1797da6c28aaSamw 	return (error);
1798da6c28aaSamw }
1799da6c28aaSamw 
1800da6c28aaSamw /*
1801da6c28aaSamw  * zfs_normalization_get
1802da6c28aaSamw  *
1803da6c28aaSamw  * Get the normalization flag value.  If the properties have
1804da6c28aaSamw  * non-default values, make sure the pool version is recent enough to
1805da6c28aaSamw  * support these choices.
1806da6c28aaSamw  */
1807da6c28aaSamw static int
1808da6c28aaSamw zfs_normalization_get(const char *dataset, nvlist_t *proplist, int *norm,
1809da6c28aaSamw     boolean_t update)
1810da6c28aaSamw {
1811da6c28aaSamw 	char parentname[MAXNAMELEN];
1812da6c28aaSamw 	char poolname[MAXNAMELEN];
1813da6c28aaSamw 	char *cp;
1814da6c28aaSamw 	uint64_t value;
1815da6c28aaSamw 	int check = 0;
1816da6c28aaSamw 	int error;
1817da6c28aaSamw 
1818da6c28aaSamw 	ASSERT(norm != NULL);
1819da6c28aaSamw 	*norm = 0;
1820da6c28aaSamw 
1821da6c28aaSamw 	(void) strncpy(parentname, dataset, sizeof (parentname));
1822da6c28aaSamw 	cp = strrchr(parentname, '@');
1823da6c28aaSamw 	if (cp != NULL) {
1824da6c28aaSamw 		cp[0] = '\0';
1825da6c28aaSamw 	} else {
1826da6c28aaSamw 		cp = strrchr(parentname, '/');
1827da6c28aaSamw 		if (cp == NULL)
1828da6c28aaSamw 			return (ENOENT);
1829da6c28aaSamw 		cp[0] = '\0';
1830da6c28aaSamw 	}
1831da6c28aaSamw 
1832da6c28aaSamw 	(void) strncpy(poolname, dataset, sizeof (poolname));
1833da6c28aaSamw 	cp = strchr(poolname, '/');
1834da6c28aaSamw 	if (cp != NULL)
1835da6c28aaSamw 		cp[0] = '\0';
1836da6c28aaSamw 
1837*c2a93d44Stimh 	/*
1838*c2a93d44Stimh 	 * Make sure pool is of new enough vintage to support normalization.
1839*c2a93d44Stimh 	 */
1840*c2a93d44Stimh 	if (zfs_check_version(poolname, SPA_VERSION_NORMALIZATION))
1841*c2a93d44Stimh 		return (0);
1842*c2a93d44Stimh 
1843da6c28aaSamw 	error = zfs_prop_lookup(parentname, ZFS_PROP_UTF8ONLY,
1844da6c28aaSamw 	    proplist, &value, update);
1845da6c28aaSamw 	if (error != 0)
1846da6c28aaSamw 		return (error);
1847da6c28aaSamw 	if (value != zfs_prop_default_numeric(ZFS_PROP_UTF8ONLY))
1848da6c28aaSamw 		check = 1;
1849da6c28aaSamw 
1850da6c28aaSamw 	error = zfs_prop_lookup(parentname, ZFS_PROP_NORMALIZE,
1851da6c28aaSamw 	    proplist, &value, update);
1852da6c28aaSamw 	if (error != 0)
1853da6c28aaSamw 		return (error);
1854da6c28aaSamw 	if (value != zfs_prop_default_numeric(ZFS_PROP_NORMALIZE)) {
1855da6c28aaSamw 		check = 1;
1856da6c28aaSamw 		switch ((int)value) {
1857da6c28aaSamw 		case ZFS_NORMALIZE_NONE:
1858da6c28aaSamw 			break;
1859da6c28aaSamw 		case ZFS_NORMALIZE_C:
1860da6c28aaSamw 			*norm |= U8_TEXTPREP_NFC;
1861da6c28aaSamw 			break;
1862da6c28aaSamw 		case ZFS_NORMALIZE_D:
1863da6c28aaSamw 			*norm |= U8_TEXTPREP_NFD;
1864da6c28aaSamw 			break;
1865da6c28aaSamw 		case ZFS_NORMALIZE_KC:
1866da6c28aaSamw 			*norm |= U8_TEXTPREP_NFKC;
1867da6c28aaSamw 			break;
1868da6c28aaSamw 		case ZFS_NORMALIZE_KD:
1869da6c28aaSamw 			*norm |= U8_TEXTPREP_NFKD;
1870da6c28aaSamw 			break;
1871da6c28aaSamw 		default:
1872da6c28aaSamw 			ASSERT((int)value >= ZFS_NORMALIZE_NONE);
1873da6c28aaSamw 			ASSERT((int)value <= ZFS_NORMALIZE_KD);
1874da6c28aaSamw 			break;
1875da6c28aaSamw 		}
1876da6c28aaSamw 	}
1877da6c28aaSamw 
1878da6c28aaSamw 	error = zfs_prop_lookup(parentname, ZFS_PROP_CASE,
1879da6c28aaSamw 	    proplist, &value, update);
1880da6c28aaSamw 	if (error != 0)
1881da6c28aaSamw 		return (error);
1882da6c28aaSamw 	if (value != zfs_prop_default_numeric(ZFS_PROP_CASE)) {
1883da6c28aaSamw 		check = 1;
1884da6c28aaSamw 		switch ((int)value) {
1885da6c28aaSamw 		case ZFS_CASE_SENSITIVE:
1886da6c28aaSamw 			break;
1887da6c28aaSamw 		case ZFS_CASE_INSENSITIVE:
1888da6c28aaSamw 			*norm |= U8_TEXTPREP_TOUPPER;
1889da6c28aaSamw 			break;
1890da6c28aaSamw 		case ZFS_CASE_MIXED:
1891da6c28aaSamw 			*norm |= U8_TEXTPREP_TOUPPER;
1892da6c28aaSamw 			break;
1893da6c28aaSamw 		default:
1894da6c28aaSamw 			ASSERT((int)value >= ZFS_CASE_SENSITIVE);
1895da6c28aaSamw 			ASSERT((int)value <= ZFS_CASE_MIXED);
1896da6c28aaSamw 			break;
1897da6c28aaSamw 		}
1898da6c28aaSamw 	}
1899da6c28aaSamw 
1900*c2a93d44Stimh 	/*
1901*c2a93d44Stimh 	 * At the moment we are disabling non-default values for these
1902*c2a93d44Stimh 	 * properties because they cannot be preserved properly with a
1903*c2a93d44Stimh 	 * zfs send.
1904*c2a93d44Stimh 	 */
1905da6c28aaSamw 	if (check == 1)
1906*c2a93d44Stimh 		return (ENOTSUP);
1907*c2a93d44Stimh 
1908da6c28aaSamw 	return (0);
1909fa9e4066Sahrens }
1910fa9e4066Sahrens 
19113cb34c60Sahrens /*
19123cb34c60Sahrens  * inputs:
19133cb34c60Sahrens  * zc_objset_type	type of objset to create (fs vs zvol)
19143cb34c60Sahrens  * zc_name		name of new objset
19153cb34c60Sahrens  * zc_value		name of snapshot to clone from (may be empty)
19163cb34c60Sahrens  * zc_nvlist_src{_size}	nvlist of properties to apply
19173cb34c60Sahrens  *
19183cb34c60Sahrens  * outputs:		none
19193cb34c60Sahrens  */
1920fa9e4066Sahrens static int
1921fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc)
1922fa9e4066Sahrens {
1923fa9e4066Sahrens 	objset_t *clone;
1924fa9e4066Sahrens 	int error = 0;
1925da6c28aaSamw 	zfs_creat_t zct;
1926ecd6cf80Smarks 	nvlist_t *nvprops = NULL;
1927ecd6cf80Smarks 	void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
1928fa9e4066Sahrens 	dmu_objset_type_t type = zc->zc_objset_type;
1929fa9e4066Sahrens 
1930fa9e4066Sahrens 	switch (type) {
1931fa9e4066Sahrens 
1932fa9e4066Sahrens 	case DMU_OST_ZFS:
1933fa9e4066Sahrens 		cbfunc = zfs_create_cb;
1934fa9e4066Sahrens 		break;
1935fa9e4066Sahrens 
1936fa9e4066Sahrens 	case DMU_OST_ZVOL:
1937fa9e4066Sahrens 		cbfunc = zvol_create_cb;
1938fa9e4066Sahrens 		break;
1939fa9e4066Sahrens 
1940fa9e4066Sahrens 	default:
19411d452cf5Sahrens 		cbfunc = NULL;
1942fa9e4066Sahrens 	}
1943f18faf3fSek 	if (strchr(zc->zc_name, '@') ||
1944f18faf3fSek 	    strchr(zc->zc_name, '%'))
19451d452cf5Sahrens 		return (EINVAL);
1946fa9e4066Sahrens 
1947e9dbad6fSeschrock 	if (zc->zc_nvlist_src != NULL &&
1948990b4856Slling 	    (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1949990b4856Slling 	    &nvprops)) != 0)
1950e9dbad6fSeschrock 		return (error);
1951e9dbad6fSeschrock 
1952da6c28aaSamw 	zct.zct_norm = 0;
1953da6c28aaSamw 	zct.zct_props = nvprops;
1954da6c28aaSamw 
1955e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1956fa9e4066Sahrens 		/*
1957fa9e4066Sahrens 		 * We're creating a clone of an existing snapshot.
1958fa9e4066Sahrens 		 */
1959e9dbad6fSeschrock 		zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
1960e9dbad6fSeschrock 		if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) {
1961ecd6cf80Smarks 			nvlist_free(nvprops);
1962fa9e4066Sahrens 			return (EINVAL);
1963e9dbad6fSeschrock 		}
1964fa9e4066Sahrens 
1965e9dbad6fSeschrock 		error = dmu_objset_open(zc->zc_value, type,
1966fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
1967e9dbad6fSeschrock 		if (error) {
1968ecd6cf80Smarks 			nvlist_free(nvprops);
1969fa9e4066Sahrens 			return (error);
1970e9dbad6fSeschrock 		}
1971fa9e4066Sahrens 		error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL);
1972da6c28aaSamw 		if (error) {
1973da6c28aaSamw 			dmu_objset_close(clone);
1974da6c28aaSamw 			nvlist_free(nvprops);
1975da6c28aaSamw 			return (error);
1976da6c28aaSamw 		}
1977da6c28aaSamw 		/*
1978da6c28aaSamw 		 * If caller did not provide any properties, allocate
1979da6c28aaSamw 		 * an nvlist for properties, as we will be adding our set-once
1980da6c28aaSamw 		 * properties to it.  This carries the choices made on the
1981da6c28aaSamw 		 * original file system into the clone.
1982da6c28aaSamw 		 */
1983da6c28aaSamw 		if (nvprops == NULL)
1984da6c28aaSamw 			VERIFY(nvlist_alloc(&nvprops,
1985da6c28aaSamw 			    NV_UNIQUE_NAME, KM_SLEEP) == 0);
1986da6c28aaSamw 
1987da6c28aaSamw 		/*
1988da6c28aaSamw 		 * We have to have normalization and case-folding
1989da6c28aaSamw 		 * flags correct when we do the file system creation,
1990da6c28aaSamw 		 * so go figure them out now.  All we really care about
1991da6c28aaSamw 		 * here is getting these values into the property list.
1992da6c28aaSamw 		 */
1993da6c28aaSamw 		error = zfs_normalization_get(zc->zc_value, nvprops,
1994da6c28aaSamw 		    &zct.zct_norm, B_TRUE);
1995da6c28aaSamw 		if (error != 0) {
1996da6c28aaSamw 			dmu_objset_close(clone);
1997da6c28aaSamw 			nvlist_free(nvprops);
1998da6c28aaSamw 			return (error);
1999da6c28aaSamw 		}
2000fa9e4066Sahrens 		dmu_objset_close(clone);
2001fa9e4066Sahrens 	} else {
2002e9dbad6fSeschrock 		if (cbfunc == NULL) {
2003ecd6cf80Smarks 			nvlist_free(nvprops);
20041d452cf5Sahrens 			return (EINVAL);
2005e9dbad6fSeschrock 		}
20065c5460e9Seschrock 
2007e9dbad6fSeschrock 		if (type == DMU_OST_ZVOL) {
2008e9dbad6fSeschrock 			uint64_t volsize, volblocksize;
2009e9dbad6fSeschrock 
2010ecd6cf80Smarks 			if (nvprops == NULL ||
2011ecd6cf80Smarks 			    nvlist_lookup_uint64(nvprops,
2012e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLSIZE),
2013e9dbad6fSeschrock 			    &volsize) != 0) {
2014ecd6cf80Smarks 				nvlist_free(nvprops);
2015e9dbad6fSeschrock 				return (EINVAL);
2016e9dbad6fSeschrock 			}
2017e9dbad6fSeschrock 
2018ecd6cf80Smarks 			if ((error = nvlist_lookup_uint64(nvprops,
2019e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
2020e9dbad6fSeschrock 			    &volblocksize)) != 0 && error != ENOENT) {
2021ecd6cf80Smarks 				nvlist_free(nvprops);
2022e9dbad6fSeschrock 				return (EINVAL);
2023e9dbad6fSeschrock 			}
2024e9dbad6fSeschrock 
2025e9dbad6fSeschrock 			if (error != 0)
2026e9dbad6fSeschrock 				volblocksize = zfs_prop_default_numeric(
2027e9dbad6fSeschrock 				    ZFS_PROP_VOLBLOCKSIZE);
2028e9dbad6fSeschrock 
2029e9dbad6fSeschrock 			if ((error = zvol_check_volblocksize(
2030e9dbad6fSeschrock 			    volblocksize)) != 0 ||
2031e9dbad6fSeschrock 			    (error = zvol_check_volsize(volsize,
2032e9dbad6fSeschrock 			    volblocksize)) != 0) {
2033ecd6cf80Smarks 				nvlist_free(nvprops);
20345c5460e9Seschrock 				return (error);
2035e9dbad6fSeschrock 			}
2036e7437265Sahrens 		} else if (type == DMU_OST_ZFS) {
2037e7437265Sahrens 			uint64_t version;
2038da6c28aaSamw 			int error;
2039da6c28aaSamw 
2040da6c28aaSamw 			error = nvlist_lookup_uint64(nvprops,
2041da6c28aaSamw 			    zfs_prop_to_name(ZFS_PROP_VERSION), &version);
2042e7437265Sahrens 
2043da6c28aaSamw 			if (error == 0 && (version < ZPL_VERSION_INITIAL ||
2044e7437265Sahrens 			    version > ZPL_VERSION)) {
2045e7437265Sahrens 				nvlist_free(nvprops);
2046da6c28aaSamw 				return (ENOTSUP);
2047da6c28aaSamw 			} else if (error == 0 && version >= ZPL_VERSION_FUID &&
2048da6c28aaSamw 			    zfs_check_version(zc->zc_name, SPA_VERSION_FUID)) {
2049da6c28aaSamw 				nvlist_free(nvprops);
2050da6c28aaSamw 				return (ENOTSUP);
2051e7437265Sahrens 			}
2052e9dbad6fSeschrock 
2053da6c28aaSamw 			/*
2054da6c28aaSamw 			 * We have to have normalization and
2055da6c28aaSamw 			 * case-folding flags correct when we do the
2056da6c28aaSamw 			 * file system creation, so go figure them out
2057da6c28aaSamw 			 * now.  The final argument to zfs_normalization_get()
2058da6c28aaSamw 			 * tells that routine not to update the nvprops
2059da6c28aaSamw 			 * list.
2060da6c28aaSamw 			 */
2061da6c28aaSamw 			error = zfs_normalization_get(zc->zc_name, nvprops,
2062da6c28aaSamw 			    &zct.zct_norm, B_FALSE);
2063da6c28aaSamw 			if (error != 0) {
2064da6c28aaSamw 				nvlist_free(nvprops);
2065da6c28aaSamw 				return (error);
2066da6c28aaSamw 			}
2067da6c28aaSamw 		}
2068e9dbad6fSeschrock 		error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc,
2069da6c28aaSamw 		    &zct);
2070fa9e4066Sahrens 	}
2071e9dbad6fSeschrock 
2072e9dbad6fSeschrock 	/*
2073e9dbad6fSeschrock 	 * It would be nice to do this atomically.
2074e9dbad6fSeschrock 	 */
2075e9dbad6fSeschrock 	if (error == 0) {
207691ebeef5Sahrens 		if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0)
2077e9dbad6fSeschrock 			(void) dmu_objset_destroy(zc->zc_name);
2078e9dbad6fSeschrock 	}
2079e9dbad6fSeschrock 
2080ecd6cf80Smarks 	nvlist_free(nvprops);
2081fa9e4066Sahrens 	return (error);
2082fa9e4066Sahrens }
2083fa9e4066Sahrens 
20843cb34c60Sahrens /*
20853cb34c60Sahrens  * inputs:
20863cb34c60Sahrens  * zc_name	name of filesystem
20873cb34c60Sahrens  * zc_value	short name of snapshot
20883cb34c60Sahrens  * zc_cookie	recursive flag
20893cb34c60Sahrens  *
20903cb34c60Sahrens  * outputs:	none
20913cb34c60Sahrens  */
2092fa9e4066Sahrens static int
20931d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc)
2094fa9e4066Sahrens {
2095e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
20961d452cf5Sahrens 		return (EINVAL);
20971d452cf5Sahrens 	return (dmu_objset_snapshot(zc->zc_name,
2098e9dbad6fSeschrock 	    zc->zc_value, zc->zc_cookie));
20991d452cf5Sahrens }
2100fa9e4066Sahrens 
2101cdf5b4caSmmusante int
21021d452cf5Sahrens zfs_unmount_snap(char *name, void *arg)
21031d452cf5Sahrens {
21041d452cf5Sahrens 	char *snapname = arg;
21051d452cf5Sahrens 	char *cp;
21060b69c2f0Sahrens 	vfs_t *vfsp = NULL;
21071d452cf5Sahrens 
21081d452cf5Sahrens 	/*
21091d452cf5Sahrens 	 * Snapshots (which are under .zfs control) must be unmounted
21101d452cf5Sahrens 	 * before they can be destroyed.
21111d452cf5Sahrens 	 */
21121d452cf5Sahrens 
21131d452cf5Sahrens 	if (snapname) {
21141d452cf5Sahrens 		(void) strcat(name, "@");
21151d452cf5Sahrens 		(void) strcat(name, snapname);
21161d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
21171d452cf5Sahrens 		cp = strchr(name, '@');
21181d452cf5Sahrens 		*cp = '\0';
21190b69c2f0Sahrens 	} else if (strchr(name, '@')) {
21201d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
21211d452cf5Sahrens 	}
21221d452cf5Sahrens 
21231d452cf5Sahrens 	if (vfsp) {
2124fa9e4066Sahrens 		/*
21251d452cf5Sahrens 		 * Always force the unmount for snapshots.
2126fa9e4066Sahrens 		 */
21271d452cf5Sahrens 		int flag = MS_FORCE;
21281d452cf5Sahrens 		int err;
21291d452cf5Sahrens 
21301d452cf5Sahrens 		if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) {
2131fa9e4066Sahrens 			VFS_RELE(vfsp);
21321d452cf5Sahrens 			return (err);
2133fa9e4066Sahrens 		}
21341d452cf5Sahrens 		VFS_RELE(vfsp);
21351d452cf5Sahrens 		if ((err = dounmount(vfsp, flag, kcred)) != 0)
21361d452cf5Sahrens 			return (err);
21371d452cf5Sahrens 	}
21381d452cf5Sahrens 	return (0);
21391d452cf5Sahrens }
21401d452cf5Sahrens 
21413cb34c60Sahrens /*
21423cb34c60Sahrens  * inputs:
21433cb34c60Sahrens  * zc_name	name of filesystem
21443cb34c60Sahrens  * zc_value	short name of snapshot
21453cb34c60Sahrens  *
21463cb34c60Sahrens  * outputs:	none
21473cb34c60Sahrens  */
21481d452cf5Sahrens static int
21491d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc)
21501d452cf5Sahrens {
21511d452cf5Sahrens 	int err;
21521d452cf5Sahrens 
2153e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
21541d452cf5Sahrens 		return (EINVAL);
21551d452cf5Sahrens 	err = dmu_objset_find(zc->zc_name,
2156e9dbad6fSeschrock 	    zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN);
21571d452cf5Sahrens 	if (err)
21581d452cf5Sahrens 		return (err);
2159e9dbad6fSeschrock 	return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value));
21601d452cf5Sahrens }
21611d452cf5Sahrens 
21623cb34c60Sahrens /*
21633cb34c60Sahrens  * inputs:
21643cb34c60Sahrens  * zc_name		name of dataset to destroy
21653cb34c60Sahrens  * zc_objset_type	type of objset
21663cb34c60Sahrens  *
21673cb34c60Sahrens  * outputs:		none
21683cb34c60Sahrens  */
21691d452cf5Sahrens static int
21701d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc)
21711d452cf5Sahrens {
21721d452cf5Sahrens 	if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) {
21731d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
21741d452cf5Sahrens 		if (err)
21751d452cf5Sahrens 			return (err);
2176fa9e4066Sahrens 	}
2177fa9e4066Sahrens 
2178fa9e4066Sahrens 	return (dmu_objset_destroy(zc->zc_name));
2179fa9e4066Sahrens }
2180fa9e4066Sahrens 
21813cb34c60Sahrens /*
21823cb34c60Sahrens  * inputs:
21833cb34c60Sahrens  * zc_name	name of snapshot to roll back to
21843cb34c60Sahrens  *
21853cb34c60Sahrens  * outputs:	none
21863cb34c60Sahrens  */
2187fa9e4066Sahrens static int
2188fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc)
2189fa9e4066Sahrens {
2190fa9e4066Sahrens 	return (dmu_objset_rollback(zc->zc_name));
2191fa9e4066Sahrens }
2192fa9e4066Sahrens 
21933cb34c60Sahrens /*
21943cb34c60Sahrens  * inputs:
21953cb34c60Sahrens  * zc_name	old name of dataset
21963cb34c60Sahrens  * zc_value	new name of dataset
21973cb34c60Sahrens  * zc_cookie	recursive flag (only valid for snapshots)
21983cb34c60Sahrens  *
21993cb34c60Sahrens  * outputs:	none
22003cb34c60Sahrens  */
2201fa9e4066Sahrens static int
2202fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc)
2203fa9e4066Sahrens {
22047f1f55eaSvb 	boolean_t recursive = zc->zc_cookie & 1;
2205cdf5b4caSmmusante 
2206e9dbad6fSeschrock 	zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
2207f18faf3fSek 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
2208f18faf3fSek 	    strchr(zc->zc_value, '%'))
2209fa9e4066Sahrens 		return (EINVAL);
2210fa9e4066Sahrens 
2211cdf5b4caSmmusante 	/*
2212cdf5b4caSmmusante 	 * Unmount snapshot unless we're doing a recursive rename,
2213cdf5b4caSmmusante 	 * in which case the dataset code figures out which snapshots
2214cdf5b4caSmmusante 	 * to unmount.
2215cdf5b4caSmmusante 	 */
2216cdf5b4caSmmusante 	if (!recursive && strchr(zc->zc_name, '@') != NULL &&
2217fa9e4066Sahrens 	    zc->zc_objset_type == DMU_OST_ZFS) {
22181d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
22191d452cf5Sahrens 		if (err)
22201d452cf5Sahrens 			return (err);
2221fa9e4066Sahrens 	}
2222fa9e4066Sahrens 
2223cdf5b4caSmmusante 	return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive));
2224fa9e4066Sahrens }
2225fa9e4066Sahrens 
22263cb34c60Sahrens /*
22273cb34c60Sahrens  * inputs:
22283cb34c60Sahrens  * zc_name		name of containing filesystem
22293cb34c60Sahrens  * zc_nvlist_src{_size}	nvlist of properties to apply
22303cb34c60Sahrens  * zc_value		name of snapshot to create
22313cb34c60Sahrens  * zc_string		name of clone origin (if DRR_FLAG_CLONE)
22323cb34c60Sahrens  * zc_cookie		file descriptor to recv from
22333cb34c60Sahrens  * zc_begin_record	the BEGIN record of the stream (not byteswapped)
22343cb34c60Sahrens  * zc_guid		force flag
22353cb34c60Sahrens  *
22363cb34c60Sahrens  * outputs:
22373cb34c60Sahrens  * zc_cookie		number of bytes read
22383cb34c60Sahrens  */
2239fa9e4066Sahrens static int
22403cb34c60Sahrens zfs_ioc_recv(zfs_cmd_t *zc)
2241fa9e4066Sahrens {
2242fa9e4066Sahrens 	file_t *fp;
2243f18faf3fSek 	objset_t *os;
22443cb34c60Sahrens 	dmu_recv_cookie_t drc;
2245f18faf3fSek 	zfsvfs_t *zfsvfs = NULL;
2246f18faf3fSek 	boolean_t force = (boolean_t)zc->zc_guid;
2247f18faf3fSek 	int error, fd;
22483cb34c60Sahrens 	offset_t off;
22493cb34c60Sahrens 	nvlist_t *props = NULL;
22503cb34c60Sahrens 	objset_t *origin = NULL;
22513cb34c60Sahrens 	char *tosnap;
22523cb34c60Sahrens 	char tofs[ZFS_MAXNAMELEN];
2253fa9e4066Sahrens 
22543ccfa83cSahrens 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
2255f18faf3fSek 	    strchr(zc->zc_value, '@') == NULL ||
2256f18faf3fSek 	    strchr(zc->zc_value, '%'))
22573ccfa83cSahrens 		return (EINVAL);
22583ccfa83cSahrens 
22593cb34c60Sahrens 	(void) strcpy(tofs, zc->zc_value);
22603cb34c60Sahrens 	tosnap = strchr(tofs, '@');
22613cb34c60Sahrens 	*tosnap = '\0';
22623cb34c60Sahrens 	tosnap++;
22633cb34c60Sahrens 
22643cb34c60Sahrens 	if (zc->zc_nvlist_src != NULL &&
22653cb34c60Sahrens 	    (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
22663cb34c60Sahrens 	    &props)) != 0)
22673cb34c60Sahrens 		return (error);
22683cb34c60Sahrens 
2269fa9e4066Sahrens 	fd = zc->zc_cookie;
2270fa9e4066Sahrens 	fp = getf(fd);
22713cb34c60Sahrens 	if (fp == NULL) {
22723cb34c60Sahrens 		nvlist_free(props);
2273fa9e4066Sahrens 		return (EBADF);
22743cb34c60Sahrens 	}
2275f18faf3fSek 
2276f18faf3fSek 	/*
2277f18faf3fSek 	 * Get the zfsvfs for the receiving objset. There
2278f18faf3fSek 	 * won't be one if we're operating on a zvol, if the
2279f18faf3fSek 	 * objset doesn't exist yet, or is not mounted.
2280f18faf3fSek 	 */
22813cb34c60Sahrens 
22823cb34c60Sahrens 	error = dmu_objset_open(tofs, DMU_OST_ANY,
2283f18faf3fSek 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
2284f18faf3fSek 	if (!error) {
2285f18faf3fSek 		if (dmu_objset_type(os) == DMU_OST_ZFS) {
2286f18faf3fSek 			mutex_enter(&os->os->os_user_ptr_lock);
2287f18faf3fSek 			zfsvfs = dmu_objset_get_user(os);
2288f18faf3fSek 			if (zfsvfs != NULL)
2289f18faf3fSek 				VFS_HOLD(zfsvfs->z_vfs);
2290f18faf3fSek 			mutex_exit(&os->os->os_user_ptr_lock);
2291f18faf3fSek 		}
2292f18faf3fSek 		dmu_objset_close(os);
2293f18faf3fSek 	}
2294f18faf3fSek 
22953cb34c60Sahrens 	if (zc->zc_string[0]) {
22963cb34c60Sahrens 		error = dmu_objset_open(zc->zc_string, DMU_OST_ANY,
22973cb34c60Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &origin);
22983cb34c60Sahrens 		if (error) {
22993cb34c60Sahrens 			if (zfsvfs != NULL)
23003cb34c60Sahrens 				VFS_RELE(zfsvfs->z_vfs);
23013cb34c60Sahrens 			nvlist_free(props);
23023cb34c60Sahrens 			releasef(fd);
23033cb34c60Sahrens 			return (error);
23043cb34c60Sahrens 		}
23053cb34c60Sahrens 	}
23063cb34c60Sahrens 
23073cb34c60Sahrens 	error = dmu_recv_begin(tofs, tosnap, &zc->zc_begin_record,
23083cb34c60Sahrens 	    force, origin, zfsvfs != NULL, &drc);
23093cb34c60Sahrens 	if (origin)
23103cb34c60Sahrens 		dmu_objset_close(origin);
23113cb34c60Sahrens 	if (error) {
23123cb34c60Sahrens 		if (zfsvfs != NULL)
23133cb34c60Sahrens 			VFS_RELE(zfsvfs->z_vfs);
23143cb34c60Sahrens 		nvlist_free(props);
23153cb34c60Sahrens 		releasef(fd);
23163cb34c60Sahrens 		return (error);
23173cb34c60Sahrens 	}
2318f18faf3fSek 
2319f18faf3fSek 	/*
23203cb34c60Sahrens 	 * If properties are supplied, they are to completely replace
23213cb34c60Sahrens 	 * the existing ones; "inherit" any existing properties.
2322f18faf3fSek 	 */
23233cb34c60Sahrens 	if (props) {
23243cb34c60Sahrens 		objset_t *os;
23253cb34c60Sahrens 		nvlist_t *nv = NULL;
23263cb34c60Sahrens 
23273cb34c60Sahrens 		error = dmu_objset_open(tofs, DMU_OST_ANY,
23283cb34c60Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY | DS_MODE_INCONSISTENT,
23293cb34c60Sahrens 		    &os);
23303cb34c60Sahrens 		if (error == 0) {
23313cb34c60Sahrens 			error = dsl_prop_get_all(os, &nv);
23323cb34c60Sahrens 			dmu_objset_close(os);
23333cb34c60Sahrens 		}
23343cb34c60Sahrens 		if (error == 0) {
23353cb34c60Sahrens 			nvpair_t *elem;
23363cb34c60Sahrens 			zfs_cmd_t zc2 = { 0 };
23373cb34c60Sahrens 
23383cb34c60Sahrens 			(void) strcpy(zc2.zc_name, tofs);
23393cb34c60Sahrens 			for (elem = nvlist_next_nvpair(nv, NULL); elem;
23403cb34c60Sahrens 			    elem = nvlist_next_nvpair(nv, elem)) {
23413cb34c60Sahrens 				(void) strcpy(zc2.zc_value, nvpair_name(elem));
23423cb34c60Sahrens 				if (zfs_secpolicy_inherit(&zc2, CRED()) == 0)
23433cb34c60Sahrens 					(void) zfs_ioc_inherit_prop(&zc2);
2344f18faf3fSek 			}
2345f18faf3fSek 		}
23463cb34c60Sahrens 		if (nv)
23473cb34c60Sahrens 			nvlist_free(nv);
23483cb34c60Sahrens 	}
23493cb34c60Sahrens 
23503cb34c60Sahrens 	/*
23513cb34c60Sahrens 	 * Set properties.  Note, we ignore errors.  Would be better to
23523cb34c60Sahrens 	 * do best-effort in zfs_set_prop_nvlist, too.
23533cb34c60Sahrens 	 */
23543cb34c60Sahrens 	(void) zfs_set_prop_nvlist(tofs, props);
23553cb34c60Sahrens 	nvlist_free(props);
23563cb34c60Sahrens 
23573cb34c60Sahrens 	off = fp->f_offset;
23583cb34c60Sahrens 	error = dmu_recv_stream(&drc, fp->f_vnode, &off);
2359a2eea2e1Sahrens 
23603cb34c60Sahrens 	if (error == 0) {
23613cb34c60Sahrens 		if (zfsvfs != NULL) {
23623cb34c60Sahrens 			char osname[MAXNAMELEN];
23633cb34c60Sahrens 			int mode;
23643cb34c60Sahrens 
23653cb34c60Sahrens 			(void) zfs_suspend_fs(zfsvfs, osname, &mode);
23663cb34c60Sahrens 			error = dmu_recv_end(&drc);
23673cb34c60Sahrens 			error |= zfs_resume_fs(zfsvfs, osname, mode);
23683cb34c60Sahrens 		} else {
23693cb34c60Sahrens 			error = dmu_recv_end(&drc);
23703cb34c60Sahrens 		}
2371f18faf3fSek 	}
2372f18faf3fSek 	if (zfsvfs != NULL)
2373f18faf3fSek 		VFS_RELE(zfsvfs->z_vfs);
23743cb34c60Sahrens 
23753cb34c60Sahrens 	zc->zc_cookie = off - fp->f_offset;
23763cb34c60Sahrens 	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
23773cb34c60Sahrens 		fp->f_offset = off;
2378a2eea2e1Sahrens 
2379fa9e4066Sahrens 	releasef(fd);
2380fa9e4066Sahrens 	return (error);
2381fa9e4066Sahrens }
2382fa9e4066Sahrens 
23833cb34c60Sahrens /*
23843cb34c60Sahrens  * inputs:
23853cb34c60Sahrens  * zc_name	name of snapshot to send
23863cb34c60Sahrens  * zc_value	short name of incremental fromsnap (may be empty)
23873cb34c60Sahrens  * zc_cookie	file descriptor to send stream to
23883cb34c60Sahrens  * zc_obj	fromorigin flag (mutually exclusive with zc_value)
23893cb34c60Sahrens  *
23903cb34c60Sahrens  * outputs: none
23913cb34c60Sahrens  */
2392fa9e4066Sahrens static int
23933cb34c60Sahrens zfs_ioc_send(zfs_cmd_t *zc)
2394fa9e4066Sahrens {
2395fa9e4066Sahrens 	objset_t *fromsnap = NULL;
2396fa9e4066Sahrens 	objset_t *tosnap;
2397fa9e4066Sahrens 	file_t *fp;
2398fa9e4066Sahrens 	int error;
23993cb34c60Sahrens 	offset_t off;
2400fa9e4066Sahrens 
2401fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
2402fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap);
2403fa9e4066Sahrens 	if (error)
2404fa9e4066Sahrens 		return (error);
2405fa9e4066Sahrens 
2406e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
2407a2eea2e1Sahrens 		char buf[MAXPATHLEN];
2408a2eea2e1Sahrens 		char *cp;
2409a2eea2e1Sahrens 
2410a2eea2e1Sahrens 		(void) strncpy(buf, zc->zc_name, sizeof (buf));
2411a2eea2e1Sahrens 		cp = strchr(buf, '@');
2412a2eea2e1Sahrens 		if (cp)
2413a2eea2e1Sahrens 			*(cp+1) = 0;
2414a2eea2e1Sahrens 		(void) strncat(buf, zc->zc_value, sizeof (buf));
2415a2eea2e1Sahrens 		error = dmu_objset_open(buf, DMU_OST_ANY,
2416fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap);
2417fa9e4066Sahrens 		if (error) {
2418fa9e4066Sahrens 			dmu_objset_close(tosnap);
2419fa9e4066Sahrens 			return (error);
2420fa9e4066Sahrens 		}
2421fa9e4066Sahrens 	}
2422fa9e4066Sahrens 
2423fa9e4066Sahrens 	fp = getf(zc->zc_cookie);
2424fa9e4066Sahrens 	if (fp == NULL) {
2425fa9e4066Sahrens 		dmu_objset_close(tosnap);
2426fa9e4066Sahrens 		if (fromsnap)
2427fa9e4066Sahrens 			dmu_objset_close(fromsnap);
2428fa9e4066Sahrens 		return (EBADF);
2429fa9e4066Sahrens 	}
2430fa9e4066Sahrens 
24313cb34c60Sahrens 	off = fp->f_offset;
24323cb34c60Sahrens 	error = dmu_sendbackup(tosnap, fromsnap, zc->zc_obj, fp->f_vnode, &off);
2433fa9e4066Sahrens 
24343cb34c60Sahrens 	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
24353cb34c60Sahrens 		fp->f_offset = off;
2436fa9e4066Sahrens 	releasef(zc->zc_cookie);
2437fa9e4066Sahrens 	if (fromsnap)
2438fa9e4066Sahrens 		dmu_objset_close(fromsnap);
2439fa9e4066Sahrens 	dmu_objset_close(tosnap);
2440fa9e4066Sahrens 	return (error);
2441fa9e4066Sahrens }
2442fa9e4066Sahrens 
2443ea8dc4b6Seschrock static int
2444ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc)
2445ea8dc4b6Seschrock {
2446ea8dc4b6Seschrock 	int id, error;
2447ea8dc4b6Seschrock 
2448ea8dc4b6Seschrock 	error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id,
2449ea8dc4b6Seschrock 	    &zc->zc_inject_record);
2450ea8dc4b6Seschrock 
2451ea8dc4b6Seschrock 	if (error == 0)
2452ea8dc4b6Seschrock 		zc->zc_guid = (uint64_t)id;
2453ea8dc4b6Seschrock 
2454ea8dc4b6Seschrock 	return (error);
2455ea8dc4b6Seschrock }
2456ea8dc4b6Seschrock 
2457ea8dc4b6Seschrock static int
2458ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc)
2459ea8dc4b6Seschrock {
2460ea8dc4b6Seschrock 	return (zio_clear_fault((int)zc->zc_guid));
2461ea8dc4b6Seschrock }
2462ea8dc4b6Seschrock 
2463ea8dc4b6Seschrock static int
2464ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc)
2465ea8dc4b6Seschrock {
2466ea8dc4b6Seschrock 	int id = (int)zc->zc_guid;
2467ea8dc4b6Seschrock 	int error;
2468ea8dc4b6Seschrock 
2469ea8dc4b6Seschrock 	error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name),
2470ea8dc4b6Seschrock 	    &zc->zc_inject_record);
2471ea8dc4b6Seschrock 
2472ea8dc4b6Seschrock 	zc->zc_guid = id;
2473ea8dc4b6Seschrock 
2474ea8dc4b6Seschrock 	return (error);
2475ea8dc4b6Seschrock }
2476ea8dc4b6Seschrock 
2477ea8dc4b6Seschrock static int
2478ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc)
2479ea8dc4b6Seschrock {
2480ea8dc4b6Seschrock 	spa_t *spa;
2481ea8dc4b6Seschrock 	int error;
2482e9dbad6fSeschrock 	size_t count = (size_t)zc->zc_nvlist_dst_size;
2483ea8dc4b6Seschrock 
2484ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
2485ea8dc4b6Seschrock 		return (error);
2486ea8dc4b6Seschrock 
2487e9dbad6fSeschrock 	error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst,
2488ea8dc4b6Seschrock 	    &count);
2489ea8dc4b6Seschrock 	if (error == 0)
2490e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = count;
2491ea8dc4b6Seschrock 	else
2492e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = spa_get_errlog_size(spa);
2493ea8dc4b6Seschrock 
2494ea8dc4b6Seschrock 	spa_close(spa, FTAG);
2495ea8dc4b6Seschrock 
2496ea8dc4b6Seschrock 	return (error);
2497ea8dc4b6Seschrock }
2498ea8dc4b6Seschrock 
2499ea8dc4b6Seschrock static int
2500ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc)
2501ea8dc4b6Seschrock {
2502ea8dc4b6Seschrock 	spa_t *spa;
2503ea8dc4b6Seschrock 	vdev_t *vd;
25043d7072f8Seschrock 	uint64_t txg;
2505bb8b5132Sek 	int error;
2506ea8dc4b6Seschrock 
2507ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
2508ea8dc4b6Seschrock 		return (error);
2509ea8dc4b6Seschrock 
25100a4e9518Sgw 	/*
25110a4e9518Sgw 	 * Try to resume any I/Os which may have been suspended
25120a4e9518Sgw 	 * as a result of a complete pool failure.
25130a4e9518Sgw 	 */
25140a4e9518Sgw 	if (!list_is_empty(&spa->spa_zio_list)) {
25150a4e9518Sgw 		if (zio_vdev_resume_io(spa) != 0) {
25160a4e9518Sgw 			spa_close(spa, FTAG);
25170a4e9518Sgw 			return (EIO);
25180a4e9518Sgw 		}
25190a4e9518Sgw 	}
25200a4e9518Sgw 
25213d7072f8Seschrock 	txg = spa_vdev_enter(spa);
2522ea8dc4b6Seschrock 
2523e9dbad6fSeschrock 	if (zc->zc_guid == 0) {
2524ea8dc4b6Seschrock 		vd = NULL;
2525e9dbad6fSeschrock 	} else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) {
25263d7072f8Seschrock 		(void) spa_vdev_exit(spa, NULL, txg, ENODEV);
2527ea8dc4b6Seschrock 		spa_close(spa, FTAG);
2528ea8dc4b6Seschrock 		return (ENODEV);
2529ea8dc4b6Seschrock 	}
2530ea8dc4b6Seschrock 
25310a4e9518Sgw 	vdev_clear(spa, vd, B_TRUE);
2532ea8dc4b6Seschrock 
25333d7072f8Seschrock 	(void) spa_vdev_exit(spa, NULL, txg, 0);
2534ea8dc4b6Seschrock 
2535ea8dc4b6Seschrock 	spa_close(spa, FTAG);
2536ea8dc4b6Seschrock 
2537ea8dc4b6Seschrock 	return (0);
2538ea8dc4b6Seschrock }
2539ea8dc4b6Seschrock 
25403cb34c60Sahrens /*
25413cb34c60Sahrens  * inputs:
25423cb34c60Sahrens  * zc_name	name of filesystem
25433cb34c60Sahrens  * zc_value	name of origin snapshot
25443cb34c60Sahrens  *
25453cb34c60Sahrens  * outputs:	none
25463cb34c60Sahrens  */
254799653d4eSeschrock static int
254899653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc)
254999653d4eSeschrock {
25500b69c2f0Sahrens 	char *cp;
25510b69c2f0Sahrens 
25520b69c2f0Sahrens 	/*
25530b69c2f0Sahrens 	 * We don't need to unmount *all* the origin fs's snapshots, but
25540b69c2f0Sahrens 	 * it's easier.
25550b69c2f0Sahrens 	 */
2556e9dbad6fSeschrock 	cp = strchr(zc->zc_value, '@');
25570b69c2f0Sahrens 	if (cp)
25580b69c2f0Sahrens 		*cp = '\0';
2559e9dbad6fSeschrock 	(void) dmu_objset_find(zc->zc_value,
25600b69c2f0Sahrens 	    zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS);
256199653d4eSeschrock 	return (dsl_dataset_promote(zc->zc_name));
256299653d4eSeschrock }
256399653d4eSeschrock 
2564ecd6cf80Smarks /*
2565ecd6cf80Smarks  * We don't want to have a hard dependency
2566ecd6cf80Smarks  * against some special symbols in sharefs
2567da6c28aaSamw  * nfs, and smbsrv.  Determine them if needed when
2568ecd6cf80Smarks  * the first file system is shared.
2569da6c28aaSamw  * Neither sharefs, nfs or smbsrv are unloadable modules.
2570ecd6cf80Smarks  */
2571da6c28aaSamw int (*znfsexport_fs)(void *arg);
2572ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t);
2573da6c28aaSamw int (*zsmbexport_fs)(void *arg, boolean_t add_share);
2574da6c28aaSamw 
2575da6c28aaSamw int zfs_nfsshare_inited;
2576da6c28aaSamw int zfs_smbshare_inited;
2577ecd6cf80Smarks 
2578ecd6cf80Smarks ddi_modhandle_t nfs_mod;
2579ecd6cf80Smarks ddi_modhandle_t sharefs_mod;
2580da6c28aaSamw ddi_modhandle_t smbsrv_mod;
2581ecd6cf80Smarks kmutex_t zfs_share_lock;
2582ecd6cf80Smarks 
2583da6c28aaSamw static int
2584da6c28aaSamw zfs_init_sharefs()
2585da6c28aaSamw {
2586da6c28aaSamw 	int error;
2587da6c28aaSamw 
2588da6c28aaSamw 	ASSERT(MUTEX_HELD(&zfs_share_lock));
2589da6c28aaSamw 	/* Both NFS and SMB shares also require sharetab support. */
2590da6c28aaSamw 	if (sharefs_mod == NULL && ((sharefs_mod =
2591da6c28aaSamw 	    ddi_modopen("fs/sharefs",
2592da6c28aaSamw 	    KRTLD_MODE_FIRST, &error)) == NULL)) {
2593da6c28aaSamw 		return (ENOSYS);
2594da6c28aaSamw 	}
2595da6c28aaSamw 	if (zshare_fs == NULL && ((zshare_fs =
2596da6c28aaSamw 	    (int (*)(enum sharefs_sys_op, share_t *, uint32_t))
2597da6c28aaSamw 	    ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) {
2598da6c28aaSamw 		return (ENOSYS);
2599da6c28aaSamw 	}
2600da6c28aaSamw 	return (0);
2601da6c28aaSamw }
2602da6c28aaSamw 
2603ecd6cf80Smarks static int
2604ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc)
2605ecd6cf80Smarks {
2606ecd6cf80Smarks 	int error;
2607ecd6cf80Smarks 	int opcode;
2608ecd6cf80Smarks 
2609da6c28aaSamw 	switch (zc->zc_share.z_sharetype) {
2610da6c28aaSamw 	case ZFS_SHARE_NFS:
2611da6c28aaSamw 	case ZFS_UNSHARE_NFS:
2612da6c28aaSamw 		if (zfs_nfsshare_inited == 0) {
2613da6c28aaSamw 			mutex_enter(&zfs_share_lock);
2614da6c28aaSamw 			if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs",
2615da6c28aaSamw 			    KRTLD_MODE_FIRST, &error)) == NULL)) {
2616da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2617da6c28aaSamw 				return (ENOSYS);
2618da6c28aaSamw 			}
2619da6c28aaSamw 			if (znfsexport_fs == NULL &&
2620da6c28aaSamw 			    ((znfsexport_fs = (int (*)(void *))
2621da6c28aaSamw 			    ddi_modsym(nfs_mod,
2622da6c28aaSamw 			    "nfs_export", &error)) == NULL)) {
2623da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2624da6c28aaSamw 				return (ENOSYS);
2625da6c28aaSamw 			}
2626da6c28aaSamw 			error = zfs_init_sharefs();
2627da6c28aaSamw 			if (error) {
2628da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2629da6c28aaSamw 				return (ENOSYS);
2630da6c28aaSamw 			}
2631da6c28aaSamw 			zfs_nfsshare_inited = 1;
2632ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2633ecd6cf80Smarks 		}
2634da6c28aaSamw 		break;
2635da6c28aaSamw 	case ZFS_SHARE_SMB:
2636da6c28aaSamw 	case ZFS_UNSHARE_SMB:
2637da6c28aaSamw 		if (zfs_smbshare_inited == 0) {
2638da6c28aaSamw 			mutex_enter(&zfs_share_lock);
2639da6c28aaSamw 			if (smbsrv_mod == NULL && ((smbsrv_mod =
2640da6c28aaSamw 			    ddi_modopen("drv/smbsrv",
2641da6c28aaSamw 			    KRTLD_MODE_FIRST, &error)) == NULL)) {
2642da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2643da6c28aaSamw 				return (ENOSYS);
2644da6c28aaSamw 			}
2645da6c28aaSamw 			if (zsmbexport_fs == NULL && ((zsmbexport_fs =
2646da6c28aaSamw 			    (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod,
2647da6c28aaSamw 			    "lmshrd_share_upcall", &error)) == NULL)) {
2648da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2649da6c28aaSamw 				return (ENOSYS);
2650da6c28aaSamw 			}
2651da6c28aaSamw 			error = zfs_init_sharefs();
2652da6c28aaSamw 			if (error) {
2653da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2654da6c28aaSamw 				return (ENOSYS);
2655da6c28aaSamw 			}
2656da6c28aaSamw 			zfs_smbshare_inited = 1;
2657ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2658ecd6cf80Smarks 		}
2659da6c28aaSamw 		break;
2660da6c28aaSamw 	default:
2661da6c28aaSamw 		return (EINVAL);
2662da6c28aaSamw 	}
2663ecd6cf80Smarks 
2664da6c28aaSamw 	switch (zc->zc_share.z_sharetype) {
2665da6c28aaSamw 	case ZFS_SHARE_NFS:
2666da6c28aaSamw 	case ZFS_UNSHARE_NFS:
2667da6c28aaSamw 		if (error =
2668da6c28aaSamw 		    znfsexport_fs((void *)
2669da6c28aaSamw 		    (uintptr_t)zc->zc_share.z_exportdata))
2670da6c28aaSamw 			return (error);
2671da6c28aaSamw 		break;
2672da6c28aaSamw 	case ZFS_SHARE_SMB:
2673da6c28aaSamw 	case ZFS_UNSHARE_SMB:
2674da6c28aaSamw 		if (error = zsmbexport_fs((void *)
2675da6c28aaSamw 		    (uintptr_t)zc->zc_share.z_exportdata,
2676da6c28aaSamw 		    zc->zc_share.z_sharetype == ZFS_SHARE_SMB ?
2677da6c28aaSamw 		    B_TRUE : B_FALSE)) {
2678da6c28aaSamw 			return (error);
2679ecd6cf80Smarks 		}
2680da6c28aaSamw 		break;
2681ecd6cf80Smarks 	}
2682ecd6cf80Smarks 
2683da6c28aaSamw 	opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS ||
2684da6c28aaSamw 	    zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ?
2685ecd6cf80Smarks 	    SHAREFS_ADD : SHAREFS_REMOVE;
2686ecd6cf80Smarks 
2687da6c28aaSamw 	/*
2688da6c28aaSamw 	 * Add or remove share from sharetab
2689da6c28aaSamw 	 */
2690ecd6cf80Smarks 	error = zshare_fs(opcode,
2691ecd6cf80Smarks 	    (void *)(uintptr_t)zc->zc_share.z_sharedata,
2692ecd6cf80Smarks 	    zc->zc_share.z_sharemax);
2693ecd6cf80Smarks 
2694ecd6cf80Smarks 	return (error);
2695ecd6cf80Smarks 
2696ecd6cf80Smarks }
2697ecd6cf80Smarks 
2698ecd6cf80Smarks /*
26992a6b87f0Sek  * pool create, destroy, and export don't log the history as part of
27002a6b87f0Sek  * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export
27012a6b87f0Sek  * do the logging of those commands.
2702ecd6cf80Smarks  */
2703fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = {
2704228975ccSek 	{ zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2705e7437265Sahrens 	{ zfs_ioc_pool_destroy,	zfs_secpolicy_config, POOL_NAME, B_FALSE },
2706e7437265Sahrens 	{ zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2707e7437265Sahrens 	{ zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2708e7437265Sahrens 	{ zfs_ioc_pool_configs,	zfs_secpolicy_none, NO_NAME, B_FALSE },
2709e7437265Sahrens 	{ zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE },
2710e7437265Sahrens 	{ zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE },
2711e7437265Sahrens 	{ zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2712e7437265Sahrens 	{ zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE },
2713e7437265Sahrens 	{ zfs_ioc_pool_upgrade,	zfs_secpolicy_config, POOL_NAME, B_TRUE },
2714e7437265Sahrens 	{ zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2715e7437265Sahrens 	{ zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2716e7437265Sahrens 	{ zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2717e7437265Sahrens 	{ zfs_ioc_vdev_set_state, zfs_secpolicy_config,	POOL_NAME, B_TRUE },
2718e7437265Sahrens 	{ zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2719e7437265Sahrens 	{ zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2720e7437265Sahrens 	{ zfs_ioc_vdev_setpath,	zfs_secpolicy_config, POOL_NAME, B_FALSE },
2721e7437265Sahrens 	{ zfs_ioc_objset_stats,	zfs_secpolicy_read, DATASET_NAME, B_FALSE },
2722bd00f61bSrm 	{ zfs_ioc_objset_version, zfs_secpolicy_read, DATASET_NAME, B_FALSE },
2723ecd6cf80Smarks 	{ zfs_ioc_dataset_list_next, zfs_secpolicy_read,
2724e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2725ecd6cf80Smarks 	{ zfs_ioc_snapshot_list_next, zfs_secpolicy_read,
2726e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2727e7437265Sahrens 	{ zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE },
2728e7437265Sahrens 	{ zfs_ioc_create_minor,	zfs_secpolicy_minor, DATASET_NAME, B_FALSE },
2729e7437265Sahrens 	{ zfs_ioc_remove_minor,	zfs_secpolicy_minor, DATASET_NAME, B_FALSE },
2730e7437265Sahrens 	{ zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE },
2731e7437265Sahrens 	{ zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE },
2732e7437265Sahrens 	{ zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE },
2733e7437265Sahrens 	{ zfs_ioc_rename, zfs_secpolicy_rename,	DATASET_NAME, B_TRUE },
27343cb34c60Sahrens 	{ zfs_ioc_recv, zfs_secpolicy_receive, DATASET_NAME, B_TRUE },
27353cb34c60Sahrens 	{ zfs_ioc_send, zfs_secpolicy_send, DATASET_NAME, B_TRUE },
2736e7437265Sahrens 	{ zfs_ioc_inject_fault,	zfs_secpolicy_inject, NO_NAME, B_FALSE },
2737e7437265Sahrens 	{ zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE },
2738e7437265Sahrens 	{ zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE },
2739e7437265Sahrens 	{ zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE },
2740e7437265Sahrens 	{ zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2741e7437265Sahrens 	{ zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE },
2742e7437265Sahrens 	{ zfs_ioc_destroy_snaps, zfs_secpolicy_destroy,	DATASET_NAME, B_TRUE },
2743e7437265Sahrens 	{ zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE },
2744e7437265Sahrens 	{ zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2745e7437265Sahrens 	{ zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE },
2746e7437265Sahrens 	{ zfs_ioc_pool_set_props, zfs_secpolicy_config,	POOL_NAME, B_TRUE },
2747e7437265Sahrens 	{ zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE },
2748e7437265Sahrens 	{ zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE },
2749e7437265Sahrens 	{ zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE },
2750ecd6cf80Smarks 	{ zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi,
2751e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2752e45ce728Sahrens 	{ zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE },
2753e45ce728Sahrens 	{ zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE },
2754fa9e4066Sahrens };
2755fa9e4066Sahrens 
2756fa9e4066Sahrens static int
2757fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
2758fa9e4066Sahrens {
2759fa9e4066Sahrens 	zfs_cmd_t *zc;
2760fa9e4066Sahrens 	uint_t vec;
27611d452cf5Sahrens 	int error, rc;
2762fa9e4066Sahrens 
2763fa9e4066Sahrens 	if (getminor(dev) != 0)
2764fa9e4066Sahrens 		return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp));
2765fa9e4066Sahrens 
2766fa9e4066Sahrens 	vec = cmd - ZFS_IOC;
276791ebeef5Sahrens 	ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip));
2768fa9e4066Sahrens 
2769fa9e4066Sahrens 	if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
2770fa9e4066Sahrens 		return (EINVAL);
2771fa9e4066Sahrens 
2772fa9e4066Sahrens 	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
2773fa9e4066Sahrens 
2774fa9e4066Sahrens 	error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t));
2775fa9e4066Sahrens 
277691ebeef5Sahrens 	if (error == 0)
2777ecd6cf80Smarks 		error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr);
2778fa9e4066Sahrens 
2779fa9e4066Sahrens 	/*
2780fa9e4066Sahrens 	 * Ensure that all pool/dataset names are valid before we pass down to
2781fa9e4066Sahrens 	 * the lower layers.
2782fa9e4066Sahrens 	 */
2783fa9e4066Sahrens 	if (error == 0) {
2784fa9e4066Sahrens 		zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
2785fa9e4066Sahrens 		switch (zfs_ioc_vec[vec].zvec_namecheck) {
2786e7437265Sahrens 		case POOL_NAME:
2787fa9e4066Sahrens 			if (pool_namecheck(zc->zc_name, NULL, NULL) != 0)
2788fa9e4066Sahrens 				error = EINVAL;
2789fa9e4066Sahrens 			break;
2790fa9e4066Sahrens 
2791e7437265Sahrens 		case DATASET_NAME:
2792fa9e4066Sahrens 			if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0)
2793fa9e4066Sahrens 				error = EINVAL;
2794fa9e4066Sahrens 			break;
27955ad82045Snd 
2796e7437265Sahrens 		case NO_NAME:
27975ad82045Snd 			break;
2798fa9e4066Sahrens 		}
2799fa9e4066Sahrens 	}
2800fa9e4066Sahrens 
2801fa9e4066Sahrens 	if (error == 0)
2802fa9e4066Sahrens 		error = zfs_ioc_vec[vec].zvec_func(zc);
2803fa9e4066Sahrens 
28041d452cf5Sahrens 	rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t));
2805ecd6cf80Smarks 	if (error == 0) {
28061d452cf5Sahrens 		error = rc;
2807ecd6cf80Smarks 		if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE)
2808ecd6cf80Smarks 			zfs_log_history(zc);
2809ecd6cf80Smarks 	}
2810fa9e4066Sahrens 
2811fa9e4066Sahrens 	kmem_free(zc, sizeof (zfs_cmd_t));
2812fa9e4066Sahrens 	return (error);
2813fa9e4066Sahrens }
2814fa9e4066Sahrens 
2815fa9e4066Sahrens static int
2816fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2817fa9e4066Sahrens {
2818fa9e4066Sahrens 	if (cmd != DDI_ATTACH)
2819fa9e4066Sahrens 		return (DDI_FAILURE);
2820fa9e4066Sahrens 
2821fa9e4066Sahrens 	if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0,
2822fa9e4066Sahrens 	    DDI_PSEUDO, 0) == DDI_FAILURE)
2823fa9e4066Sahrens 		return (DDI_FAILURE);
2824fa9e4066Sahrens 
2825fa9e4066Sahrens 	zfs_dip = dip;
2826fa9e4066Sahrens 
2827fa9e4066Sahrens 	ddi_report_dev(dip);
2828fa9e4066Sahrens 
2829fa9e4066Sahrens 	return (DDI_SUCCESS);
2830fa9e4066Sahrens }
2831fa9e4066Sahrens 
2832fa9e4066Sahrens static int
2833fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2834fa9e4066Sahrens {
2835fa9e4066Sahrens 	if (spa_busy() || zfs_busy() || zvol_busy())
2836fa9e4066Sahrens 		return (DDI_FAILURE);
2837fa9e4066Sahrens 
2838fa9e4066Sahrens 	if (cmd != DDI_DETACH)
2839fa9e4066Sahrens 		return (DDI_FAILURE);
2840fa9e4066Sahrens 
2841fa9e4066Sahrens 	zfs_dip = NULL;
2842fa9e4066Sahrens 
2843fa9e4066Sahrens 	ddi_prop_remove_all(dip);
2844fa9e4066Sahrens 	ddi_remove_minor_node(dip, NULL);
2845fa9e4066Sahrens 
2846fa9e4066Sahrens 	return (DDI_SUCCESS);
2847fa9e4066Sahrens }
2848fa9e4066Sahrens 
2849fa9e4066Sahrens /*ARGSUSED*/
2850fa9e4066Sahrens static int
2851fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2852fa9e4066Sahrens {
2853fa9e4066Sahrens 	switch (infocmd) {
2854fa9e4066Sahrens 	case DDI_INFO_DEVT2DEVINFO:
2855fa9e4066Sahrens 		*result = zfs_dip;
2856fa9e4066Sahrens 		return (DDI_SUCCESS);
2857fa9e4066Sahrens 
2858fa9e4066Sahrens 	case DDI_INFO_DEVT2INSTANCE:
2859a0965f35Sbonwick 		*result = (void *)0;
2860fa9e4066Sahrens 		return (DDI_SUCCESS);
2861fa9e4066Sahrens 	}
2862fa9e4066Sahrens 
2863fa9e4066Sahrens 	return (DDI_FAILURE);
2864fa9e4066Sahrens }
2865fa9e4066Sahrens 
2866fa9e4066Sahrens /*
2867fa9e4066Sahrens  * OK, so this is a little weird.
2868fa9e4066Sahrens  *
2869fa9e4066Sahrens  * /dev/zfs is the control node, i.e. minor 0.
2870fa9e4066Sahrens  * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0.
2871fa9e4066Sahrens  *
2872fa9e4066Sahrens  * /dev/zfs has basically nothing to do except serve up ioctls,
2873fa9e4066Sahrens  * so most of the standard driver entry points are in zvol.c.
2874fa9e4066Sahrens  */
2875fa9e4066Sahrens static struct cb_ops zfs_cb_ops = {
2876fa9e4066Sahrens 	zvol_open,	/* open */
2877fa9e4066Sahrens 	zvol_close,	/* close */
2878fa9e4066Sahrens 	zvol_strategy,	/* strategy */
2879fa9e4066Sahrens 	nodev,		/* print */
2880fa9e4066Sahrens 	nodev,		/* dump */
2881fa9e4066Sahrens 	zvol_read,	/* read */
2882fa9e4066Sahrens 	zvol_write,	/* write */
2883fa9e4066Sahrens 	zfsdev_ioctl,	/* ioctl */
2884fa9e4066Sahrens 	nodev,		/* devmap */
2885fa9e4066Sahrens 	nodev,		/* mmap */
2886fa9e4066Sahrens 	nodev,		/* segmap */
2887fa9e4066Sahrens 	nochpoll,	/* poll */
2888fa9e4066Sahrens 	ddi_prop_op,	/* prop_op */
2889fa9e4066Sahrens 	NULL,		/* streamtab */
2890fa9e4066Sahrens 	D_NEW | D_MP | D_64BIT,		/* Driver compatibility flag */
2891fa9e4066Sahrens 	CB_REV,		/* version */
2892feb08c6bSbillm 	nodev,		/* async read */
2893feb08c6bSbillm 	nodev,		/* async write */
2894fa9e4066Sahrens };
2895fa9e4066Sahrens 
2896fa9e4066Sahrens static struct dev_ops zfs_dev_ops = {
2897fa9e4066Sahrens 	DEVO_REV,	/* version */
2898fa9e4066Sahrens 	0,		/* refcnt */
2899fa9e4066Sahrens 	zfs_info,	/* info */
2900fa9e4066Sahrens 	nulldev,	/* identify */
2901fa9e4066Sahrens 	nulldev,	/* probe */
2902fa9e4066Sahrens 	zfs_attach,	/* attach */
2903fa9e4066Sahrens 	zfs_detach,	/* detach */
2904fa9e4066Sahrens 	nodev,		/* reset */
2905fa9e4066Sahrens 	&zfs_cb_ops,	/* driver operations */
2906fa9e4066Sahrens 	NULL		/* no bus operations */
2907fa9e4066Sahrens };
2908fa9e4066Sahrens 
2909fa9e4066Sahrens static struct modldrv zfs_modldrv = {
2910e7437265Sahrens 	&mod_driverops, "ZFS storage pool version " SPA_VERSION_STRING,
2911e9dbad6fSeschrock 	    &zfs_dev_ops
2912fa9e4066Sahrens };
2913fa9e4066Sahrens 
2914fa9e4066Sahrens static struct modlinkage modlinkage = {
2915fa9e4066Sahrens 	MODREV_1,
2916fa9e4066Sahrens 	(void *)&zfs_modlfs,
2917fa9e4066Sahrens 	(void *)&zfs_modldrv,
2918fa9e4066Sahrens 	NULL
2919fa9e4066Sahrens };
2920fa9e4066Sahrens 
2921ec533521Sfr 
2922ec533521Sfr uint_t zfs_fsyncer_key;
2923f18faf3fSek extern uint_t rrw_tsd_key;
2924ec533521Sfr 
2925fa9e4066Sahrens int
2926fa9e4066Sahrens _init(void)
2927fa9e4066Sahrens {
2928fa9e4066Sahrens 	int error;
2929fa9e4066Sahrens 
2930a0965f35Sbonwick 	spa_init(FREAD | FWRITE);
2931a0965f35Sbonwick 	zfs_init();
2932a0965f35Sbonwick 	zvol_init();
2933a0965f35Sbonwick 
2934a0965f35Sbonwick 	if ((error = mod_install(&modlinkage)) != 0) {
2935a0965f35Sbonwick 		zvol_fini();
2936a0965f35Sbonwick 		zfs_fini();
2937a0965f35Sbonwick 		spa_fini();
2938fa9e4066Sahrens 		return (error);
2939a0965f35Sbonwick 	}
2940fa9e4066Sahrens 
2941ec533521Sfr 	tsd_create(&zfs_fsyncer_key, NULL);
2942f18faf3fSek 	tsd_create(&rrw_tsd_key, NULL);
2943ec533521Sfr 
2944fa9e4066Sahrens 	error = ldi_ident_from_mod(&modlinkage, &zfs_li);
2945fa9e4066Sahrens 	ASSERT(error == 0);
2946ecd6cf80Smarks 	mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL);
2947fa9e4066Sahrens 
2948fa9e4066Sahrens 	return (0);
2949fa9e4066Sahrens }
2950fa9e4066Sahrens 
2951fa9e4066Sahrens int
2952fa9e4066Sahrens _fini(void)
2953fa9e4066Sahrens {
2954fa9e4066Sahrens 	int error;
2955fa9e4066Sahrens 
2956ea8dc4b6Seschrock 	if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled)
2957fa9e4066Sahrens 		return (EBUSY);
2958fa9e4066Sahrens 
2959fa9e4066Sahrens 	if ((error = mod_remove(&modlinkage)) != 0)
2960fa9e4066Sahrens 		return (error);
2961fa9e4066Sahrens 
2962fa9e4066Sahrens 	zvol_fini();
2963fa9e4066Sahrens 	zfs_fini();
2964fa9e4066Sahrens 	spa_fini();
2965da6c28aaSamw 	if (zfs_nfsshare_inited)
2966ecd6cf80Smarks 		(void) ddi_modclose(nfs_mod);
2967da6c28aaSamw 	if (zfs_smbshare_inited)
2968da6c28aaSamw 		(void) ddi_modclose(smbsrv_mod);
2969da6c28aaSamw 	if (zfs_nfsshare_inited || zfs_smbshare_inited)
2970ecd6cf80Smarks 		(void) ddi_modclose(sharefs_mod);
2971fa9e4066Sahrens 
2972ec533521Sfr 	tsd_destroy(&zfs_fsyncer_key);
2973fa9e4066Sahrens 	ldi_ident_release(zfs_li);
2974fa9e4066Sahrens 	zfs_li = NULL;
2975ecd6cf80Smarks 	mutex_destroy(&zfs_share_lock);
2976fa9e4066Sahrens 
2977fa9e4066Sahrens 	return (error);
2978fa9e4066Sahrens }
2979fa9e4066Sahrens 
2980fa9e4066Sahrens int
2981fa9e4066Sahrens _info(struct modinfo *modinfop)
2982fa9e4066Sahrens {
2983fa9e4066Sahrens 	return (mod_info(&modlinkage, modinfop));
2984fa9e4066Sahrens }
2985