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