xref: /onnv-gate/usr/src/uts/common/fs/zfs/zfs_ioctl.c (revision 2856:6f4d5ee1906a)
1789Sahrens /*
2789Sahrens  * CDDL HEADER START
3789Sahrens  *
4789Sahrens  * The contents of this file are subject to the terms of the
51485Slling  * Common Development and Distribution License (the "License").
61485Slling  * You may not use this file except in compliance with the License.
7789Sahrens  *
8789Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens  * or http://www.opensolaris.org/os/licensing.
10789Sahrens  * See the License for the specific language governing permissions
11789Sahrens  * and limitations under the License.
12789Sahrens  *
13789Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens  *
19789Sahrens  * CDDL HEADER END
20789Sahrens  */
21789Sahrens /*
221354Seschrock  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23789Sahrens  * Use is subject to license terms.
24789Sahrens  */
25789Sahrens 
26789Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
27789Sahrens 
28789Sahrens #include <sys/types.h>
29789Sahrens #include <sys/param.h>
30789Sahrens #include <sys/errno.h>
31789Sahrens #include <sys/uio.h>
32789Sahrens #include <sys/buf.h>
33789Sahrens #include <sys/modctl.h>
34789Sahrens #include <sys/open.h>
35789Sahrens #include <sys/file.h>
36789Sahrens #include <sys/kmem.h>
37789Sahrens #include <sys/conf.h>
38789Sahrens #include <sys/cmn_err.h>
39789Sahrens #include <sys/stat.h>
40789Sahrens #include <sys/zfs_ioctl.h>
41789Sahrens #include <sys/zap.h>
42789Sahrens #include <sys/spa.h>
43789Sahrens #include <sys/vdev.h>
44789Sahrens #include <sys/dmu.h>
45789Sahrens #include <sys/dsl_dir.h>
46789Sahrens #include <sys/dsl_dataset.h>
47789Sahrens #include <sys/dsl_prop.h>
48789Sahrens #include <sys/ddi.h>
49789Sahrens #include <sys/sunddi.h>
50789Sahrens #include <sys/sunldi.h>
51789Sahrens #include <sys/policy.h>
52789Sahrens #include <sys/zone.h>
53789Sahrens #include <sys/nvpair.h>
54789Sahrens #include <sys/pathname.h>
55789Sahrens #include <sys/mount.h>
56789Sahrens #include <sys/sdt.h>
57789Sahrens #include <sys/fs/zfs.h>
58789Sahrens #include <sys/zfs_ctldir.h>
59789Sahrens 
60789Sahrens #include "zfs_namecheck.h"
612676Seschrock #include "zfs_prop.h"
62789Sahrens 
63789Sahrens extern struct modlfs zfs_modlfs;
64789Sahrens 
65789Sahrens extern void zfs_init(void);
66789Sahrens extern void zfs_fini(void);
67789Sahrens 
68789Sahrens ldi_ident_t zfs_li = NULL;
69789Sahrens dev_info_t *zfs_dip;
70789Sahrens 
71789Sahrens typedef int zfs_ioc_func_t(zfs_cmd_t *);
722676Seschrock typedef int zfs_secpolicy_func_t(const char *, cred_t *);
73789Sahrens 
74789Sahrens typedef struct zfs_ioc_vec {
75789Sahrens 	zfs_ioc_func_t		*zvec_func;
76789Sahrens 	zfs_secpolicy_func_t	*zvec_secpolicy;
77789Sahrens 	enum {
78789Sahrens 		no_name,
79789Sahrens 		pool_name,
80789Sahrens 		dataset_name
81789Sahrens 	}			zvec_namecheck;
82789Sahrens } zfs_ioc_vec_t;
83789Sahrens 
84789Sahrens /* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */
85789Sahrens void
86789Sahrens __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
87789Sahrens {
88789Sahrens 	const char *newfile;
89789Sahrens 	char buf[256];
90789Sahrens 	va_list adx;
91789Sahrens 
92789Sahrens 	/*
93789Sahrens 	 * Get rid of annoying "../common/" prefix to filename.
94789Sahrens 	 */
95789Sahrens 	newfile = strrchr(file, '/');
96789Sahrens 	if (newfile != NULL) {
97789Sahrens 		newfile = newfile + 1; /* Get rid of leading / */
98789Sahrens 	} else {
99789Sahrens 		newfile = file;
100789Sahrens 	}
101789Sahrens 
102789Sahrens 	va_start(adx, fmt);
103789Sahrens 	(void) vsnprintf(buf, sizeof (buf), fmt, adx);
104789Sahrens 	va_end(adx);
105789Sahrens 
106789Sahrens 	/*
107789Sahrens 	 * To get this data, use the zfs-dprintf probe as so:
108789Sahrens 	 * dtrace -q -n 'zfs-dprintf \
109789Sahrens 	 *	/stringof(arg0) == "dbuf.c"/ \
110789Sahrens 	 *	{printf("%s: %s", stringof(arg1), stringof(arg3))}'
111789Sahrens 	 * arg0 = file name
112789Sahrens 	 * arg1 = function name
113789Sahrens 	 * arg2 = line number
114789Sahrens 	 * arg3 = message
115789Sahrens 	 */
116789Sahrens 	DTRACE_PROBE4(zfs__dprintf,
117789Sahrens 	    char *, newfile, char *, func, int, line, char *, buf);
118789Sahrens }
119789Sahrens 
120789Sahrens /*
121789Sahrens  * Policy for top-level read operations (list pools).  Requires no privileges,
122789Sahrens  * and can be used in the local zone, as there is no associated dataset.
123789Sahrens  */
124789Sahrens /* ARGSUSED */
125789Sahrens static int
1262676Seschrock zfs_secpolicy_none(const char *unused1, cred_t *cr)
127789Sahrens {
128789Sahrens 	return (0);
129789Sahrens }
130789Sahrens 
131789Sahrens /*
132789Sahrens  * Policy for dataset read operations (list children, get statistics).  Requires
133789Sahrens  * no privileges, but must be visible in the local zone.
134789Sahrens  */
135789Sahrens /* ARGSUSED */
136789Sahrens static int
1372676Seschrock zfs_secpolicy_read(const char *dataset, cred_t *cr)
138789Sahrens {
139789Sahrens 	if (INGLOBALZONE(curproc) ||
140789Sahrens 	    zone_dataset_visible(dataset, NULL))
141789Sahrens 		return (0);
142789Sahrens 
143789Sahrens 	return (ENOENT);
144789Sahrens }
145789Sahrens 
146789Sahrens static int
147789Sahrens zfs_dozonecheck(const char *dataset, cred_t *cr)
148789Sahrens {
149789Sahrens 	uint64_t zoned;
150789Sahrens 	int writable = 1;
151789Sahrens 
152789Sahrens 	/*
153789Sahrens 	 * The dataset must be visible by this zone -- check this first
154789Sahrens 	 * so they don't see EPERM on something they shouldn't know about.
155789Sahrens 	 */
156789Sahrens 	if (!INGLOBALZONE(curproc) &&
157789Sahrens 	    !zone_dataset_visible(dataset, &writable))
158789Sahrens 		return (ENOENT);
159789Sahrens 
160789Sahrens 	if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL))
161789Sahrens 		return (ENOENT);
162789Sahrens 
163789Sahrens 	if (INGLOBALZONE(curproc)) {
164789Sahrens 		/*
165789Sahrens 		 * If the fs is zoned, only root can access it from the
166789Sahrens 		 * global zone.
167789Sahrens 		 */
168789Sahrens 		if (secpolicy_zfs(cr) && zoned)
169789Sahrens 			return (EPERM);
170789Sahrens 	} else {
171789Sahrens 		/*
172789Sahrens 		 * If we are in a local zone, the 'zoned' property must be set.
173789Sahrens 		 */
174789Sahrens 		if (!zoned)
175789Sahrens 			return (EPERM);
176789Sahrens 
177789Sahrens 		/* must be writable by this zone */
178789Sahrens 		if (!writable)
179789Sahrens 			return (EPERM);
180789Sahrens 	}
181789Sahrens 	return (0);
182789Sahrens }
183789Sahrens 
184789Sahrens /*
185789Sahrens  * Policy for dataset write operations (create children, set properties, etc).
186789Sahrens  * Requires SYS_MOUNT privilege, and must be writable in the local zone.
187789Sahrens  */
188789Sahrens int
1892676Seschrock zfs_secpolicy_write(const char *dataset, cred_t *cr)
190789Sahrens {
191789Sahrens 	int error;
192789Sahrens 
193789Sahrens 	if (error = zfs_dozonecheck(dataset, cr))
194789Sahrens 		return (error);
195789Sahrens 
196789Sahrens 	return (secpolicy_zfs(cr));
197789Sahrens }
198789Sahrens 
199789Sahrens /*
200789Sahrens  * Policy for operations that want to write a dataset's parent:
201789Sahrens  * create, destroy, snapshot, clone, restore.
202789Sahrens  */
203789Sahrens static int
2042676Seschrock zfs_secpolicy_parent(const char *dataset, cred_t *cr)
205789Sahrens {
206789Sahrens 	char parentname[MAXNAMELEN];
207789Sahrens 	char *cp;
208789Sahrens 
209789Sahrens 	/*
210789Sahrens 	 * Remove the @bla or /bla from the end of the name to get the parent.
211789Sahrens 	 */
212789Sahrens 	(void) strncpy(parentname, dataset, sizeof (parentname));
213789Sahrens 	cp = strrchr(parentname, '@');
214789Sahrens 	if (cp != NULL) {
215789Sahrens 		cp[0] = '\0';
216789Sahrens 	} else {
217789Sahrens 		cp = strrchr(parentname, '/');
218789Sahrens 		if (cp == NULL)
219789Sahrens 			return (ENOENT);
220789Sahrens 		cp[0] = '\0';
221789Sahrens 
222789Sahrens 	}
223789Sahrens 
2242676Seschrock 	return (zfs_secpolicy_write(parentname, cr));
225789Sahrens }
226789Sahrens 
227789Sahrens /*
228789Sahrens  * Policy for pool operations - create/destroy pools, add vdevs, etc.  Requires
229789Sahrens  * SYS_CONFIG privilege, which is not available in a local zone.
230789Sahrens  */
231789Sahrens /* ARGSUSED */
232789Sahrens static int
2332676Seschrock zfs_secpolicy_config(const char *unused, cred_t *cr)
234789Sahrens {
235789Sahrens 	if (secpolicy_sys_config(cr, B_FALSE) != 0)
236789Sahrens 		return (EPERM);
237789Sahrens 
238789Sahrens 	return (0);
239789Sahrens }
240789Sahrens 
241789Sahrens /*
2421544Seschrock  * Policy for fault injection.  Requires all privileges.
2431544Seschrock  */
2441544Seschrock /* ARGSUSED */
2451544Seschrock static int
2462676Seschrock zfs_secpolicy_inject(const char *unused, cred_t *cr)
2471544Seschrock {
2481544Seschrock 	return (secpolicy_zinject(cr));
2491544Seschrock }
2501544Seschrock 
2511544Seschrock /*
252789Sahrens  * Returns the nvlist as specified by the user in the zfs_cmd_t.
253789Sahrens  */
254789Sahrens static int
2552676Seschrock get_nvlist(zfs_cmd_t *zc, nvlist_t **nvp)
256789Sahrens {
257789Sahrens 	char *packed;
258789Sahrens 	size_t size;
259789Sahrens 	int error;
260789Sahrens 	nvlist_t *config = NULL;
261789Sahrens 
262789Sahrens 	/*
2632676Seschrock 	 * Read in and unpack the user-supplied nvlist.
264789Sahrens 	 */
2652676Seschrock 	if ((size = zc->zc_nvlist_src_size) == 0)
266789Sahrens 		return (EINVAL);
267789Sahrens 
268789Sahrens 	packed = kmem_alloc(size, KM_SLEEP);
269789Sahrens 
2702676Seschrock 	if ((error = xcopyin((void *)(uintptr_t)zc->zc_nvlist_src, packed,
271789Sahrens 	    size)) != 0) {
272789Sahrens 		kmem_free(packed, size);
273789Sahrens 		return (error);
274789Sahrens 	}
275789Sahrens 
276789Sahrens 	if ((error = nvlist_unpack(packed, size, &config, 0)) != 0) {
277789Sahrens 		kmem_free(packed, size);
278789Sahrens 		return (error);
279789Sahrens 	}
280789Sahrens 
281789Sahrens 	kmem_free(packed, size);
282789Sahrens 
283789Sahrens 	*nvp = config;
284789Sahrens 	return (0);
285789Sahrens }
286789Sahrens 
287789Sahrens static int
2882676Seschrock put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
2892676Seschrock {
2902676Seschrock 	char *packed = NULL;
2912676Seschrock 	size_t size;
2922676Seschrock 	int error;
2932676Seschrock 
2942676Seschrock 	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
2952676Seschrock 
2962676Seschrock 	if (size > zc->zc_nvlist_dst_size) {
2972676Seschrock 		error = ENOMEM;
2982676Seschrock 	} else {
2992676Seschrock 		VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
3002676Seschrock 		    KM_SLEEP) == 0);
3012676Seschrock 		error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst,
3022676Seschrock 		    size);
3032676Seschrock 		kmem_free(packed, size);
3042676Seschrock 	}
3052676Seschrock 
3062676Seschrock 	zc->zc_nvlist_dst_size = size;
3072676Seschrock 	return (error);
3082676Seschrock }
3092676Seschrock 
3102676Seschrock static int
311789Sahrens zfs_ioc_pool_create(zfs_cmd_t *zc)
312789Sahrens {
313789Sahrens 	int error;
314789Sahrens 	nvlist_t *config;
315789Sahrens 
3162676Seschrock 	if ((error = get_nvlist(zc, &config)) != 0)
317789Sahrens 		return (error);
318789Sahrens 
3192676Seschrock 	error = spa_create(zc->zc_name, config, zc->zc_value[0] == '\0' ?
3202676Seschrock 	    NULL : zc->zc_value);
321789Sahrens 
322789Sahrens 	nvlist_free(config);
323789Sahrens 
324789Sahrens 	return (error);
325789Sahrens }
326789Sahrens 
327789Sahrens static int
328789Sahrens zfs_ioc_pool_destroy(zfs_cmd_t *zc)
329789Sahrens {
330789Sahrens 	return (spa_destroy(zc->zc_name));
331789Sahrens }
332789Sahrens 
333789Sahrens static int
334789Sahrens zfs_ioc_pool_import(zfs_cmd_t *zc)
335789Sahrens {
336789Sahrens 	int error;
337789Sahrens 	nvlist_t *config;
338789Sahrens 	uint64_t guid;
339789Sahrens 
3402676Seschrock 	if ((error = get_nvlist(zc, &config)) != 0)
341789Sahrens 		return (error);
342789Sahrens 
343789Sahrens 	if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
3441544Seschrock 	    guid != zc->zc_guid)
345789Sahrens 		error = EINVAL;
346789Sahrens 	else
347789Sahrens 		error = spa_import(zc->zc_name, config,
3482676Seschrock 		    zc->zc_value[0] == '\0' ? NULL : zc->zc_value);
349789Sahrens 
350789Sahrens 	nvlist_free(config);
351789Sahrens 
352789Sahrens 	return (error);
353789Sahrens }
354789Sahrens 
355789Sahrens static int
356789Sahrens zfs_ioc_pool_export(zfs_cmd_t *zc)
357789Sahrens {
3581775Sbillm 	return (spa_export(zc->zc_name, NULL));
359789Sahrens }
360789Sahrens 
361789Sahrens static int
362789Sahrens zfs_ioc_pool_configs(zfs_cmd_t *zc)
363789Sahrens {
364789Sahrens 	nvlist_t *configs;
365789Sahrens 	int error;
366789Sahrens 
367789Sahrens 	if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
368789Sahrens 		return (EEXIST);
369789Sahrens 
3702676Seschrock 	error = put_nvlist(zc, configs);
371789Sahrens 
372789Sahrens 	nvlist_free(configs);
373789Sahrens 
374789Sahrens 	return (error);
375789Sahrens }
376789Sahrens 
377789Sahrens static int
378789Sahrens zfs_ioc_pool_stats(zfs_cmd_t *zc)
379789Sahrens {
380789Sahrens 	nvlist_t *config;
381789Sahrens 	int error;
3821544Seschrock 	int ret = 0;
383789Sahrens 
3842676Seschrock 	error = spa_get_stats(zc->zc_name, &config, zc->zc_value,
3852676Seschrock 	    sizeof (zc->zc_value));
386789Sahrens 
387789Sahrens 	if (config != NULL) {
3882676Seschrock 		ret = put_nvlist(zc, config);
389789Sahrens 		nvlist_free(config);
3901544Seschrock 
3911544Seschrock 		/*
3921544Seschrock 		 * The config may be present even if 'error' is non-zero.
3931544Seschrock 		 * In this case we return success, and preserve the real errno
3941544Seschrock 		 * in 'zc_cookie'.
3951544Seschrock 		 */
3961544Seschrock 		zc->zc_cookie = error;
397789Sahrens 	} else {
3981544Seschrock 		ret = error;
399789Sahrens 	}
400789Sahrens 
4011544Seschrock 	return (ret);
402789Sahrens }
403789Sahrens 
404789Sahrens /*
405789Sahrens  * Try to import the given pool, returning pool stats as appropriate so that
406789Sahrens  * user land knows which devices are available and overall pool health.
407789Sahrens  */
408789Sahrens static int
409789Sahrens zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
410789Sahrens {
411789Sahrens 	nvlist_t *tryconfig, *config;
412789Sahrens 	int error;
413789Sahrens 
4142676Seschrock 	if ((error = get_nvlist(zc, &tryconfig)) != 0)
415789Sahrens 		return (error);
416789Sahrens 
417789Sahrens 	config = spa_tryimport(tryconfig);
418789Sahrens 
419789Sahrens 	nvlist_free(tryconfig);
420789Sahrens 
421789Sahrens 	if (config == NULL)
422789Sahrens 		return (EINVAL);
423789Sahrens 
4242676Seschrock 	error = put_nvlist(zc, config);
425789Sahrens 	nvlist_free(config);
426789Sahrens 
427789Sahrens 	return (error);
428789Sahrens }
429789Sahrens 
430789Sahrens static int
431789Sahrens zfs_ioc_pool_scrub(zfs_cmd_t *zc)
432789Sahrens {
433789Sahrens 	spa_t *spa;
434789Sahrens 	int error;
435789Sahrens 
436789Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
437789Sahrens 	if (error == 0) {
438789Sahrens 		error = spa_scrub(spa, zc->zc_cookie, B_FALSE);
439789Sahrens 		spa_close(spa, FTAG);
440789Sahrens 	}
441789Sahrens 	return (error);
442789Sahrens }
443789Sahrens 
444789Sahrens static int
445789Sahrens zfs_ioc_pool_freeze(zfs_cmd_t *zc)
446789Sahrens {
447789Sahrens 	spa_t *spa;
448789Sahrens 	int error;
449789Sahrens 
450789Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
451789Sahrens 	if (error == 0) {
452789Sahrens 		spa_freeze(spa);
453789Sahrens 		spa_close(spa, FTAG);
454789Sahrens 	}
455789Sahrens 	return (error);
456789Sahrens }
457789Sahrens 
458789Sahrens static int
4591760Seschrock zfs_ioc_pool_upgrade(zfs_cmd_t *zc)
4601760Seschrock {
4611760Seschrock 	spa_t *spa;
4621760Seschrock 	int error;
4631760Seschrock 
4641760Seschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
4651760Seschrock 	if (error == 0) {
4661760Seschrock 		spa_upgrade(spa);
4671760Seschrock 		spa_close(spa, FTAG);
4681760Seschrock 	}
4691760Seschrock 	return (error);
4701760Seschrock }
4711760Seschrock 
4721760Seschrock static int
473789Sahrens zfs_ioc_vdev_add(zfs_cmd_t *zc)
474789Sahrens {
475789Sahrens 	spa_t *spa;
476789Sahrens 	int error;
477789Sahrens 	nvlist_t *config;
478789Sahrens 
479789Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
480789Sahrens 	if (error != 0)
481789Sahrens 		return (error);
482789Sahrens 
4832676Seschrock 	if ((error = get_nvlist(zc, &config)) == 0) {
484789Sahrens 		error = spa_vdev_add(spa, config);
485789Sahrens 		nvlist_free(config);
486789Sahrens 	}
487789Sahrens 
488789Sahrens 	spa_close(spa, FTAG);
489789Sahrens 	return (error);
490789Sahrens }
491789Sahrens 
492789Sahrens static int
493789Sahrens zfs_ioc_vdev_remove(zfs_cmd_t *zc)
494789Sahrens {
4952082Seschrock 	spa_t *spa;
4962082Seschrock 	int error;
4972082Seschrock 
4982082Seschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
4992082Seschrock 	if (error != 0)
5002082Seschrock 		return (error);
5012082Seschrock 	error = spa_vdev_remove(spa, zc->zc_guid, B_FALSE);
5022082Seschrock 	spa_close(spa, FTAG);
5032082Seschrock 	return (error);
504789Sahrens }
505789Sahrens 
506789Sahrens static int
507789Sahrens zfs_ioc_vdev_online(zfs_cmd_t *zc)
508789Sahrens {
509789Sahrens 	spa_t *spa;
510789Sahrens 	int error;
511789Sahrens 
512789Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
513789Sahrens 	if (error != 0)
514789Sahrens 		return (error);
5151544Seschrock 	error = vdev_online(spa, zc->zc_guid);
516789Sahrens 	spa_close(spa, FTAG);
517789Sahrens 	return (error);
518789Sahrens }
519789Sahrens 
520789Sahrens static int
521789Sahrens zfs_ioc_vdev_offline(zfs_cmd_t *zc)
522789Sahrens {
523789Sahrens 	spa_t *spa;
5241485Slling 	int istmp = zc->zc_cookie;
525789Sahrens 	int error;
526789Sahrens 
527789Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
528789Sahrens 	if (error != 0)
529789Sahrens 		return (error);
5301544Seschrock 	error = vdev_offline(spa, zc->zc_guid, istmp);
531789Sahrens 	spa_close(spa, FTAG);
532789Sahrens 	return (error);
533789Sahrens }
534789Sahrens 
535789Sahrens static int
536789Sahrens zfs_ioc_vdev_attach(zfs_cmd_t *zc)
537789Sahrens {
538789Sahrens 	spa_t *spa;
539789Sahrens 	int replacing = zc->zc_cookie;
540789Sahrens 	nvlist_t *config;
541789Sahrens 	int error;
542789Sahrens 
543789Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
544789Sahrens 	if (error != 0)
545789Sahrens 		return (error);
546789Sahrens 
5472676Seschrock 	if ((error = get_nvlist(zc, &config)) == 0) {
5481544Seschrock 		error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
549789Sahrens 		nvlist_free(config);
550789Sahrens 	}
551789Sahrens 
552789Sahrens 	spa_close(spa, FTAG);
553789Sahrens 	return (error);
554789Sahrens }
555789Sahrens 
556789Sahrens static int
557789Sahrens zfs_ioc_vdev_detach(zfs_cmd_t *zc)
558789Sahrens {
559789Sahrens 	spa_t *spa;
560789Sahrens 	int error;
561789Sahrens 
562789Sahrens 	error = spa_open(zc->zc_name, &spa, FTAG);
563789Sahrens 	if (error != 0)
564789Sahrens 		return (error);
565789Sahrens 
5661544Seschrock 	error = spa_vdev_detach(spa, zc->zc_guid, B_FALSE);
567789Sahrens 
568789Sahrens 	spa_close(spa, FTAG);
569789Sahrens 	return (error);
570789Sahrens }
571789Sahrens 
572789Sahrens static int
5731354Seschrock zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
5741354Seschrock {
5751354Seschrock 	spa_t *spa;
5762676Seschrock 	char *path = zc->zc_value;
5771544Seschrock 	uint64_t guid = zc->zc_guid;
5781354Seschrock 	int error;
5791354Seschrock 
5801354Seschrock 	error = spa_open(zc->zc_name, &spa, FTAG);
5811354Seschrock 	if (error != 0)
5821354Seschrock 		return (error);
5831354Seschrock 
5841354Seschrock 	error = spa_vdev_setpath(spa, guid, path);
5851354Seschrock 
5861354Seschrock 	spa_close(spa, FTAG);
5871354Seschrock 	return (error);
5881354Seschrock }
5891354Seschrock 
5901354Seschrock static int
591789Sahrens zfs_ioc_objset_stats(zfs_cmd_t *zc)
592789Sahrens {
593789Sahrens 	objset_t *os = NULL;
594789Sahrens 	int error;
5951356Seschrock 	nvlist_t *nv;
596789Sahrens 
597789Sahrens retry:
598789Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
599789Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
600789Sahrens 	if (error != 0) {
601789Sahrens 		/*
602789Sahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
603789Sahrens 		 * the objset is held exclusively. Fortunately this hold is
604789Sahrens 		 * only for a short while, so we retry here.
605789Sahrens 		 * This avoids user code having to handle EBUSY,
606789Sahrens 		 * for example for a "zfs list".
607789Sahrens 		 */
608789Sahrens 		if (error == EBUSY) {
609789Sahrens 			delay(1);
610789Sahrens 			goto retry;
611789Sahrens 		}
612789Sahrens 		return (error);
613789Sahrens 	}
614789Sahrens 
615789Sahrens 	dmu_objset_stats(os, &zc->zc_objset_stats);
616789Sahrens 
617*2856Snd150628 	if (zc->zc_nvlist_dst != 0 &&
6181356Seschrock 	    (error = dsl_prop_get_all(os, &nv)) == 0) {
6192676Seschrock 		error = put_nvlist(zc, nv);
6201356Seschrock 		nvlist_free(nv);
6211356Seschrock 	}
622789Sahrens 
6231356Seschrock 	if (!error && zc->zc_objset_stats.dds_type == DMU_OST_ZVOL)
6242676Seschrock 		error = zvol_get_stats(os, &zc->zc_vol_stats);
625789Sahrens 
6262676Seschrock 	spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value));
6271544Seschrock 
628789Sahrens 	dmu_objset_close(os);
629789Sahrens 	return (error);
630789Sahrens }
631789Sahrens 
632789Sahrens static int
633789Sahrens zfs_ioc_dataset_list_next(zfs_cmd_t *zc)
634789Sahrens {
635885Sahrens 	objset_t *os;
636789Sahrens 	int error;
637789Sahrens 	char *p;
638789Sahrens 
639885Sahrens retry:
640885Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
641885Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
642885Sahrens 	if (error != 0) {
643885Sahrens 		/*
644885Sahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
645885Sahrens 		 * the objset is held exclusively. Fortunately this hold is
646885Sahrens 		 * only for a short while, so we retry here.
647885Sahrens 		 * This avoids user code having to handle EBUSY,
648885Sahrens 		 * for example for a "zfs list".
649885Sahrens 		 */
650885Sahrens 		if (error == EBUSY) {
651885Sahrens 			delay(1);
652885Sahrens 			goto retry;
653885Sahrens 		}
654885Sahrens 		if (error == ENOENT)
655885Sahrens 			error = ESRCH;
656885Sahrens 		return (error);
657789Sahrens 	}
658789Sahrens 
659789Sahrens 	p = strrchr(zc->zc_name, '/');
660789Sahrens 	if (p == NULL || p[1] != '\0')
661789Sahrens 		(void) strlcat(zc->zc_name, "/", sizeof (zc->zc_name));
662789Sahrens 	p = zc->zc_name + strlen(zc->zc_name);
663789Sahrens 
664789Sahrens 	do {
665885Sahrens 		error = dmu_dir_list_next(os,
666885Sahrens 		    sizeof (zc->zc_name) - (p - zc->zc_name), p,
667885Sahrens 		    NULL, &zc->zc_cookie);
668789Sahrens 		if (error == ENOENT)
669789Sahrens 			error = ESRCH;
670885Sahrens 	} while (error == 0 && !INGLOBALZONE(curproc) &&
671789Sahrens 	    !zone_dataset_visible(zc->zc_name, NULL));
672789Sahrens 
673885Sahrens 	/*
674885Sahrens 	 * If it's a hidden dataset (ie. with a '$' in its name), don't
675885Sahrens 	 * try to get stats for it.  Userland will skip over it.
676885Sahrens 	 */
677885Sahrens 	if (error == 0 && strchr(zc->zc_name, '$') == NULL)
678885Sahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
679789Sahrens 
680885Sahrens 	dmu_objset_close(os);
681789Sahrens 	return (error);
682789Sahrens }
683789Sahrens 
684789Sahrens static int
685789Sahrens zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
686789Sahrens {
687885Sahrens 	objset_t *os;
688789Sahrens 	int error;
689789Sahrens 
690789Sahrens retry:
691885Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
692885Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &os);
693885Sahrens 	if (error != 0) {
694789Sahrens 		/*
695885Sahrens 		 * This is ugly: dmu_objset_open() can return EBUSY if
696789Sahrens 		 * the objset is held exclusively. Fortunately this hold is
697789Sahrens 		 * only for a short while, so we retry here.
698789Sahrens 		 * This avoids user code having to handle EBUSY,
699885Sahrens 		 * for example for a "zfs list".
700789Sahrens 		 */
701789Sahrens 		if (error == EBUSY) {
702789Sahrens 			delay(1);
703789Sahrens 			goto retry;
704789Sahrens 		}
705789Sahrens 		if (error == ENOENT)
706885Sahrens 			error = ESRCH;
707789Sahrens 		return (error);
708789Sahrens 	}
709789Sahrens 
7101003Slling 	/*
7111003Slling 	 * A dataset name of maximum length cannot have any snapshots,
7121003Slling 	 * so exit immediately.
7131003Slling 	 */
7141003Slling 	if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) {
715885Sahrens 		dmu_objset_close(os);
7161003Slling 		return (ESRCH);
717789Sahrens 	}
718789Sahrens 
719885Sahrens 	error = dmu_snapshot_list_next(os,
720885Sahrens 	    sizeof (zc->zc_name) - strlen(zc->zc_name),
721885Sahrens 	    zc->zc_name + strlen(zc->zc_name), NULL, &zc->zc_cookie);
722789Sahrens 	if (error == ENOENT)
723789Sahrens 		error = ESRCH;
724789Sahrens 
725885Sahrens 	if (error == 0)
726885Sahrens 		error = zfs_ioc_objset_stats(zc); /* fill in the stats */
727789Sahrens 
728885Sahrens 	dmu_objset_close(os);
729789Sahrens 	return (error);
730789Sahrens }
731789Sahrens 
732789Sahrens static int
7332676Seschrock zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl)
734789Sahrens {
7352676Seschrock 	nvpair_t *elem;
7362676Seschrock 	int error;
7372676Seschrock 	const char *propname;
7382676Seschrock 	zfs_prop_t prop;
7392676Seschrock 	uint64_t intval;
7402676Seschrock 	char *strval;
7412717Seschrock 	const char *unused;
7422676Seschrock 
7432676Seschrock 	elem = NULL;
7442676Seschrock 	while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
7452676Seschrock 		propname = nvpair_name(elem);
7462676Seschrock 
7472676Seschrock 		if ((prop = zfs_name_to_prop(propname)) ==
7482676Seschrock 		    ZFS_PROP_INVAL) {
7492676Seschrock 			/*
7502676Seschrock 			 * If this is a user-defined property, it must be a
7512676Seschrock 			 * string, and there is no further validation to do.
7522676Seschrock 			 */
7532676Seschrock 			if (!zfs_prop_user(propname) ||
7542676Seschrock 			    nvpair_type(elem) != DATA_TYPE_STRING)
7552676Seschrock 				return (EINVAL);
7562676Seschrock 
7572676Seschrock 			VERIFY(nvpair_value_string(elem, &strval) == 0);
7582676Seschrock 			error = dsl_prop_set(name, propname, 1,
7592676Seschrock 			    strlen(strval) + 1, strval);
7602676Seschrock 			if (error == 0)
7612676Seschrock 				continue;
7622676Seschrock 			else
7632676Seschrock 				break;
7642676Seschrock 		}
7652676Seschrock 
7662676Seschrock 		/*
7672676Seschrock 		 * Check permissions for special properties.
7682676Seschrock 		 */
7692676Seschrock 		switch (prop) {
7702676Seschrock 		case ZFS_PROP_ZONED:
7712676Seschrock 			/*
7722676Seschrock 			 * Disallow setting of 'zoned' from within a local zone.
7732676Seschrock 			 */
7742676Seschrock 			if (!INGLOBALZONE(curproc))
7752676Seschrock 				return (EPERM);
7762676Seschrock 			break;
7772676Seschrock 
7782676Seschrock 		case ZFS_PROP_QUOTA:
7792676Seschrock 			if (error = zfs_dozonecheck(name, cr))
7802676Seschrock 				return (error);
7812676Seschrock 
7822676Seschrock 			if (!INGLOBALZONE(curproc)) {
7832676Seschrock 				uint64_t zoned;
7842676Seschrock 				char setpoint[MAXNAMELEN];
7852676Seschrock 				int dslen;
7862676Seschrock 				/*
7872676Seschrock 				 * Unprivileged users are allowed to modify the
7882676Seschrock 				 * quota on things *under* (ie. contained by)
7892676Seschrock 				 * the thing they own.
7902676Seschrock 				 */
7912676Seschrock 				if (dsl_prop_get_integer(name, "zoned", &zoned,
7922676Seschrock 				    setpoint))
7932676Seschrock 					return (EPERM);
7942676Seschrock 				if (!zoned) /* this shouldn't happen */
7952676Seschrock 					return (EPERM);
7962676Seschrock 				dslen = strlen(name);
7972676Seschrock 				if (dslen <= strlen(setpoint))
7982676Seschrock 					return (EPERM);
7992676Seschrock 			}
8002676Seschrock 		}
8012676Seschrock 
8022676Seschrock 		switch (prop) {
8032676Seschrock 		case ZFS_PROP_QUOTA:
8042676Seschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
8052676Seschrock 			    (error = dsl_dir_set_quota(name,
8062676Seschrock 			    intval)) != 0)
8072676Seschrock 				return (error);
8082676Seschrock 			break;
8092676Seschrock 
8102676Seschrock 		case ZFS_PROP_RESERVATION:
8112676Seschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
8122676Seschrock 			    (error = dsl_dir_set_reservation(name,
8132676Seschrock 			    intval)) != 0)
8142676Seschrock 				return (error);
8152676Seschrock 			break;
816789Sahrens 
8172676Seschrock 		case ZFS_PROP_VOLSIZE:
8182676Seschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
8192676Seschrock 			    (error = zvol_set_volsize(name, dev,
8202676Seschrock 			    intval)) != 0)
8212676Seschrock 				return (error);
8222676Seschrock 			break;
8232676Seschrock 
8242676Seschrock 		case ZFS_PROP_VOLBLOCKSIZE:
8252676Seschrock 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
8262676Seschrock 			    (error = zvol_set_volblocksize(name,
8272676Seschrock 			    intval)) != 0)
8282676Seschrock 				return (error);
8292676Seschrock 			break;
8302676Seschrock 
8312676Seschrock 		default:
8322676Seschrock 			if (nvpair_type(elem) == DATA_TYPE_STRING) {
8332676Seschrock 				if (zfs_prop_get_type(prop) !=
8342676Seschrock 				    prop_type_string)
8352676Seschrock 					return (EINVAL);
8362717Seschrock 				VERIFY(nvpair_value_string(elem, &strval) == 0);
8372717Seschrock 				if ((error = dsl_prop_set(name,
8382676Seschrock 				    nvpair_name(elem), 1, strlen(strval) + 1,
8392717Seschrock 				    strval)) != 0)
8402717Seschrock 					return (error);
8412676Seschrock 			} else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
8422717Seschrock 				VERIFY(nvpair_value_uint64(elem, &intval) == 0);
8432676Seschrock 
8442676Seschrock 				switch (zfs_prop_get_type(prop)) {
8452676Seschrock 				case prop_type_number:
8462676Seschrock 					break;
8472676Seschrock 				case prop_type_boolean:
8482676Seschrock 					if (intval > 1)
8492717Seschrock 						return (EINVAL);
8502676Seschrock 					break;
8512676Seschrock 				case prop_type_string:
8522717Seschrock 					return (EINVAL);
8532676Seschrock 				case prop_type_index:
8542717Seschrock 					if (zfs_prop_index_to_string(prop,
8552717Seschrock 					    intval, &unused) != 0)
8562717Seschrock 						return (EINVAL);
8572676Seschrock 					break;
8582676Seschrock 				default:
8592676Seschrock 					cmn_err(CE_PANIC, "unknown property "
8602676Seschrock 					    "type");
8612676Seschrock 					break;
8622676Seschrock 				}
8632676Seschrock 
8642717Seschrock 				if ((error = dsl_prop_set(name, propname,
8652717Seschrock 				    8, 1, &intval)) != 0)
8662717Seschrock 					return (error);
8672676Seschrock 			} else {
8682676Seschrock 				return (EINVAL);
8692676Seschrock 			}
8702676Seschrock 			break;
8712676Seschrock 		}
8722676Seschrock 	}
8732676Seschrock 
8742676Seschrock 	return (0);
875789Sahrens }
876789Sahrens 
877789Sahrens static int
8782676Seschrock zfs_ioc_set_prop(zfs_cmd_t *zc)
879789Sahrens {
8802676Seschrock 	nvlist_t *nvl;
8812676Seschrock 	int error;
8822676Seschrock 	zfs_prop_t prop;
883789Sahrens 
8842676Seschrock 	/*
8852676Seschrock 	 * If zc_value is set, then this is an attempt to inherit a value.
8862676Seschrock 	 * Otherwise, zc_nvlist refers to a list of properties to set.
8872676Seschrock 	 */
8882676Seschrock 	if (zc->zc_value[0] != '\0') {
8892676Seschrock 		if (!zfs_prop_user(zc->zc_value) &&
8902676Seschrock 		    ((prop = zfs_name_to_prop(zc->zc_value)) ==
8912676Seschrock 		    ZFS_PROP_INVAL ||
8922676Seschrock 		    !zfs_prop_inheritable(prop)))
8932676Seschrock 			return (EINVAL);
8942676Seschrock 
8952676Seschrock 		return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL));
8962676Seschrock 	}
8972676Seschrock 
8982676Seschrock 	if ((error = get_nvlist(zc, &nvl)) != 0)
8992676Seschrock 		return (error);
9002676Seschrock 
9012676Seschrock 	error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev,
9022676Seschrock 	    (cred_t *)(uintptr_t)zc->zc_cred, nvl);
9032676Seschrock 	nvlist_free(nvl);
9042676Seschrock 	return (error);
905789Sahrens }
906789Sahrens 
907789Sahrens static int
908789Sahrens zfs_ioc_create_minor(zfs_cmd_t *zc)
909789Sahrens {
9102676Seschrock 	return (zvol_create_minor(zc->zc_name, zc->zc_dev));
911789Sahrens }
912789Sahrens 
913789Sahrens static int
914789Sahrens zfs_ioc_remove_minor(zfs_cmd_t *zc)
915789Sahrens {
9162676Seschrock 	return (zvol_remove_minor(zc->zc_name));
917789Sahrens }
918789Sahrens 
919789Sahrens /*
920789Sahrens  * Search the vfs list for a specified resource.  Returns a pointer to it
921789Sahrens  * or NULL if no suitable entry is found. The caller of this routine
922789Sahrens  * is responsible for releasing the returned vfs pointer.
923789Sahrens  */
924789Sahrens static vfs_t *
925789Sahrens zfs_get_vfs(const char *resource)
926789Sahrens {
927789Sahrens 	struct vfs *vfsp;
928789Sahrens 	struct vfs *vfs_found = NULL;
929789Sahrens 
930789Sahrens 	vfs_list_read_lock();
931789Sahrens 	vfsp = rootvfs;
932789Sahrens 	do {
933789Sahrens 		if (strcmp(refstr_value(vfsp->vfs_resource), resource) == 0) {
934789Sahrens 			VFS_HOLD(vfsp);
935789Sahrens 			vfs_found = vfsp;
936789Sahrens 			break;
937789Sahrens 		}
938789Sahrens 		vfsp = vfsp->vfs_next;
939789Sahrens 	} while (vfsp != rootvfs);
940789Sahrens 	vfs_list_unlock();
941789Sahrens 	return (vfs_found);
942789Sahrens }
943789Sahrens 
944789Sahrens static void
945789Sahrens zfs_create_cb(objset_t *os, void *arg, dmu_tx_t *tx)
946789Sahrens {
9472676Seschrock 	zfs_create_data_t *zc = arg;
948789Sahrens 	zfs_create_fs(os, (cred_t *)(uintptr_t)zc->zc_cred, tx);
949789Sahrens }
950789Sahrens 
951789Sahrens static int
952789Sahrens zfs_ioc_create(zfs_cmd_t *zc)
953789Sahrens {
954789Sahrens 	objset_t *clone;
955789Sahrens 	int error = 0;
9562676Seschrock 	zfs_create_data_t cbdata = { 0 };
957789Sahrens 	void (*cbfunc)(objset_t *os, void *arg, dmu_tx_t *tx);
958789Sahrens 	dmu_objset_type_t type = zc->zc_objset_type;
959789Sahrens 
960789Sahrens 	switch (type) {
961789Sahrens 
962789Sahrens 	case DMU_OST_ZFS:
963789Sahrens 		cbfunc = zfs_create_cb;
964789Sahrens 		break;
965789Sahrens 
966789Sahrens 	case DMU_OST_ZVOL:
967789Sahrens 		cbfunc = zvol_create_cb;
968789Sahrens 		break;
969789Sahrens 
970789Sahrens 	default:
9712199Sahrens 		cbfunc = NULL;
9722199Sahrens 	}
9732199Sahrens 	if (strchr(zc->zc_name, '@'))
974789Sahrens 		return (EINVAL);
975789Sahrens 
9762676Seschrock 	if (zc->zc_nvlist_src != NULL &&
9772676Seschrock 	    (error = get_nvlist(zc, &cbdata.zc_props)) != 0)
9782676Seschrock 		return (error);
9792676Seschrock 
9802676Seschrock 	cbdata.zc_cred = (cred_t *)(uintptr_t)zc->zc_cred;
9812676Seschrock 	cbdata.zc_dev = (dev_t)zc->zc_dev;
9822676Seschrock 
9832676Seschrock 	if (zc->zc_value[0] != '\0') {
984789Sahrens 		/*
985789Sahrens 		 * We're creating a clone of an existing snapshot.
986789Sahrens 		 */
9872676Seschrock 		zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
9882676Seschrock 		if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) {
9892676Seschrock 			nvlist_free(cbdata.zc_props);
990789Sahrens 			return (EINVAL);
9912676Seschrock 		}
992789Sahrens 
9932676Seschrock 		error = dmu_objset_open(zc->zc_value, type,
994789Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
9952676Seschrock 		if (error) {
9962676Seschrock 			nvlist_free(cbdata.zc_props);
997789Sahrens 			return (error);
9982676Seschrock 		}
999789Sahrens 		error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL);
1000789Sahrens 		dmu_objset_close(clone);
1001789Sahrens 	} else {
10022676Seschrock 		if (cbfunc == NULL) {
10032676Seschrock 			nvlist_free(cbdata.zc_props);
10042199Sahrens 			return (EINVAL);
10052676Seschrock 		}
10062676Seschrock 
1007789Sahrens 		if (type == DMU_OST_ZVOL) {
10082676Seschrock 			uint64_t volsize, volblocksize;
10092676Seschrock 
10102676Seschrock 			if (cbdata.zc_props == NULL ||
10112676Seschrock 			    nvlist_lookup_uint64(cbdata.zc_props,
10122676Seschrock 			    zfs_prop_to_name(ZFS_PROP_VOLSIZE),
10132676Seschrock 			    &volsize) != 0) {
10142676Seschrock 				nvlist_free(cbdata.zc_props);
10152676Seschrock 				return (EINVAL);
10162676Seschrock 			}
10172676Seschrock 
10182676Seschrock 			if ((error = nvlist_lookup_uint64(cbdata.zc_props,
10192676Seschrock 			    zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
10202676Seschrock 			    &volblocksize)) != 0 && error != ENOENT) {
10212676Seschrock 				nvlist_free(cbdata.zc_props);
10222676Seschrock 				return (EINVAL);
10232676Seschrock 			}
10241133Seschrock 
10252676Seschrock 			if (error != 0)
10262676Seschrock 				volblocksize = zfs_prop_default_numeric(
10272676Seschrock 				    ZFS_PROP_VOLBLOCKSIZE);
10282676Seschrock 
10292676Seschrock 			if ((error = zvol_check_volblocksize(
10302676Seschrock 			    volblocksize)) != 0 ||
10312676Seschrock 			    (error = zvol_check_volsize(volsize,
10322676Seschrock 			    volblocksize)) != 0) {
10332676Seschrock 				nvlist_free(cbdata.zc_props);
1034789Sahrens 				return (error);
10352676Seschrock 			}
10362676Seschrock 		}
10371133Seschrock 
10382676Seschrock 		error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc,
10392676Seschrock 		    &cbdata);
1040789Sahrens 	}
10412676Seschrock 
10422676Seschrock 	/*
10432676Seschrock 	 * It would be nice to do this atomically.
10442676Seschrock 	 */
10452676Seschrock 	if (error == 0) {
10462676Seschrock 		if ((error = zfs_set_prop_nvlist(zc->zc_name,
10472676Seschrock 		    zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred,
10482676Seschrock 		    cbdata.zc_props)) != 0)
10492676Seschrock 			(void) dmu_objset_destroy(zc->zc_name);
10502676Seschrock 	}
10512676Seschrock 
10522676Seschrock 	nvlist_free(cbdata.zc_props);
1053789Sahrens 	return (error);
1054789Sahrens }
1055789Sahrens 
1056789Sahrens static int
10572199Sahrens zfs_ioc_snapshot(zfs_cmd_t *zc)
10582199Sahrens {
10592676Seschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
10602199Sahrens 		return (EINVAL);
10612199Sahrens 	return (dmu_objset_snapshot(zc->zc_name,
10622676Seschrock 	    zc->zc_value, zc->zc_cookie));
10632199Sahrens }
10642199Sahrens 
10652199Sahrens static int
10662199Sahrens zfs_unmount_snap(char *name, void *arg)
1067789Sahrens {
10682199Sahrens 	char *snapname = arg;
10692199Sahrens 	char *cp;
10702417Sahrens 	vfs_t *vfsp = NULL;
10712199Sahrens 
10722199Sahrens 	/*
10732199Sahrens 	 * Snapshots (which are under .zfs control) must be unmounted
10742199Sahrens 	 * before they can be destroyed.
10752199Sahrens 	 */
10762199Sahrens 
10772199Sahrens 	if (snapname) {
10782199Sahrens 		(void) strcat(name, "@");
10792199Sahrens 		(void) strcat(name, snapname);
10802199Sahrens 		vfsp = zfs_get_vfs(name);
10812199Sahrens 		cp = strchr(name, '@');
10822199Sahrens 		*cp = '\0';
10832417Sahrens 	} else if (strchr(name, '@')) {
10842199Sahrens 		vfsp = zfs_get_vfs(name);
10852199Sahrens 	}
10862199Sahrens 
10872199Sahrens 	if (vfsp) {
10882199Sahrens 		/*
10892199Sahrens 		 * Always force the unmount for snapshots.
10902199Sahrens 		 */
10912199Sahrens 		int flag = MS_FORCE;
1092789Sahrens 		int err;
1093789Sahrens 
10942199Sahrens 		if ((err = vn_vfswlock(vfsp->vfs_vnodecovered)) != 0) {
10952199Sahrens 			VFS_RELE(vfsp);
10962199Sahrens 			return (err);
10972199Sahrens 		}
10982199Sahrens 		VFS_RELE(vfsp);
10992199Sahrens 		if ((err = dounmount(vfsp, flag, kcred)) != 0)
11002199Sahrens 			return (err);
11012199Sahrens 	}
11022199Sahrens 	return (0);
11032199Sahrens }
11042199Sahrens 
11052199Sahrens static int
11062199Sahrens zfs_ioc_destroy_snaps(zfs_cmd_t *zc)
11072199Sahrens {
11082199Sahrens 	int err;
1109789Sahrens 
11102676Seschrock 	if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
11112199Sahrens 		return (EINVAL);
11122199Sahrens 	err = dmu_objset_find(zc->zc_name,
11132676Seschrock 	    zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN);
11142199Sahrens 	if (err)
11152199Sahrens 		return (err);
11162676Seschrock 	return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value));
11172199Sahrens }
11182199Sahrens 
11192199Sahrens static int
11202199Sahrens zfs_ioc_destroy(zfs_cmd_t *zc)
11212199Sahrens {
11222199Sahrens 	if (strchr(zc->zc_name, '@') && zc->zc_objset_type == DMU_OST_ZFS) {
11232199Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
11242199Sahrens 		if (err)
11252199Sahrens 			return (err);
1126789Sahrens 	}
1127789Sahrens 
1128789Sahrens 	return (dmu_objset_destroy(zc->zc_name));
1129789Sahrens }
1130789Sahrens 
1131789Sahrens static int
1132789Sahrens zfs_ioc_rollback(zfs_cmd_t *zc)
1133789Sahrens {
1134789Sahrens 	return (dmu_objset_rollback(zc->zc_name));
1135789Sahrens }
1136789Sahrens 
1137789Sahrens static int
1138789Sahrens zfs_ioc_rename(zfs_cmd_t *zc)
1139789Sahrens {
11402676Seschrock 	zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
11412676Seschrock 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0)
1142789Sahrens 		return (EINVAL);
1143789Sahrens 
1144789Sahrens 	if (strchr(zc->zc_name, '@') != NULL &&
1145789Sahrens 	    zc->zc_objset_type == DMU_OST_ZFS) {
11462199Sahrens 		int err = zfs_unmount_snap(zc->zc_name, NULL);
11472199Sahrens 		if (err)
11482199Sahrens 			return (err);
1149789Sahrens 	}
1150789Sahrens 
11512676Seschrock 	return (dmu_objset_rename(zc->zc_name, zc->zc_value));
1152789Sahrens }
1153789Sahrens 
1154789Sahrens static int
1155789Sahrens zfs_ioc_recvbackup(zfs_cmd_t *zc)
1156789Sahrens {
1157789Sahrens 	file_t *fp;
1158789Sahrens 	int error, fd;
1159789Sahrens 
1160789Sahrens 	fd = zc->zc_cookie;
1161789Sahrens 	fp = getf(fd);
1162789Sahrens 	if (fp == NULL)
1163789Sahrens 		return (EBADF);
11642676Seschrock 	error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record,
11652676Seschrock 	    &zc->zc_cookie, (boolean_t)zc->zc_guid, fp->f_vnode,
11662665Snd150628 	    fp->f_offset);
1167789Sahrens 	releasef(fd);
1168789Sahrens 	return (error);
1169789Sahrens }
1170789Sahrens 
1171789Sahrens static int
1172789Sahrens zfs_ioc_sendbackup(zfs_cmd_t *zc)
1173789Sahrens {
1174789Sahrens 	objset_t *fromsnap = NULL;
1175789Sahrens 	objset_t *tosnap;
1176789Sahrens 	file_t *fp;
1177789Sahrens 	int error;
1178789Sahrens 
1179789Sahrens 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
1180789Sahrens 	    DS_MODE_STANDARD | DS_MODE_READONLY, &tosnap);
1181789Sahrens 	if (error)
1182789Sahrens 		return (error);
1183789Sahrens 
11842676Seschrock 	if (zc->zc_value[0] != '\0') {
11852676Seschrock 		error = dmu_objset_open(zc->zc_value, DMU_OST_ANY,
1186789Sahrens 		    DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap);
1187789Sahrens 		if (error) {
1188789Sahrens 			dmu_objset_close(tosnap);
1189789Sahrens 			return (error);
1190789Sahrens 		}
1191789Sahrens 	}
1192789Sahrens 
1193789Sahrens 	fp = getf(zc->zc_cookie);
1194789Sahrens 	if (fp == NULL) {
1195789Sahrens 		dmu_objset_close(tosnap);
1196789Sahrens 		if (fromsnap)
1197789Sahrens 			dmu_objset_close(fromsnap);
1198789Sahrens 		return (EBADF);
1199789Sahrens 	}
1200789Sahrens 
1201789Sahrens 	error = dmu_sendbackup(tosnap, fromsnap, fp->f_vnode);
1202789Sahrens 
1203789Sahrens 	releasef(zc->zc_cookie);
1204789Sahrens 	if (fromsnap)
1205789Sahrens 		dmu_objset_close(fromsnap);
1206789Sahrens 	dmu_objset_close(tosnap);
1207789Sahrens 	return (error);
1208789Sahrens }
1209789Sahrens 
12101544Seschrock static int
12111544Seschrock zfs_ioc_inject_fault(zfs_cmd_t *zc)
12121544Seschrock {
12131544Seschrock 	int id, error;
12141544Seschrock 
12151544Seschrock 	error = zio_inject_fault(zc->zc_name, (int)zc->zc_guid, &id,
12161544Seschrock 	    &zc->zc_inject_record);
12171544Seschrock 
12181544Seschrock 	if (error == 0)
12191544Seschrock 		zc->zc_guid = (uint64_t)id;
12201544Seschrock 
12211544Seschrock 	return (error);
12221544Seschrock }
12231544Seschrock 
12241544Seschrock static int
12251544Seschrock zfs_ioc_clear_fault(zfs_cmd_t *zc)
12261544Seschrock {
12271544Seschrock 	return (zio_clear_fault((int)zc->zc_guid));
12281544Seschrock }
12291544Seschrock 
12301544Seschrock static int
12311544Seschrock zfs_ioc_inject_list_next(zfs_cmd_t *zc)
12321544Seschrock {
12331544Seschrock 	int id = (int)zc->zc_guid;
12341544Seschrock 	int error;
12351544Seschrock 
12361544Seschrock 	error = zio_inject_list_next(&id, zc->zc_name, sizeof (zc->zc_name),
12371544Seschrock 	    &zc->zc_inject_record);
12381544Seschrock 
12391544Seschrock 	zc->zc_guid = id;
12401544Seschrock 
12411544Seschrock 	return (error);
12421544Seschrock }
12431544Seschrock 
12441544Seschrock static int
12451544Seschrock zfs_ioc_error_log(zfs_cmd_t *zc)
12461544Seschrock {
12471544Seschrock 	spa_t *spa;
12481544Seschrock 	int error;
12492676Seschrock 	size_t count = (size_t)zc->zc_nvlist_dst_size;
12501544Seschrock 
12511544Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
12521544Seschrock 		return (error);
12531544Seschrock 
12542676Seschrock 	error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst,
12551544Seschrock 	    &count);
12561544Seschrock 	if (error == 0)
12572676Seschrock 		zc->zc_nvlist_dst_size = count;
12581544Seschrock 	else
12592676Seschrock 		zc->zc_nvlist_dst_size = spa_get_errlog_size(spa);
12601544Seschrock 
12611544Seschrock 	spa_close(spa, FTAG);
12621544Seschrock 
12631544Seschrock 	return (error);
12641544Seschrock }
12651544Seschrock 
12661544Seschrock static int
12671544Seschrock zfs_ioc_clear(zfs_cmd_t *zc)
12681544Seschrock {
12691544Seschrock 	spa_t *spa;
12701544Seschrock 	vdev_t *vd;
12711544Seschrock 	int error;
12721544Seschrock 
12731544Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
12741544Seschrock 		return (error);
12751544Seschrock 
12761544Seschrock 	spa_config_enter(spa, RW_WRITER, FTAG);
12771544Seschrock 
12782676Seschrock 	if (zc->zc_guid == 0) {
12791544Seschrock 		vd = NULL;
12802676Seschrock 	} else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) {
12811544Seschrock 		spa_config_exit(spa, FTAG);
12821544Seschrock 		spa_close(spa, FTAG);
12831544Seschrock 		return (ENODEV);
12841544Seschrock 	}
12851544Seschrock 
12861544Seschrock 	vdev_clear(spa, vd);
12871544Seschrock 
12881544Seschrock 	spa_config_exit(spa, FTAG);
12891544Seschrock 
12901544Seschrock 	spa_close(spa, FTAG);
12911544Seschrock 
12921544Seschrock 	return (0);
12931544Seschrock }
12941544Seschrock 
12951544Seschrock static int
12961544Seschrock zfs_ioc_bookmark_name(zfs_cmd_t *zc)
12971544Seschrock {
12981544Seschrock 	spa_t *spa;
12991544Seschrock 	int error;
13002676Seschrock 	nvlist_t *nvl;
13011544Seschrock 
13021544Seschrock 	if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
13031544Seschrock 		return (error);
13041544Seschrock 
13052676Seschrock 	VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
13062676Seschrock 
13072676Seschrock 	error = spa_bookmark_name(spa, &zc->zc_bookmark, nvl);
13082676Seschrock 	if (error == 0)
13092676Seschrock 		error = put_nvlist(zc, nvl);
13102676Seschrock 	nvlist_free(nvl);
13111544Seschrock 
13121544Seschrock 	spa_close(spa, FTAG);
13131544Seschrock 
13141544Seschrock 	return (error);
13151544Seschrock }
13161544Seschrock 
13172082Seschrock static int
13182082Seschrock zfs_ioc_promote(zfs_cmd_t *zc)
13192082Seschrock {
13202417Sahrens 	char *cp;
13212417Sahrens 
13222417Sahrens 	/*
13232417Sahrens 	 * We don't need to unmount *all* the origin fs's snapshots, but
13242417Sahrens 	 * it's easier.
13252417Sahrens 	 */
13262676Seschrock 	cp = strchr(zc->zc_value, '@');
13272417Sahrens 	if (cp)
13282417Sahrens 		*cp = '\0';
13292676Seschrock 	(void) dmu_objset_find(zc->zc_value,
13302417Sahrens 	    zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS);
13312082Seschrock 	return (dsl_dataset_promote(zc->zc_name));
13322082Seschrock }
13332082Seschrock 
1334789Sahrens static zfs_ioc_vec_t zfs_ioc_vec[] = {
1335789Sahrens 	{ zfs_ioc_pool_create,		zfs_secpolicy_config,	pool_name },
1336789Sahrens 	{ zfs_ioc_pool_destroy,		zfs_secpolicy_config,	pool_name },
1337789Sahrens 	{ zfs_ioc_pool_import,		zfs_secpolicy_config,	pool_name },
1338789Sahrens 	{ zfs_ioc_pool_export,		zfs_secpolicy_config,	pool_name },
1339789Sahrens 	{ zfs_ioc_pool_configs,		zfs_secpolicy_none,	no_name },
1340789Sahrens 	{ zfs_ioc_pool_stats,		zfs_secpolicy_read,	pool_name },
1341789Sahrens 	{ zfs_ioc_pool_tryimport,	zfs_secpolicy_config,	no_name },
1342789Sahrens 	{ zfs_ioc_pool_scrub,		zfs_secpolicy_config,	pool_name },
1343789Sahrens 	{ zfs_ioc_pool_freeze,		zfs_secpolicy_config,	no_name },
13441760Seschrock 	{ zfs_ioc_pool_upgrade,		zfs_secpolicy_config,	pool_name },
1345789Sahrens 	{ zfs_ioc_vdev_add,		zfs_secpolicy_config,	pool_name },
1346789Sahrens 	{ zfs_ioc_vdev_remove,		zfs_secpolicy_config,	pool_name },
1347789Sahrens 	{ zfs_ioc_vdev_online,		zfs_secpolicy_config,	pool_name },
1348789Sahrens 	{ zfs_ioc_vdev_offline,		zfs_secpolicy_config,	pool_name },
1349789Sahrens 	{ zfs_ioc_vdev_attach,		zfs_secpolicy_config,	pool_name },
1350789Sahrens 	{ zfs_ioc_vdev_detach,		zfs_secpolicy_config,	pool_name },
13511354Seschrock 	{ zfs_ioc_vdev_setpath,		zfs_secpolicy_config,	pool_name },
1352789Sahrens 	{ zfs_ioc_objset_stats,		zfs_secpolicy_read,	dataset_name },
1353789Sahrens 	{ zfs_ioc_dataset_list_next,	zfs_secpolicy_read,	dataset_name },
1354789Sahrens 	{ zfs_ioc_snapshot_list_next,	zfs_secpolicy_read,	dataset_name },
13552676Seschrock 	{ zfs_ioc_set_prop,		zfs_secpolicy_write,	dataset_name },
1356789Sahrens 	{ zfs_ioc_create_minor,		zfs_secpolicy_config,	dataset_name },
1357789Sahrens 	{ zfs_ioc_remove_minor,		zfs_secpolicy_config,	dataset_name },
1358789Sahrens 	{ zfs_ioc_create,		zfs_secpolicy_parent,	dataset_name },
1359789Sahrens 	{ zfs_ioc_destroy,		zfs_secpolicy_parent,	dataset_name },
1360789Sahrens 	{ zfs_ioc_rollback,		zfs_secpolicy_write,	dataset_name },
1361789Sahrens 	{ zfs_ioc_rename,		zfs_secpolicy_write,	dataset_name },
1362789Sahrens 	{ zfs_ioc_recvbackup,		zfs_secpolicy_write,	dataset_name },
1363789Sahrens 	{ zfs_ioc_sendbackup,		zfs_secpolicy_write,	dataset_name },
13641544Seschrock 	{ zfs_ioc_inject_fault,		zfs_secpolicy_inject,	no_name },
13651544Seschrock 	{ zfs_ioc_clear_fault,		zfs_secpolicy_inject,	no_name },
13661544Seschrock 	{ zfs_ioc_inject_list_next,	zfs_secpolicy_inject,	no_name },
13671544Seschrock 	{ zfs_ioc_error_log,		zfs_secpolicy_inject,	pool_name },
13681544Seschrock 	{ zfs_ioc_clear,		zfs_secpolicy_config,	pool_name },
13692082Seschrock 	{ zfs_ioc_bookmark_name,	zfs_secpolicy_inject,	pool_name },
13702199Sahrens 	{ zfs_ioc_promote,		zfs_secpolicy_write,	dataset_name },
13712199Sahrens 	{ zfs_ioc_destroy_snaps,	zfs_secpolicy_write,	dataset_name },
13722199Sahrens 	{ zfs_ioc_snapshot,		zfs_secpolicy_write,	dataset_name }
1373789Sahrens };
1374789Sahrens 
1375789Sahrens static int
1376789Sahrens zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
1377789Sahrens {
1378789Sahrens 	zfs_cmd_t *zc;
1379789Sahrens 	uint_t vec;
13802199Sahrens 	int error, rc;
1381789Sahrens 
1382789Sahrens 	if (getminor(dev) != 0)
1383789Sahrens 		return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp));
1384789Sahrens 
1385789Sahrens 	vec = cmd - ZFS_IOC;
1386789Sahrens 
1387789Sahrens 	if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
1388789Sahrens 		return (EINVAL);
1389789Sahrens 
1390789Sahrens 	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
1391789Sahrens 
1392789Sahrens 	error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t));
1393789Sahrens 
1394789Sahrens 	if (error == 0) {
1395789Sahrens 		zc->zc_cred = (uintptr_t)cr;
1396789Sahrens 		zc->zc_dev = dev;
13972676Seschrock 		error = zfs_ioc_vec[vec].zvec_secpolicy(zc->zc_name, cr);
1398789Sahrens 	}
1399789Sahrens 
1400789Sahrens 	/*
1401789Sahrens 	 * Ensure that all pool/dataset names are valid before we pass down to
1402789Sahrens 	 * the lower layers.
1403789Sahrens 	 */
1404789Sahrens 	if (error == 0) {
1405789Sahrens 		zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
1406789Sahrens 		switch (zfs_ioc_vec[vec].zvec_namecheck) {
1407789Sahrens 		case pool_name:
1408789Sahrens 			if (pool_namecheck(zc->zc_name, NULL, NULL) != 0)
1409789Sahrens 				error = EINVAL;
1410789Sahrens 			break;
1411789Sahrens 
1412789Sahrens 		case dataset_name:
1413789Sahrens 			if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0)
1414789Sahrens 				error = EINVAL;
1415789Sahrens 			break;
1416*2856Snd150628 
1417*2856Snd150628 		case no_name:
1418*2856Snd150628 			break;
1419789Sahrens 		}
1420789Sahrens 	}
1421789Sahrens 
1422789Sahrens 	if (error == 0)
1423789Sahrens 		error = zfs_ioc_vec[vec].zvec_func(zc);
1424789Sahrens 
14252199Sahrens 	rc = xcopyout(zc, (void *)arg, sizeof (zfs_cmd_t));
14262199Sahrens 	if (error == 0)
14272199Sahrens 		error = rc;
1428789Sahrens 
1429789Sahrens 	kmem_free(zc, sizeof (zfs_cmd_t));
1430789Sahrens 	return (error);
1431789Sahrens }
1432789Sahrens 
1433789Sahrens static int
1434789Sahrens zfs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1435789Sahrens {
1436789Sahrens 	if (cmd != DDI_ATTACH)
1437789Sahrens 		return (DDI_FAILURE);
1438789Sahrens 
1439789Sahrens 	if (ddi_create_minor_node(dip, "zfs", S_IFCHR, 0,
1440789Sahrens 	    DDI_PSEUDO, 0) == DDI_FAILURE)
1441789Sahrens 		return (DDI_FAILURE);
1442789Sahrens 
1443789Sahrens 	zfs_dip = dip;
1444789Sahrens 
1445789Sahrens 	ddi_report_dev(dip);
1446789Sahrens 
1447789Sahrens 	return (DDI_SUCCESS);
1448789Sahrens }
1449789Sahrens 
1450789Sahrens static int
1451789Sahrens zfs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1452789Sahrens {
1453789Sahrens 	if (spa_busy() || zfs_busy() || zvol_busy())
1454789Sahrens 		return (DDI_FAILURE);
1455789Sahrens 
1456789Sahrens 	if (cmd != DDI_DETACH)
1457789Sahrens 		return (DDI_FAILURE);
1458789Sahrens 
1459789Sahrens 	zfs_dip = NULL;
1460789Sahrens 
1461789Sahrens 	ddi_prop_remove_all(dip);
1462789Sahrens 	ddi_remove_minor_node(dip, NULL);
1463789Sahrens 
1464789Sahrens 	return (DDI_SUCCESS);
1465789Sahrens }
1466789Sahrens 
1467789Sahrens /*ARGSUSED*/
1468789Sahrens static int
1469789Sahrens zfs_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
1470789Sahrens {
1471789Sahrens 	switch (infocmd) {
1472789Sahrens 	case DDI_INFO_DEVT2DEVINFO:
1473789Sahrens 		*result = zfs_dip;
1474789Sahrens 		return (DDI_SUCCESS);
1475789Sahrens 
1476789Sahrens 	case DDI_INFO_DEVT2INSTANCE:
1477849Sbonwick 		*result = (void *)0;
1478789Sahrens 		return (DDI_SUCCESS);
1479789Sahrens 	}
1480789Sahrens 
1481789Sahrens 	return (DDI_FAILURE);
1482789Sahrens }
1483789Sahrens 
1484789Sahrens /*
1485789Sahrens  * OK, so this is a little weird.
1486789Sahrens  *
1487789Sahrens  * /dev/zfs is the control node, i.e. minor 0.
1488789Sahrens  * /dev/zvol/[r]dsk/pool/dataset are the zvols, minor > 0.
1489789Sahrens  *
1490789Sahrens  * /dev/zfs has basically nothing to do except serve up ioctls,
1491789Sahrens  * so most of the standard driver entry points are in zvol.c.
1492789Sahrens  */
1493789Sahrens static struct cb_ops zfs_cb_ops = {
1494789Sahrens 	zvol_open,	/* open */
1495789Sahrens 	zvol_close,	/* close */
1496789Sahrens 	zvol_strategy,	/* strategy */
1497789Sahrens 	nodev,		/* print */
1498789Sahrens 	nodev,		/* dump */
1499789Sahrens 	zvol_read,	/* read */
1500789Sahrens 	zvol_write,	/* write */
1501789Sahrens 	zfsdev_ioctl,	/* ioctl */
1502789Sahrens 	nodev,		/* devmap */
1503789Sahrens 	nodev,		/* mmap */
1504789Sahrens 	nodev,		/* segmap */
1505789Sahrens 	nochpoll,	/* poll */
1506789Sahrens 	ddi_prop_op,	/* prop_op */
1507789Sahrens 	NULL,		/* streamtab */
1508789Sahrens 	D_NEW | D_MP | D_64BIT,		/* Driver compatibility flag */
1509789Sahrens 	CB_REV,		/* version */
1510789Sahrens 	zvol_aread,	/* async read */
1511789Sahrens 	zvol_awrite,	/* async write */
1512789Sahrens };
1513789Sahrens 
1514789Sahrens static struct dev_ops zfs_dev_ops = {
1515789Sahrens 	DEVO_REV,	/* version */
1516789Sahrens 	0,		/* refcnt */
1517789Sahrens 	zfs_info,	/* info */
1518789Sahrens 	nulldev,	/* identify */
1519789Sahrens 	nulldev,	/* probe */
1520789Sahrens 	zfs_attach,	/* attach */
1521789Sahrens 	zfs_detach,	/* detach */
1522789Sahrens 	nodev,		/* reset */
1523789Sahrens 	&zfs_cb_ops,	/* driver operations */
1524789Sahrens 	NULL		/* no bus operations */
1525789Sahrens };
1526789Sahrens 
1527789Sahrens static struct modldrv zfs_modldrv = {
15282676Seschrock 	&mod_driverops, "ZFS storage pool version " ZFS_VERSION_STRING,
15292676Seschrock 	    &zfs_dev_ops
1530789Sahrens };
1531789Sahrens 
1532789Sahrens static struct modlinkage modlinkage = {
1533789Sahrens 	MODREV_1,
1534789Sahrens 	(void *)&zfs_modlfs,
1535789Sahrens 	(void *)&zfs_modldrv,
1536789Sahrens 	NULL
1537789Sahrens };
1538789Sahrens 
1539789Sahrens int
1540789Sahrens _init(void)
1541789Sahrens {
1542789Sahrens 	int error;
1543789Sahrens 
1544849Sbonwick 	spa_init(FREAD | FWRITE);
1545849Sbonwick 	zfs_init();
1546849Sbonwick 	zvol_init();
1547849Sbonwick 
1548849Sbonwick 	if ((error = mod_install(&modlinkage)) != 0) {
1549849Sbonwick 		zvol_fini();
1550849Sbonwick 		zfs_fini();
1551849Sbonwick 		spa_fini();
1552789Sahrens 		return (error);
1553849Sbonwick 	}
1554789Sahrens 
1555789Sahrens 	error = ldi_ident_from_mod(&modlinkage, &zfs_li);
1556789Sahrens 	ASSERT(error == 0);
1557789Sahrens 
1558789Sahrens 	return (0);
1559789Sahrens }
1560789Sahrens 
1561789Sahrens int
1562789Sahrens _fini(void)
1563789Sahrens {
1564789Sahrens 	int error;
1565789Sahrens 
15661544Seschrock 	if (spa_busy() || zfs_busy() || zvol_busy() || zio_injection_enabled)
1567789Sahrens 		return (EBUSY);
1568789Sahrens 
1569789Sahrens 	if ((error = mod_remove(&modlinkage)) != 0)
1570789Sahrens 		return (error);
1571789Sahrens 
1572789Sahrens 	zvol_fini();
1573789Sahrens 	zfs_fini();
1574789Sahrens 	spa_fini();
1575789Sahrens 
1576789Sahrens 	ldi_ident_release(zfs_li);
1577789Sahrens 	zfs_li = NULL;
1578789Sahrens 
1579789Sahrens 	return (error);
1580789Sahrens }
1581789Sahrens 
1582789Sahrens int
1583789Sahrens _info(struct modinfo *modinfop)
1584789Sahrens {
1585789Sahrens 	return (mod_info(&modlinkage, modinfop));
1586789Sahrens }
1587