xref: /illumos-gate/usr/src/uts/common/fs/zfs/zvol.c (revision fa9e4066)
1*fa9e4066Sahrens /*
2*fa9e4066Sahrens  * CDDL HEADER START
3*fa9e4066Sahrens  *
4*fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5*fa9e4066Sahrens  * Common Development and Distribution License, Version 1.0 only
6*fa9e4066Sahrens  * (the "License").  You may not use this file except in compliance
7*fa9e4066Sahrens  * with the License.
8*fa9e4066Sahrens  *
9*fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
11*fa9e4066Sahrens  * See the License for the specific language governing permissions
12*fa9e4066Sahrens  * and limitations under the License.
13*fa9e4066Sahrens  *
14*fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
15*fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
17*fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
18*fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
19*fa9e4066Sahrens  *
20*fa9e4066Sahrens  * CDDL HEADER END
21*fa9e4066Sahrens  */
22*fa9e4066Sahrens /*
23*fa9e4066Sahrens  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*fa9e4066Sahrens  * Use is subject to license terms.
25*fa9e4066Sahrens  */
26*fa9e4066Sahrens 
27*fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*fa9e4066Sahrens 
29*fa9e4066Sahrens /*
30*fa9e4066Sahrens  * ZFS volume emulation driver.
31*fa9e4066Sahrens  *
32*fa9e4066Sahrens  * Makes a DMU object look like a volume of arbitrary size, up to 2^64 bytes.
33*fa9e4066Sahrens  * Volumes are accessed through the symbolic links named:
34*fa9e4066Sahrens  *
35*fa9e4066Sahrens  * /dev/zvol/dsk/<pool_name>/<dataset_name>
36*fa9e4066Sahrens  * /dev/zvol/rdsk/<pool_name>/<dataset_name>
37*fa9e4066Sahrens  *
38*fa9e4066Sahrens  * These links are created by the ZFS-specific devfsadm link generator.
39*fa9e4066Sahrens  * Volumes are persistent through reboot.  No user command needs to be
40*fa9e4066Sahrens  * run before opening and using a device.
41*fa9e4066Sahrens  */
42*fa9e4066Sahrens 
43*fa9e4066Sahrens #include <sys/types.h>
44*fa9e4066Sahrens #include <sys/param.h>
45*fa9e4066Sahrens #include <sys/errno.h>
46*fa9e4066Sahrens #include <sys/aio_req.h>
47*fa9e4066Sahrens #include <sys/uio.h>
48*fa9e4066Sahrens #include <sys/buf.h>
49*fa9e4066Sahrens #include <sys/modctl.h>
50*fa9e4066Sahrens #include <sys/open.h>
51*fa9e4066Sahrens #include <sys/kmem.h>
52*fa9e4066Sahrens #include <sys/conf.h>
53*fa9e4066Sahrens #include <sys/cmn_err.h>
54*fa9e4066Sahrens #include <sys/stat.h>
55*fa9e4066Sahrens #include <sys/zap.h>
56*fa9e4066Sahrens #include <sys/spa.h>
57*fa9e4066Sahrens #include <sys/zio.h>
58*fa9e4066Sahrens #include <sys/dsl_prop.h>
59*fa9e4066Sahrens #include <sys/dkio.h>
60*fa9e4066Sahrens #include <sys/efi_partition.h>
61*fa9e4066Sahrens #include <sys/byteorder.h>
62*fa9e4066Sahrens #include <sys/pathname.h>
63*fa9e4066Sahrens #include <sys/ddi.h>
64*fa9e4066Sahrens #include <sys/sunddi.h>
65*fa9e4066Sahrens #include <sys/crc32.h>
66*fa9e4066Sahrens #include <sys/dirent.h>
67*fa9e4066Sahrens #include <sys/policy.h>
68*fa9e4066Sahrens #include <sys/fs/zfs.h>
69*fa9e4066Sahrens #include <sys/zfs_ioctl.h>
70*fa9e4066Sahrens #include <sys/mkdev.h>
71*fa9e4066Sahrens 
72*fa9e4066Sahrens #include "zfs_namecheck.h"
73*fa9e4066Sahrens 
74*fa9e4066Sahrens #define	ZVOL_OBJ		1ULL
75*fa9e4066Sahrens #define	ZVOL_ZAP_OBJ		2ULL
76*fa9e4066Sahrens #define	ZVOL_MAX_MINOR		MAXMIN32
77*fa9e4066Sahrens 
78*fa9e4066Sahrens static void *zvol_state;
79*fa9e4066Sahrens 
80*fa9e4066Sahrens /*
81*fa9e4066Sahrens  * This lock protects the zvol_state structure from being modified
82*fa9e4066Sahrens  * while it's being used, e.g. an open that comes in before a create
83*fa9e4066Sahrens  * finishes.  It also protects temporary opens of the dataset so that,
84*fa9e4066Sahrens  * e.g., an open doesn't get a spurious EBUSY.
85*fa9e4066Sahrens  */
86*fa9e4066Sahrens static kmutex_t zvol_state_lock;
87*fa9e4066Sahrens static uint32_t zvol_minors;
88*fa9e4066Sahrens 
89*fa9e4066Sahrens /*
90*fa9e4066Sahrens  * The in-core state of each volume.
91*fa9e4066Sahrens  */
92*fa9e4066Sahrens typedef struct zvol_state {
93*fa9e4066Sahrens 	char		zv_name[MAXPATHLEN]; /* pool/dd name */
94*fa9e4066Sahrens 	uint64_t	zv_volsize;	/* amount of space we advertise */
95*fa9e4066Sahrens 	minor_t		zv_minor;	/* minor number */
96*fa9e4066Sahrens 	uint8_t		zv_min_bs;	/* minimum addressable block shift */
97*fa9e4066Sahrens 	uint8_t		zv_readonly;	/* hard readonly; like write-protect */
98*fa9e4066Sahrens 	objset_t	*zv_objset;	/* objset handle */
99*fa9e4066Sahrens 	uint32_t	zv_mode;	/* DS_MODE_* flags at open time */
100*fa9e4066Sahrens 	uint32_t	zv_open_count[OTYPCNT];	/* open counts */
101*fa9e4066Sahrens 	uint32_t	zv_total_opens;	/* total open count */
102*fa9e4066Sahrens } zvol_state_t;
103*fa9e4066Sahrens 
104*fa9e4066Sahrens static void
105*fa9e4066Sahrens zvol_size_changed(zvol_state_t *zv, dev_t dev)
106*fa9e4066Sahrens {
107*fa9e4066Sahrens 	dev = makedevice(getmajor(dev), zv->zv_minor);
108*fa9e4066Sahrens 
109*fa9e4066Sahrens 	VERIFY(ddi_prop_update_int64(dev, zfs_dip,
110*fa9e4066Sahrens 	    "Size", zv->zv_volsize) == DDI_SUCCESS);
111*fa9e4066Sahrens 	VERIFY(ddi_prop_update_int64(dev, zfs_dip,
112*fa9e4066Sahrens 	    "Nblocks", lbtodb(zv->zv_volsize)) == DDI_SUCCESS);
113*fa9e4066Sahrens }
114*fa9e4066Sahrens 
115*fa9e4066Sahrens int
116*fa9e4066Sahrens zvol_check_volsize(zfs_cmd_t *zc)
117*fa9e4066Sahrens {
118*fa9e4066Sahrens 	if (zc->zc_volsize == 0)
119*fa9e4066Sahrens 		return (EINVAL);
120*fa9e4066Sahrens 
121*fa9e4066Sahrens 	zc->zc_volsize = P2ROUNDUP(zc->zc_volsize, SPA_MAXBLOCKSIZE);
122*fa9e4066Sahrens #ifdef _ILP32
123*fa9e4066Sahrens 	if (zc->zc_volsize - 1 > SPEC_MAXOFFSET_T)
124*fa9e4066Sahrens 		return (EOVERFLOW);
125*fa9e4066Sahrens #endif
126*fa9e4066Sahrens 	return (0);
127*fa9e4066Sahrens }
128*fa9e4066Sahrens 
129*fa9e4066Sahrens int
130*fa9e4066Sahrens zvol_check_volblocksize(zfs_cmd_t *zc)
131*fa9e4066Sahrens {
132*fa9e4066Sahrens 	if (zc->zc_volblocksize < SPA_MINBLOCKSIZE ||
133*fa9e4066Sahrens 	    zc->zc_volblocksize > SPA_MAXBLOCKSIZE ||
134*fa9e4066Sahrens 	    !ISP2(zc->zc_volblocksize))
135*fa9e4066Sahrens 		return (EDOM);
136*fa9e4066Sahrens 
137*fa9e4066Sahrens 	return (0);
138*fa9e4066Sahrens }
139*fa9e4066Sahrens 
140*fa9e4066Sahrens static void
141*fa9e4066Sahrens zvol_readonly_changed_cb(void *arg, uint64_t newval)
142*fa9e4066Sahrens {
143*fa9e4066Sahrens 	zvol_state_t *zv = arg;
144*fa9e4066Sahrens 
145*fa9e4066Sahrens 	zv->zv_readonly = (uint8_t)newval;
146*fa9e4066Sahrens }
147*fa9e4066Sahrens 
148*fa9e4066Sahrens int
149*fa9e4066Sahrens zvol_get_stats(zfs_cmd_t *zc, objset_t *os)
150*fa9e4066Sahrens {
151*fa9e4066Sahrens 	int error;
152*fa9e4066Sahrens 	dmu_object_info_t doi;
153*fa9e4066Sahrens 
154*fa9e4066Sahrens 	error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &zc->zc_volsize);
155*fa9e4066Sahrens 
156*fa9e4066Sahrens 	if (error)
157*fa9e4066Sahrens 		return (error);
158*fa9e4066Sahrens 
159*fa9e4066Sahrens 	error = dmu_object_info(os, ZVOL_OBJ, &doi);
160*fa9e4066Sahrens 
161*fa9e4066Sahrens 	if (error == 0)
162*fa9e4066Sahrens 		zc->zc_volblocksize = doi.doi_data_block_size;
163*fa9e4066Sahrens 
164*fa9e4066Sahrens 	return (error);
165*fa9e4066Sahrens }
166*fa9e4066Sahrens 
167*fa9e4066Sahrens /*
168*fa9e4066Sahrens  * Find a free minor number.
169*fa9e4066Sahrens  */
170*fa9e4066Sahrens static minor_t
171*fa9e4066Sahrens zvol_minor_alloc(void)
172*fa9e4066Sahrens {
173*fa9e4066Sahrens 	minor_t minor;
174*fa9e4066Sahrens 
175*fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zvol_state_lock));
176*fa9e4066Sahrens 
177*fa9e4066Sahrens 	for (minor = 1; minor <= ZVOL_MAX_MINOR; minor++)
178*fa9e4066Sahrens 		if (ddi_get_soft_state(zvol_state, minor) == NULL)
179*fa9e4066Sahrens 			return (minor);
180*fa9e4066Sahrens 
181*fa9e4066Sahrens 	return (0);
182*fa9e4066Sahrens }
183*fa9e4066Sahrens 
184*fa9e4066Sahrens static zvol_state_t *
185*fa9e4066Sahrens zvol_minor_lookup(char *name)
186*fa9e4066Sahrens {
187*fa9e4066Sahrens 	minor_t minor;
188*fa9e4066Sahrens 	zvol_state_t *zv;
189*fa9e4066Sahrens 
190*fa9e4066Sahrens 	ASSERT(MUTEX_HELD(&zvol_state_lock));
191*fa9e4066Sahrens 
192*fa9e4066Sahrens 	for (minor = 1; minor <= ZVOL_MAX_MINOR; minor++) {
193*fa9e4066Sahrens 		zv = ddi_get_soft_state(zvol_state, minor);
194*fa9e4066Sahrens 		if (zv == NULL)
195*fa9e4066Sahrens 			continue;
196*fa9e4066Sahrens 		if (strcmp(zv->zv_name, name) == 0)
197*fa9e4066Sahrens 			break;
198*fa9e4066Sahrens 	}
199*fa9e4066Sahrens 
200*fa9e4066Sahrens 	return (zv);
201*fa9e4066Sahrens }
202*fa9e4066Sahrens 
203*fa9e4066Sahrens void
204*fa9e4066Sahrens zvol_create_cb(objset_t *os, void *arg, dmu_tx_t *tx)
205*fa9e4066Sahrens {
206*fa9e4066Sahrens 	zfs_cmd_t *zc = arg;
207*fa9e4066Sahrens 	int error;
208*fa9e4066Sahrens 
209*fa9e4066Sahrens 	error = dmu_object_claim(os, ZVOL_OBJ, DMU_OT_ZVOL, zc->zc_volblocksize,
210*fa9e4066Sahrens 	    DMU_OT_NONE, 0, tx);
211*fa9e4066Sahrens 	ASSERT(error == 0);
212*fa9e4066Sahrens 
213*fa9e4066Sahrens 	error = zap_create_claim(os, ZVOL_ZAP_OBJ, DMU_OT_ZVOL_PROP,
214*fa9e4066Sahrens 	    DMU_OT_NONE, 0, tx);
215*fa9e4066Sahrens 	ASSERT(error == 0);
216*fa9e4066Sahrens 
217*fa9e4066Sahrens 	error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, &zc->zc_volsize, tx);
218*fa9e4066Sahrens 	ASSERT(error == 0);
219*fa9e4066Sahrens }
220*fa9e4066Sahrens 
221*fa9e4066Sahrens /*
222*fa9e4066Sahrens  * Create a minor node for the specified volume.
223*fa9e4066Sahrens  */
224*fa9e4066Sahrens int
225*fa9e4066Sahrens zvol_create_minor(zfs_cmd_t *zc)
226*fa9e4066Sahrens {
227*fa9e4066Sahrens 	char *name = zc->zc_name;
228*fa9e4066Sahrens 	dev_t dev = zc->zc_dev;
229*fa9e4066Sahrens 	zvol_state_t *zv;
230*fa9e4066Sahrens 	objset_t *os;
231*fa9e4066Sahrens 	uint64_t volsize;
232*fa9e4066Sahrens 	minor_t minor = 0;
233*fa9e4066Sahrens 	struct pathname linkpath;
234*fa9e4066Sahrens 	int ds_mode = DS_MODE_PRIMARY;
235*fa9e4066Sahrens 	vnode_t *vp = NULL;
236*fa9e4066Sahrens 	char *devpath;
237*fa9e4066Sahrens 	size_t devpathlen = strlen(ZVOL_FULL_DEV_DIR) + 1 + strlen(name) + 1;
238*fa9e4066Sahrens 	char chrbuf[30], blkbuf[30];
239*fa9e4066Sahrens 	int error;
240*fa9e4066Sahrens 
241*fa9e4066Sahrens 	mutex_enter(&zvol_state_lock);
242*fa9e4066Sahrens 
243*fa9e4066Sahrens 	if ((zv = zvol_minor_lookup(name)) != NULL) {
244*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
245*fa9e4066Sahrens 		return (EEXIST);
246*fa9e4066Sahrens 	}
247*fa9e4066Sahrens 
248*fa9e4066Sahrens 	if (strchr(name, '@') != 0)
249*fa9e4066Sahrens 		ds_mode |= DS_MODE_READONLY;
250*fa9e4066Sahrens 
251*fa9e4066Sahrens 	error = dmu_objset_open(name, DMU_OST_ZVOL, ds_mode, &os);
252*fa9e4066Sahrens 
253*fa9e4066Sahrens 	if (error) {
254*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
255*fa9e4066Sahrens 		return (error);
256*fa9e4066Sahrens 	}
257*fa9e4066Sahrens 
258*fa9e4066Sahrens 	error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize);
259*fa9e4066Sahrens 
260*fa9e4066Sahrens 	if (error) {
261*fa9e4066Sahrens 		dmu_objset_close(os);
262*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
263*fa9e4066Sahrens 		return (error);
264*fa9e4066Sahrens 	}
265*fa9e4066Sahrens 
266*fa9e4066Sahrens 	/*
267*fa9e4066Sahrens 	 * If there's an existing /dev/zvol symlink, try to use the
268*fa9e4066Sahrens 	 * same minor number we used last time.
269*fa9e4066Sahrens 	 */
270*fa9e4066Sahrens 	devpath = kmem_alloc(devpathlen, KM_SLEEP);
271*fa9e4066Sahrens 
272*fa9e4066Sahrens 	(void) sprintf(devpath, "%s/%s", ZVOL_FULL_DEV_DIR, name);
273*fa9e4066Sahrens 
274*fa9e4066Sahrens 	error = lookupname(devpath, UIO_SYSSPACE, NO_FOLLOW, NULL, &vp);
275*fa9e4066Sahrens 
276*fa9e4066Sahrens 	kmem_free(devpath, devpathlen);
277*fa9e4066Sahrens 
278*fa9e4066Sahrens 	if (error == 0 && vp->v_type != VLNK)
279*fa9e4066Sahrens 		error = EINVAL;
280*fa9e4066Sahrens 
281*fa9e4066Sahrens 	if (error == 0) {
282*fa9e4066Sahrens 		pn_alloc(&linkpath);
283*fa9e4066Sahrens 		error = pn_getsymlink(vp, &linkpath, kcred);
284*fa9e4066Sahrens 		if (error == 0) {
285*fa9e4066Sahrens 			char *ms = strstr(linkpath.pn_path, ZVOL_PSEUDO_DEV);
286*fa9e4066Sahrens 			if (ms != NULL) {
287*fa9e4066Sahrens 				ms += strlen(ZVOL_PSEUDO_DEV);
288*fa9e4066Sahrens 				minor = stoi(&ms);
289*fa9e4066Sahrens 			}
290*fa9e4066Sahrens 		}
291*fa9e4066Sahrens 		pn_free(&linkpath);
292*fa9e4066Sahrens 	}
293*fa9e4066Sahrens 
294*fa9e4066Sahrens 	if (vp != NULL)
295*fa9e4066Sahrens 		VN_RELE(vp);
296*fa9e4066Sahrens 
297*fa9e4066Sahrens 	/*
298*fa9e4066Sahrens 	 * If we found a minor but it's already in use, we must pick a new one.
299*fa9e4066Sahrens 	 */
300*fa9e4066Sahrens 	if (minor != 0 && ddi_get_soft_state(zvol_state, minor) != NULL)
301*fa9e4066Sahrens 		minor = 0;
302*fa9e4066Sahrens 
303*fa9e4066Sahrens 	if (minor == 0)
304*fa9e4066Sahrens 		minor = zvol_minor_alloc();
305*fa9e4066Sahrens 
306*fa9e4066Sahrens 	if (minor == 0) {
307*fa9e4066Sahrens 		dmu_objset_close(os);
308*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
309*fa9e4066Sahrens 		return (ENXIO);
310*fa9e4066Sahrens 	}
311*fa9e4066Sahrens 
312*fa9e4066Sahrens 	if (ddi_soft_state_zalloc(zvol_state, minor) != DDI_SUCCESS) {
313*fa9e4066Sahrens 		dmu_objset_close(os);
314*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
315*fa9e4066Sahrens 		return (EAGAIN);
316*fa9e4066Sahrens 	}
317*fa9e4066Sahrens 
318*fa9e4066Sahrens 	(void) ddi_prop_update_string(minor, zfs_dip, ZVOL_PROP_NAME, name);
319*fa9e4066Sahrens 
320*fa9e4066Sahrens 	(void) sprintf(chrbuf, "%uc,raw", minor);
321*fa9e4066Sahrens 
322*fa9e4066Sahrens 	if (ddi_create_minor_node(zfs_dip, chrbuf, S_IFCHR,
323*fa9e4066Sahrens 	    minor, DDI_PSEUDO, 0) == DDI_FAILURE) {
324*fa9e4066Sahrens 		ddi_soft_state_free(zvol_state, minor);
325*fa9e4066Sahrens 		dmu_objset_close(os);
326*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
327*fa9e4066Sahrens 		return (EAGAIN);
328*fa9e4066Sahrens 	}
329*fa9e4066Sahrens 
330*fa9e4066Sahrens 	(void) sprintf(blkbuf, "%uc", minor);
331*fa9e4066Sahrens 
332*fa9e4066Sahrens 	if (ddi_create_minor_node(zfs_dip, blkbuf, S_IFBLK,
333*fa9e4066Sahrens 	    minor, DDI_PSEUDO, 0) == DDI_FAILURE) {
334*fa9e4066Sahrens 		ddi_remove_minor_node(zfs_dip, chrbuf);
335*fa9e4066Sahrens 		ddi_soft_state_free(zvol_state, minor);
336*fa9e4066Sahrens 		dmu_objset_close(os);
337*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
338*fa9e4066Sahrens 		return (EAGAIN);
339*fa9e4066Sahrens 	}
340*fa9e4066Sahrens 
341*fa9e4066Sahrens 	zv = ddi_get_soft_state(zvol_state, minor);
342*fa9e4066Sahrens 
343*fa9e4066Sahrens 	(void) strcpy(zv->zv_name, name);
344*fa9e4066Sahrens 	zv->zv_min_bs = DEV_BSHIFT;
345*fa9e4066Sahrens 	zv->zv_minor = minor;
346*fa9e4066Sahrens 	zv->zv_volsize = volsize;
347*fa9e4066Sahrens 	zv->zv_objset = os;
348*fa9e4066Sahrens 	zv->zv_mode = ds_mode;
349*fa9e4066Sahrens 
350*fa9e4066Sahrens 	zvol_size_changed(zv, dev);
351*fa9e4066Sahrens 
352*fa9e4066Sahrens 	VERIFY(dsl_prop_register(dmu_objset_ds(zv->zv_objset),
353*fa9e4066Sahrens 	    "readonly", zvol_readonly_changed_cb, zv) == 0);
354*fa9e4066Sahrens 
355*fa9e4066Sahrens 	zvol_minors++;
356*fa9e4066Sahrens 
357*fa9e4066Sahrens 	mutex_exit(&zvol_state_lock);
358*fa9e4066Sahrens 
359*fa9e4066Sahrens 	return (0);
360*fa9e4066Sahrens }
361*fa9e4066Sahrens 
362*fa9e4066Sahrens /*
363*fa9e4066Sahrens  * Remove minor node for the specified volume.
364*fa9e4066Sahrens  */
365*fa9e4066Sahrens int
366*fa9e4066Sahrens zvol_remove_minor(zfs_cmd_t *zc)
367*fa9e4066Sahrens {
368*fa9e4066Sahrens 	zvol_state_t *zv;
369*fa9e4066Sahrens 	char namebuf[30];
370*fa9e4066Sahrens 
371*fa9e4066Sahrens 	mutex_enter(&zvol_state_lock);
372*fa9e4066Sahrens 
373*fa9e4066Sahrens 	if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) {
374*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
375*fa9e4066Sahrens 		return (ENXIO);
376*fa9e4066Sahrens 	}
377*fa9e4066Sahrens 
378*fa9e4066Sahrens 	if (zv->zv_total_opens != 0) {
379*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
380*fa9e4066Sahrens 		return (EBUSY);
381*fa9e4066Sahrens 	}
382*fa9e4066Sahrens 
383*fa9e4066Sahrens 	(void) sprintf(namebuf, "%uc,raw", zv->zv_minor);
384*fa9e4066Sahrens 	ddi_remove_minor_node(zfs_dip, namebuf);
385*fa9e4066Sahrens 
386*fa9e4066Sahrens 	(void) sprintf(namebuf, "%uc", zv->zv_minor);
387*fa9e4066Sahrens 	ddi_remove_minor_node(zfs_dip, namebuf);
388*fa9e4066Sahrens 
389*fa9e4066Sahrens 	VERIFY(dsl_prop_unregister(dmu_objset_ds(zv->zv_objset),
390*fa9e4066Sahrens 	    "readonly", zvol_readonly_changed_cb, zv) == 0);
391*fa9e4066Sahrens 
392*fa9e4066Sahrens 	dmu_objset_close(zv->zv_objset);
393*fa9e4066Sahrens 
394*fa9e4066Sahrens 	zv->zv_objset = NULL;
395*fa9e4066Sahrens 
396*fa9e4066Sahrens 	ddi_soft_state_free(zvol_state, zv->zv_minor);
397*fa9e4066Sahrens 
398*fa9e4066Sahrens 	zvol_minors--;
399*fa9e4066Sahrens 
400*fa9e4066Sahrens 	mutex_exit(&zvol_state_lock);
401*fa9e4066Sahrens 
402*fa9e4066Sahrens 	return (0);
403*fa9e4066Sahrens }
404*fa9e4066Sahrens 
405*fa9e4066Sahrens int
406*fa9e4066Sahrens zvol_set_volsize(zfs_cmd_t *zc)
407*fa9e4066Sahrens {
408*fa9e4066Sahrens 	zvol_state_t *zv;
409*fa9e4066Sahrens 	dev_t dev = zc->zc_dev;
410*fa9e4066Sahrens 	dmu_tx_t *tx;
411*fa9e4066Sahrens 	int error;
412*fa9e4066Sahrens 
413*fa9e4066Sahrens 	if ((error = zvol_check_volsize(zc)) != 0)
414*fa9e4066Sahrens 		return (error);
415*fa9e4066Sahrens 
416*fa9e4066Sahrens 	mutex_enter(&zvol_state_lock);
417*fa9e4066Sahrens 
418*fa9e4066Sahrens 	if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) {
419*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
420*fa9e4066Sahrens 		return (ENXIO);
421*fa9e4066Sahrens 	}
422*fa9e4066Sahrens 
423*fa9e4066Sahrens 	if (zv->zv_readonly || (zv->zv_mode & DS_MODE_READONLY)) {
424*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
425*fa9e4066Sahrens 		return (EROFS);
426*fa9e4066Sahrens 	}
427*fa9e4066Sahrens 
428*fa9e4066Sahrens 	tx = dmu_tx_create(zv->zv_objset);
429*fa9e4066Sahrens 	dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, 1);
430*fa9e4066Sahrens 	dmu_tx_hold_free(tx, ZVOL_OBJ, zc->zc_volsize, DMU_OBJECT_END);
431*fa9e4066Sahrens 	error = dmu_tx_assign(tx, TXG_WAIT);
432*fa9e4066Sahrens 	if (error) {
433*fa9e4066Sahrens 		dmu_tx_abort(tx);
434*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
435*fa9e4066Sahrens 		return (error);
436*fa9e4066Sahrens 	}
437*fa9e4066Sahrens 
438*fa9e4066Sahrens 	error = zap_update(zv->zv_objset, ZVOL_ZAP_OBJ, "size", 8, 1,
439*fa9e4066Sahrens 	    &zc->zc_volsize, tx);
440*fa9e4066Sahrens 	if (error == 0)
441*fa9e4066Sahrens 		dmu_free_range(zv->zv_objset, ZVOL_OBJ, zc->zc_volsize,
442*fa9e4066Sahrens 		    DMU_OBJECT_END, tx);
443*fa9e4066Sahrens 
444*fa9e4066Sahrens 	dmu_tx_commit(tx);
445*fa9e4066Sahrens 
446*fa9e4066Sahrens 	if (error == 0) {
447*fa9e4066Sahrens 		zv->zv_volsize = zc->zc_volsize;
448*fa9e4066Sahrens 		zvol_size_changed(zv, dev);
449*fa9e4066Sahrens 	}
450*fa9e4066Sahrens 
451*fa9e4066Sahrens 	mutex_exit(&zvol_state_lock);
452*fa9e4066Sahrens 
453*fa9e4066Sahrens 	return (error);
454*fa9e4066Sahrens }
455*fa9e4066Sahrens 
456*fa9e4066Sahrens int
457*fa9e4066Sahrens zvol_set_volblocksize(zfs_cmd_t *zc)
458*fa9e4066Sahrens {
459*fa9e4066Sahrens 	zvol_state_t *zv;
460*fa9e4066Sahrens 	dmu_tx_t *tx;
461*fa9e4066Sahrens 	int error;
462*fa9e4066Sahrens 
463*fa9e4066Sahrens 	mutex_enter(&zvol_state_lock);
464*fa9e4066Sahrens 
465*fa9e4066Sahrens 	if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) {
466*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
467*fa9e4066Sahrens 		return (ENXIO);
468*fa9e4066Sahrens 	}
469*fa9e4066Sahrens 
470*fa9e4066Sahrens 	if (zv->zv_readonly || (zv->zv_mode & DS_MODE_READONLY)) {
471*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
472*fa9e4066Sahrens 		return (EROFS);
473*fa9e4066Sahrens 	}
474*fa9e4066Sahrens 
475*fa9e4066Sahrens 	tx = dmu_tx_create(zv->zv_objset);
476*fa9e4066Sahrens 	dmu_tx_hold_bonus(tx, ZVOL_OBJ);
477*fa9e4066Sahrens 	error = dmu_tx_assign(tx, TXG_WAIT);
478*fa9e4066Sahrens 	if (error) {
479*fa9e4066Sahrens 		dmu_tx_abort(tx);
480*fa9e4066Sahrens 	} else {
481*fa9e4066Sahrens 		error = dmu_object_set_blocksize(zv->zv_objset, ZVOL_OBJ,
482*fa9e4066Sahrens 		    zc->zc_volblocksize, 0, tx);
483*fa9e4066Sahrens 		if (error == ENOTSUP)
484*fa9e4066Sahrens 			error = EBUSY;
485*fa9e4066Sahrens 		dmu_tx_commit(tx);
486*fa9e4066Sahrens 	}
487*fa9e4066Sahrens 
488*fa9e4066Sahrens 	mutex_exit(&zvol_state_lock);
489*fa9e4066Sahrens 
490*fa9e4066Sahrens 	return (error);
491*fa9e4066Sahrens }
492*fa9e4066Sahrens 
493*fa9e4066Sahrens /*ARGSUSED*/
494*fa9e4066Sahrens int
495*fa9e4066Sahrens zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr)
496*fa9e4066Sahrens {
497*fa9e4066Sahrens 	minor_t minor = getminor(*devp);
498*fa9e4066Sahrens 	zvol_state_t *zv;
499*fa9e4066Sahrens 
500*fa9e4066Sahrens 	if (minor == 0)			/* This is the control device */
501*fa9e4066Sahrens 		return (0);
502*fa9e4066Sahrens 
503*fa9e4066Sahrens 	mutex_enter(&zvol_state_lock);
504*fa9e4066Sahrens 
505*fa9e4066Sahrens 	zv = ddi_get_soft_state(zvol_state, minor);
506*fa9e4066Sahrens 	if (zv == NULL) {
507*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
508*fa9e4066Sahrens 		return (ENXIO);
509*fa9e4066Sahrens 	}
510*fa9e4066Sahrens 
511*fa9e4066Sahrens 	ASSERT(zv->zv_objset != NULL);
512*fa9e4066Sahrens 
513*fa9e4066Sahrens 	if ((flag & FWRITE) &&
514*fa9e4066Sahrens 	    (zv->zv_readonly || (zv->zv_mode & DS_MODE_READONLY))) {
515*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
516*fa9e4066Sahrens 		return (EROFS);
517*fa9e4066Sahrens 	}
518*fa9e4066Sahrens 
519*fa9e4066Sahrens 	if (zv->zv_open_count[otyp] == 0 || otyp == OTYP_LYR) {
520*fa9e4066Sahrens 		zv->zv_open_count[otyp]++;
521*fa9e4066Sahrens 		zv->zv_total_opens++;
522*fa9e4066Sahrens 	}
523*fa9e4066Sahrens 
524*fa9e4066Sahrens 	mutex_exit(&zvol_state_lock);
525*fa9e4066Sahrens 
526*fa9e4066Sahrens 	return (0);
527*fa9e4066Sahrens }
528*fa9e4066Sahrens 
529*fa9e4066Sahrens /*ARGSUSED*/
530*fa9e4066Sahrens int
531*fa9e4066Sahrens zvol_close(dev_t dev, int flag, int otyp, cred_t *cr)
532*fa9e4066Sahrens {
533*fa9e4066Sahrens 	minor_t minor = getminor(dev);
534*fa9e4066Sahrens 	zvol_state_t *zv;
535*fa9e4066Sahrens 
536*fa9e4066Sahrens 	if (minor == 0)		/* This is the control device */
537*fa9e4066Sahrens 		return (0);
538*fa9e4066Sahrens 
539*fa9e4066Sahrens 	mutex_enter(&zvol_state_lock);
540*fa9e4066Sahrens 
541*fa9e4066Sahrens 	zv = ddi_get_soft_state(zvol_state, minor);
542*fa9e4066Sahrens 	if (zv == NULL) {
543*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
544*fa9e4066Sahrens 		return (ENXIO);
545*fa9e4066Sahrens 	}
546*fa9e4066Sahrens 
547*fa9e4066Sahrens 	/*
548*fa9e4066Sahrens 	 * The next statement is a workaround for the following DDI bug:
549*fa9e4066Sahrens 	 * 6343604 specfs race: multiple "last-close" of the same device
550*fa9e4066Sahrens 	 */
551*fa9e4066Sahrens 	if (zv->zv_total_opens == 0) {
552*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
553*fa9e4066Sahrens 		return (0);
554*fa9e4066Sahrens 	}
555*fa9e4066Sahrens 
556*fa9e4066Sahrens 	/*
557*fa9e4066Sahrens 	 * If the open count is zero, this is a spurious close.
558*fa9e4066Sahrens 	 * That indicates a bug in the kernel / DDI framework.
559*fa9e4066Sahrens 	 */
560*fa9e4066Sahrens 	ASSERT(zv->zv_open_count[otyp] != 0);
561*fa9e4066Sahrens 	ASSERT(zv->zv_total_opens != 0);
562*fa9e4066Sahrens 
563*fa9e4066Sahrens 	/*
564*fa9e4066Sahrens 	 * You may get multiple opens, but only one close.
565*fa9e4066Sahrens 	 */
566*fa9e4066Sahrens 	zv->zv_open_count[otyp]--;
567*fa9e4066Sahrens 	zv->zv_total_opens--;
568*fa9e4066Sahrens 
569*fa9e4066Sahrens 	mutex_exit(&zvol_state_lock);
570*fa9e4066Sahrens 
571*fa9e4066Sahrens 	return (0);
572*fa9e4066Sahrens }
573*fa9e4066Sahrens 
574*fa9e4066Sahrens int
575*fa9e4066Sahrens zvol_strategy(buf_t *bp)
576*fa9e4066Sahrens {
577*fa9e4066Sahrens 	zvol_state_t *zv = ddi_get_soft_state(zvol_state, getminor(bp->b_edev));
578*fa9e4066Sahrens 	uint64_t off, volsize;
579*fa9e4066Sahrens 	size_t size, resid;
580*fa9e4066Sahrens 	char *addr;
581*fa9e4066Sahrens 	int error = 0;
582*fa9e4066Sahrens 
583*fa9e4066Sahrens 	if (zv == NULL) {
584*fa9e4066Sahrens 		bioerror(bp, ENXIO);
585*fa9e4066Sahrens 		biodone(bp);
586*fa9e4066Sahrens 		return (0);
587*fa9e4066Sahrens 	}
588*fa9e4066Sahrens 
589*fa9e4066Sahrens 	if (getminor(bp->b_edev) == 0) {
590*fa9e4066Sahrens 		bioerror(bp, EINVAL);
591*fa9e4066Sahrens 		biodone(bp);
592*fa9e4066Sahrens 		return (0);
593*fa9e4066Sahrens 	}
594*fa9e4066Sahrens 
595*fa9e4066Sahrens 	if (zv->zv_readonly && !(bp->b_flags & B_READ)) {
596*fa9e4066Sahrens 		bioerror(bp, EROFS);
597*fa9e4066Sahrens 		biodone(bp);
598*fa9e4066Sahrens 		return (0);
599*fa9e4066Sahrens 	}
600*fa9e4066Sahrens 
601*fa9e4066Sahrens 	off = ldbtob(bp->b_blkno);
602*fa9e4066Sahrens 	volsize = zv->zv_volsize;
603*fa9e4066Sahrens 
604*fa9e4066Sahrens 	ASSERT(zv->zv_objset != NULL);
605*fa9e4066Sahrens 
606*fa9e4066Sahrens 	bp_mapin(bp);
607*fa9e4066Sahrens 	addr = bp->b_un.b_addr;
608*fa9e4066Sahrens 	resid = bp->b_bcount;
609*fa9e4066Sahrens 
610*fa9e4066Sahrens 	while (resid != 0 && off < volsize) {
611*fa9e4066Sahrens 
612*fa9e4066Sahrens 		size = MIN(resid, 1UL << 20);	/* cap at 1MB per tx */
613*fa9e4066Sahrens 
614*fa9e4066Sahrens 		if (size > volsize - off)	/* don't write past the end */
615*fa9e4066Sahrens 			size = volsize - off;
616*fa9e4066Sahrens 
617*fa9e4066Sahrens 		if (bp->b_flags & B_READ) {
618*fa9e4066Sahrens 			error = dmu_read_canfail(zv->zv_objset, ZVOL_OBJ,
619*fa9e4066Sahrens 			    off, size, addr);
620*fa9e4066Sahrens 		} else {
621*fa9e4066Sahrens 			dmu_tx_t *tx = dmu_tx_create(zv->zv_objset);
622*fa9e4066Sahrens 			dmu_tx_hold_write(tx, ZVOL_OBJ, off, size);
623*fa9e4066Sahrens 			error = dmu_tx_assign(tx, TXG_WAIT);
624*fa9e4066Sahrens 			if (error) {
625*fa9e4066Sahrens 				dmu_tx_abort(tx);
626*fa9e4066Sahrens 			} else {
627*fa9e4066Sahrens 				dmu_write(zv->zv_objset, ZVOL_OBJ,
628*fa9e4066Sahrens 				    off, size, addr, tx);
629*fa9e4066Sahrens 				dmu_tx_commit(tx);
630*fa9e4066Sahrens 			}
631*fa9e4066Sahrens 		}
632*fa9e4066Sahrens 		if (error)
633*fa9e4066Sahrens 			break;
634*fa9e4066Sahrens 		off += size;
635*fa9e4066Sahrens 		addr += size;
636*fa9e4066Sahrens 		resid -= size;
637*fa9e4066Sahrens 	}
638*fa9e4066Sahrens 
639*fa9e4066Sahrens 	if ((bp->b_resid = resid) == bp->b_bcount)
640*fa9e4066Sahrens 		bioerror(bp, off > volsize ? EINVAL : error);
641*fa9e4066Sahrens 
642*fa9e4066Sahrens 	biodone(bp);
643*fa9e4066Sahrens 	return (0);
644*fa9e4066Sahrens }
645*fa9e4066Sahrens 
646*fa9e4066Sahrens /*ARGSUSED*/
647*fa9e4066Sahrens int
648*fa9e4066Sahrens zvol_read(dev_t dev, uio_t *uiop, cred_t *cr)
649*fa9e4066Sahrens {
650*fa9e4066Sahrens 	return (physio(zvol_strategy, NULL, dev, B_READ, minphys, uiop));
651*fa9e4066Sahrens }
652*fa9e4066Sahrens 
653*fa9e4066Sahrens /*ARGSUSED*/
654*fa9e4066Sahrens int
655*fa9e4066Sahrens zvol_write(dev_t dev, uio_t *uiop, cred_t *cr)
656*fa9e4066Sahrens {
657*fa9e4066Sahrens 	return (physio(zvol_strategy, NULL, dev, B_WRITE, minphys, uiop));
658*fa9e4066Sahrens }
659*fa9e4066Sahrens 
660*fa9e4066Sahrens /*ARGSUSED*/
661*fa9e4066Sahrens int
662*fa9e4066Sahrens zvol_aread(dev_t dev, struct aio_req *aio, cred_t *cr)
663*fa9e4066Sahrens {
664*fa9e4066Sahrens 	return (aphysio(zvol_strategy, anocancel, dev, B_READ, minphys, aio));
665*fa9e4066Sahrens }
666*fa9e4066Sahrens 
667*fa9e4066Sahrens /*ARGSUSED*/
668*fa9e4066Sahrens int
669*fa9e4066Sahrens zvol_awrite(dev_t dev, struct aio_req *aio, cred_t *cr)
670*fa9e4066Sahrens {
671*fa9e4066Sahrens 	return (aphysio(zvol_strategy, anocancel, dev, B_WRITE, minphys, aio));
672*fa9e4066Sahrens }
673*fa9e4066Sahrens 
674*fa9e4066Sahrens /*
675*fa9e4066Sahrens  * Dirtbag ioctls to support mkfs(1M) for UFS filesystems.  See dkio(7I).
676*fa9e4066Sahrens  */
677*fa9e4066Sahrens /*ARGSUSED*/
678*fa9e4066Sahrens int
679*fa9e4066Sahrens zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
680*fa9e4066Sahrens {
681*fa9e4066Sahrens 	zvol_state_t *zv;
682*fa9e4066Sahrens 	struct dk_cinfo dkc;
683*fa9e4066Sahrens 	struct dk_minfo dkm;
684*fa9e4066Sahrens 	dk_efi_t efi;
685*fa9e4066Sahrens 	efi_gpt_t gpt;
686*fa9e4066Sahrens 	efi_gpe_t gpe;
687*fa9e4066Sahrens 	struct uuid uuid = EFI_RESERVED;
688*fa9e4066Sahrens 	uint32_t crc;
689*fa9e4066Sahrens 	int error = 0;
690*fa9e4066Sahrens 
691*fa9e4066Sahrens 	mutex_enter(&zvol_state_lock);
692*fa9e4066Sahrens 
693*fa9e4066Sahrens 	zv = ddi_get_soft_state(zvol_state, getminor(dev));
694*fa9e4066Sahrens 
695*fa9e4066Sahrens 	if (zv == NULL) {
696*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
697*fa9e4066Sahrens 		return (ENXIO);
698*fa9e4066Sahrens 	}
699*fa9e4066Sahrens 
700*fa9e4066Sahrens 	switch (cmd) {
701*fa9e4066Sahrens 
702*fa9e4066Sahrens 	case DKIOCINFO:
703*fa9e4066Sahrens 		bzero(&dkc, sizeof (dkc));
704*fa9e4066Sahrens 		(void) strcpy(dkc.dki_cname, "zvol");
705*fa9e4066Sahrens 		(void) strcpy(dkc.dki_dname, "zvol");
706*fa9e4066Sahrens 		dkc.dki_ctype = DKC_UNKNOWN;
707*fa9e4066Sahrens 		dkc.dki_maxtransfer = 1 << 15;
708*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
709*fa9e4066Sahrens 		if (ddi_copyout(&dkc, (void *)arg, sizeof (dkc), flag))
710*fa9e4066Sahrens 			error = EFAULT;
711*fa9e4066Sahrens 		return (error);
712*fa9e4066Sahrens 
713*fa9e4066Sahrens 	case DKIOCGMEDIAINFO:
714*fa9e4066Sahrens 		bzero(&dkm, sizeof (dkm));
715*fa9e4066Sahrens 		dkm.dki_lbsize = 1U << zv->zv_min_bs;
716*fa9e4066Sahrens 		dkm.dki_capacity = zv->zv_volsize >> zv->zv_min_bs;
717*fa9e4066Sahrens 		dkm.dki_media_type = DK_UNKNOWN;
718*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
719*fa9e4066Sahrens 		if (ddi_copyout(&dkm, (void *)arg, sizeof (dkm), flag))
720*fa9e4066Sahrens 			error = EFAULT;
721*fa9e4066Sahrens 		return (error);
722*fa9e4066Sahrens 
723*fa9e4066Sahrens 	case DKIOCGETEFI:
724*fa9e4066Sahrens 		if (ddi_copyin((void *)arg, &efi, sizeof (dk_efi_t), flag)) {
725*fa9e4066Sahrens 			mutex_exit(&zvol_state_lock);
726*fa9e4066Sahrens 			return (EFAULT);
727*fa9e4066Sahrens 		}
728*fa9e4066Sahrens 
729*fa9e4066Sahrens 		bzero(&gpt, sizeof (gpt));
730*fa9e4066Sahrens 		bzero(&gpe, sizeof (gpe));
731*fa9e4066Sahrens 
732*fa9e4066Sahrens 		efi.dki_data = (void *)(uintptr_t)efi.dki_data_64;
733*fa9e4066Sahrens 
734*fa9e4066Sahrens 		if (efi.dki_length < sizeof (gpt) + sizeof (gpe)) {
735*fa9e4066Sahrens 			mutex_exit(&zvol_state_lock);
736*fa9e4066Sahrens 			return (EINVAL);
737*fa9e4066Sahrens 		}
738*fa9e4066Sahrens 
739*fa9e4066Sahrens 		efi.dki_length = sizeof (gpt) + sizeof (gpe);
740*fa9e4066Sahrens 
741*fa9e4066Sahrens 		gpt.efi_gpt_Signature = LE_64(EFI_SIGNATURE);
742*fa9e4066Sahrens 		gpt.efi_gpt_Revision = LE_32(EFI_VERSION102);
743*fa9e4066Sahrens 		gpt.efi_gpt_HeaderSize = LE_32(sizeof (gpt));
744*fa9e4066Sahrens 		gpt.efi_gpt_FirstUsableLBA = LE_64(0ULL);
745*fa9e4066Sahrens 		gpt.efi_gpt_LastUsableLBA =
746*fa9e4066Sahrens 		    LE_64((zv->zv_volsize >> zv->zv_min_bs) - 1);
747*fa9e4066Sahrens 		gpt.efi_gpt_NumberOfPartitionEntries = LE_32(1);
748*fa9e4066Sahrens 		gpt.efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (gpe));
749*fa9e4066Sahrens 
750*fa9e4066Sahrens 		UUID_LE_CONVERT(gpe.efi_gpe_PartitionTypeGUID, uuid);
751*fa9e4066Sahrens 		gpe.efi_gpe_StartingLBA = gpt.efi_gpt_FirstUsableLBA;
752*fa9e4066Sahrens 		gpe.efi_gpe_EndingLBA = gpt.efi_gpt_LastUsableLBA;
753*fa9e4066Sahrens 
754*fa9e4066Sahrens 		CRC32(crc, &gpe, sizeof (gpe), -1U, crc32_table);
755*fa9e4066Sahrens 		gpt.efi_gpt_PartitionEntryArrayCRC32 = LE_32(~crc);
756*fa9e4066Sahrens 
757*fa9e4066Sahrens 		CRC32(crc, &gpt, sizeof (gpt), -1U, crc32_table);
758*fa9e4066Sahrens 		gpt.efi_gpt_HeaderCRC32 = LE_32(~crc);
759*fa9e4066Sahrens 
760*fa9e4066Sahrens 		mutex_exit(&zvol_state_lock);
761*fa9e4066Sahrens 		if (ddi_copyout(&gpt, efi.dki_data, sizeof (gpt), flag) ||
762*fa9e4066Sahrens 		    ddi_copyout(&gpe, efi.dki_data + 1, sizeof (gpe), flag))
763*fa9e4066Sahrens 			error = EFAULT;
764*fa9e4066Sahrens 		return (error);
765*fa9e4066Sahrens 
766*fa9e4066Sahrens 	default:
767*fa9e4066Sahrens 		error = ENOTSUP;
768*fa9e4066Sahrens 		break;
769*fa9e4066Sahrens 
770*fa9e4066Sahrens 	}
771*fa9e4066Sahrens 	mutex_exit(&zvol_state_lock);
772*fa9e4066Sahrens 	return (error);
773*fa9e4066Sahrens }
774*fa9e4066Sahrens 
775*fa9e4066Sahrens int
776*fa9e4066Sahrens zvol_busy(void)
777*fa9e4066Sahrens {
778*fa9e4066Sahrens 	return (zvol_minors != 0);
779*fa9e4066Sahrens }
780*fa9e4066Sahrens 
781*fa9e4066Sahrens void
782*fa9e4066Sahrens zvol_init(void)
783*fa9e4066Sahrens {
784*fa9e4066Sahrens 	VERIFY(ddi_soft_state_init(&zvol_state, sizeof (zvol_state_t), 1) == 0);
785*fa9e4066Sahrens 	mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL);
786*fa9e4066Sahrens }
787*fa9e4066Sahrens 
788*fa9e4066Sahrens void
789*fa9e4066Sahrens zvol_fini(void)
790*fa9e4066Sahrens {
791*fa9e4066Sahrens 	mutex_destroy(&zvol_state_lock);
792*fa9e4066Sahrens 	ddi_soft_state_fini(&zvol_state);
793*fa9e4066Sahrens }
794