xref: /illumos-gate/usr/src/uts/common/fs/zfs/zfs_ioctl.c (revision da6c28aa)
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>
41*da6c28aaSamw #include <sys/zfs_i18n.h>
42*da6c28aaSamw #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>
65*da6c28aaSamw #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*da6c28aaSamw static int
161*da6c28aaSamw zfs_check_version(const char *name, int version)
162*da6c28aaSamw {
163*da6c28aaSamw 
164*da6c28aaSamw 	spa_t *spa;
165*da6c28aaSamw 
166*da6c28aaSamw 	if (spa_open(name, &spa, FTAG) == 0) {
167*da6c28aaSamw 		if (spa_version(spa) < version) {
168*da6c28aaSamw 			spa_close(spa, FTAG);
169*da6c28aaSamw 			return (1);
170*da6c28aaSamw 		}
171*da6c28aaSamw 		spa_close(spa, FTAG);
172*da6c28aaSamw 	}
173*da6c28aaSamw 	return (0);
174*da6c28aaSamw }
175*da6c28aaSamw 
176228975ccSek static void
177228975ccSek zfs_log_history(zfs_cmd_t *zc)
178228975ccSek {
179228975ccSek 	spa_t *spa;
180228975ccSek 	char *buf;
181ecd6cf80Smarks 
182228975ccSek 	if ((buf = history_str_get(zc)) == NULL)
183228975ccSek 		return;
184228975ccSek 
185228975ccSek 	if (spa_open(zc->zc_name, &spa, FTAG) == 0) {
186228975ccSek 		if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY)
187228975ccSek 			(void) spa_history_log(spa, buf, LOG_CMD_NORMAL);
188228975ccSek 		spa_close(spa, FTAG);
189228975ccSek 	}
190228975ccSek 	history_str_free(buf);
191ecd6cf80Smarks }
192ecd6cf80Smarks 
193fa9e4066Sahrens /*
194fa9e4066Sahrens  * Policy for top-level read operations (list pools).  Requires no privileges,
195fa9e4066Sahrens  * and can be used in the local zone, as there is no associated dataset.
196fa9e4066Sahrens  */
197fa9e4066Sahrens /* ARGSUSED */
198fa9e4066Sahrens static int
199ecd6cf80Smarks zfs_secpolicy_none(zfs_cmd_t *zc, cred_t *cr)
200fa9e4066Sahrens {
201fa9e4066Sahrens 	return (0);
202fa9e4066Sahrens }
203fa9e4066Sahrens 
204fa9e4066Sahrens /*
205fa9e4066Sahrens  * Policy for dataset read operations (list children, get statistics).  Requires
206fa9e4066Sahrens  * no privileges, but must be visible in the local zone.
207fa9e4066Sahrens  */
208fa9e4066Sahrens /* ARGSUSED */
209fa9e4066Sahrens static int
210ecd6cf80Smarks zfs_secpolicy_read(zfs_cmd_t *zc, cred_t *cr)
211fa9e4066Sahrens {
212fa9e4066Sahrens 	if (INGLOBALZONE(curproc) ||
213ecd6cf80Smarks 	    zone_dataset_visible(zc->zc_name, NULL))
214fa9e4066Sahrens 		return (0);
215fa9e4066Sahrens 
216fa9e4066Sahrens 	return (ENOENT);
217fa9e4066Sahrens }
218fa9e4066Sahrens 
219fa9e4066Sahrens static int
220fa9e4066Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr)
221fa9e4066Sahrens {
222fa9e4066Sahrens 	uint64_t zoned;
223fa9e4066Sahrens 	int writable = 1;
224fa9e4066Sahrens 
225fa9e4066Sahrens 	/*
226fa9e4066Sahrens 	 * The dataset must be visible by this zone -- check this first
227fa9e4066Sahrens 	 * so they don't see EPERM on something they shouldn't know about.
228fa9e4066Sahrens 	 */
229fa9e4066Sahrens 	if (!INGLOBALZONE(curproc) &&
230fa9e4066Sahrens 	    !zone_dataset_visible(dataset, &writable))
231fa9e4066Sahrens 		return (ENOENT);
232fa9e4066Sahrens 
233fa9e4066Sahrens 	if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL))
234fa9e4066Sahrens 		return (ENOENT);
235fa9e4066Sahrens 
236fa9e4066Sahrens 	if (INGLOBALZONE(curproc)) {
237fa9e4066Sahrens 		/*
238fa9e4066Sahrens 		 * If the fs is zoned, only root can access it from the
239fa9e4066Sahrens 		 * global zone.
240fa9e4066Sahrens 		 */
241fa9e4066Sahrens 		if (secpolicy_zfs(cr) && zoned)
242fa9e4066Sahrens 			return (EPERM);
243fa9e4066Sahrens 	} else {
244fa9e4066Sahrens 		/*
245fa9e4066Sahrens 		 * If we are in a local zone, the 'zoned' property must be set.
246fa9e4066Sahrens 		 */
247fa9e4066Sahrens 		if (!zoned)
248fa9e4066Sahrens 			return (EPERM);
249fa9e4066Sahrens 
250fa9e4066Sahrens 		/* must be writable by this zone */
251fa9e4066Sahrens 		if (!writable)
252fa9e4066Sahrens 			return (EPERM);
253fa9e4066Sahrens 	}
254fa9e4066Sahrens 	return (0);
255fa9e4066Sahrens }
256fa9e4066Sahrens 
257fa9e4066Sahrens int
258ecd6cf80Smarks zfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr)
259fa9e4066Sahrens {
260fa9e4066Sahrens 	int error;
261fa9e4066Sahrens 
262ecd6cf80Smarks 	error = zfs_dozonecheck(name, cr);
263ecd6cf80Smarks 	if (error == 0) {
264ecd6cf80Smarks 		error = secpolicy_zfs(cr);
265db870a07Sahrens 		if (error)
266ecd6cf80Smarks 			error = dsl_deleg_access(name, perm, cr);
267ecd6cf80Smarks 	}
268ecd6cf80Smarks 	return (error);
269ecd6cf80Smarks }
270ecd6cf80Smarks 
271ecd6cf80Smarks static int
272ecd6cf80Smarks zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr)
273ecd6cf80Smarks {
274ecd6cf80Smarks 	/*
275ecd6cf80Smarks 	 * Check permissions for special properties.
276ecd6cf80Smarks 	 */
277ecd6cf80Smarks 	switch (prop) {
278ecd6cf80Smarks 	case ZFS_PROP_ZONED:
279ecd6cf80Smarks 		/*
280ecd6cf80Smarks 		 * Disallow setting of 'zoned' from within a local zone.
281ecd6cf80Smarks 		 */
282ecd6cf80Smarks 		if (!INGLOBALZONE(curproc))
283ecd6cf80Smarks 			return (EPERM);
284ecd6cf80Smarks 		break;
285ecd6cf80Smarks 
286ecd6cf80Smarks 	case ZFS_PROP_QUOTA:
287ecd6cf80Smarks 		if (!INGLOBALZONE(curproc)) {
288ecd6cf80Smarks 			uint64_t zoned;
289ecd6cf80Smarks 			char setpoint[MAXNAMELEN];
290ecd6cf80Smarks 			/*
291ecd6cf80Smarks 			 * Unprivileged users are allowed to modify the
292ecd6cf80Smarks 			 * quota on things *under* (ie. contained by)
293ecd6cf80Smarks 			 * the thing they own.
294ecd6cf80Smarks 			 */
295ecd6cf80Smarks 			if (dsl_prop_get_integer(name, "zoned", &zoned,
296ecd6cf80Smarks 			    setpoint))
297ecd6cf80Smarks 				return (EPERM);
298db870a07Sahrens 			if (!zoned || strlen(name) <= strlen(setpoint))
299ecd6cf80Smarks 				return (EPERM);
300ecd6cf80Smarks 		}
301db870a07Sahrens 		break;
302ecd6cf80Smarks 	}
303ecd6cf80Smarks 
30491ebeef5Sahrens 	return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr));
305ecd6cf80Smarks }
306ecd6cf80Smarks 
307ecd6cf80Smarks int
308ecd6cf80Smarks zfs_secpolicy_fsacl(zfs_cmd_t *zc, cred_t *cr)
309ecd6cf80Smarks {
310ecd6cf80Smarks 	int error;
311ecd6cf80Smarks 
312ecd6cf80Smarks 	error = zfs_dozonecheck(zc->zc_name, cr);
313ecd6cf80Smarks 	if (error)
314fa9e4066Sahrens 		return (error);
315fa9e4066Sahrens 
316ecd6cf80Smarks 	/*
317ecd6cf80Smarks 	 * permission to set permissions will be evaluated later in
318ecd6cf80Smarks 	 * dsl_deleg_can_allow()
319ecd6cf80Smarks 	 */
320ecd6cf80Smarks 	return (0);
321ecd6cf80Smarks }
322ecd6cf80Smarks 
323ecd6cf80Smarks int
324ecd6cf80Smarks zfs_secpolicy_rollback(zfs_cmd_t *zc, cred_t *cr)
325ecd6cf80Smarks {
326ecd6cf80Smarks 	int error;
327ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(zc->zc_name,
328ecd6cf80Smarks 	    ZFS_DELEG_PERM_ROLLBACK, cr);
329ecd6cf80Smarks 	if (error == 0)
330ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(zc->zc_name,
331ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr);
332ecd6cf80Smarks 	return (error);
333ecd6cf80Smarks }
334ecd6cf80Smarks 
335ecd6cf80Smarks int
336ecd6cf80Smarks zfs_secpolicy_send(zfs_cmd_t *zc, cred_t *cr)
337ecd6cf80Smarks {
338ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(zc->zc_name,
339ecd6cf80Smarks 	    ZFS_DELEG_PERM_SEND, cr));
340ecd6cf80Smarks }
341ecd6cf80Smarks 
342ecd6cf80Smarks int
343ecd6cf80Smarks zfs_secpolicy_share(zfs_cmd_t *zc, cred_t *cr)
344ecd6cf80Smarks {
345ecd6cf80Smarks 	if (!INGLOBALZONE(curproc))
346ecd6cf80Smarks 		return (EPERM);
347ecd6cf80Smarks 
348ecd6cf80Smarks 	if (secpolicy_nfs(CRED()) == 0) {
349ecd6cf80Smarks 		return (0);
350ecd6cf80Smarks 	} else {
351ecd6cf80Smarks 		vnode_t *vp;
352ecd6cf80Smarks 		int error;
353ecd6cf80Smarks 
354ecd6cf80Smarks 		if ((error = lookupname(zc->zc_value, UIO_SYSSPACE,
355ecd6cf80Smarks 		    NO_FOLLOW, NULL, &vp)) != 0)
356ecd6cf80Smarks 			return (error);
357ecd6cf80Smarks 
358ecd6cf80Smarks 		/* Now make sure mntpnt and dataset are ZFS */
359ecd6cf80Smarks 
360ecd6cf80Smarks 		if (vp->v_vfsp->vfs_fstype != zfsfstype ||
361ecd6cf80Smarks 		    (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource),
362ecd6cf80Smarks 		    zc->zc_name) != 0)) {
363ecd6cf80Smarks 			VN_RELE(vp);
364ecd6cf80Smarks 			return (EPERM);
365ecd6cf80Smarks 		}
366ecd6cf80Smarks 
367ecd6cf80Smarks 		VN_RELE(vp);
368ecd6cf80Smarks 		return (dsl_deleg_access(zc->zc_name,
369ecd6cf80Smarks 		    ZFS_DELEG_PERM_SHARE, cr));
370ecd6cf80Smarks 	}
371fa9e4066Sahrens }
372fa9e4066Sahrens 
373fa9e4066Sahrens static int
374ecd6cf80Smarks zfs_get_parent(const char *datasetname, char *parent, int parentsize)
375fa9e4066Sahrens {
376fa9e4066Sahrens 	char *cp;
377fa9e4066Sahrens 
378fa9e4066Sahrens 	/*
379fa9e4066Sahrens 	 * Remove the @bla or /bla from the end of the name to get the parent.
380fa9e4066Sahrens 	 */
381ecd6cf80Smarks 	(void) strncpy(parent, datasetname, parentsize);
382ecd6cf80Smarks 	cp = strrchr(parent, '@');
383fa9e4066Sahrens 	if (cp != NULL) {
384fa9e4066Sahrens 		cp[0] = '\0';
385fa9e4066Sahrens 	} else {
386ecd6cf80Smarks 		cp = strrchr(parent, '/');
387fa9e4066Sahrens 		if (cp == NULL)
388fa9e4066Sahrens 			return (ENOENT);
389fa9e4066Sahrens 		cp[0] = '\0';
390ecd6cf80Smarks 	}
391ecd6cf80Smarks 
392ecd6cf80Smarks 	return (0);
393ecd6cf80Smarks }
394ecd6cf80Smarks 
395ecd6cf80Smarks int
396ecd6cf80Smarks zfs_secpolicy_destroy_perms(const char *name, cred_t *cr)
397ecd6cf80Smarks {
398ecd6cf80Smarks 	int error;
399ecd6cf80Smarks 
400ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(name,
401ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
402ecd6cf80Smarks 		return (error);
403ecd6cf80Smarks 
404ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(name, ZFS_DELEG_PERM_DESTROY, cr));
405ecd6cf80Smarks }
406ecd6cf80Smarks 
407ecd6cf80Smarks static int
408ecd6cf80Smarks zfs_secpolicy_destroy(zfs_cmd_t *zc, cred_t *cr)
409ecd6cf80Smarks {
410ecd6cf80Smarks 	return (zfs_secpolicy_destroy_perms(zc->zc_name, cr));
411ecd6cf80Smarks }
412ecd6cf80Smarks 
413ecd6cf80Smarks /*
414ecd6cf80Smarks  * Must have sys_config privilege to check the iscsi permission
415ecd6cf80Smarks  */
416ecd6cf80Smarks /* ARGSUSED */
417ecd6cf80Smarks static int
418ecd6cf80Smarks zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr)
419ecd6cf80Smarks {
420ecd6cf80Smarks 	return (secpolicy_zfs(cr));
421ecd6cf80Smarks }
422ecd6cf80Smarks 
423ecd6cf80Smarks int
424ecd6cf80Smarks zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
425ecd6cf80Smarks {
426ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
427ecd6cf80Smarks 	int	error;
428ecd6cf80Smarks 
429ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(from,
430ecd6cf80Smarks 	    ZFS_DELEG_PERM_RENAME, cr)) != 0)
431ecd6cf80Smarks 		return (error);
432ecd6cf80Smarks 
433ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(from,
434ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
435ecd6cf80Smarks 		return (error);
436ecd6cf80Smarks 
437ecd6cf80Smarks 	if ((error = zfs_get_parent(to, parentname,
438ecd6cf80Smarks 	    sizeof (parentname))) != 0)
439ecd6cf80Smarks 		return (error);
440ecd6cf80Smarks 
441ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
442ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr)) != 0)
443ecd6cf80Smarks 		return (error);
444ecd6cf80Smarks 
445ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
446ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
447ecd6cf80Smarks 		return (error);
448ecd6cf80Smarks 
449ecd6cf80Smarks 	return (error);
450ecd6cf80Smarks }
451ecd6cf80Smarks 
452ecd6cf80Smarks static int
453ecd6cf80Smarks zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr)
454ecd6cf80Smarks {
455ecd6cf80Smarks 	return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr));
456ecd6cf80Smarks }
457ecd6cf80Smarks 
458ecd6cf80Smarks static int
459ecd6cf80Smarks zfs_secpolicy_promote(zfs_cmd_t *zc, cred_t *cr)
460ecd6cf80Smarks {
461ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
462ecd6cf80Smarks 	objset_t *clone;
463ecd6cf80Smarks 	int error;
464ecd6cf80Smarks 
465ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(zc->zc_name,
466ecd6cf80Smarks 	    ZFS_DELEG_PERM_PROMOTE, cr);
467ecd6cf80Smarks 	if (error)
468ecd6cf80Smarks 		return (error);
469ecd6cf80Smarks 
470ecd6cf80Smarks 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
471ecd6cf80Smarks 	    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
472ecd6cf80Smarks 
473ecd6cf80Smarks 	if (error == 0) {
474ecd6cf80Smarks 		dsl_dataset_t *pclone = NULL;
475ecd6cf80Smarks 		dsl_dir_t *dd;
476ecd6cf80Smarks 		dd = clone->os->os_dsl_dataset->ds_dir;
477ecd6cf80Smarks 
478ecd6cf80Smarks 		rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
479ecd6cf80Smarks 		error = dsl_dataset_open_obj(dd->dd_pool,
480ecd6cf80Smarks 		    dd->dd_phys->dd_clone_parent_obj, NULL,
481ecd6cf80Smarks 		    DS_MODE_NONE, FTAG, &pclone);
482ecd6cf80Smarks 		rw_exit(&dd->dd_pool->dp_config_rwlock);
483ecd6cf80Smarks 		if (error) {
484ecd6cf80Smarks 			dmu_objset_close(clone);
485ecd6cf80Smarks 			return (error);
486ecd6cf80Smarks 		}
487ecd6cf80Smarks 
488ecd6cf80Smarks 		error = zfs_secpolicy_write_perms(zc->zc_name,
489ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr);
490ecd6cf80Smarks 
491ecd6cf80Smarks 		dsl_dataset_name(pclone, parentname);
492ecd6cf80Smarks 		dmu_objset_close(clone);
493ecd6cf80Smarks 		dsl_dataset_close(pclone, DS_MODE_NONE, FTAG);
494ecd6cf80Smarks 		if (error == 0)
495ecd6cf80Smarks 			error = zfs_secpolicy_write_perms(parentname,
496ecd6cf80Smarks 			    ZFS_DELEG_PERM_PROMOTE, cr);
497ecd6cf80Smarks 	}
498ecd6cf80Smarks 	return (error);
499ecd6cf80Smarks }
500ecd6cf80Smarks 
501ecd6cf80Smarks static int
502ecd6cf80Smarks zfs_secpolicy_receive(zfs_cmd_t *zc, cred_t *cr)
503ecd6cf80Smarks {
504ecd6cf80Smarks 	int error;
505ecd6cf80Smarks 
506ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(zc->zc_name,
507ecd6cf80Smarks 	    ZFS_DELEG_PERM_RECEIVE, cr)) != 0)
508ecd6cf80Smarks 		return (error);
509ecd6cf80Smarks 
510ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(zc->zc_name,
511ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr)) != 0)
512ecd6cf80Smarks 		return (error);
513ecd6cf80Smarks 
514ecd6cf80Smarks 	return (zfs_secpolicy_write_perms(zc->zc_name,
515ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr));
516ecd6cf80Smarks }
517ecd6cf80Smarks 
518ecd6cf80Smarks int
519ecd6cf80Smarks zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
520ecd6cf80Smarks {
521ecd6cf80Smarks 	int error;
522ecd6cf80Smarks 
523ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(name,
524ecd6cf80Smarks 	    ZFS_DELEG_PERM_SNAPSHOT, cr)) != 0)
525ecd6cf80Smarks 		return (error);
526ecd6cf80Smarks 
527ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(name,
528ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr);
529ecd6cf80Smarks 
530ecd6cf80Smarks 	return (error);
531ecd6cf80Smarks }
532ecd6cf80Smarks 
533ecd6cf80Smarks static int
534ecd6cf80Smarks zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr)
535ecd6cf80Smarks {
536ecd6cf80Smarks 
537ecd6cf80Smarks 	return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr));
538ecd6cf80Smarks }
539ecd6cf80Smarks 
540ecd6cf80Smarks static int
541ecd6cf80Smarks zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr)
542ecd6cf80Smarks {
543ecd6cf80Smarks 	char 	parentname[MAXNAMELEN];
544ecd6cf80Smarks 	int 	error;
545ecd6cf80Smarks 
546ecd6cf80Smarks 	if ((error = zfs_get_parent(zc->zc_name, parentname,
547ecd6cf80Smarks 	    sizeof (parentname))) != 0)
548ecd6cf80Smarks 		return (error);
549fa9e4066Sahrens 
550ecd6cf80Smarks 	if (zc->zc_value[0] != '\0') {
551ecd6cf80Smarks 		if ((error = zfs_secpolicy_write_perms(zc->zc_value,
552ecd6cf80Smarks 		    ZFS_DELEG_PERM_CLONE, cr)) != 0)
553ecd6cf80Smarks 			return (error);
554fa9e4066Sahrens 	}
555fa9e4066Sahrens 
556ecd6cf80Smarks 	if ((error = zfs_secpolicy_write_perms(parentname,
557ecd6cf80Smarks 	    ZFS_DELEG_PERM_CREATE, cr)) != 0)
558ecd6cf80Smarks 		return (error);
559ecd6cf80Smarks 
560ecd6cf80Smarks 	error = zfs_secpolicy_write_perms(parentname,
561ecd6cf80Smarks 	    ZFS_DELEG_PERM_MOUNT, cr);
562ecd6cf80Smarks 
563ecd6cf80Smarks 	return (error);
564ecd6cf80Smarks }
565ecd6cf80Smarks 
566ecd6cf80Smarks static int
567ecd6cf80Smarks zfs_secpolicy_umount(zfs_cmd_t *zc, cred_t *cr)
568ecd6cf80Smarks {
569ecd6cf80Smarks 	int error;
570ecd6cf80Smarks 
571ecd6cf80Smarks 	error = secpolicy_fs_unmount(cr, NULL);
572ecd6cf80Smarks 	if (error) {
573ecd6cf80Smarks 		error = dsl_deleg_access(zc->zc_name, ZFS_DELEG_PERM_MOUNT, cr);
574ecd6cf80Smarks 	}
575ecd6cf80Smarks 	return (error);
576fa9e4066Sahrens }
577fa9e4066Sahrens 
578fa9e4066Sahrens /*
579fa9e4066Sahrens  * Policy for pool operations - create/destroy pools, add vdevs, etc.  Requires
580fa9e4066Sahrens  * SYS_CONFIG privilege, which is not available in a local zone.
581fa9e4066Sahrens  */
582fa9e4066Sahrens /* ARGSUSED */
583fa9e4066Sahrens static int
584ecd6cf80Smarks zfs_secpolicy_config(zfs_cmd_t *zc, cred_t *cr)
585fa9e4066Sahrens {
586fa9e4066Sahrens 	if (secpolicy_sys_config(cr, B_FALSE) != 0)
587fa9e4066Sahrens 		return (EPERM);
588fa9e4066Sahrens 
589fa9e4066Sahrens 	return (0);
590fa9e4066Sahrens }
591fa9e4066Sahrens 
592ecd6cf80Smarks /*
593ecd6cf80Smarks  * Just like zfs_secpolicy_config, except that we will check for
594ecd6cf80Smarks  * mount permission on the dataset for permission to create/remove
595ecd6cf80Smarks  * the minor nodes.
596ecd6cf80Smarks  */
597ecd6cf80Smarks static int
598ecd6cf80Smarks zfs_secpolicy_minor(zfs_cmd_t *zc, cred_t *cr)
599ecd6cf80Smarks {
600ecd6cf80Smarks 	if (secpolicy_sys_config(cr, B_FALSE) != 0) {
601ecd6cf80Smarks 		return (dsl_deleg_access(zc->zc_name,
602ecd6cf80Smarks 		    ZFS_DELEG_PERM_MOUNT, cr));
603ecd6cf80Smarks 	}
604ecd6cf80Smarks 
605ecd6cf80Smarks 	return (0);
606ecd6cf80Smarks }
607ecd6cf80Smarks 
608ea8dc4b6Seschrock /*
609ea8dc4b6Seschrock  * Policy for fault injection.  Requires all privileges.
610ea8dc4b6Seschrock  */
611ea8dc4b6Seschrock /* ARGSUSED */
612ea8dc4b6Seschrock static int
613ecd6cf80Smarks zfs_secpolicy_inject(zfs_cmd_t *zc, cred_t *cr)
614ea8dc4b6Seschrock {
615ea8dc4b6Seschrock 	return (secpolicy_zinject(cr));
616ea8dc4b6Seschrock }
617ea8dc4b6Seschrock 
618e45ce728Sahrens static int
619e45ce728Sahrens zfs_secpolicy_inherit(zfs_cmd_t *zc, cred_t *cr)
620e45ce728Sahrens {
621e45ce728Sahrens 	zfs_prop_t prop = zfs_name_to_prop(zc->zc_value);
622e45ce728Sahrens 
623990b4856Slling 	if (prop == ZPROP_INVAL) {
624e45ce728Sahrens 		if (!zfs_prop_user(zc->zc_value))
625e45ce728Sahrens 			return (EINVAL);
626e45ce728Sahrens 		return (zfs_secpolicy_write_perms(zc->zc_name,
627e45ce728Sahrens 		    ZFS_DELEG_PERM_USERPROP, cr));
628e45ce728Sahrens 	} else {
629e45ce728Sahrens 		if (!zfs_prop_inheritable(prop))
630e45ce728Sahrens 			return (EINVAL);
631e45ce728Sahrens 		return (zfs_secpolicy_setprop(zc->zc_name, prop, cr));
632e45ce728Sahrens 	}
633e45ce728Sahrens }
634e45ce728Sahrens 
635fa9e4066Sahrens /*
636fa9e4066Sahrens  * Returns the nvlist as specified by the user in the zfs_cmd_t.
637fa9e4066Sahrens  */
638fa9e4066Sahrens static int
639990b4856Slling get_nvlist(uint64_t nvl, uint64_t size, nvlist_t **nvp)
640fa9e4066Sahrens {
641fa9e4066Sahrens 	char *packed;
642fa9e4066Sahrens 	int error;
643990b4856Slling 	nvlist_t *list = NULL;
644fa9e4066Sahrens 
645fa9e4066Sahrens 	/*
646e9dbad6fSeschrock 	 * Read in and unpack the user-supplied nvlist.
647fa9e4066Sahrens 	 */
648990b4856Slling 	if (size == 0)
649fa9e4066Sahrens 		return (EINVAL);
650fa9e4066Sahrens 
651fa9e4066Sahrens 	packed = kmem_alloc(size, KM_SLEEP);
652fa9e4066Sahrens 
653990b4856Slling 	if ((error = xcopyin((void *)(uintptr_t)nvl, packed, size)) != 0) {
654fa9e4066Sahrens 		kmem_free(packed, size);
655fa9e4066Sahrens 		return (error);
656fa9e4066Sahrens 	}
657fa9e4066Sahrens 
658990b4856Slling 	if ((error = nvlist_unpack(packed, size, &list, 0)) != 0) {
659fa9e4066Sahrens 		kmem_free(packed, size);
660fa9e4066Sahrens 		return (error);
661fa9e4066Sahrens 	}
662fa9e4066Sahrens 
663fa9e4066Sahrens 	kmem_free(packed, size);
664fa9e4066Sahrens 
665990b4856Slling 	*nvp = list;
666fa9e4066Sahrens 	return (0);
667fa9e4066Sahrens }
668fa9e4066Sahrens 
669e9dbad6fSeschrock static int
670e9dbad6fSeschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
671e9dbad6fSeschrock {
672e9dbad6fSeschrock 	char *packed = NULL;
673e9dbad6fSeschrock 	size_t size;
674e9dbad6fSeschrock 	int error;
675e9dbad6fSeschrock 
676e9dbad6fSeschrock 	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
677e9dbad6fSeschrock 
678e9dbad6fSeschrock 	if (size > zc->zc_nvlist_dst_size) {
679e9dbad6fSeschrock 		error = ENOMEM;
680e9dbad6fSeschrock 	} else {
681da165920Smarks 		packed = kmem_alloc(size, KM_SLEEP);
682e9dbad6fSeschrock 		VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
683e9dbad6fSeschrock 		    KM_SLEEP) == 0);
684e9dbad6fSeschrock 		error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst,
685e9dbad6fSeschrock 		    size);
686e9dbad6fSeschrock 		kmem_free(packed, size);
687e9dbad6fSeschrock 	}
688e9dbad6fSeschrock 
689e9dbad6fSeschrock 	zc->zc_nvlist_dst_size = size;
690e9dbad6fSeschrock 	return (error);
691e9dbad6fSeschrock }
692e9dbad6fSeschrock 
693fa9e4066Sahrens static int
694fa9e4066Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc)
695fa9e4066Sahrens {
696fa9e4066Sahrens 	int error;
697990b4856Slling 	nvlist_t *config, *props = NULL;
698228975ccSek 	char *buf;
699fa9e4066Sahrens 
700990b4856Slling 	if (error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
701990b4856Slling 	    &config))
702fa9e4066Sahrens 		return (error);
7032a6b87f0Sek 
704990b4856Slling 	if (zc->zc_nvlist_src_size != 0 && (error =
705990b4856Slling 	    get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) {
706990b4856Slling 		nvlist_free(config);
707990b4856Slling 		return (error);
708990b4856Slling 	}
709990b4856Slling 
7102a6b87f0Sek 	buf = history_str_get(zc);
711fa9e4066Sahrens 
712990b4856Slling 	error = spa_create(zc->zc_name, config, props, buf);
713fa9e4066Sahrens 
7142a6b87f0Sek 	if (buf != NULL)
7152a6b87f0Sek 		history_str_free(buf);
716990b4856Slling 
717fa9e4066Sahrens 	nvlist_free(config);
718fa9e4066Sahrens 
719990b4856Slling 	if (props)
720990b4856Slling 		nvlist_free(props);
721990b4856Slling 
722fa9e4066Sahrens 	return (error);
723fa9e4066Sahrens }
724fa9e4066Sahrens 
725fa9e4066Sahrens static int
726fa9e4066Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc)
727fa9e4066Sahrens {
728ecd6cf80Smarks 	int error;
729ecd6cf80Smarks 	zfs_log_history(zc);
730ecd6cf80Smarks 	error = spa_destroy(zc->zc_name);
731ecd6cf80Smarks 	return (error);
732fa9e4066Sahrens }
733fa9e4066Sahrens 
734fa9e4066Sahrens static int
735fa9e4066Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc)
736fa9e4066Sahrens {
737fa9e4066Sahrens 	int error;
738990b4856Slling 	nvlist_t *config, *props = NULL;
739fa9e4066Sahrens 	uint64_t guid;
740fa9e4066Sahrens 
741990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
742990b4856Slling 	    &config)) != 0)
743990b4856Slling 		return (error);
744990b4856Slling 
745990b4856Slling 	if (zc->zc_nvlist_src_size != 0 && (error =
746990b4856Slling 	    get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, &props))) {
747990b4856Slling 		nvlist_free(config);
748fa9e4066Sahrens 		return (error);
749990b4856Slling 	}
750fa9e4066Sahrens 
751fa9e4066Sahrens 	if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
752ea8dc4b6Seschrock 	    guid != zc->zc_guid)
753fa9e4066Sahrens 		error = EINVAL;
754fa9e4066Sahrens 	else
755990b4856Slling 		error = spa_import(zc->zc_name, config, props);
756fa9e4066Sahrens 
757fa9e4066Sahrens 	nvlist_free(config);
758fa9e4066Sahrens 
759990b4856Slling 	if (props)
760990b4856Slling 		nvlist_free(props);
761990b4856Slling 
762fa9e4066Sahrens 	return (error);
763fa9e4066Sahrens }
764fa9e4066Sahrens 
765fa9e4066Sahrens static int
766fa9e4066Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc)
767fa9e4066Sahrens {
768ecd6cf80Smarks 	int error;
769ecd6cf80Smarks 	zfs_log_history(zc);
770ecd6cf80Smarks 	error = spa_export(zc->zc_name, NULL);
771ecd6cf80Smarks 	return (error);
772fa9e4066Sahrens }
773fa9e4066Sahrens 
774fa9e4066Sahrens static int
775fa9e4066Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc)
776fa9e4066Sahrens {
777fa9e4066Sahrens 	nvlist_t *configs;
778fa9e4066Sahrens 	int error;
779fa9e4066Sahrens 
780fa9e4066Sahrens 	if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
781fa9e4066Sahrens 		return (EEXIST);
782fa9e4066Sahrens 
783e9dbad6fSeschrock 	error = put_nvlist(zc, configs);
784fa9e4066Sahrens 
785fa9e4066Sahrens 	nvlist_free(configs);
786fa9e4066Sahrens 
787fa9e4066Sahrens 	return (error);
788fa9e4066Sahrens }
789fa9e4066Sahrens 
790fa9e4066Sahrens static int
791fa9e4066Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc)
792fa9e4066Sahrens {
793fa9e4066Sahrens 	nvlist_t *config;
794fa9e4066Sahrens 	int error;
795ea8dc4b6Seschrock 	int ret = 0;
796fa9e4066Sahrens 
797e9dbad6fSeschrock 	error = spa_get_stats(zc->zc_name, &config, zc->zc_value,
798e9dbad6fSeschrock 	    sizeof (zc->zc_value));
799fa9e4066Sahrens 
800fa9e4066Sahrens 	if (config != NULL) {
801e9dbad6fSeschrock 		ret = put_nvlist(zc, config);
802fa9e4066Sahrens 		nvlist_free(config);
803ea8dc4b6Seschrock 
804ea8dc4b6Seschrock 		/*
805ea8dc4b6Seschrock 		 * The config may be present even if 'error' is non-zero.
806ea8dc4b6Seschrock 		 * In this case we return success, and preserve the real errno
807ea8dc4b6Seschrock 		 * in 'zc_cookie'.
808ea8dc4b6Seschrock 		 */
809ea8dc4b6Seschrock 		zc->zc_cookie = error;
810fa9e4066Sahrens 	} else {
811ea8dc4b6Seschrock 		ret = error;
812fa9e4066Sahrens 	}
813fa9e4066Sahrens 
814ea8dc4b6Seschrock 	return (ret);
815fa9e4066Sahrens }
816fa9e4066Sahrens 
817fa9e4066Sahrens /*
818fa9e4066Sahrens  * Try to import the given pool, returning pool stats as appropriate so that
819fa9e4066Sahrens  * user land knows which devices are available and overall pool health.
820fa9e4066Sahrens  */
821fa9e4066Sahrens static int
822fa9e4066Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
823fa9e4066Sahrens {
824fa9e4066Sahrens 	nvlist_t *tryconfig, *config;
825fa9e4066Sahrens 	int error;
826fa9e4066Sahrens 
827990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
828990b4856Slling 	    &tryconfig)) != 0)
829fa9e4066Sahrens 		return (error);
830fa9e4066Sahrens 
831fa9e4066Sahrens 	config = spa_tryimport(tryconfig);
832fa9e4066Sahrens 
833fa9e4066Sahrens 	nvlist_free(tryconfig);
834fa9e4066Sahrens 
835fa9e4066Sahrens 	if (config == NULL)
836fa9e4066Sahrens 		return (EINVAL);
837fa9e4066Sahrens 
838e9dbad6fSeschrock 	error = put_nvlist(zc, config);
839fa9e4066Sahrens 	nvlist_free(config);
840fa9e4066Sahrens 
841fa9e4066Sahrens 	return (error);
842fa9e4066Sahrens }
843fa9e4066Sahrens 
844fa9e4066Sahrens static int
845fa9e4066Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc)
846fa9e4066Sahrens {
847fa9e4066Sahrens 	spa_t *spa;
848fa9e4066Sahrens 	int error;
849fa9e4066Sahrens 
85006eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
85106eeb2adSek 		return (error);
85206eeb2adSek 
853bb8b5132Sek 	mutex_enter(&spa_namespace_lock);
85406eeb2adSek 	error = spa_scrub(spa, zc->zc_cookie, B_FALSE);
855bb8b5132Sek 	mutex_exit(&spa_namespace_lock);
85606eeb2adSek 
85706eeb2adSek 	spa_close(spa, FTAG);
85806eeb2adSek 
859fa9e4066Sahrens 	return (error);
860fa9e4066Sahrens }
861fa9e4066Sahrens 
862fa9e4066Sahrens static int
863fa9e4066Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc)
864fa9e4066Sahrens {
865fa9e4066Sahrens 	spa_t *spa;
866fa9e4066Sahrens 	int error;
867fa9e4066Sahrens 
868fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
869fa9e4066Sahrens 	if (error == 0) {
870fa9e4066Sahrens 		spa_freeze(spa);
871fa9e4066Sahrens 		spa_close(spa, FTAG);
872fa9e4066Sahrens 	}
873fa9e4066Sahrens 	return (error);
874fa9e4066Sahrens }
875fa9e4066Sahrens 
876eaca9bbdSeschrock static int
877eaca9bbdSeschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc)
878eaca9bbdSeschrock {
879eaca9bbdSeschrock 	spa_t *spa;
880eaca9bbdSeschrock 	int error;
881eaca9bbdSeschrock 
88206eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
88306eeb2adSek 		return (error);
88406eeb2adSek 
885558d2d50Slling 	if (zc->zc_cookie < spa_version(spa) || zc->zc_cookie > SPA_VERSION) {
886558d2d50Slling 		spa_close(spa, FTAG);
887558d2d50Slling 		return (EINVAL);
888558d2d50Slling 	}
889558d2d50Slling 
890990b4856Slling 	spa_upgrade(spa, zc->zc_cookie);
89106eeb2adSek 	spa_close(spa, FTAG);
89206eeb2adSek 
89306eeb2adSek 	return (error);
89406eeb2adSek }
89506eeb2adSek 
89606eeb2adSek static int
89706eeb2adSek zfs_ioc_pool_get_history(zfs_cmd_t *zc)
89806eeb2adSek {
89906eeb2adSek 	spa_t *spa;
90006eeb2adSek 	char *hist_buf;
90106eeb2adSek 	uint64_t size;
90206eeb2adSek 	int error;
90306eeb2adSek 
90406eeb2adSek 	if ((size = zc->zc_history_len) == 0)
90506eeb2adSek 		return (EINVAL);
90606eeb2adSek 
90706eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
90806eeb2adSek 		return (error);
90906eeb2adSek 
910e7437265Sahrens 	if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) {
911d7306b64Sek 		spa_close(spa, FTAG);
912d7306b64Sek 		return (ENOTSUP);
913d7306b64Sek 	}
914d7306b64Sek 
91506eeb2adSek 	hist_buf = kmem_alloc(size, KM_SLEEP);
91606eeb2adSek 	if ((error = spa_history_get(spa, &zc->zc_history_offset,
91706eeb2adSek 	    &zc->zc_history_len, hist_buf)) == 0) {
918ecd6cf80Smarks 		error = xcopyout(hist_buf,
919ecd6cf80Smarks 		    (char *)(uintptr_t)zc->zc_history,
92006eeb2adSek 		    zc->zc_history_len);
92106eeb2adSek 	}
92206eeb2adSek 
92306eeb2adSek 	spa_close(spa, FTAG);
92406eeb2adSek 	kmem_free(hist_buf, size);
92506eeb2adSek 	return (error);
92606eeb2adSek }
92706eeb2adSek 
92855434c77Sek static int
92955434c77Sek zfs_ioc_dsobj_to_dsname(zfs_cmd_t *zc)
93055434c77Sek {
93155434c77Sek 	int error;
93255434c77Sek 
933b1b8ab34Slling 	if (error = dsl_dsobj_to_dsname(zc->zc_name, zc->zc_obj, zc->zc_value))
93455434c77Sek 		return (error);
93555434c77Sek 
93655434c77Sek 	return (0);
93755434c77Sek }
93855434c77Sek 
93955434c77Sek static int
94055434c77Sek zfs_ioc_obj_to_path(zfs_cmd_t *zc)
94155434c77Sek {
94255434c77Sek 	objset_t *osp;
94355434c77Sek 	int error;
94455434c77Sek 
94555434c77Sek 	if ((error = dmu_objset_open(zc->zc_name, DMU_OST_ZFS,
94655434c77Sek 	    DS_MODE_NONE | DS_MODE_READONLY, &osp)) != 0)
94755434c77Sek 		return (error);
94855434c77Sek 
94955434c77Sek 	error = zfs_obj_to_path(osp, zc->zc_obj, zc->zc_value,
95055434c77Sek 	    sizeof (zc->zc_value));
95155434c77Sek 	dmu_objset_close(osp);
95255434c77Sek 
95355434c77Sek 	return (error);
95455434c77Sek }
95555434c77Sek 
956fa9e4066Sahrens static int
957fa9e4066Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc)
958fa9e4066Sahrens {
959fa9e4066Sahrens 	spa_t *spa;
960fa9e4066Sahrens 	int error;
961fa9e4066Sahrens 	nvlist_t *config;
962fa9e4066Sahrens 
963fa9e4066Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
964fa9e4066Sahrens 	if (error != 0)
965fa9e4066Sahrens 		return (error);
966fa9e4066Sahrens 
967b1b8ab34Slling 	/*
968b1b8ab34Slling 	 * A root pool with concatenated devices is not supported.
969b1b8ab34Slling 	 * Thus, can not add a device to a root pool with one device.
970b1b8ab34Slling 	 */
971b1b8ab34Slling 	if (spa->spa_root_vdev->vdev_children == 1 && spa->spa_bootfs != 0) {
972b1b8ab34Slling 		spa_close(spa, FTAG);
973b1b8ab34Slling 		return (EDOM);
974b1b8ab34Slling 	}
975b1b8ab34Slling 
976990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
977990b4856Slling 	    &config)) == 0) {
978fa9e4066Sahrens 		error = spa_vdev_add(spa, config);
979fa9e4066Sahrens 		nvlist_free(config);
980fa9e4066Sahrens 	}
981fa9e4066Sahrens 	spa_close(spa, FTAG);
982fa9e4066Sahrens 	return (error);
983fa9e4066Sahrens }
984fa9e4066Sahrens 
985fa9e4066Sahrens static int
986fa9e4066Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc)
987fa9e4066Sahrens {
98899653d4eSeschrock 	spa_t *spa;
98999653d4eSeschrock 	int error;
99099653d4eSeschrock 
99199653d4eSeschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
99299653d4eSeschrock 	if (error != 0)
99399653d4eSeschrock 		return (error);
99499653d4eSeschrock 	error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE);
99599653d4eSeschrock 	spa_close(spa, FTAG);
99699653d4eSeschrock 	return (error);
997fa9e4066Sahrens }
998fa9e4066Sahrens 
999fa9e4066Sahrens static int
10003d7072f8Seschrock zfs_ioc_vdev_set_state(zfs_cmd_t *zc)
1001fa9e4066Sahrens {
1002fa9e4066Sahrens 	spa_t *spa;
1003fa9e4066Sahrens 	int error;
10043d7072f8Seschrock 	vdev_state_t newstate = VDEV_STATE_UNKNOWN;
1005fa9e4066Sahrens 
100606eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1007fa9e4066Sahrens 		return (error);
10083d7072f8Seschrock 	switch (zc->zc_cookie) {
10093d7072f8Seschrock 	case VDEV_STATE_ONLINE:
10103d7072f8Seschrock 		error = vdev_online(spa, zc->zc_guid, zc->zc_obj, &newstate);
10113d7072f8Seschrock 		break;
1012fa9e4066Sahrens 
10133d7072f8Seschrock 	case VDEV_STATE_OFFLINE:
10143d7072f8Seschrock 		error = vdev_offline(spa, zc->zc_guid, zc->zc_obj);
10153d7072f8Seschrock 		break;
1016fa9e4066Sahrens 
10173d7072f8Seschrock 	case VDEV_STATE_FAULTED:
10183d7072f8Seschrock 		error = vdev_fault(spa, zc->zc_guid);
10193d7072f8Seschrock 		break;
10203d7072f8Seschrock 
10213d7072f8Seschrock 	case VDEV_STATE_DEGRADED:
10223d7072f8Seschrock 		error = vdev_degrade(spa, zc->zc_guid);
10233d7072f8Seschrock 		break;
10243d7072f8Seschrock 
10253d7072f8Seschrock 	default:
10263d7072f8Seschrock 		error = EINVAL;
10273d7072f8Seschrock 	}
10283d7072f8Seschrock 	zc->zc_cookie = newstate;
1029fa9e4066Sahrens 	spa_close(spa, FTAG);
1030fa9e4066Sahrens 	return (error);
1031fa9e4066Sahrens }
1032fa9e4066Sahrens 
1033fa9e4066Sahrens static int
1034fa9e4066Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc)
1035fa9e4066Sahrens {
1036fa9e4066Sahrens 	spa_t *spa;
1037fa9e4066Sahrens 	int replacing = zc->zc_cookie;
1038fa9e4066Sahrens 	nvlist_t *config;
1039fa9e4066Sahrens 	int error;
1040fa9e4066Sahrens 
104106eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1042fa9e4066Sahrens 		return (error);
1043fa9e4066Sahrens 
1044990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
1045990b4856Slling 	    &config)) == 0) {
1046ea8dc4b6Seschrock 		error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
1047fa9e4066Sahrens 		nvlist_free(config);
1048fa9e4066Sahrens 	}
1049fa9e4066Sahrens 
1050fa9e4066Sahrens 	spa_close(spa, FTAG);
1051fa9e4066Sahrens 	return (error);
1052fa9e4066Sahrens }
1053fa9e4066Sahrens 
1054fa9e4066Sahrens static int
1055fa9e4066Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc)
1056fa9e4066Sahrens {
1057fa9e4066Sahrens 	spa_t *spa;
1058fa9e4066Sahrens 	int error;
1059fa9e4066Sahrens 
106006eeb2adSek 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1061fa9e4066Sahrens 		return (error);
1062fa9e4066Sahrens 
1063ea8dc4b6Seschrock 	error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE);
1064fa9e4066Sahrens 
1065fa9e4066Sahrens 	spa_close(spa, FTAG);
1066fa9e4066Sahrens 	return (error);
1067fa9e4066Sahrens }
1068fa9e4066Sahrens 
1069c67d9675Seschrock static int
1070c67d9675Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
1071c67d9675Seschrock {
1072c67d9675Seschrock 	spa_t *spa;
1073e9dbad6fSeschrock 	char *path = zc->zc_value;
1074ea8dc4b6Seschrock 	uint64_t guid = zc->zc_guid;
1075c67d9675Seschrock 	int error;
1076c67d9675Seschrock 
1077c67d9675Seschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
1078c67d9675Seschrock 	if (error != 0)
1079c67d9675Seschrock 		return (error);
1080c67d9675Seschrock 
1081c67d9675Seschrock 	error = spa_vdev_setpath(spa, guid, path);
1082c67d9675Seschrock 	spa_close(spa, FTAG);
1083c67d9675Seschrock 	return (error);
1084c67d9675Seschrock }
1085c67d9675Seschrock 
1086fa9e4066Sahrens static int
1087fa9e4066Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc)
1088fa9e4066Sahrens {
1089fa9e4066Sahrens 	objset_t *os = NULL;
1090fa9e4066Sahrens 	int error;
10917f7322feSeschrock 	nvlist_t *nv;
1092fa9e4066Sahrens 
1093fa9e4066Sahrens retry:
1094fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1095fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
1096fa9e4066Sahrens 	if (error != 0) {
1097fa9e4066Sahrens 		/*
1098fa9e4066Sahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
1099fa9e4066Sahrens 		 * the objset is held exclusively. Fortunately this hold is
1100fa9e4066Sahrens 		 * only for a short while, so we retry here.
1101fa9e4066Sahrens 		 * This avoids user code having to handle EBUSY,
1102fa9e4066Sahrens 		 * for example for a "zfs list".
1103fa9e4066Sahrens 		 */
1104fa9e4066Sahrens 		if (error == EBUSY) {
1105fa9e4066Sahrens 			delay(1);
1106fa9e4066Sahrens 			goto retry;
1107fa9e4066Sahrens 		}
1108fa9e4066Sahrens 		return (error);
1109fa9e4066Sahrens 	}
1110fa9e4066Sahrens 
1111a2eea2e1Sahrens 	dmu_objset_fast_stat(os, &zc->zc_objset_stats);
1112fa9e4066Sahrens 
11135ad82045Snd 	if (zc->zc_nvlist_dst != 0 &&
11147f7322feSeschrock 	    (error = dsl_prop_get_all(os, &nv)) == 0) {
1115a2eea2e1Sahrens 		dmu_objset_stats(os, nv);
1116432f72fdSahrens 		/*
1117bd00f61bSrm 		 * NB: zvol_get_stats() will read the objset contents,
1118432f72fdSahrens 		 * which we aren't supposed to do with a
1119432f72fdSahrens 		 * DS_MODE_STANDARD open, because it could be
1120432f72fdSahrens 		 * inconsistent.  So this is a bit of a workaround...
1121432f72fdSahrens 		 */
1122e7437265Sahrens 		if (!zc->zc_objset_stats.dds_inconsistent) {
1123e7437265Sahrens 			if (dmu_objset_type(os) == DMU_OST_ZVOL)
1124e7437265Sahrens 				VERIFY(zvol_get_stats(os, nv) == 0);
1125e7437265Sahrens 		}
1126e9dbad6fSeschrock 		error = put_nvlist(zc, nv);
11277f7322feSeschrock 		nvlist_free(nv);
11287f7322feSeschrock 	}
1129fa9e4066Sahrens 
1130e9dbad6fSeschrock 	spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value));
1131ea8dc4b6Seschrock 
1132fa9e4066Sahrens 	dmu_objset_close(os);
1133fa9e4066Sahrens 	return (error);
1134fa9e4066Sahrens }
1135fa9e4066Sahrens 
1136bd00f61bSrm static int
1137bd00f61bSrm zfs_ioc_objset_version(zfs_cmd_t *zc)
1138bd00f61bSrm {
1139bd00f61bSrm 	objset_t *os = NULL;
1140bd00f61bSrm 	int error;
1141bd00f61bSrm 
1142bd00f61bSrm retry:
1143bd00f61bSrm 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1144bd00f61bSrm 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
1145bd00f61bSrm 	if (error != 0) {
1146bd00f61bSrm 		/*
1147bd00f61bSrm 		 * This is ugly: dmu_objset_open() can return EBUSY if
1148bd00f61bSrm 		 * the objset is held exclusively. Fortunately this hold is
1149bd00f61bSrm 		 * only for a short while, so we retry here.
1150bd00f61bSrm 		 * This avoids user code having to handle EBUSY,
1151bd00f61bSrm 		 * for example for a "zfs list".
1152bd00f61bSrm 		 */
1153bd00f61bSrm 		if (error == EBUSY) {
1154bd00f61bSrm 			delay(1);
1155bd00f61bSrm 			goto retry;
1156bd00f61bSrm 		}
1157bd00f61bSrm 		return (error);
1158bd00f61bSrm 	}
1159bd00f61bSrm 
1160bd00f61bSrm 	dmu_objset_fast_stat(os, &zc->zc_objset_stats);
1161bd00f61bSrm 
1162bd00f61bSrm 	/*
1163bd00f61bSrm 	 * NB: zfs_get_version() will read the objset contents,
1164bd00f61bSrm 	 * which we aren't supposed to do with a
1165bd00f61bSrm 	 * DS_MODE_STANDARD open, because it could be
1166bd00f61bSrm 	 * inconsistent.  So this is a bit of a workaround...
1167bd00f61bSrm 	 */
1168bd00f61bSrm 	zc->zc_cookie = 0;
1169bd00f61bSrm 	if (!zc->zc_objset_stats.dds_inconsistent)
1170bd00f61bSrm 		if (dmu_objset_type(os) == DMU_OST_ZFS)
1171bd00f61bSrm 			(void) zfs_get_version(os, &zc->zc_cookie);
1172bd00f61bSrm 
1173bd00f61bSrm 	dmu_objset_close(os);
1174bd00f61bSrm 	return (0);
1175bd00f61bSrm }
1176bd00f61bSrm 
1177fa9e4066Sahrens static int
1178fa9e4066Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc)
1179fa9e4066Sahrens {
118087e5029aSahrens 	objset_t *os;
1181fa9e4066Sahrens 	int error;
1182fa9e4066Sahrens 	char *p;
1183fa9e4066Sahrens 
118487e5029aSahrens retry:
118587e5029aSahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
118687e5029aSahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
118787e5029aSahrens 	if (error != 0) {
118887e5029aSahrens 		/*
118987e5029aSahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
119087e5029aSahrens 		 * the objset is held exclusively. Fortunately this hold is
119187e5029aSahrens 		 * only for a short while, so we retry here.
119287e5029aSahrens 		 * This avoids user code having to handle EBUSY,
119387e5029aSahrens 		 * for example for a "zfs list".
119487e5029aSahrens 		 */
119587e5029aSahrens 		if (error == EBUSY) {
119687e5029aSahrens 			delay(1);
119787e5029aSahrens 			goto retry;
119887e5029aSahrens 		}
119987e5029aSahrens 		if (error == ENOENT)
120087e5029aSahrens 			error = ESRCH;
120187e5029aSahrens 		return (error);
1202fa9e4066Sahrens 	}
1203fa9e4066Sahrens 
1204fa9e4066Sahrens 	p = strrchr(zc->zc_name, '/');
1205fa9e4066Sahrens 	if (p == NULL || p[1] != '\0')
1206fa9e4066Sahrens 		(void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name));
1207fa9e4066Sahrens 	p = zc->zc_name + strlen(zc->zc_name);
1208fa9e4066Sahrens 
1209fa9e4066Sahrens 	do {
121087e5029aSahrens 		error = dmu_dir_list_next(os,
121187e5029aSahrens 		    sizeof (zc->zc_name) - (p - zc->zc_name), p,
121287e5029aSahrens 		    NULL, &zc->zc_cookie);
1213fa9e4066Sahrens 		if (error == ENOENT)
1214fa9e4066Sahrens 			error = ESRCH;
121587e5029aSahrens 	} while (error == 0 && !INGLOBALZONE(curproc) &&
1216fa9e4066Sahrens 	    !zone_dataset_visible(zc->zc_name, NULL));
1217fa9e4066Sahrens 
1218fa9e4066Sahrens 	/*
121987e5029aSahrens 	 * If it's a hidden dataset (ie. with a '$' in its name), don't
122087e5029aSahrens 	 * try to get stats for it.  Userland will skip over it.
1221fa9e4066Sahrens 	 */
122287e5029aSahrens 	if (error == 0 && strchr(zc->zc_name, '$') == NULL)
122387e5029aSahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
1224fa9e4066Sahrens 
122587e5029aSahrens 	dmu_objset_close(os);
1226fa9e4066Sahrens 	return (error);
1227fa9e4066Sahrens }
1228fa9e4066Sahrens 
1229fa9e4066Sahrens static int
1230fa9e4066Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
1231fa9e4066Sahrens {
123287e5029aSahrens 	objset_t *os;
1233fa9e4066Sahrens 	int error;
1234fa9e4066Sahrens 
1235fa9e4066Sahrens retry:
123687e5029aSahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
123787e5029aSahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
123887e5029aSahrens 	if (error != 0) {
1239fa9e4066Sahrens 		/*
124087e5029aSahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
1241fa9e4066Sahrens 		 * the objset is held exclusively. Fortunately this hold is
1242fa9e4066Sahrens 		 * only for a short while, so we retry here.
1243fa9e4066Sahrens 		 * This avoids user code having to handle EBUSY,
124487e5029aSahrens 		 * for example for a "zfs list".
1245fa9e4066Sahrens 		 */
1246fa9e4066Sahrens 		if (error == EBUSY) {
1247fa9e4066Sahrens 			delay(1);
1248fa9e4066Sahrens 			goto retry;
1249fa9e4066Sahrens 		}
1250fa9e4066Sahrens 		if (error == ENOENT)
125187e5029aSahrens 			error = ESRCH;
1252fa9e4066Sahrens 		return (error);
1253fa9e4066Sahrens 	}
1254fa9e4066Sahrens 
1255b81d61a6Slling 	/*
1256b81d61a6Slling 	 * A dataset name of maximum length cannot have any snapshots,
1257b81d61a6Slling 	 * so exit immediately.
1258b81d61a6Slling 	 */
1259b81d61a6Slling 	if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) {
126087e5029aSahrens 		dmu_objset_close(os);
1261b81d61a6Slling 		return (ESRCH);
1262fa9e4066Sahrens 	}
1263fa9e4066Sahrens 
126487e5029aSahrens 	error = dmu_snapshot_list_next(os,
126587e5029aSahrens 	    sizeof (zc->zc_name) - strlen(zc->zc_name),
126687e5029aSahrens 	    zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie);
126787e5029aSahrens 	if (error == ENOENT)
126887e5029aSahrens 		error = ESRCH;
1269fa9e4066Sahrens 
127087e5029aSahrens 	if (error == 0)
127187e5029aSahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
1272fa9e4066Sahrens 
127387e5029aSahrens 	dmu_objset_close(os);
1274fa9e4066Sahrens 	return (error);
1275fa9e4066Sahrens }
1276fa9e4066Sahrens 
1277fa9e4066Sahrens static int
127891ebeef5Sahrens zfs_set_prop_nvlist(const char *name, nvlist_t *nvl)
1279fa9e4066Sahrens {
1280e9dbad6fSeschrock 	nvpair_t *elem;
1281e9dbad6fSeschrock 	int error;
1282e9dbad6fSeschrock 	uint64_t intval;
1283e9dbad6fSeschrock 	char *strval;
1284e9dbad6fSeschrock 
1285ecd6cf80Smarks 	/*
1286ecd6cf80Smarks 	 * First validate permission to set all of the properties
1287ecd6cf80Smarks 	 */
1288e9dbad6fSeschrock 	elem = NULL;
1289e9dbad6fSeschrock 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1290db870a07Sahrens 		const char *propname = nvpair_name(elem);
1291db870a07Sahrens 		zfs_prop_t prop = zfs_name_to_prop(propname);
1292e9dbad6fSeschrock 
1293990b4856Slling 		if (prop == ZPROP_INVAL) {
1294e9dbad6fSeschrock 			/*
1295e9dbad6fSeschrock 			 * If this is a user-defined property, it must be a
1296e9dbad6fSeschrock 			 * string, and there is no further validation to do.
1297e9dbad6fSeschrock 			 */
1298e9dbad6fSeschrock 			if (!zfs_prop_user(propname) ||
1299e9dbad6fSeschrock 			    nvpair_type(elem) != DATA_TYPE_STRING)
1300e9dbad6fSeschrock 				return (EINVAL);
1301e9dbad6fSeschrock 
1302*da6c28aaSamw 			if (error = zfs_secpolicy_write_perms(name,
1303*da6c28aaSamw 			    ZFS_DELEG_PERM_USERPROP, CRED()))
1304db870a07Sahrens 				return (error);
1305ecd6cf80Smarks 			continue;
1306e9dbad6fSeschrock 		}
1307fa9e4066Sahrens 
130891ebeef5Sahrens 		if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0)
1309db870a07Sahrens 			return (error);
1310db870a07Sahrens 
1311e9dbad6fSeschrock 		/*
1312db870a07Sahrens 		 * Check that this value is valid for this pool version
1313e9dbad6fSeschrock 		 */
1314e9dbad6fSeschrock 		switch (prop) {
1315c9431fa1Sahl 		case ZFS_PROP_COMPRESSION:
1316c9431fa1Sahl 			/*
1317c9431fa1Sahl 			 * If the user specified gzip compression, make sure
1318c9431fa1Sahl 			 * the SPA supports it. We ignore any errors here since
1319c9431fa1Sahl 			 * we'll catch them later.
1320c9431fa1Sahl 			 */
1321c9431fa1Sahl 			if (nvpair_type(elem) == DATA_TYPE_UINT64 &&
1322c9431fa1Sahl 			    nvpair_value_uint64(elem, &intval) == 0 &&
1323c9431fa1Sahl 			    intval >= ZIO_COMPRESS_GZIP_1 &&
1324c9431fa1Sahl 			    intval <= ZIO_COMPRESS_GZIP_9) {
1325*da6c28aaSamw 				if (zfs_check_version(name,
1326*da6c28aaSamw 				    SPA_VERSION_GZIP_COMPRESSION))
1327*da6c28aaSamw 					return (ENOTSUP);
1328c9431fa1Sahl 			}
1329c9431fa1Sahl 			break;
133040feaa91Sahrens 
133140feaa91Sahrens 		case ZFS_PROP_COPIES:
1332*da6c28aaSamw 			if (zfs_check_version(name, SPA_VERSION_DITTO_BLOCKS))
1333*da6c28aaSamw 				return (ENOTSUP);
133440feaa91Sahrens 			break;
1335*da6c28aaSamw 		case ZFS_PROP_NORMALIZE:
1336*da6c28aaSamw 		case ZFS_PROP_UTF8ONLY:
1337*da6c28aaSamw 		case ZFS_PROP_CASE:
1338*da6c28aaSamw 			if (zfs_check_version(name, SPA_VERSION_NORMALIZATION))
1339*da6c28aaSamw 				return (ENOTSUP);
1340*da6c28aaSamw 
134140feaa91Sahrens 		}
1342*da6c28aaSamw 		if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0)
1343*da6c28aaSamw 			return (error);
1344ecd6cf80Smarks 	}
1345ecd6cf80Smarks 
1346ecd6cf80Smarks 	elem = NULL;
1347ecd6cf80Smarks 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
1348db870a07Sahrens 		const char *propname = nvpair_name(elem);
1349db870a07Sahrens 		zfs_prop_t prop = zfs_name_to_prop(propname);
1350ecd6cf80Smarks 
1351990b4856Slling 		if (prop == ZPROP_INVAL) {
1352ecd6cf80Smarks 			VERIFY(nvpair_value_string(elem, &strval) == 0);
1353ecd6cf80Smarks 			error = dsl_prop_set(name, propname, 1,
1354ecd6cf80Smarks 			    strlen(strval) + 1, strval);
1355ecd6cf80Smarks 			if (error == 0)
1356ecd6cf80Smarks 				continue;
1357ecd6cf80Smarks 			else
1358ecd6cf80Smarks 				return (error);
1359ecd6cf80Smarks 		}
1360e9dbad6fSeschrock 
1361e9dbad6fSeschrock 		switch (prop) {
1362e9dbad6fSeschrock 		case ZFS_PROP_QUOTA:
1363e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1364e7437265Sahrens 			    (error = dsl_dir_set_quota(name, intval)) != 0)
1365e9dbad6fSeschrock 				return (error);
1366e9dbad6fSeschrock 			break;
1367e9dbad6fSeschrock 
1368e9dbad6fSeschrock 		case ZFS_PROP_RESERVATION:
1369e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1370e9dbad6fSeschrock 			    (error = dsl_dir_set_reservation(name,
1371e9dbad6fSeschrock 			    intval)) != 0)
1372e9dbad6fSeschrock 				return (error);
1373e9dbad6fSeschrock 			break;
1374e9dbad6fSeschrock 
1375e9dbad6fSeschrock 		case ZFS_PROP_VOLSIZE:
1376e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
137791ebeef5Sahrens 			    (error = zvol_set_volsize(name,
137891ebeef5Sahrens 			    ddi_driver_major(zfs_dip), intval)) != 0)
1379e9dbad6fSeschrock 				return (error);
1380e9dbad6fSeschrock 			break;
1381e9dbad6fSeschrock 
1382e9dbad6fSeschrock 		case ZFS_PROP_VOLBLOCKSIZE:
1383e9dbad6fSeschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1384e7437265Sahrens 			    (error = zvol_set_volblocksize(name, intval)) != 0)
1385e7437265Sahrens 				return (error);
1386e7437265Sahrens 			break;
1387e7437265Sahrens 
1388e7437265Sahrens 		case ZFS_PROP_VERSION:
1389e7437265Sahrens 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
1390e7437265Sahrens 			    (error = zfs_set_version(name, intval)) != 0)
1391e9dbad6fSeschrock 				return (error);
1392e9dbad6fSeschrock 			break;
1393e9dbad6fSeschrock 
1394e9dbad6fSeschrock 		default:
1395e9dbad6fSeschrock 			if (nvpair_type(elem) == DATA_TYPE_STRING) {
1396e9dbad6fSeschrock 				if (zfs_prop_get_type(prop) !=
139791ebeef5Sahrens 				    PROP_TYPE_STRING)
1398e9dbad6fSeschrock 					return (EINVAL);
1399acd76fe5Seschrock 				VERIFY(nvpair_value_string(elem, &strval) == 0);
1400acd76fe5Seschrock 				if ((error = dsl_prop_set(name,
1401e9dbad6fSeschrock 				    nvpair_name(elem), 1, strlen(strval) + 1,
1402acd76fe5Seschrock 				    strval)) != 0)
1403acd76fe5Seschrock 					return (error);
1404e9dbad6fSeschrock 			} else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
1405a2eea2e1Sahrens 				const char *unused;
1406a2eea2e1Sahrens 
1407acd76fe5Seschrock 				VERIFY(nvpair_value_uint64(elem, &intval) == 0);
1408e9dbad6fSeschrock 
1409e9dbad6fSeschrock 				switch (zfs_prop_get_type(prop)) {
141091ebeef5Sahrens 				case PROP_TYPE_NUMBER:
1411e9dbad6fSeschrock 					break;
141291ebeef5Sahrens 				case PROP_TYPE_STRING:
1413acd76fe5Seschrock 					return (EINVAL);
141491ebeef5Sahrens 				case PROP_TYPE_INDEX:
1415acd76fe5Seschrock 					if (zfs_prop_index_to_string(prop,
1416acd76fe5Seschrock 					    intval, &unused) != 0)
1417acd76fe5Seschrock 						return (EINVAL);
1418e9dbad6fSeschrock 					break;
1419e9dbad6fSeschrock 				default:
1420e7437265Sahrens 					cmn_err(CE_PANIC,
1421e7437265Sahrens 					    "unknown property type");
1422e9dbad6fSeschrock 					break;
1423e9dbad6fSeschrock 				}
1424e9dbad6fSeschrock 
1425acd76fe5Seschrock 				if ((error = dsl_prop_set(name, propname,
1426acd76fe5Seschrock 				    8, 1, &intval)) != 0)
1427acd76fe5Seschrock 					return (error);
1428e9dbad6fSeschrock 			} else {
1429e9dbad6fSeschrock 				return (EINVAL);
1430e9dbad6fSeschrock 			}
1431e9dbad6fSeschrock 			break;
1432e9dbad6fSeschrock 		}
1433e9dbad6fSeschrock 	}
1434e9dbad6fSeschrock 
1435e9dbad6fSeschrock 	return (0);
1436fa9e4066Sahrens }
1437fa9e4066Sahrens 
1438fa9e4066Sahrens static int
1439e9dbad6fSeschrock zfs_ioc_set_prop(zfs_cmd_t *zc)
1440fa9e4066Sahrens {
1441e9dbad6fSeschrock 	nvlist_t *nvl;
1442e9dbad6fSeschrock 	int error;
1443e9dbad6fSeschrock 
1444990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1445990b4856Slling 	    &nvl)) != 0)
1446e9dbad6fSeschrock 		return (error);
1447e9dbad6fSeschrock 
144891ebeef5Sahrens 	error = zfs_set_prop_nvlist(zc->zc_name, nvl);
1449ecd6cf80Smarks 
1450e9dbad6fSeschrock 	nvlist_free(nvl);
1451e9dbad6fSeschrock 	return (error);
1452fa9e4066Sahrens }
1453fa9e4066Sahrens 
1454e45ce728Sahrens static int
1455e45ce728Sahrens zfs_ioc_inherit_prop(zfs_cmd_t *zc)
1456e45ce728Sahrens {
1457e45ce728Sahrens 	/* the property name has been validated by zfs_secpolicy_inherit() */
1458e45ce728Sahrens 	return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL));
1459e45ce728Sahrens }
1460e45ce728Sahrens 
1461b1b8ab34Slling static int
146211a41203Slling zfs_ioc_pool_set_props(zfs_cmd_t *zc)
1463b1b8ab34Slling {
1464990b4856Slling 	nvlist_t *props;
1465b1b8ab34Slling 	spa_t *spa;
1466990b4856Slling 	int error;
1467b1b8ab34Slling 
1468990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1469990b4856Slling 	    &props)))
1470b1b8ab34Slling 		return (error);
1471b1b8ab34Slling 
1472b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) {
1473990b4856Slling 		nvlist_free(props);
1474b1b8ab34Slling 		return (error);
1475b1b8ab34Slling 	}
1476b1b8ab34Slling 
1477990b4856Slling 	error = spa_prop_set(spa, props);
1478b1b8ab34Slling 
1479990b4856Slling 	nvlist_free(props);
1480b1b8ab34Slling 	spa_close(spa, FTAG);
1481b1b8ab34Slling 
1482b1b8ab34Slling 	return (error);
1483b1b8ab34Slling }
1484b1b8ab34Slling 
1485b1b8ab34Slling static int
148611a41203Slling zfs_ioc_pool_get_props(zfs_cmd_t *zc)
1487b1b8ab34Slling {
1488b1b8ab34Slling 	spa_t *spa;
1489b1b8ab34Slling 	int error;
1490b1b8ab34Slling 	nvlist_t *nvp = NULL;
1491b1b8ab34Slling 
1492b1b8ab34Slling 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
1493b1b8ab34Slling 		return (error);
1494b1b8ab34Slling 
1495990b4856Slling 	error = spa_prop_get(spa, &nvp);
1496b1b8ab34Slling 
1497b1b8ab34Slling 	if (error == 0 && zc->zc_nvlist_dst != NULL)
1498b1b8ab34Slling 		error = put_nvlist(zc, nvp);
1499b1b8ab34Slling 	else
1500b1b8ab34Slling 		error = EFAULT;
1501b1b8ab34Slling 
1502b1b8ab34Slling 	spa_close(spa, FTAG);
1503b1b8ab34Slling 
1504b1b8ab34Slling 	if (nvp)
1505b1b8ab34Slling 		nvlist_free(nvp);
1506b1b8ab34Slling 	return (error);
1507b1b8ab34Slling }
1508b1b8ab34Slling 
1509ecd6cf80Smarks static int
1510ecd6cf80Smarks zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc)
1511ecd6cf80Smarks {
1512ecd6cf80Smarks 	nvlist_t *nvp;
1513ecd6cf80Smarks 	int error;
1514ecd6cf80Smarks 	uint32_t uid;
1515ecd6cf80Smarks 	uint32_t gid;
1516ecd6cf80Smarks 	uint32_t *groups;
1517ecd6cf80Smarks 	uint_t group_cnt;
1518ecd6cf80Smarks 	cred_t	*usercred;
1519ecd6cf80Smarks 
1520990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1521990b4856Slling 	    &nvp)) != 0) {
1522ecd6cf80Smarks 		return (error);
1523ecd6cf80Smarks 	}
1524ecd6cf80Smarks 
1525ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32(nvp,
1526ecd6cf80Smarks 	    ZFS_DELEG_PERM_UID, &uid)) != 0) {
1527ecd6cf80Smarks 		nvlist_free(nvp);
1528ecd6cf80Smarks 		return (EPERM);
1529ecd6cf80Smarks 	}
1530ecd6cf80Smarks 
1531ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32(nvp,
1532ecd6cf80Smarks 	    ZFS_DELEG_PERM_GID, &gid)) != 0) {
1533ecd6cf80Smarks 		nvlist_free(nvp);
1534ecd6cf80Smarks 		return (EPERM);
1535ecd6cf80Smarks 	}
1536ecd6cf80Smarks 
1537ecd6cf80Smarks 	if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS,
1538ecd6cf80Smarks 	    &groups, &group_cnt)) != 0) {
1539ecd6cf80Smarks 		nvlist_free(nvp);
1540ecd6cf80Smarks 		return (EPERM);
1541ecd6cf80Smarks 	}
1542ecd6cf80Smarks 	usercred = cralloc();
1543ecd6cf80Smarks 	if ((crsetugid(usercred, uid, gid) != 0) ||
1544ecd6cf80Smarks 	    (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) {
1545ecd6cf80Smarks 		nvlist_free(nvp);
1546ecd6cf80Smarks 		crfree(usercred);
1547ecd6cf80Smarks 		return (EPERM);
1548ecd6cf80Smarks 	}
1549ecd6cf80Smarks 	nvlist_free(nvp);
1550ecd6cf80Smarks 	error = dsl_deleg_access(zc->zc_name,
155191ebeef5Sahrens 	    zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred);
1552ecd6cf80Smarks 	crfree(usercred);
1553ecd6cf80Smarks 	return (error);
1554ecd6cf80Smarks }
1555ecd6cf80Smarks 
1556ecd6cf80Smarks static int
1557ecd6cf80Smarks zfs_ioc_set_fsacl(zfs_cmd_t *zc)
1558ecd6cf80Smarks {
1559ecd6cf80Smarks 	int error;
1560ecd6cf80Smarks 	nvlist_t *fsaclnv = NULL;
1561ecd6cf80Smarks 
1562990b4856Slling 	if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1563990b4856Slling 	    &fsaclnv)) != 0)
1564ecd6cf80Smarks 		return (error);
1565ecd6cf80Smarks 
1566ecd6cf80Smarks 	/*
1567ecd6cf80Smarks 	 * Verify nvlist is constructed correctly
1568ecd6cf80Smarks 	 */
1569ecd6cf80Smarks 	if ((error = zfs_deleg_verify_nvlist(fsaclnv)) != 0) {
1570ecd6cf80Smarks 		nvlist_free(fsaclnv);
1571ecd6cf80Smarks 		return (EINVAL);
1572ecd6cf80Smarks 	}
1573ecd6cf80Smarks 
1574ecd6cf80Smarks 	/*
1575ecd6cf80Smarks 	 * If we don't have PRIV_SYS_MOUNT, then validate
1576ecd6cf80Smarks 	 * that user is allowed to hand out each permission in
1577ecd6cf80Smarks 	 * the nvlist(s)
1578ecd6cf80Smarks 	 */
1579ecd6cf80Smarks 
158091ebeef5Sahrens 	error = secpolicy_zfs(CRED());
1581ecd6cf80Smarks 	if (error) {
158291ebeef5Sahrens 		if (zc->zc_perm_action == B_FALSE) {
158391ebeef5Sahrens 			error = dsl_deleg_can_allow(zc->zc_name,
158491ebeef5Sahrens 			    fsaclnv, CRED());
158591ebeef5Sahrens 		} else {
158691ebeef5Sahrens 			error = dsl_deleg_can_unallow(zc->zc_name,
158791ebeef5Sahrens 			    fsaclnv, CRED());
158891ebeef5Sahrens 		}
1589ecd6cf80Smarks 	}
1590ecd6cf80Smarks 
1591ecd6cf80Smarks 	if (error == 0)
1592ecd6cf80Smarks 		error = dsl_deleg_set(zc->zc_name, fsaclnv, zc->zc_perm_action);
1593ecd6cf80Smarks 
1594ecd6cf80Smarks 	nvlist_free(fsaclnv);
1595ecd6cf80Smarks 	return (error);
1596ecd6cf80Smarks }
1597ecd6cf80Smarks 
1598ecd6cf80Smarks static int
1599ecd6cf80Smarks zfs_ioc_get_fsacl(zfs_cmd_t *zc)
1600ecd6cf80Smarks {
1601ecd6cf80Smarks 	nvlist_t *nvp;
1602ecd6cf80Smarks 	int error;
1603ecd6cf80Smarks 
1604ecd6cf80Smarks 	if ((error = dsl_deleg_get(zc->zc_name, &nvp)) == 0) {
1605ecd6cf80Smarks 		error = put_nvlist(zc, nvp);
1606ecd6cf80Smarks 		nvlist_free(nvp);
1607ecd6cf80Smarks 	}
1608ecd6cf80Smarks 
1609ecd6cf80Smarks 	return (error);
1610ecd6cf80Smarks }
1611ecd6cf80Smarks 
1612fa9e4066Sahrens static int
1613fa9e4066Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc)
1614fa9e4066Sahrens {
161591ebeef5Sahrens 	return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip)));
1616fa9e4066Sahrens }
1617fa9e4066Sahrens 
1618fa9e4066Sahrens static int
1619fa9e4066Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc)
1620fa9e4066Sahrens {
1621e9dbad6fSeschrock 	return (zvol_remove_minor(zc->zc_name));
1622fa9e4066Sahrens }
1623fa9e4066Sahrens 
1624fa9e4066Sahrens /*
1625fa9e4066Sahrens  * Search the vfs list for a specified resource.  Returns a pointer to it
1626fa9e4066Sahrens  * or NULL if no suitable entry is found. The caller of this routine
1627fa9e4066Sahrens  * is responsible for releasing the returned vfs pointer.
1628fa9e4066Sahrens  */
1629fa9e4066Sahrens static vfs_t *
1630fa9e4066Sahrens zfs_get_vfs(const char *resource)
1631fa9e4066Sahrens {
1632fa9e4066Sahrens 	struct vfs *vfsp;
1633fa9e4066Sahrens 	struct vfs *vfs_found = NULL;
1634fa9e4066Sahrens 
1635fa9e4066Sahrens 	vfs_list_read_lock();
1636fa9e4066Sahrens 	vfsp = rootvfs;
1637fa9e4066Sahrens 	do {
1638fa9e4066Sahrens 		if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) {
1639fa9e4066Sahrens 			VFS_HOLD(vfsp);
1640fa9e4066Sahrens 			vfs_found = vfsp;
1641fa9e4066Sahrens 			break;
1642fa9e4066Sahrens 		}
1643fa9e4066Sahrens 		vfsp = vfsp->vfs_next;
1644fa9e4066Sahrens 	} while (vfsp != rootvfs);
1645fa9e4066Sahrens 	vfs_list_unlock();
1646fa9e4066Sahrens 	return (vfs_found);
1647fa9e4066Sahrens }
1648fa9e4066Sahrens 
1649ecd6cf80Smarks /* ARGSUSED */
1650fa9e4066Sahrens static void
1651ecd6cf80Smarks zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
1652fa9e4066Sahrens {
1653*da6c28aaSamw 	zfs_creat_t *zct = arg;
1654*da6c28aaSamw 	uint64_t version;
1655*da6c28aaSamw 
1656*da6c28aaSamw 	if (spa_version(dmu_objset_spa(os)) >= SPA_VERSION_FUID)
1657*da6c28aaSamw 		version = ZPL_VERSION;
1658*da6c28aaSamw 	else
1659*da6c28aaSamw 		version = ZPL_VERSION_FUID - 1;
1660e7437265Sahrens 
1661*da6c28aaSamw 	(void) nvlist_lookup_uint64(zct->zct_props,
1662e7437265Sahrens 	    zfs_prop_to_name(ZFS_PROP_VERSION), &version);
1663e7437265Sahrens 
1664*da6c28aaSamw 	zfs_create_fs(os, cr, version, zct->zct_norm, tx);
1665*da6c28aaSamw }
1666*da6c28aaSamw 
1667*da6c28aaSamw /*
1668*da6c28aaSamw  * zfs_prop_lookup()
1669*da6c28aaSamw  *
1670*da6c28aaSamw  * Look for the property first in the existing property nvlist.  If
1671*da6c28aaSamw  * it's already present, you're done.  If it's not there, attempt to
1672*da6c28aaSamw  * find the property value from a parent dataset.  If that fails, fall
1673*da6c28aaSamw  * back to the property's default value.  In either of these two
1674*da6c28aaSamw  * cases, if update is TRUE, add a value for the property to the
1675*da6c28aaSamw  * property nvlist.
1676*da6c28aaSamw  *
1677*da6c28aaSamw  * If the rval pointer is non-NULL, copy the discovered value to rval.
1678*da6c28aaSamw  *
1679*da6c28aaSamw  * If we get any unexpected errors, bail and return the error number
1680*da6c28aaSamw  * to the caller.
1681*da6c28aaSamw  *
1682*da6c28aaSamw  * If we succeed, return 0.
1683*da6c28aaSamw  */
1684*da6c28aaSamw static int
1685*da6c28aaSamw zfs_prop_lookup(const char *parentname, zfs_prop_t propnum,
1686*da6c28aaSamw     nvlist_t *proplist, uint64_t *rval, boolean_t update)
1687*da6c28aaSamw {
1688*da6c28aaSamw 	const char *propname;
1689*da6c28aaSamw 	uint64_t value;
1690*da6c28aaSamw 	int error = ENOENT;
1691*da6c28aaSamw 
1692*da6c28aaSamw 	propname = zfs_prop_to_name(propnum);
1693*da6c28aaSamw 	if (proplist != NULL)
1694*da6c28aaSamw 		error = nvlist_lookup_uint64(proplist, propname, &value);
1695*da6c28aaSamw 	if (error == ENOENT) {
1696*da6c28aaSamw 		error = dsl_prop_get_integer(parentname, propname,
1697*da6c28aaSamw 		    &value, NULL);
1698*da6c28aaSamw 		if (error == ENOENT)
1699*da6c28aaSamw 			value = zfs_prop_default_numeric(propnum);
1700*da6c28aaSamw 		else if (error != 0)
1701*da6c28aaSamw 			return (error);
1702*da6c28aaSamw 		if (update) {
1703*da6c28aaSamw 			ASSERT(proplist != NULL);
1704*da6c28aaSamw 			error = nvlist_add_uint64(proplist, propname, value);
1705*da6c28aaSamw 		}
1706*da6c28aaSamw 	}
1707*da6c28aaSamw 	if (error == 0 && rval)
1708*da6c28aaSamw 		*rval = value;
1709*da6c28aaSamw 	return (error);
1710*da6c28aaSamw }
1711*da6c28aaSamw 
1712*da6c28aaSamw /*
1713*da6c28aaSamw  * zfs_normalization_get
1714*da6c28aaSamw  *
1715*da6c28aaSamw  * Get the normalization flag value.  If the properties have
1716*da6c28aaSamw  * non-default values, make sure the pool version is recent enough to
1717*da6c28aaSamw  * support these choices.
1718*da6c28aaSamw  */
1719*da6c28aaSamw static int
1720*da6c28aaSamw zfs_normalization_get(const char *dataset, nvlist_t *proplist, int *norm,
1721*da6c28aaSamw     boolean_t update)
1722*da6c28aaSamw {
1723*da6c28aaSamw 	char parentname[MAXNAMELEN];
1724*da6c28aaSamw 	char poolname[MAXNAMELEN];
1725*da6c28aaSamw 	char *cp;
1726*da6c28aaSamw 	uint64_t value;
1727*da6c28aaSamw 	int check = 0;
1728*da6c28aaSamw 	int error;
1729*da6c28aaSamw 
1730*da6c28aaSamw 	ASSERT(norm != NULL);
1731*da6c28aaSamw 	*norm = 0;
1732*da6c28aaSamw 
1733*da6c28aaSamw 	(void) strncpy(parentname, dataset, sizeof (parentname));
1734*da6c28aaSamw 	cp = strrchr(parentname, '@');
1735*da6c28aaSamw 	if (cp != NULL) {
1736*da6c28aaSamw 		cp[0] = '\0';
1737*da6c28aaSamw 	} else {
1738*da6c28aaSamw 		cp = strrchr(parentname, '/');
1739*da6c28aaSamw 		if (cp == NULL)
1740*da6c28aaSamw 			return (ENOENT);
1741*da6c28aaSamw 		cp[0] = '\0';
1742*da6c28aaSamw 	}
1743*da6c28aaSamw 
1744*da6c28aaSamw 	(void) strncpy(poolname, dataset, sizeof (poolname));
1745*da6c28aaSamw 	cp = strchr(poolname, '/');
1746*da6c28aaSamw 	if (cp != NULL)
1747*da6c28aaSamw 		cp[0] = '\0';
1748*da6c28aaSamw 
1749*da6c28aaSamw 	error = zfs_prop_lookup(parentname, ZFS_PROP_UTF8ONLY,
1750*da6c28aaSamw 	    proplist, &value, update);
1751*da6c28aaSamw 	if (error != 0)
1752*da6c28aaSamw 		return (error);
1753*da6c28aaSamw 	if (value != zfs_prop_default_numeric(ZFS_PROP_UTF8ONLY))
1754*da6c28aaSamw 		check = 1;
1755*da6c28aaSamw 
1756*da6c28aaSamw 	error = zfs_prop_lookup(parentname, ZFS_PROP_NORMALIZE,
1757*da6c28aaSamw 	    proplist, &value, update);
1758*da6c28aaSamw 	if (error != 0)
1759*da6c28aaSamw 		return (error);
1760*da6c28aaSamw 	if (value != zfs_prop_default_numeric(ZFS_PROP_NORMALIZE)) {
1761*da6c28aaSamw 		check = 1;
1762*da6c28aaSamw 		switch ((int)value) {
1763*da6c28aaSamw 		case ZFS_NORMALIZE_NONE:
1764*da6c28aaSamw 			break;
1765*da6c28aaSamw 		case ZFS_NORMALIZE_C:
1766*da6c28aaSamw 			*norm |= U8_TEXTPREP_NFC;
1767*da6c28aaSamw 			break;
1768*da6c28aaSamw 		case ZFS_NORMALIZE_D:
1769*da6c28aaSamw 			*norm |= U8_TEXTPREP_NFD;
1770*da6c28aaSamw 			break;
1771*da6c28aaSamw 		case ZFS_NORMALIZE_KC:
1772*da6c28aaSamw 			*norm |= U8_TEXTPREP_NFKC;
1773*da6c28aaSamw 			break;
1774*da6c28aaSamw 		case ZFS_NORMALIZE_KD:
1775*da6c28aaSamw 			*norm |= U8_TEXTPREP_NFKD;
1776*da6c28aaSamw 			break;
1777*da6c28aaSamw 		default:
1778*da6c28aaSamw 			ASSERT((int)value >= ZFS_NORMALIZE_NONE);
1779*da6c28aaSamw 			ASSERT((int)value <= ZFS_NORMALIZE_KD);
1780*da6c28aaSamw 			break;
1781*da6c28aaSamw 		}
1782*da6c28aaSamw 	}
1783*da6c28aaSamw 
1784*da6c28aaSamw 	error = zfs_prop_lookup(parentname, ZFS_PROP_CASE,
1785*da6c28aaSamw 	    proplist, &value, update);
1786*da6c28aaSamw 	if (error != 0)
1787*da6c28aaSamw 		return (error);
1788*da6c28aaSamw 	if (value != zfs_prop_default_numeric(ZFS_PROP_CASE)) {
1789*da6c28aaSamw 		check = 1;
1790*da6c28aaSamw 		switch ((int)value) {
1791*da6c28aaSamw 		case ZFS_CASE_SENSITIVE:
1792*da6c28aaSamw 			break;
1793*da6c28aaSamw 		case ZFS_CASE_INSENSITIVE:
1794*da6c28aaSamw 			*norm |= U8_TEXTPREP_TOUPPER;
1795*da6c28aaSamw 			break;
1796*da6c28aaSamw 		case ZFS_CASE_MIXED:
1797*da6c28aaSamw 			*norm |= U8_TEXTPREP_TOUPPER;
1798*da6c28aaSamw 			break;
1799*da6c28aaSamw 		default:
1800*da6c28aaSamw 			ASSERT((int)value >= ZFS_CASE_SENSITIVE);
1801*da6c28aaSamw 			ASSERT((int)value <= ZFS_CASE_MIXED);
1802*da6c28aaSamw 			break;
1803*da6c28aaSamw 		}
1804*da6c28aaSamw 	}
1805*da6c28aaSamw 
1806*da6c28aaSamw 	if (check == 1)
1807*da6c28aaSamw 		if (zfs_check_version(poolname, SPA_VERSION_NORMALIZATION))
1808*da6c28aaSamw 			return (ENOTSUP);
1809*da6c28aaSamw 	return (0);
1810fa9e4066Sahrens }
1811fa9e4066Sahrens 
1812fa9e4066Sahrens static int
1813fa9e4066Sahrens zfs_ioc_create(zfs_cmd_t *zc)
1814fa9e4066Sahrens {
1815fa9e4066Sahrens 	objset_t *clone;
1816fa9e4066Sahrens 	int error = 0;
1817*da6c28aaSamw 	zfs_creat_t zct;
1818ecd6cf80Smarks 	nvlist_t *nvprops = NULL;
1819ecd6cf80Smarks 	void (*cbfunc)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
1820fa9e4066Sahrens 	dmu_objset_type_t type = zc->zc_objset_type;
1821fa9e4066Sahrens 
1822fa9e4066Sahrens 	switch (type) {
1823fa9e4066Sahrens 
1824fa9e4066Sahrens 	case DMU_OST_ZFS:
1825fa9e4066Sahrens 		cbfunc = zfs_create_cb;
1826fa9e4066Sahrens 		break;
1827fa9e4066Sahrens 
1828fa9e4066Sahrens 	case DMU_OST_ZVOL:
1829fa9e4066Sahrens 		cbfunc = zvol_create_cb;
1830fa9e4066Sahrens 		break;
1831fa9e4066Sahrens 
1832fa9e4066Sahrens 	default:
18331d452cf5Sahrens 		cbfunc = NULL;
1834fa9e4066Sahrens 	}
1835f18faf3fSek 	if (strchr(zc->zc_name, '@') ||
1836f18faf3fSek 	    strchr(zc->zc_name, '%'))
18371d452cf5Sahrens 		return (EINVAL);
1838fa9e4066Sahrens 
1839e9dbad6fSeschrock 	if (zc->zc_nvlist_src != NULL &&
1840990b4856Slling 	    (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
1841990b4856Slling 	    &nvprops)) != 0)
1842e9dbad6fSeschrock 		return (error);
1843e9dbad6fSeschrock 
1844*da6c28aaSamw 	zct.zct_norm = 0;
1845*da6c28aaSamw 	zct.zct_props = nvprops;
1846*da6c28aaSamw 
1847e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
1848fa9e4066Sahrens 		/*
1849fa9e4066Sahrens 		 * We're creating a clone of an existing snapshot.
1850fa9e4066Sahrens 		 */
1851e9dbad6fSeschrock 		zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
1852e9dbad6fSeschrock 		if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) {
1853ecd6cf80Smarks 			nvlist_free(nvprops);
1854fa9e4066Sahrens 			return (EINVAL);
1855e9dbad6fSeschrock 		}
1856fa9e4066Sahrens 
1857e9dbad6fSeschrock 		error = dmu_objset_open(zc->zc_value, type,
1858fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
1859e9dbad6fSeschrock 		if (error) {
1860ecd6cf80Smarks 			nvlist_free(nvprops);
1861fa9e4066Sahrens 			return (error);
1862e9dbad6fSeschrock 		}
1863fa9e4066Sahrens 		error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL);
1864*da6c28aaSamw 		if (error) {
1865*da6c28aaSamw 			dmu_objset_close(clone);
1866*da6c28aaSamw 			nvlist_free(nvprops);
1867*da6c28aaSamw 			return (error);
1868*da6c28aaSamw 		}
1869*da6c28aaSamw 		/*
1870*da6c28aaSamw 		 * If caller did not provide any properties, allocate
1871*da6c28aaSamw 		 * an nvlist for properties, as we will be adding our set-once
1872*da6c28aaSamw 		 * properties to it.  This carries the choices made on the
1873*da6c28aaSamw 		 * original file system into the clone.
1874*da6c28aaSamw 		 */
1875*da6c28aaSamw 		if (nvprops == NULL)
1876*da6c28aaSamw 			VERIFY(nvlist_alloc(&nvprops,
1877*da6c28aaSamw 			    NV_UNIQUE_NAME, KM_SLEEP) == 0);
1878*da6c28aaSamw 
1879*da6c28aaSamw 		/*
1880*da6c28aaSamw 		 * We have to have normalization and case-folding
1881*da6c28aaSamw 		 * flags correct when we do the file system creation,
1882*da6c28aaSamw 		 * so go figure them out now.  All we really care about
1883*da6c28aaSamw 		 * here is getting these values into the property list.
1884*da6c28aaSamw 		 */
1885*da6c28aaSamw 		error = zfs_normalization_get(zc->zc_value, nvprops,
1886*da6c28aaSamw 		    &zct.zct_norm, B_TRUE);
1887*da6c28aaSamw 		if (error != 0) {
1888*da6c28aaSamw 			dmu_objset_close(clone);
1889*da6c28aaSamw 			nvlist_free(nvprops);
1890*da6c28aaSamw 			return (error);
1891*da6c28aaSamw 		}
1892fa9e4066Sahrens 		dmu_objset_close(clone);
1893fa9e4066Sahrens 	} else {
1894e9dbad6fSeschrock 		if (cbfunc == NULL) {
1895ecd6cf80Smarks 			nvlist_free(nvprops);
18961d452cf5Sahrens 			return (EINVAL);
1897e9dbad6fSeschrock 		}
18985c5460e9Seschrock 
1899e9dbad6fSeschrock 		if (type == DMU_OST_ZVOL) {
1900e9dbad6fSeschrock 			uint64_t volsize, volblocksize;
1901e9dbad6fSeschrock 
1902ecd6cf80Smarks 			if (nvprops == NULL ||
1903ecd6cf80Smarks 			    nvlist_lookup_uint64(nvprops,
1904e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLSIZE),
1905e9dbad6fSeschrock 			    &volsize) != 0) {
1906ecd6cf80Smarks 				nvlist_free(nvprops);
1907e9dbad6fSeschrock 				return (EINVAL);
1908e9dbad6fSeschrock 			}
1909e9dbad6fSeschrock 
1910ecd6cf80Smarks 			if ((error = nvlist_lookup_uint64(nvprops,
1911e9dbad6fSeschrock 			    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
1912e9dbad6fSeschrock 			    &volblocksize)) != 0 && error != ENOENT) {
1913ecd6cf80Smarks 				nvlist_free(nvprops);
1914e9dbad6fSeschrock 				return (EINVAL);
1915e9dbad6fSeschrock 			}
1916e9dbad6fSeschrock 
1917e9dbad6fSeschrock 			if (error != 0)
1918e9dbad6fSeschrock 				volblocksize = zfs_prop_default_numeric(
1919e9dbad6fSeschrock 				    ZFS_PROP_VOLBLOCKSIZE);
1920e9dbad6fSeschrock 
1921e9dbad6fSeschrock 			if ((error = zvol_check_volblocksize(
1922e9dbad6fSeschrock 			    volblocksize)) != 0 ||
1923e9dbad6fSeschrock 			    (error = zvol_check_volsize(volsize,
1924e9dbad6fSeschrock 			    volblocksize)) != 0) {
1925ecd6cf80Smarks 				nvlist_free(nvprops);
19265c5460e9Seschrock 				return (error);
1927e9dbad6fSeschrock 			}
1928e7437265Sahrens 		} else if (type == DMU_OST_ZFS) {
1929e7437265Sahrens 			uint64_t version;
1930*da6c28aaSamw 			int error;
1931*da6c28aaSamw 
1932*da6c28aaSamw 			error = nvlist_lookup_uint64(nvprops,
1933*da6c28aaSamw 			    zfs_prop_to_name(ZFS_PROP_VERSION), &version);
1934e7437265Sahrens 
1935*da6c28aaSamw 			if (error == 0 && (version < ZPL_VERSION_INITIAL ||
1936e7437265Sahrens 			    version > ZPL_VERSION)) {
1937e7437265Sahrens 				nvlist_free(nvprops);
1938*da6c28aaSamw 				return (ENOTSUP);
1939*da6c28aaSamw 			} else if (error == 0 && version >= ZPL_VERSION_FUID &&
1940*da6c28aaSamw 			    zfs_check_version(zc->zc_name, SPA_VERSION_FUID)) {
1941*da6c28aaSamw 				nvlist_free(nvprops);
1942*da6c28aaSamw 				return (ENOTSUP);
1943e7437265Sahrens 			}
1944e9dbad6fSeschrock 
1945*da6c28aaSamw 			/*
1946*da6c28aaSamw 			 * We have to have normalization and
1947*da6c28aaSamw 			 * case-folding flags correct when we do the
1948*da6c28aaSamw 			 * file system creation, so go figure them out
1949*da6c28aaSamw 			 * now.  The final argument to zfs_normalization_get()
1950*da6c28aaSamw 			 * tells that routine not to update the nvprops
1951*da6c28aaSamw 			 * list.
1952*da6c28aaSamw 			 */
1953*da6c28aaSamw 			error = zfs_normalization_get(zc->zc_name, nvprops,
1954*da6c28aaSamw 			    &zct.zct_norm, B_FALSE);
1955*da6c28aaSamw 			if (error != 0) {
1956*da6c28aaSamw 				nvlist_free(nvprops);
1957*da6c28aaSamw 				return (error);
1958*da6c28aaSamw 			}
1959*da6c28aaSamw 		}
1960e9dbad6fSeschrock 		error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc,
1961*da6c28aaSamw 		    &zct);
1962fa9e4066Sahrens 	}
1963e9dbad6fSeschrock 
1964e9dbad6fSeschrock 	/*
1965e9dbad6fSeschrock 	 * It would be nice to do this atomically.
1966e9dbad6fSeschrock 	 */
1967e9dbad6fSeschrock 	if (error == 0) {
196891ebeef5Sahrens 		if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0)
1969e9dbad6fSeschrock 			(void) dmu_objset_destroy(zc->zc_name);
1970e9dbad6fSeschrock 	}
1971e9dbad6fSeschrock 
1972ecd6cf80Smarks 	nvlist_free(nvprops);
1973fa9e4066Sahrens 	return (error);
1974fa9e4066Sahrens }
1975fa9e4066Sahrens 
1976fa9e4066Sahrens static int
19771d452cf5Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc)
1978fa9e4066Sahrens {
1979e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
19801d452cf5Sahrens 		return (EINVAL);
19811d452cf5Sahrens 	return (dmu_objset_snapshot(zc->zc_name,
1982e9dbad6fSeschrock 	    zc->zc_value, zc->zc_cookie));
19831d452cf5Sahrens }
1984fa9e4066Sahrens 
1985cdf5b4caSmmusante int
19861d452cf5Sahrens zfs_unmount_snap(char *name, void *arg)
19871d452cf5Sahrens {
19881d452cf5Sahrens 	char *snapname = arg;
19891d452cf5Sahrens 	char *cp;
19900b69c2f0Sahrens 	vfs_t *vfsp = NULL;
19911d452cf5Sahrens 
19921d452cf5Sahrens 	/*
19931d452cf5Sahrens 	 * Snapshots (which are under .zfs control) must be unmounted
19941d452cf5Sahrens 	 * before they can be destroyed.
19951d452cf5Sahrens 	 */
19961d452cf5Sahrens 
19971d452cf5Sahrens 	if (snapname) {
19981d452cf5Sahrens 		(void) strcat(name, "@");
19991d452cf5Sahrens 		(void) strcat(name, snapname);
20001d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
20011d452cf5Sahrens 		cp = strchr(name, '@');
20021d452cf5Sahrens 		*cp = '\0';
20030b69c2f0Sahrens 	} else if (strchr(name, '@')) {
20041d452cf5Sahrens 		vfsp = zfs_get_vfs(name);
20051d452cf5Sahrens 	}
20061d452cf5Sahrens 
20071d452cf5Sahrens 	if (vfsp) {
2008fa9e4066Sahrens 		/*
20091d452cf5Sahrens 		 * Always force the unmount for snapshots.
2010fa9e4066Sahrens 		 */
20111d452cf5Sahrens 		int flag = MS_FORCE;
20121d452cf5Sahrens 		int err;
20131d452cf5Sahrens 
20141d452cf5Sahrens 		if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) {
2015fa9e4066Sahrens 			VFS_RELE(vfsp);
20161d452cf5Sahrens 			return (err);
2017fa9e4066Sahrens 		}
20181d452cf5Sahrens 		VFS_RELE(vfsp);
20191d452cf5Sahrens 		if ((err = dounmount(vfsp, flag, kcred)) != 0)
20201d452cf5Sahrens 			return (err);
20211d452cf5Sahrens 	}
20221d452cf5Sahrens 	return (0);
20231d452cf5Sahrens }
20241d452cf5Sahrens 
20251d452cf5Sahrens static int
20261d452cf5Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc)
20271d452cf5Sahrens {
20281d452cf5Sahrens 	int err;
20291d452cf5Sahrens 
2030e9dbad6fSeschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
20311d452cf5Sahrens 		return (EINVAL);
20321d452cf5Sahrens 	err = dmu_objset_find(zc->zc_name,
2033e9dbad6fSeschrock 	    zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN);
20341d452cf5Sahrens 	if (err)
20351d452cf5Sahrens 		return (err);
2036e9dbad6fSeschrock 	return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value));
20371d452cf5Sahrens }
20381d452cf5Sahrens 
20391d452cf5Sahrens static int
20401d452cf5Sahrens zfs_ioc_destroy(zfs_cmd_t *zc)
20411d452cf5Sahrens {
20421d452cf5Sahrens 	if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) {
20431d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
20441d452cf5Sahrens 		if (err)
20451d452cf5Sahrens 			return (err);
2046fa9e4066Sahrens 	}
2047fa9e4066Sahrens 
2048fa9e4066Sahrens 	return (dmu_objset_destroy(zc->zc_name));
2049fa9e4066Sahrens }
2050fa9e4066Sahrens 
2051fa9e4066Sahrens static int
2052fa9e4066Sahrens zfs_ioc_rollback(zfs_cmd_t *zc)
2053fa9e4066Sahrens {
2054fa9e4066Sahrens 	return (dmu_objset_rollback(zc->zc_name));
2055fa9e4066Sahrens }
2056fa9e4066Sahrens 
2057fa9e4066Sahrens static int
2058fa9e4066Sahrens zfs_ioc_rename(zfs_cmd_t *zc)
2059fa9e4066Sahrens {
20607f1f55eaSvb 	boolean_t recursive = zc->zc_cookie & 1;
2061cdf5b4caSmmusante 
2062e9dbad6fSeschrock 	zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
2063f18faf3fSek 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
2064f18faf3fSek 	    strchr(zc->zc_value, '%'))
2065fa9e4066Sahrens 		return (EINVAL);
2066fa9e4066Sahrens 
2067cdf5b4caSmmusante 	/*
2068cdf5b4caSmmusante 	 * Unmount snapshot unless we're doing a recursive rename,
2069cdf5b4caSmmusante 	 * in which case the dataset code figures out which snapshots
2070cdf5b4caSmmusante 	 * to unmount.
2071cdf5b4caSmmusante 	 */
2072cdf5b4caSmmusante 	if (!recursive && strchr(zc->zc_name, '@') != NULL &&
2073fa9e4066Sahrens 	    zc->zc_objset_type == DMU_OST_ZFS) {
20741d452cf5Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
20751d452cf5Sahrens 		if (err)
20761d452cf5Sahrens 			return (err);
2077fa9e4066Sahrens 	}
2078fa9e4066Sahrens 
2079cdf5b4caSmmusante 	return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive));
2080fa9e4066Sahrens }
2081fa9e4066Sahrens 
2082fa9e4066Sahrens static int
2083fa9e4066Sahrens zfs_ioc_recvbackup(zfs_cmd_t *zc)
2084fa9e4066Sahrens {
2085fa9e4066Sahrens 	file_t *fp;
2086a2eea2e1Sahrens 	offset_t new_off;
2087f18faf3fSek 	objset_t *os;
2088f18faf3fSek 	zfsvfs_t *zfsvfs = NULL;
2089f18faf3fSek 	char *cp;
2090f18faf3fSek 	char cosname[MAXNAMELEN];
2091f18faf3fSek 	boolean_t force = (boolean_t)zc->zc_guid;
2092f18faf3fSek 	int error, fd;
2093fa9e4066Sahrens 
20943ccfa83cSahrens 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
2095f18faf3fSek 	    strchr(zc->zc_value, '@') == NULL ||
2096f18faf3fSek 	    strchr(zc->zc_value, '%'))
20973ccfa83cSahrens 		return (EINVAL);
20983ccfa83cSahrens 
2099fa9e4066Sahrens 	fd = zc->zc_cookie;
2100fa9e4066Sahrens 	fp = getf(fd);
2101fa9e4066Sahrens 	if (fp == NULL)
2102fa9e4066Sahrens 		return (EBADF);
2103f18faf3fSek 
2104f18faf3fSek 	/*
2105f18faf3fSek 	 * Get the zfsvfs for the receiving objset. There
2106f18faf3fSek 	 * won't be one if we're operating on a zvol, if the
2107f18faf3fSek 	 * objset doesn't exist yet, or is not mounted.
2108f18faf3fSek 	 */
2109f18faf3fSek 	cp = strchr(zc->zc_value, '@');
2110f18faf3fSek 	*cp = '\0';
2111f18faf3fSek 	error = dmu_objset_open(zc->zc_value, DMU_OST_ANY,
2112f18faf3fSek 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
2113f18faf3fSek 	*cp = '@';
2114f18faf3fSek 	if (!error) {
2115f18faf3fSek 		if (dmu_objset_type(os) == DMU_OST_ZFS) {
2116f18faf3fSek 			mutex_enter(&os->os->os_user_ptr_lock);
2117f18faf3fSek 			zfsvfs = dmu_objset_get_user(os);
2118f18faf3fSek 			if (zfsvfs != NULL)
2119f18faf3fSek 				VFS_HOLD(zfsvfs->z_vfs);
2120f18faf3fSek 			mutex_exit(&os->os->os_user_ptr_lock);
2121f18faf3fSek 		}
2122f18faf3fSek 		dmu_objset_close(os);
2123f18faf3fSek 	}
2124f18faf3fSek 
2125e9dbad6fSeschrock 	error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record,
2126f18faf3fSek 	    &zc->zc_cookie, force, zfsvfs != NULL, fp->f_vnode,
2127f18faf3fSek 	    fp->f_offset, cosname);
2128f18faf3fSek 
2129f18faf3fSek 	/*
2130f18faf3fSek 	 * For incremental snapshots where we created a
2131f18faf3fSek 	 * temporary clone, we now swap zfsvfs::z_os with
2132f18faf3fSek 	 * the newly created and received "cosname".
2133f18faf3fSek 	 */
2134f18faf3fSek 	if (!error && zfsvfs != NULL) {
2135f18faf3fSek 		char osname[MAXNAMELEN];
2136f18faf3fSek 		int mode;
2137f18faf3fSek 
2138f18faf3fSek 		error = zfs_suspend_fs(zfsvfs, osname, &mode);
2139f18faf3fSek 		if (!error) {
2140f18faf3fSek 			int swap_err;
2141f18faf3fSek 			int snap_err = 0;
2142f18faf3fSek 
2143f18faf3fSek 			swap_err = dsl_dataset_clone_swap(cosname, force);
2144f18faf3fSek 			if (!swap_err) {
2145f18faf3fSek 				char *cp = strrchr(zc->zc_value, '@');
2146f18faf3fSek 
2147f18faf3fSek 				*cp = '\0';
2148f18faf3fSek 				snap_err = dmu_replay_end_snapshot(zc->zc_value,
2149f18faf3fSek 				    &zc->zc_begin_record);
2150f18faf3fSek 				*cp = '@';
2151f18faf3fSek 			}
2152f18faf3fSek 			error = zfs_resume_fs(zfsvfs, osname, mode);
2153f18faf3fSek 			if (!error)
2154f18faf3fSek 				error = swap_err;
2155f18faf3fSek 			if (!error)
2156f18faf3fSek 				error = snap_err;
2157f18faf3fSek 		}
2158a2eea2e1Sahrens 
2159f18faf3fSek 		/* destroy the clone we created */
2160f18faf3fSek 		(void) dmu_objset_destroy(cosname);
2161f18faf3fSek 	}
2162f18faf3fSek 	if (zfsvfs != NULL)
2163f18faf3fSek 		VFS_RELE(zfsvfs->z_vfs);
2164a2eea2e1Sahrens 	new_off = fp->f_offset + zc->zc_cookie;
2165*da6c28aaSamw 	if (VOP_SEEK(fp->f_vnode, fp->f_offset, &new_off, NULL) == 0)
2166a2eea2e1Sahrens 		fp->f_offset = new_off;
2167a2eea2e1Sahrens 
2168fa9e4066Sahrens 	releasef(fd);
2169fa9e4066Sahrens 	return (error);
2170fa9e4066Sahrens }
2171fa9e4066Sahrens 
2172fa9e4066Sahrens static int
2173fa9e4066Sahrens zfs_ioc_sendbackup(zfs_cmd_t *zc)
2174fa9e4066Sahrens {
2175fa9e4066Sahrens 	objset_t *fromsnap = NULL;
2176fa9e4066Sahrens 	objset_t *tosnap;
2177fa9e4066Sahrens 	file_t *fp;
2178fa9e4066Sahrens 	int error;
2179fa9e4066Sahrens 
2180fa9e4066Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
2181fa9e4066Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap);
2182fa9e4066Sahrens 	if (error)
2183fa9e4066Sahrens 		return (error);
2184fa9e4066Sahrens 
2185e9dbad6fSeschrock 	if (zc->zc_value[0] != '\0') {
2186a2eea2e1Sahrens 		char buf[MAXPATHLEN];
2187a2eea2e1Sahrens 		char *cp;
2188a2eea2e1Sahrens 
2189a2eea2e1Sahrens 		(void) strncpy(buf, zc->zc_name, sizeof (buf));
2190a2eea2e1Sahrens 		cp = strchr(buf, '@');
2191a2eea2e1Sahrens 		if (cp)
2192a2eea2e1Sahrens 			*(cp+1) = 0;
2193a2eea2e1Sahrens 		(void) strncat(buf, zc->zc_value, sizeof (buf));
2194a2eea2e1Sahrens 		error = dmu_objset_open(buf, DMU_OST_ANY,
2195fa9e4066Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap);
2196fa9e4066Sahrens 		if (error) {
2197fa9e4066Sahrens 			dmu_objset_close(tosnap);
2198fa9e4066Sahrens 			return (error);
2199fa9e4066Sahrens 		}
2200fa9e4066Sahrens 	}
2201fa9e4066Sahrens 
2202fa9e4066Sahrens 	fp = getf(zc->zc_cookie);
2203fa9e4066Sahrens 	if (fp == NULL) {
2204fa9e4066Sahrens 		dmu_objset_close(tosnap);
2205fa9e4066Sahrens 		if (fromsnap)
2206fa9e4066Sahrens 			dmu_objset_close(fromsnap);
2207fa9e4066Sahrens 		return (EBADF);
2208fa9e4066Sahrens 	}
2209fa9e4066Sahrens 
2210fa9e4066Sahrens 	error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode);
2211fa9e4066Sahrens 
2212fa9e4066Sahrens 	releasef(zc->zc_cookie);
2213fa9e4066Sahrens 	if (fromsnap)
2214fa9e4066Sahrens 		dmu_objset_close(fromsnap);
2215fa9e4066Sahrens 	dmu_objset_close(tosnap);
2216fa9e4066Sahrens 	return (error);
2217fa9e4066Sahrens }
2218fa9e4066Sahrens 
2219ea8dc4b6Seschrock static int
2220ea8dc4b6Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc)
2221ea8dc4b6Seschrock {
2222ea8dc4b6Seschrock 	int id, error;
2223ea8dc4b6Seschrock 
2224ea8dc4b6Seschrock 	error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id,
2225ea8dc4b6Seschrock 	    &zc->zc_inject_record);
2226ea8dc4b6Seschrock 
2227ea8dc4b6Seschrock 	if (error == 0)
2228ea8dc4b6Seschrock 		zc->zc_guid = (uint64_t)id;
2229ea8dc4b6Seschrock 
2230ea8dc4b6Seschrock 	return (error);
2231ea8dc4b6Seschrock }
2232ea8dc4b6Seschrock 
2233ea8dc4b6Seschrock static int
2234ea8dc4b6Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc)
2235ea8dc4b6Seschrock {
2236ea8dc4b6Seschrock 	return (zio_clear_fault((int)zc->zc_guid));
2237ea8dc4b6Seschrock }
2238ea8dc4b6Seschrock 
2239ea8dc4b6Seschrock static int
2240ea8dc4b6Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc)
2241ea8dc4b6Seschrock {
2242ea8dc4b6Seschrock 	int id = (int)zc->zc_guid;
2243ea8dc4b6Seschrock 	int error;
2244ea8dc4b6Seschrock 
2245ea8dc4b6Seschrock 	error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name),
2246ea8dc4b6Seschrock 	    &zc->zc_inject_record);
2247ea8dc4b6Seschrock 
2248ea8dc4b6Seschrock 	zc->zc_guid = id;
2249ea8dc4b6Seschrock 
2250ea8dc4b6Seschrock 	return (error);
2251ea8dc4b6Seschrock }
2252ea8dc4b6Seschrock 
2253ea8dc4b6Seschrock static int
2254ea8dc4b6Seschrock zfs_ioc_error_log(zfs_cmd_t *zc)
2255ea8dc4b6Seschrock {
2256ea8dc4b6Seschrock 	spa_t *spa;
2257ea8dc4b6Seschrock 	int error;
2258e9dbad6fSeschrock 	size_t count = (size_t)zc->zc_nvlist_dst_size;
2259ea8dc4b6Seschrock 
2260ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
2261ea8dc4b6Seschrock 		return (error);
2262ea8dc4b6Seschrock 
2263e9dbad6fSeschrock 	error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst,
2264ea8dc4b6Seschrock 	    &count);
2265ea8dc4b6Seschrock 	if (error == 0)
2266e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = count;
2267ea8dc4b6Seschrock 	else
2268e9dbad6fSeschrock 		zc->zc_nvlist_dst_size = spa_get_errlog_size(spa);
2269ea8dc4b6Seschrock 
2270ea8dc4b6Seschrock 	spa_close(spa, FTAG);
2271ea8dc4b6Seschrock 
2272ea8dc4b6Seschrock 	return (error);
2273ea8dc4b6Seschrock }
2274ea8dc4b6Seschrock 
2275ea8dc4b6Seschrock static int
2276ea8dc4b6Seschrock zfs_ioc_clear(zfs_cmd_t *zc)
2277ea8dc4b6Seschrock {
2278ea8dc4b6Seschrock 	spa_t *spa;
2279ea8dc4b6Seschrock 	vdev_t *vd;
22803d7072f8Seschrock 	uint64_t txg;
2281bb8b5132Sek 	int error;
2282ea8dc4b6Seschrock 
2283ea8dc4b6Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
2284ea8dc4b6Seschrock 		return (error);
2285ea8dc4b6Seschrock 
22860a4e9518Sgw 	/*
22870a4e9518Sgw 	 * Try to resume any I/Os which may have been suspended
22880a4e9518Sgw 	 * as a result of a complete pool failure.
22890a4e9518Sgw 	 */
22900a4e9518Sgw 	if (!list_is_empty(&spa->spa_zio_list)) {
22910a4e9518Sgw 		if (zio_vdev_resume_io(spa) != 0) {
22920a4e9518Sgw 			spa_close(spa, FTAG);
22930a4e9518Sgw 			return (EIO);
22940a4e9518Sgw 		}
22950a4e9518Sgw 	}
22960a4e9518Sgw 
22973d7072f8Seschrock 	txg = spa_vdev_enter(spa);
2298ea8dc4b6Seschrock 
2299e9dbad6fSeschrock 	if (zc->zc_guid == 0) {
2300ea8dc4b6Seschrock 		vd = NULL;
2301e9dbad6fSeschrock 	} else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) {
23023d7072f8Seschrock 		(void) spa_vdev_exit(spa, NULL, txg, ENODEV);
2303ea8dc4b6Seschrock 		spa_close(spa, FTAG);
2304ea8dc4b6Seschrock 		return (ENODEV);
2305ea8dc4b6Seschrock 	}
2306ea8dc4b6Seschrock 
23070a4e9518Sgw 	vdev_clear(spa, vd, B_TRUE);
2308ea8dc4b6Seschrock 
23093d7072f8Seschrock 	(void) spa_vdev_exit(spa, NULL, txg, 0);
2310ea8dc4b6Seschrock 
2311ea8dc4b6Seschrock 	spa_close(spa, FTAG);
2312ea8dc4b6Seschrock 
2313ea8dc4b6Seschrock 	return (0);
2314ea8dc4b6Seschrock }
2315ea8dc4b6Seschrock 
231699653d4eSeschrock static int
231799653d4eSeschrock zfs_ioc_promote(zfs_cmd_t *zc)
231899653d4eSeschrock {
23190b69c2f0Sahrens 	char *cp;
23200b69c2f0Sahrens 
23210b69c2f0Sahrens 	/*
23220b69c2f0Sahrens 	 * We don't need to unmount *all* the origin fs's snapshots, but
23230b69c2f0Sahrens 	 * it's easier.
23240b69c2f0Sahrens 	 */
2325e9dbad6fSeschrock 	cp = strchr(zc->zc_value, '@');
23260b69c2f0Sahrens 	if (cp)
23270b69c2f0Sahrens 		*cp = '\0';
2328e9dbad6fSeschrock 	(void) dmu_objset_find(zc->zc_value,
23290b69c2f0Sahrens 	    zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS);
233099653d4eSeschrock 	return (dsl_dataset_promote(zc->zc_name));
233199653d4eSeschrock }
233299653d4eSeschrock 
2333ecd6cf80Smarks /*
2334ecd6cf80Smarks  * We don't want to have a hard dependency
2335ecd6cf80Smarks  * against some special symbols in sharefs
2336*da6c28aaSamw  * nfs, and smbsrv.  Determine them if needed when
2337ecd6cf80Smarks  * the first file system is shared.
2338*da6c28aaSamw  * Neither sharefs, nfs or smbsrv are unloadable modules.
2339ecd6cf80Smarks  */
2340*da6c28aaSamw int (*znfsexport_fs)(void *arg);
2341ecd6cf80Smarks int (*zshare_fs)(enum sharefs_sys_op, share_t *, uint32_t);
2342*da6c28aaSamw int (*zsmbexport_fs)(void *arg, boolean_t add_share);
2343*da6c28aaSamw 
2344*da6c28aaSamw int zfs_nfsshare_inited;
2345*da6c28aaSamw int zfs_smbshare_inited;
2346ecd6cf80Smarks 
2347ecd6cf80Smarks ddi_modhandle_t nfs_mod;
2348ecd6cf80Smarks ddi_modhandle_t sharefs_mod;
2349*da6c28aaSamw ddi_modhandle_t smbsrv_mod;
2350ecd6cf80Smarks kmutex_t zfs_share_lock;
2351ecd6cf80Smarks 
2352*da6c28aaSamw static int
2353*da6c28aaSamw zfs_init_sharefs()
2354*da6c28aaSamw {
2355*da6c28aaSamw 	int error;
2356*da6c28aaSamw 
2357*da6c28aaSamw 	ASSERT(MUTEX_HELD(&zfs_share_lock));
2358*da6c28aaSamw 	/* Both NFS and SMB shares also require sharetab support. */
2359*da6c28aaSamw 	if (sharefs_mod == NULL && ((sharefs_mod =
2360*da6c28aaSamw 	    ddi_modopen("fs/sharefs",
2361*da6c28aaSamw 	    KRTLD_MODE_FIRST, &error)) == NULL)) {
2362*da6c28aaSamw 		return (ENOSYS);
2363*da6c28aaSamw 	}
2364*da6c28aaSamw 	if (zshare_fs == NULL && ((zshare_fs =
2365*da6c28aaSamw 	    (int (*)(enum sharefs_sys_op, share_t *, uint32_t))
2366*da6c28aaSamw 	    ddi_modsym(sharefs_mod, "sharefs_impl", &error)) == NULL)) {
2367*da6c28aaSamw 		return (ENOSYS);
2368*da6c28aaSamw 	}
2369*da6c28aaSamw 	return (0);
2370*da6c28aaSamw }
2371*da6c28aaSamw 
2372ecd6cf80Smarks static int
2373ecd6cf80Smarks zfs_ioc_share(zfs_cmd_t *zc)
2374ecd6cf80Smarks {
2375ecd6cf80Smarks 	int error;
2376ecd6cf80Smarks 	int opcode;
2377ecd6cf80Smarks 
2378*da6c28aaSamw 	switch (zc->zc_share.z_sharetype) {
2379*da6c28aaSamw 	case ZFS_SHARE_NFS:
2380*da6c28aaSamw 	case ZFS_UNSHARE_NFS:
2381*da6c28aaSamw 		if (zfs_nfsshare_inited == 0) {
2382*da6c28aaSamw 			mutex_enter(&zfs_share_lock);
2383*da6c28aaSamw 			if (nfs_mod == NULL && ((nfs_mod = ddi_modopen("fs/nfs",
2384*da6c28aaSamw 			    KRTLD_MODE_FIRST, &error)) == NULL)) {
2385*da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2386*da6c28aaSamw 				return (ENOSYS);
2387*da6c28aaSamw 			}
2388*da6c28aaSamw 			if (znfsexport_fs == NULL &&
2389*da6c28aaSamw 			    ((znfsexport_fs = (int (*)(void *))
2390*da6c28aaSamw 			    ddi_modsym(nfs_mod,
2391*da6c28aaSamw 			    "nfs_export", &error)) == NULL)) {
2392*da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2393*da6c28aaSamw 				return (ENOSYS);
2394*da6c28aaSamw 			}
2395*da6c28aaSamw 			error = zfs_init_sharefs();
2396*da6c28aaSamw 			if (error) {
2397*da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2398*da6c28aaSamw 				return (ENOSYS);
2399*da6c28aaSamw 			}
2400*da6c28aaSamw 			zfs_nfsshare_inited = 1;
2401ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2402ecd6cf80Smarks 		}
2403*da6c28aaSamw 		break;
2404*da6c28aaSamw 	case ZFS_SHARE_SMB:
2405*da6c28aaSamw 	case ZFS_UNSHARE_SMB:
2406*da6c28aaSamw 		if (zfs_smbshare_inited == 0) {
2407*da6c28aaSamw 			mutex_enter(&zfs_share_lock);
2408*da6c28aaSamw 			if (smbsrv_mod == NULL && ((smbsrv_mod =
2409*da6c28aaSamw 			    ddi_modopen("drv/smbsrv",
2410*da6c28aaSamw 			    KRTLD_MODE_FIRST, &error)) == NULL)) {
2411*da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2412*da6c28aaSamw 				return (ENOSYS);
2413*da6c28aaSamw 			}
2414*da6c28aaSamw 			if (zsmbexport_fs == NULL && ((zsmbexport_fs =
2415*da6c28aaSamw 			    (int (*)(void *, boolean_t))ddi_modsym(smbsrv_mod,
2416*da6c28aaSamw 			    "lmshrd_share_upcall", &error)) == NULL)) {
2417*da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2418*da6c28aaSamw 				return (ENOSYS);
2419*da6c28aaSamw 			}
2420*da6c28aaSamw 			error = zfs_init_sharefs();
2421*da6c28aaSamw 			if (error) {
2422*da6c28aaSamw 				mutex_exit(&zfs_share_lock);
2423*da6c28aaSamw 				return (ENOSYS);
2424*da6c28aaSamw 			}
2425*da6c28aaSamw 			zfs_smbshare_inited = 1;
2426ecd6cf80Smarks 			mutex_exit(&zfs_share_lock);
2427ecd6cf80Smarks 		}
2428*da6c28aaSamw 		break;
2429*da6c28aaSamw 	default:
2430*da6c28aaSamw 		return (EINVAL);
2431*da6c28aaSamw 	}
2432ecd6cf80Smarks 
2433*da6c28aaSamw 	switch (zc->zc_share.z_sharetype) {
2434*da6c28aaSamw 	case ZFS_SHARE_NFS:
2435*da6c28aaSamw 	case ZFS_UNSHARE_NFS:
2436*da6c28aaSamw 		if (error =
2437*da6c28aaSamw 		    znfsexport_fs((void *)
2438*da6c28aaSamw 		    (uintptr_t)zc->zc_share.z_exportdata))
2439*da6c28aaSamw 			return (error);
2440*da6c28aaSamw 		break;
2441*da6c28aaSamw 	case ZFS_SHARE_SMB:
2442*da6c28aaSamw 	case ZFS_UNSHARE_SMB:
2443*da6c28aaSamw 		if (error = zsmbexport_fs((void *)
2444*da6c28aaSamw 		    (uintptr_t)zc->zc_share.z_exportdata,
2445*da6c28aaSamw 		    zc->zc_share.z_sharetype == ZFS_SHARE_SMB ?
2446*da6c28aaSamw 		    B_TRUE : B_FALSE)) {
2447*da6c28aaSamw 			return (error);
2448ecd6cf80Smarks 		}
2449*da6c28aaSamw 		break;
2450ecd6cf80Smarks 	}
2451ecd6cf80Smarks 
2452*da6c28aaSamw 	opcode = (zc->zc_share.z_sharetype == ZFS_SHARE_NFS ||
2453*da6c28aaSamw 	    zc->zc_share.z_sharetype == ZFS_SHARE_SMB) ?
2454ecd6cf80Smarks 	    SHAREFS_ADD : SHAREFS_REMOVE;
2455ecd6cf80Smarks 
2456*da6c28aaSamw 	/*
2457*da6c28aaSamw 	 * Add or remove share from sharetab
2458*da6c28aaSamw 	 */
2459ecd6cf80Smarks 	error = zshare_fs(opcode,
2460ecd6cf80Smarks 	    (void *)(uintptr_t)zc->zc_share.z_sharedata,
2461ecd6cf80Smarks 	    zc->zc_share.z_sharemax);
2462ecd6cf80Smarks 
2463ecd6cf80Smarks 	return (error);
2464ecd6cf80Smarks 
2465ecd6cf80Smarks }
2466ecd6cf80Smarks 
2467ecd6cf80Smarks /*
24682a6b87f0Sek  * pool create, destroy, and export don't log the history as part of
24692a6b87f0Sek  * zfsdev_ioctl, but rather zfs_ioc_pool_create, and zfs_ioc_pool_export
24702a6b87f0Sek  * do the logging of those commands.
2471ecd6cf80Smarks  */
2472fa9e4066Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = {
2473228975ccSek 	{ zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2474e7437265Sahrens 	{ zfs_ioc_pool_destroy,	zfs_secpolicy_config, POOL_NAME, B_FALSE },
2475e7437265Sahrens 	{ zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2476e7437265Sahrens 	{ zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2477e7437265Sahrens 	{ zfs_ioc_pool_configs,	zfs_secpolicy_none, NO_NAME, B_FALSE },
2478e7437265Sahrens 	{ zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE },
2479e7437265Sahrens 	{ zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE },
2480e7437265Sahrens 	{ zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2481e7437265Sahrens 	{ zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE },
2482e7437265Sahrens 	{ zfs_ioc_pool_upgrade,	zfs_secpolicy_config, POOL_NAME, B_TRUE },
2483e7437265Sahrens 	{ zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2484e7437265Sahrens 	{ zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2485e7437265Sahrens 	{ zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2486e7437265Sahrens 	{ zfs_ioc_vdev_set_state, zfs_secpolicy_config,	POOL_NAME, B_TRUE },
2487e7437265Sahrens 	{ zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2488e7437265Sahrens 	{ zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2489e7437265Sahrens 	{ zfs_ioc_vdev_setpath,	zfs_secpolicy_config, POOL_NAME, B_FALSE },
2490e7437265Sahrens 	{ zfs_ioc_objset_stats,	zfs_secpolicy_read, DATASET_NAME, B_FALSE },
2491bd00f61bSrm 	{ zfs_ioc_objset_version, zfs_secpolicy_read, DATASET_NAME, B_FALSE },
2492ecd6cf80Smarks 	{ zfs_ioc_dataset_list_next, zfs_secpolicy_read,
2493e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2494ecd6cf80Smarks 	{ zfs_ioc_snapshot_list_next, zfs_secpolicy_read,
2495e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2496e7437265Sahrens 	{ zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE },
2497e7437265Sahrens 	{ zfs_ioc_create_minor,	zfs_secpolicy_minor, DATASET_NAME, B_FALSE },
2498e7437265Sahrens 	{ zfs_ioc_remove_minor,	zfs_secpolicy_minor, DATASET_NAME, B_FALSE },
2499e7437265Sahrens 	{ zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE },
2500e7437265Sahrens 	{ zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE },
2501e7437265Sahrens 	{ zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE },
2502e7437265Sahrens 	{ zfs_ioc_rename, zfs_secpolicy_rename,	DATASET_NAME, B_TRUE },
2503e7437265Sahrens 	{ zfs_ioc_recvbackup, zfs_secpolicy_receive, DATASET_NAME, B_TRUE },
2504e7437265Sahrens 	{ zfs_ioc_sendbackup, zfs_secpolicy_send, DATASET_NAME, B_TRUE },
2505e7437265Sahrens 	{ zfs_ioc_inject_fault,	zfs_secpolicy_inject, NO_NAME, B_FALSE },
2506e7437265Sahrens 	{ zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE },
2507e7437265Sahrens 	{ zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE },
2508e7437265Sahrens 	{ zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE },
2509e7437265Sahrens 	{ zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE },
2510e7437265Sahrens 	{ zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE },
2511e7437265Sahrens 	{ zfs_ioc_destroy_snaps, zfs_secpolicy_destroy,	DATASET_NAME, B_TRUE },
2512e7437265Sahrens 	{ zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE },
2513e7437265Sahrens 	{ zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE },
2514e7437265Sahrens 	{ zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE },
2515e7437265Sahrens 	{ zfs_ioc_pool_set_props, zfs_secpolicy_config,	POOL_NAME, B_TRUE },
2516e7437265Sahrens 	{ zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE },
2517e7437265Sahrens 	{ zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE },
2518e7437265Sahrens 	{ zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE },
2519ecd6cf80Smarks 	{ zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi,
2520e7437265Sahrens 	    DATASET_NAME, B_FALSE },
2521e45ce728Sahrens 	{ zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE },
2522e45ce728Sahrens 	{ zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE },
2523fa9e4066Sahrens };
2524fa9e4066Sahrens 
2525fa9e4066Sahrens static int
2526fa9e4066Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
2527fa9e4066Sahrens {
2528fa9e4066Sahrens 	zfs_cmd_t *zc;
2529fa9e4066Sahrens 	uint_t vec;
25301d452cf5Sahrens 	int error, rc;
2531fa9e4066Sahrens 
2532fa9e4066Sahrens 	if (getminor(dev) != 0)
2533fa9e4066Sahrens 		return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp));
2534fa9e4066Sahrens 
2535fa9e4066Sahrens 	vec = cmd - ZFS_IOC;
253691ebeef5Sahrens 	ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip));
2537fa9e4066Sahrens 
2538fa9e4066Sahrens 	if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
2539fa9e4066Sahrens 		return (EINVAL);
2540fa9e4066Sahrens 
2541fa9e4066Sahrens 	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
2542fa9e4066Sahrens 
2543fa9e4066Sahrens 	error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t));
2544fa9e4066Sahrens 
254591ebeef5Sahrens 	if (error == 0)
2546ecd6cf80Smarks 		error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr);
2547fa9e4066Sahrens 
2548fa9e4066Sahrens 	/*
2549fa9e4066Sahrens 	 * Ensure that all pool/dataset names are valid before we pass down to
2550fa9e4066Sahrens 	 * the lower layers.
2551fa9e4066Sahrens 	 */
2552fa9e4066Sahrens 	if (error == 0) {
2553fa9e4066Sahrens 		zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
2554fa9e4066Sahrens 		switch (zfs_ioc_vec[vec].zvec_namecheck) {
2555e7437265Sahrens 		case POOL_NAME:
2556fa9e4066Sahrens 			if (pool_namecheck(zc->zc_name, NULL, NULL) != 0)
2557fa9e4066Sahrens 				error = EINVAL;
2558fa9e4066Sahrens 			break;
2559fa9e4066Sahrens 
2560e7437265Sahrens 		case DATASET_NAME:
2561fa9e4066Sahrens 			if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0)
2562fa9e4066Sahrens 				error = EINVAL;
2563fa9e4066Sahrens 			break;
25645ad82045Snd 
2565e7437265Sahrens 		case NO_NAME:
25665ad82045Snd 			break;
2567fa9e4066Sahrens 		}
2568fa9e4066Sahrens 	}
2569fa9e4066Sahrens 
2570fa9e4066Sahrens 	if (error == 0)
2571fa9e4066Sahrens 		error = zfs_ioc_vec[vec].zvec_func(zc);
2572fa9e4066Sahrens 
25731d452cf5Sahrens 	rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t));
2574ecd6cf80Smarks 	if (error == 0) {
25751d452cf5Sahrens 		error = rc;
2576ecd6cf80Smarks 		if (zfs_ioc_vec[vec].zvec_his_log == B_TRUE)
2577ecd6cf80Smarks 			zfs_log_history(zc);
2578ecd6cf80Smarks 	}
2579fa9e4066Sahrens 
2580fa9e4066Sahrens 	kmem_free(zc, sizeof (zfs_cmd_t));
2581fa9e4066Sahrens 	return (error);
2582fa9e4066Sahrens }
2583fa9e4066Sahrens 
2584fa9e4066Sahrens static int
2585fa9e4066Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2586fa9e4066Sahrens {
2587fa9e4066Sahrens 	if (cmd != DDI_ATTACH)
2588fa9e4066Sahrens 		return (DDI_FAILURE);
2589fa9e4066Sahrens 
2590fa9e4066Sahrens 	if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0,
2591fa9e4066Sahrens 	    DDI_PSEUDO, 0) == DDI_FAILURE)
2592fa9e4066Sahrens 		return (DDI_FAILURE);
2593fa9e4066Sahrens 
2594fa9e4066Sahrens 	zfs_dip = dip;
2595fa9e4066Sahrens 
2596fa9e4066Sahrens 	ddi_report_dev(dip);
2597fa9e4066Sahrens 
2598fa9e4066Sahrens 	return (DDI_SUCCESS);
2599fa9e4066Sahrens }
2600fa9e4066Sahrens 
2601fa9e4066Sahrens static int
2602fa9e4066Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2603fa9e4066Sahrens {
2604fa9e4066Sahrens 	if (spa_busy() || zfs_busy() || zvol_busy())
2605fa9e4066Sahrens 		return (DDI_FAILURE);
2606fa9e4066Sahrens 
2607fa9e4066Sahrens 	if (cmd != DDI_DETACH)
2608fa9e4066Sahrens 		return (DDI_FAILURE);
2609fa9e4066Sahrens 
2610fa9e4066Sahrens 	zfs_dip = NULL;
2611fa9e4066Sahrens 
2612fa9e4066Sahrens 	ddi_prop_remove_all(dip);
2613fa9e4066Sahrens 	ddi_remove_minor_node(dip, NULL);
2614fa9e4066Sahrens 
2615fa9e4066Sahrens 	return (DDI_SUCCESS);
2616fa9e4066Sahrens }
2617fa9e4066Sahrens 
2618fa9e4066Sahrens /*ARGSUSED*/
2619fa9e4066Sahrens static int
2620fa9e4066Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2621fa9e4066Sahrens {
2622fa9e4066Sahrens 	switch (infocmd) {
2623fa9e4066Sahrens 	case DDI_INFO_DEVT2DEVINFO:
2624fa9e4066Sahrens 		*result = zfs_dip;
2625fa9e4066Sahrens 		return (DDI_SUCCESS);
2626fa9e4066Sahrens 
2627fa9e4066Sahrens 	case DDI_INFO_DEVT2INSTANCE:
2628a0965f35Sbonwick 		*result = (void *)0;
2629fa9e4066Sahrens 		return (DDI_SUCCESS);
2630fa9e4066Sahrens 	}
2631fa9e4066Sahrens 
2632fa9e4066Sahrens 	return (DDI_FAILURE);
2633fa9e4066Sahrens }
2634fa9e4066Sahrens 
2635fa9e4066Sahrens /*
2636fa9e4066Sahrens  * OK, so this is a little weird.
2637fa9e4066Sahrens  *
2638fa9e4066Sahrens  * /dev/zfs is the control node, i.e. minor 0.
2639fa9e4066Sahrens  * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0.
2640fa9e4066Sahrens  *
2641fa9e4066Sahrens  * /dev/zfs has basically nothing to do except serve up ioctls,
2642fa9e4066Sahrens  * so most of the standard driver entry points are in zvol.c.
2643fa9e4066Sahrens  */
2644fa9e4066Sahrens static struct cb_ops zfs_cb_ops = {
2645fa9e4066Sahrens 	zvol_open,	/* open */
2646fa9e4066Sahrens 	zvol_close,	/* close */
2647fa9e4066Sahrens 	zvol_strategy,	/* strategy */
2648fa9e4066Sahrens 	nodev,		/* print */
2649fa9e4066Sahrens 	nodev,		/* dump */
2650fa9e4066Sahrens 	zvol_read,	/* read */
2651fa9e4066Sahrens 	zvol_write,	/* write */
2652fa9e4066Sahrens 	zfsdev_ioctl,	/* ioctl */
2653fa9e4066Sahrens 	nodev,		/* devmap */
2654fa9e4066Sahrens 	nodev,		/* mmap */
2655fa9e4066Sahrens 	nodev,		/* segmap */
2656fa9e4066Sahrens 	nochpoll,	/* poll */
2657fa9e4066Sahrens 	ddi_prop_op,	/* prop_op */
2658fa9e4066Sahrens 	NULL,		/* streamtab */
2659fa9e4066Sahrens 	D_NEW | D_MP | D_64BIT,		/* Driver compatibility flag */
2660fa9e4066Sahrens 	CB_REV,		/* version */
2661feb08c6bSbillm 	nodev,		/* async read */
2662feb08c6bSbillm 	nodev,		/* async write */
2663fa9e4066Sahrens };
2664fa9e4066Sahrens 
2665fa9e4066Sahrens static struct dev_ops zfs_dev_ops = {
2666fa9e4066Sahrens 	DEVO_REV,	/* version */
2667fa9e4066Sahrens 	0,		/* refcnt */
2668fa9e4066Sahrens 	zfs_info,	/* info */
2669fa9e4066Sahrens 	nulldev,	/* identify */
2670fa9e4066Sahrens 	nulldev,	/* probe */
2671fa9e4066Sahrens 	zfs_attach,	/* attach */
2672fa9e4066Sahrens 	zfs_detach,	/* detach */
2673fa9e4066Sahrens 	nodev,		/* reset */
2674fa9e4066Sahrens 	&zfs_cb_ops,	/* driver operations */
2675fa9e4066Sahrens 	NULL		/* no bus operations */
2676fa9e4066Sahrens };
2677fa9e4066Sahrens 
2678fa9e4066Sahrens static struct modldrv zfs_modldrv = {
2679e7437265Sahrens 	&mod_driverops, "ZFS storage pool version " SPA_VERSION_STRING,
2680e9dbad6fSeschrock 	    &zfs_dev_ops
2681fa9e4066Sahrens };
2682fa9e4066Sahrens 
2683fa9e4066Sahrens static struct modlinkage modlinkage = {
2684fa9e4066Sahrens 	MODREV_1,
2685fa9e4066Sahrens 	(void *)&zfs_modlfs,
2686fa9e4066Sahrens 	(void *)&zfs_modldrv,
2687fa9e4066Sahrens 	NULL
2688fa9e4066Sahrens };
2689fa9e4066Sahrens 
2690ec533521Sfr 
2691ec533521Sfr uint_t zfs_fsyncer_key;
2692f18faf3fSek extern uint_t rrw_tsd_key;
2693ec533521Sfr 
2694fa9e4066Sahrens int
2695fa9e4066Sahrens _init(void)
2696fa9e4066Sahrens {
2697fa9e4066Sahrens 	int error;
2698fa9e4066Sahrens 
2699a0965f35Sbonwick 	spa_init(FREAD | FWRITE);
2700a0965f35Sbonwick 	zfs_init();
2701a0965f35Sbonwick 	zvol_init();
2702a0965f35Sbonwick 
2703a0965f35Sbonwick 	if ((error = mod_install(&modlinkage)) != 0) {
2704a0965f35Sbonwick 		zvol_fini();
2705a0965f35Sbonwick 		zfs_fini();
2706a0965f35Sbonwick 		spa_fini();
2707fa9e4066Sahrens 		return (error);
2708a0965f35Sbonwick 	}
2709fa9e4066Sahrens 
2710ec533521Sfr 	tsd_create(&zfs_fsyncer_key, NULL);
2711f18faf3fSek 	tsd_create(&rrw_tsd_key, NULL);
2712ec533521Sfr 
2713fa9e4066Sahrens 	error = ldi_ident_from_mod(&modlinkage, &zfs_li);
2714fa9e4066Sahrens 	ASSERT(error == 0);
2715ecd6cf80Smarks 	mutex_init(&zfs_share_lock, NULL, MUTEX_DEFAULT, NULL);
2716fa9e4066Sahrens 
2717fa9e4066Sahrens 	return (0);
2718fa9e4066Sahrens }
2719fa9e4066Sahrens 
2720fa9e4066Sahrens int
2721fa9e4066Sahrens _fini(void)
2722fa9e4066Sahrens {
2723fa9e4066Sahrens 	int error;
2724fa9e4066Sahrens 
2725ea8dc4b6Seschrock 	if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled)
2726fa9e4066Sahrens 		return (EBUSY);
2727fa9e4066Sahrens 
2728fa9e4066Sahrens 	if ((error = mod_remove(&modlinkage)) != 0)
2729fa9e4066Sahrens 		return (error);
2730fa9e4066Sahrens 
2731fa9e4066Sahrens 	zvol_fini();
2732fa9e4066Sahrens 	zfs_fini();
2733fa9e4066Sahrens 	spa_fini();
2734*da6c28aaSamw 	if (zfs_nfsshare_inited)
2735ecd6cf80Smarks 		(void) ddi_modclose(nfs_mod);
2736*da6c28aaSamw 	if (zfs_smbshare_inited)
2737*da6c28aaSamw 		(void) ddi_modclose(smbsrv_mod);
2738*da6c28aaSamw 	if (zfs_nfsshare_inited || zfs_smbshare_inited)
2739ecd6cf80Smarks 		(void) ddi_modclose(sharefs_mod);
2740fa9e4066Sahrens 
2741ec533521Sfr 	tsd_destroy(&zfs_fsyncer_key);
2742fa9e4066Sahrens 	ldi_ident_release(zfs_li);
2743fa9e4066Sahrens 	zfs_li = NULL;
2744ecd6cf80Smarks 	mutex_destroy(&zfs_share_lock);
2745fa9e4066Sahrens 
2746fa9e4066Sahrens 	return (error);
2747fa9e4066Sahrens }
2748fa9e4066Sahrens 
2749fa9e4066Sahrens int
2750fa9e4066Sahrens _info(struct modinfo *modinfop)
2751fa9e4066Sahrens {
2752fa9e4066Sahrens 	return (mod_info(&modlinkage, modinfop));
2753fa9e4066Sahrens }
2754