10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51657Sheppo * Common Development and Distribution License (the "License"). 61657Sheppo * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*4451Seschrock * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * lofi (loopback file) driver - allows you to attach a file to a device, 300Sstevel@tonic-gate * which can then be accessed through that device. The simple model is that 310Sstevel@tonic-gate * you tell lofi to open a file, and then use the block device you get as 320Sstevel@tonic-gate * you would any block device. lofi translates access to the block device 330Sstevel@tonic-gate * into I/O on the underlying file. This is mostly useful for 340Sstevel@tonic-gate * mounting images of filesystems. 350Sstevel@tonic-gate * 360Sstevel@tonic-gate * lofi is controlled through /dev/lofictl - this is the only device exported 370Sstevel@tonic-gate * during attach, and is minor number 0. lofiadm communicates with lofi through 380Sstevel@tonic-gate * ioctls on this device. When a file is attached to lofi, block and character 390Sstevel@tonic-gate * devices are exported in /dev/lofi and /dev/rlofi. Currently, these devices 400Sstevel@tonic-gate * are identified by their minor number, and the minor number is also used 410Sstevel@tonic-gate * as the name in /dev/lofi. If we ever decide to support virtual disks, 420Sstevel@tonic-gate * we'll have to divide the minor number space to identify fdisk partitions 430Sstevel@tonic-gate * and slices, and the name will then be the minor number shifted down a 440Sstevel@tonic-gate * few bits. Minor devices are tracked with state structures handled with 450Sstevel@tonic-gate * ddi_soft_state(9F) for simplicity. 460Sstevel@tonic-gate * 470Sstevel@tonic-gate * A file attached to lofi is opened when attached and not closed until 480Sstevel@tonic-gate * explicitly detached from lofi. This seems more sensible than deferring 490Sstevel@tonic-gate * the open until the /dev/lofi device is opened, for a number of reasons. 500Sstevel@tonic-gate * One is that any failure is likely to be noticed by the person (or script) 510Sstevel@tonic-gate * running lofiadm. Another is that it would be a security problem if the 520Sstevel@tonic-gate * file was replaced by another one after being added but before being opened. 530Sstevel@tonic-gate * 540Sstevel@tonic-gate * The only hard part about lofi is the ioctls. In order to support things 550Sstevel@tonic-gate * like 'newfs' on a lofi device, it needs to support certain disk ioctls. 560Sstevel@tonic-gate * So it has to fake disk geometry and partition information. More may need 570Sstevel@tonic-gate * to be faked if your favorite utility doesn't work and you think it should 580Sstevel@tonic-gate * (fdformat doesn't work because it really wants to know the type of floppy 590Sstevel@tonic-gate * controller to talk to, and that didn't seem easy to fake. Or possibly even 600Sstevel@tonic-gate * necessary, since we have mkfs_pcfs now). 610Sstevel@tonic-gate * 62*4451Seschrock * Normally, a lofi device cannot be detached if it is open (i.e. busy). To 63*4451Seschrock * support simulation of hotplug events, an optional force flag is provided. 64*4451Seschrock * If a lofi device is open when a force detach is requested, then the 65*4451Seschrock * underlying file is closed and any subsequent operations return EIO. When the 66*4451Seschrock * device is closed for the last time, it will be cleaned up at that time. In 67*4451Seschrock * addition, the DKIOCSTATE ioctl will return DKIO_DEV_GONE when the device is 68*4451Seschrock * detached but not removed. 69*4451Seschrock * 700Sstevel@tonic-gate * Known problems: 710Sstevel@tonic-gate * 720Sstevel@tonic-gate * UFS logging. Mounting a UFS filesystem image "logging" 730Sstevel@tonic-gate * works for basic copy testing but wedges during a build of ON through 740Sstevel@tonic-gate * that image. Some deadlock in lufs holding the log mutex and then 750Sstevel@tonic-gate * getting stuck on a buf. So for now, don't do that. 760Sstevel@tonic-gate * 770Sstevel@tonic-gate * Direct I/O. Since the filesystem data is being cached in the buffer 780Sstevel@tonic-gate * cache, _and_ again in the underlying filesystem, it's tempting to 790Sstevel@tonic-gate * enable direct I/O on the underlying file. Don't, because that deadlocks. 800Sstevel@tonic-gate * I think to fix the cache-twice problem we might need filesystem support. 810Sstevel@tonic-gate * 820Sstevel@tonic-gate * lofi on itself. The simple lock strategy (lofi_lock) precludes this 830Sstevel@tonic-gate * because you'll be in lofi_ioctl, holding the lock when you open the 840Sstevel@tonic-gate * file, which, if it's lofi, will grab lofi_lock. We prevent this for 850Sstevel@tonic-gate * now, though not using ddi_soft_state(9F) would make it possible to 860Sstevel@tonic-gate * do. Though it would still be silly. 870Sstevel@tonic-gate * 880Sstevel@tonic-gate * Interesting things to do: 890Sstevel@tonic-gate * 900Sstevel@tonic-gate * Allow multiple files for each device. A poor-man's metadisk, basically. 910Sstevel@tonic-gate * 920Sstevel@tonic-gate * Pass-through ioctls on block devices. You can (though it's not 930Sstevel@tonic-gate * documented), give lofi a block device as a file name. Then we shouldn't 940Sstevel@tonic-gate * need to fake a geometry. But this is also silly unless you're replacing 950Sstevel@tonic-gate * metadisk. 960Sstevel@tonic-gate * 970Sstevel@tonic-gate * Encryption. tpm would like this. Apparently Windows 2000 has it, and 980Sstevel@tonic-gate * so does Linux. 990Sstevel@tonic-gate */ 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate #include <sys/types.h> 1020Sstevel@tonic-gate #include <sys/sysmacros.h> 1030Sstevel@tonic-gate #include <sys/cmn_err.h> 1040Sstevel@tonic-gate #include <sys/uio.h> 1050Sstevel@tonic-gate #include <sys/kmem.h> 1060Sstevel@tonic-gate #include <sys/cred.h> 1070Sstevel@tonic-gate #include <sys/mman.h> 1080Sstevel@tonic-gate #include <sys/errno.h> 1090Sstevel@tonic-gate #include <sys/aio_req.h> 1100Sstevel@tonic-gate #include <sys/stat.h> 1110Sstevel@tonic-gate #include <sys/file.h> 1120Sstevel@tonic-gate #include <sys/modctl.h> 1130Sstevel@tonic-gate #include <sys/conf.h> 1140Sstevel@tonic-gate #include <sys/debug.h> 1150Sstevel@tonic-gate #include <sys/vnode.h> 1160Sstevel@tonic-gate #include <sys/lofi.h> 1170Sstevel@tonic-gate #include <sys/fcntl.h> 1180Sstevel@tonic-gate #include <sys/pathname.h> 1190Sstevel@tonic-gate #include <sys/filio.h> 1200Sstevel@tonic-gate #include <sys/fdio.h> 1210Sstevel@tonic-gate #include <sys/open.h> 1220Sstevel@tonic-gate #include <sys/disp.h> 1230Sstevel@tonic-gate #include <vm/seg_map.h> 1240Sstevel@tonic-gate #include <sys/ddi.h> 1250Sstevel@tonic-gate #include <sys/sunddi.h> 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* seems safer than having to get the string right many times */ 1280Sstevel@tonic-gate #define NBLOCKS_PROP_NAME "Nblocks" 1290Sstevel@tonic-gate #define SIZE_PROP_NAME "Size" 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate static dev_info_t *lofi_dip; 1320Sstevel@tonic-gate static void *lofi_statep; 1330Sstevel@tonic-gate static kmutex_t lofi_lock; /* state lock */ 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate /* 1360Sstevel@tonic-gate * Because lofi_taskq_nthreads limits the actual swamping of the device, the 1370Sstevel@tonic-gate * maxalloc parameter (lofi_taskq_maxalloc) should be tuned conservatively 1380Sstevel@tonic-gate * high. If we want to be assured that the underlying device is always busy, 1390Sstevel@tonic-gate * we must be sure that the number of bytes enqueued when the number of 1400Sstevel@tonic-gate * enqueued tasks exceeds maxalloc is sufficient to keep the device busy for 1410Sstevel@tonic-gate * the duration of the sleep time in taskq_ent_alloc(). That is, lofi should 1420Sstevel@tonic-gate * set maxalloc to be the maximum throughput (in bytes per second) of the 1430Sstevel@tonic-gate * underlying device divided by the minimum I/O size. We assume a realistic 1440Sstevel@tonic-gate * maximum throughput of one hundred megabytes per second; we set maxalloc on 1450Sstevel@tonic-gate * the lofi task queue to be 104857600 divided by DEV_BSIZE. 1460Sstevel@tonic-gate */ 1470Sstevel@tonic-gate static int lofi_taskq_maxalloc = 104857600 / DEV_BSIZE; 1480Sstevel@tonic-gate static int lofi_taskq_nthreads = 4; /* # of taskq threads per device */ 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate uint32_t lofi_max_files = LOFI_MAX_FILES; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate static int 1530Sstevel@tonic-gate lofi_busy(void) 1540Sstevel@tonic-gate { 1550Sstevel@tonic-gate minor_t minor; 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate /* 1580Sstevel@tonic-gate * We need to make sure no mappings exist - mod_remove won't 1590Sstevel@tonic-gate * help because the device isn't open. 1600Sstevel@tonic-gate */ 1610Sstevel@tonic-gate mutex_enter(&lofi_lock); 1620Sstevel@tonic-gate for (minor = 1; minor <= lofi_max_files; minor++) { 1630Sstevel@tonic-gate if (ddi_get_soft_state(lofi_statep, minor) != NULL) { 1640Sstevel@tonic-gate mutex_exit(&lofi_lock); 1650Sstevel@tonic-gate return (EBUSY); 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate mutex_exit(&lofi_lock); 1690Sstevel@tonic-gate return (0); 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate static int 1730Sstevel@tonic-gate is_opened(struct lofi_state *lsp) 1740Sstevel@tonic-gate { 1750Sstevel@tonic-gate ASSERT(mutex_owned(&lofi_lock)); 1760Sstevel@tonic-gate return (lsp->ls_chr_open || lsp->ls_blk_open || lsp->ls_lyr_open_count); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate static int 1800Sstevel@tonic-gate mark_opened(struct lofi_state *lsp, int otyp) 1810Sstevel@tonic-gate { 1820Sstevel@tonic-gate ASSERT(mutex_owned(&lofi_lock)); 1830Sstevel@tonic-gate switch (otyp) { 1840Sstevel@tonic-gate case OTYP_CHR: 1850Sstevel@tonic-gate lsp->ls_chr_open = 1; 1860Sstevel@tonic-gate break; 1870Sstevel@tonic-gate case OTYP_BLK: 1880Sstevel@tonic-gate lsp->ls_blk_open = 1; 1890Sstevel@tonic-gate break; 1900Sstevel@tonic-gate case OTYP_LYR: 1910Sstevel@tonic-gate lsp->ls_lyr_open_count++; 1920Sstevel@tonic-gate break; 1930Sstevel@tonic-gate default: 1940Sstevel@tonic-gate return (-1); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate return (0); 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate static void 2000Sstevel@tonic-gate mark_closed(struct lofi_state *lsp, int otyp) 2010Sstevel@tonic-gate { 2020Sstevel@tonic-gate ASSERT(mutex_owned(&lofi_lock)); 2030Sstevel@tonic-gate switch (otyp) { 2040Sstevel@tonic-gate case OTYP_CHR: 2050Sstevel@tonic-gate lsp->ls_chr_open = 0; 2060Sstevel@tonic-gate break; 2070Sstevel@tonic-gate case OTYP_BLK: 2080Sstevel@tonic-gate lsp->ls_blk_open = 0; 2090Sstevel@tonic-gate break; 2100Sstevel@tonic-gate case OTYP_LYR: 2110Sstevel@tonic-gate lsp->ls_lyr_open_count--; 2120Sstevel@tonic-gate break; 2130Sstevel@tonic-gate default: 2140Sstevel@tonic-gate break; 2150Sstevel@tonic-gate } 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 218*4451Seschrock static void 219*4451Seschrock lofi_free_handle(dev_t dev, minor_t minor, struct lofi_state *lsp, 220*4451Seschrock cred_t *credp) 221*4451Seschrock { 222*4451Seschrock dev_t newdev; 223*4451Seschrock char namebuf[50]; 224*4451Seschrock 225*4451Seschrock if (lsp->ls_vp) { 226*4451Seschrock (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag, 1, 0, credp); 227*4451Seschrock VN_RELE(lsp->ls_vp); 228*4451Seschrock lsp->ls_vp = NULL; 229*4451Seschrock } 230*4451Seschrock 231*4451Seschrock newdev = makedevice(getmajor(dev), minor); 232*4451Seschrock (void) ddi_prop_remove(newdev, lofi_dip, SIZE_PROP_NAME); 233*4451Seschrock (void) ddi_prop_remove(newdev, lofi_dip, NBLOCKS_PROP_NAME); 234*4451Seschrock 235*4451Seschrock (void) snprintf(namebuf, sizeof (namebuf), "%d", minor); 236*4451Seschrock ddi_remove_minor_node(lofi_dip, namebuf); 237*4451Seschrock (void) snprintf(namebuf, sizeof (namebuf), "%d,raw", minor); 238*4451Seschrock ddi_remove_minor_node(lofi_dip, namebuf); 239*4451Seschrock 240*4451Seschrock kmem_free(lsp->ls_filename, lsp->ls_filename_sz); 241*4451Seschrock taskq_destroy(lsp->ls_taskq); 242*4451Seschrock if (lsp->ls_kstat) { 243*4451Seschrock kstat_delete(lsp->ls_kstat); 244*4451Seschrock mutex_destroy(&lsp->ls_kstat_lock); 245*4451Seschrock } 246*4451Seschrock ddi_soft_state_free(lofi_statep, minor); 247*4451Seschrock } 248*4451Seschrock 249*4451Seschrock /*ARGSUSED*/ 2500Sstevel@tonic-gate static int 2510Sstevel@tonic-gate lofi_open(dev_t *devp, int flag, int otyp, struct cred *credp) 2520Sstevel@tonic-gate { 2530Sstevel@tonic-gate minor_t minor; 2540Sstevel@tonic-gate struct lofi_state *lsp; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate mutex_enter(&lofi_lock); 2570Sstevel@tonic-gate minor = getminor(*devp); 2580Sstevel@tonic-gate if (minor == 0) { 2590Sstevel@tonic-gate /* master control device */ 2600Sstevel@tonic-gate /* must be opened exclusively */ 2610Sstevel@tonic-gate if (((flag & FEXCL) != FEXCL) || (otyp != OTYP_CHR)) { 2620Sstevel@tonic-gate mutex_exit(&lofi_lock); 2630Sstevel@tonic-gate return (EINVAL); 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate lsp = ddi_get_soft_state(lofi_statep, 0); 2660Sstevel@tonic-gate if (lsp == NULL) { 2670Sstevel@tonic-gate mutex_exit(&lofi_lock); 2680Sstevel@tonic-gate return (ENXIO); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate if (is_opened(lsp)) { 2710Sstevel@tonic-gate mutex_exit(&lofi_lock); 2720Sstevel@tonic-gate return (EBUSY); 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate (void) mark_opened(lsp, OTYP_CHR); 2750Sstevel@tonic-gate mutex_exit(&lofi_lock); 2760Sstevel@tonic-gate return (0); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate /* otherwise, the mapping should already exist */ 2800Sstevel@tonic-gate lsp = ddi_get_soft_state(lofi_statep, minor); 2810Sstevel@tonic-gate if (lsp == NULL) { 2820Sstevel@tonic-gate mutex_exit(&lofi_lock); 2830Sstevel@tonic-gate return (EINVAL); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 286*4451Seschrock if (lsp->ls_vp == NULL) { 287*4451Seschrock mutex_exit(&lofi_lock); 288*4451Seschrock return (ENXIO); 289*4451Seschrock } 290*4451Seschrock 2910Sstevel@tonic-gate if (mark_opened(lsp, otyp) == -1) { 2920Sstevel@tonic-gate mutex_exit(&lofi_lock); 2930Sstevel@tonic-gate return (EINVAL); 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate mutex_exit(&lofi_lock); 2970Sstevel@tonic-gate return (0); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 300*4451Seschrock /*ARGSUSED*/ 3010Sstevel@tonic-gate static int 3020Sstevel@tonic-gate lofi_close(dev_t dev, int flag, int otyp, struct cred *credp) 3030Sstevel@tonic-gate { 3040Sstevel@tonic-gate minor_t minor; 3050Sstevel@tonic-gate struct lofi_state *lsp; 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate mutex_enter(&lofi_lock); 3080Sstevel@tonic-gate minor = getminor(dev); 3090Sstevel@tonic-gate lsp = ddi_get_soft_state(lofi_statep, minor); 3100Sstevel@tonic-gate if (lsp == NULL) { 3110Sstevel@tonic-gate mutex_exit(&lofi_lock); 3120Sstevel@tonic-gate return (EINVAL); 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate mark_closed(lsp, otyp); 315*4451Seschrock 316*4451Seschrock /* 317*4451Seschrock * If we have forcibly closed the underlying device, and this is the 318*4451Seschrock * last close, then tear down the rest of the device. 319*4451Seschrock */ 320*4451Seschrock if (minor != 0 && lsp->ls_vp == NULL && !is_opened(lsp)) 321*4451Seschrock lofi_free_handle(dev, minor, lsp, credp); 3220Sstevel@tonic-gate mutex_exit(&lofi_lock); 3230Sstevel@tonic-gate return (0); 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate /* 3270Sstevel@tonic-gate * This is basically what strategy used to be before we found we 3280Sstevel@tonic-gate * needed task queues. 3290Sstevel@tonic-gate */ 3300Sstevel@tonic-gate static void 3310Sstevel@tonic-gate lofi_strategy_task(void *arg) 3320Sstevel@tonic-gate { 3330Sstevel@tonic-gate struct buf *bp = (struct buf *)arg; 3340Sstevel@tonic-gate int error; 3350Sstevel@tonic-gate struct lofi_state *lsp; 3360Sstevel@tonic-gate offset_t offset, alignedoffset; 3370Sstevel@tonic-gate offset_t mapoffset; 3380Sstevel@tonic-gate caddr_t bufaddr; 3390Sstevel@tonic-gate caddr_t mapaddr; 3400Sstevel@tonic-gate size_t xfersize; 3410Sstevel@tonic-gate size_t len; 3420Sstevel@tonic-gate int isread; 3430Sstevel@tonic-gate int smflags; 3440Sstevel@tonic-gate enum seg_rw srw; 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate lsp = ddi_get_soft_state(lofi_statep, getminor(bp->b_edev)); 3470Sstevel@tonic-gate if (lsp->ls_kstat) { 3480Sstevel@tonic-gate mutex_enter(lsp->ls_kstat->ks_lock); 3490Sstevel@tonic-gate kstat_waitq_to_runq(KSTAT_IO_PTR(lsp->ls_kstat)); 3500Sstevel@tonic-gate mutex_exit(lsp->ls_kstat->ks_lock); 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate bp_mapin(bp); 3530Sstevel@tonic-gate bufaddr = bp->b_un.b_addr; 3540Sstevel@tonic-gate offset = bp->b_lblkno * DEV_BSIZE; /* offset within file */ 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate /* 3570Sstevel@tonic-gate * We used to always use vn_rdwr here, but we cannot do that because 3580Sstevel@tonic-gate * we might decide to read or write from the the underlying 3590Sstevel@tonic-gate * file during this call, which would be a deadlock because 3600Sstevel@tonic-gate * we have the rw_lock. So instead we page, unless it's not 3610Sstevel@tonic-gate * mapable or it's a character device. 3620Sstevel@tonic-gate */ 363*4451Seschrock if (lsp->ls_vp == NULL || lsp->ls_vp_closereq) { 364*4451Seschrock error = EIO; 365*4451Seschrock } else if (((lsp->ls_vp->v_flag & VNOMAP) == 0) && 3660Sstevel@tonic-gate (lsp->ls_vp->v_type != VCHR)) { 3670Sstevel@tonic-gate /* 3680Sstevel@tonic-gate * segmap always gives us an 8K (MAXBSIZE) chunk, aligned on 3690Sstevel@tonic-gate * an 8K boundary, but the buf transfer address may not be 3700Sstevel@tonic-gate * aligned on more than a 512-byte boundary (we don't 3710Sstevel@tonic-gate * enforce that, though we could). This matters since the 3720Sstevel@tonic-gate * initial part of the transfer may not start at offset 0 3730Sstevel@tonic-gate * within the segmap'd chunk. So we have to compensate for 3740Sstevel@tonic-gate * that with 'mapoffset'. Subsequent chunks always start 3750Sstevel@tonic-gate * off at the beginning, and the last is capped by b_resid. 3760Sstevel@tonic-gate */ 3770Sstevel@tonic-gate mapoffset = offset & MAXBOFFSET; 3780Sstevel@tonic-gate alignedoffset = offset - mapoffset; /* now map-aligned */ 3790Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 3800Sstevel@tonic-gate isread = bp->b_flags & B_READ; 3810Sstevel@tonic-gate srw = isread ? S_READ : S_WRITE; 3820Sstevel@tonic-gate do { 3830Sstevel@tonic-gate xfersize = MIN(lsp->ls_vp_size - offset, 3840Sstevel@tonic-gate MIN(MAXBSIZE - mapoffset, bp->b_resid)); 3850Sstevel@tonic-gate len = roundup(mapoffset + xfersize, PAGESIZE); 3860Sstevel@tonic-gate mapaddr = segmap_getmapflt(segkmap, lsp->ls_vp, 3870Sstevel@tonic-gate alignedoffset, MAXBSIZE, 1, srw); 3880Sstevel@tonic-gate /* 3890Sstevel@tonic-gate * Now fault in the pages. This lets us check 3900Sstevel@tonic-gate * for errors before we reference mapaddr and 3910Sstevel@tonic-gate * try to resolve the fault in bcopy (which would 3920Sstevel@tonic-gate * panic instead). And this can easily happen, 3930Sstevel@tonic-gate * particularly if you've lofi'd a file over NFS 3940Sstevel@tonic-gate * and someone deletes the file on the server. 3950Sstevel@tonic-gate */ 3960Sstevel@tonic-gate error = segmap_fault(kas.a_hat, segkmap, mapaddr, 3970Sstevel@tonic-gate len, F_SOFTLOCK, srw); 3980Sstevel@tonic-gate if (error) { 3990Sstevel@tonic-gate (void) segmap_release(segkmap, mapaddr, 0); 4000Sstevel@tonic-gate if (FC_CODE(error) == FC_OBJERR) 4010Sstevel@tonic-gate error = FC_ERRNO(error); 4020Sstevel@tonic-gate else 4030Sstevel@tonic-gate error = EIO; 4040Sstevel@tonic-gate break; 4050Sstevel@tonic-gate } 4060Sstevel@tonic-gate smflags = 0; 4070Sstevel@tonic-gate if (isread) { 4080Sstevel@tonic-gate bcopy(mapaddr + mapoffset, bufaddr, xfersize); 4090Sstevel@tonic-gate } else { 4100Sstevel@tonic-gate smflags |= SM_WRITE; 4110Sstevel@tonic-gate bcopy(bufaddr, mapaddr + mapoffset, xfersize); 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate bp->b_resid -= xfersize; 4140Sstevel@tonic-gate bufaddr += xfersize; 4150Sstevel@tonic-gate offset += xfersize; 4160Sstevel@tonic-gate (void) segmap_fault(kas.a_hat, segkmap, mapaddr, 4170Sstevel@tonic-gate len, F_SOFTUNLOCK, srw); 4180Sstevel@tonic-gate error = segmap_release(segkmap, mapaddr, smflags); 4190Sstevel@tonic-gate /* only the first map may start partial */ 4200Sstevel@tonic-gate mapoffset = 0; 4210Sstevel@tonic-gate alignedoffset += MAXBSIZE; 4220Sstevel@tonic-gate } while ((error == 0) && (bp->b_resid > 0) && 4230Sstevel@tonic-gate (offset < lsp->ls_vp_size)); 4240Sstevel@tonic-gate } else { 4250Sstevel@tonic-gate ssize_t resid; 4260Sstevel@tonic-gate enum uio_rw rw; 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate if (bp->b_flags & B_READ) 4290Sstevel@tonic-gate rw = UIO_READ; 4300Sstevel@tonic-gate else 4310Sstevel@tonic-gate rw = UIO_WRITE; 4320Sstevel@tonic-gate error = vn_rdwr(rw, lsp->ls_vp, bufaddr, bp->b_bcount, 4330Sstevel@tonic-gate offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid); 4340Sstevel@tonic-gate bp->b_resid = resid; 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate if (lsp->ls_kstat) { 4380Sstevel@tonic-gate size_t n_done = bp->b_bcount - bp->b_resid; 4390Sstevel@tonic-gate kstat_io_t *kioptr; 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate mutex_enter(lsp->ls_kstat->ks_lock); 4420Sstevel@tonic-gate kioptr = KSTAT_IO_PTR(lsp->ls_kstat); 4430Sstevel@tonic-gate if (bp->b_flags & B_READ) { 4440Sstevel@tonic-gate kioptr->nread += n_done; 4450Sstevel@tonic-gate kioptr->reads++; 4460Sstevel@tonic-gate } else { 4470Sstevel@tonic-gate kioptr->nwritten += n_done; 4480Sstevel@tonic-gate kioptr->writes++; 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate kstat_runq_exit(kioptr); 4510Sstevel@tonic-gate mutex_exit(lsp->ls_kstat->ks_lock); 4520Sstevel@tonic-gate } 453*4451Seschrock 454*4451Seschrock mutex_enter(&lsp->ls_vp_lock); 455*4451Seschrock if (--lsp->ls_vp_iocount == 0) 456*4451Seschrock cv_broadcast(&lsp->ls_vp_cv); 457*4451Seschrock mutex_exit(&lsp->ls_vp_lock); 458*4451Seschrock 4590Sstevel@tonic-gate bioerror(bp, error); 4600Sstevel@tonic-gate biodone(bp); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate static int 4640Sstevel@tonic-gate lofi_strategy(struct buf *bp) 4650Sstevel@tonic-gate { 4660Sstevel@tonic-gate struct lofi_state *lsp; 4670Sstevel@tonic-gate offset_t offset; 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate /* 4700Sstevel@tonic-gate * We cannot just do I/O here, because the current thread 4710Sstevel@tonic-gate * _might_ end up back in here because the underlying filesystem 4720Sstevel@tonic-gate * wants a buffer, which eventually gets into bio_recycle and 4730Sstevel@tonic-gate * might call into lofi to write out a delayed-write buffer. 4740Sstevel@tonic-gate * This is bad if the filesystem above lofi is the same as below. 4750Sstevel@tonic-gate * 4760Sstevel@tonic-gate * We could come up with a complex strategy using threads to 4770Sstevel@tonic-gate * do the I/O asynchronously, or we could use task queues. task 4780Sstevel@tonic-gate * queues were incredibly easy so they win. 4790Sstevel@tonic-gate */ 4800Sstevel@tonic-gate lsp = ddi_get_soft_state(lofi_statep, getminor(bp->b_edev)); 481*4451Seschrock mutex_enter(&lsp->ls_vp_lock); 482*4451Seschrock if (lsp->ls_vp == NULL || lsp->ls_vp_closereq) { 483*4451Seschrock bioerror(bp, EIO); 484*4451Seschrock biodone(bp); 485*4451Seschrock mutex_exit(&lsp->ls_vp_lock); 486*4451Seschrock return (0); 487*4451Seschrock } 488*4451Seschrock 4890Sstevel@tonic-gate offset = bp->b_lblkno * DEV_BSIZE; /* offset within file */ 4900Sstevel@tonic-gate if (offset == lsp->ls_vp_size) { 4910Sstevel@tonic-gate /* EOF */ 4920Sstevel@tonic-gate if ((bp->b_flags & B_READ) != 0) { 4930Sstevel@tonic-gate bp->b_resid = bp->b_bcount; 4940Sstevel@tonic-gate bioerror(bp, 0); 4950Sstevel@tonic-gate } else { 4960Sstevel@tonic-gate /* writes should fail */ 4970Sstevel@tonic-gate bioerror(bp, ENXIO); 4980Sstevel@tonic-gate } 4990Sstevel@tonic-gate biodone(bp); 500*4451Seschrock mutex_exit(&lsp->ls_vp_lock); 5010Sstevel@tonic-gate return (0); 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate if (offset > lsp->ls_vp_size) { 5040Sstevel@tonic-gate bioerror(bp, ENXIO); 5050Sstevel@tonic-gate biodone(bp); 506*4451Seschrock mutex_exit(&lsp->ls_vp_lock); 5070Sstevel@tonic-gate return (0); 5080Sstevel@tonic-gate } 509*4451Seschrock lsp->ls_vp_iocount++; 510*4451Seschrock mutex_exit(&lsp->ls_vp_lock); 511*4451Seschrock 5120Sstevel@tonic-gate if (lsp->ls_kstat) { 5130Sstevel@tonic-gate mutex_enter(lsp->ls_kstat->ks_lock); 5140Sstevel@tonic-gate kstat_waitq_enter(KSTAT_IO_PTR(lsp->ls_kstat)); 5150Sstevel@tonic-gate mutex_exit(lsp->ls_kstat->ks_lock); 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate (void) taskq_dispatch(lsp->ls_taskq, lofi_strategy_task, bp, KM_SLEEP); 5180Sstevel@tonic-gate return (0); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate /*ARGSUSED2*/ 5220Sstevel@tonic-gate static int 5230Sstevel@tonic-gate lofi_read(dev_t dev, struct uio *uio, struct cred *credp) 5240Sstevel@tonic-gate { 5250Sstevel@tonic-gate if (getminor(dev) == 0) 5260Sstevel@tonic-gate return (EINVAL); 5270Sstevel@tonic-gate return (physio(lofi_strategy, NULL, dev, B_READ, minphys, uio)); 5280Sstevel@tonic-gate } 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate /*ARGSUSED2*/ 5310Sstevel@tonic-gate static int 5320Sstevel@tonic-gate lofi_write(dev_t dev, struct uio *uio, struct cred *credp) 5330Sstevel@tonic-gate { 5340Sstevel@tonic-gate if (getminor(dev) == 0) 5350Sstevel@tonic-gate return (EINVAL); 5360Sstevel@tonic-gate return (physio(lofi_strategy, NULL, dev, B_WRITE, minphys, uio)); 5370Sstevel@tonic-gate } 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate /*ARGSUSED2*/ 5400Sstevel@tonic-gate static int 5410Sstevel@tonic-gate lofi_aread(dev_t dev, struct aio_req *aio, struct cred *credp) 5420Sstevel@tonic-gate { 5430Sstevel@tonic-gate if (getminor(dev) == 0) 5440Sstevel@tonic-gate return (EINVAL); 5450Sstevel@tonic-gate return (aphysio(lofi_strategy, anocancel, dev, B_READ, minphys, aio)); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate /*ARGSUSED2*/ 5490Sstevel@tonic-gate static int 5500Sstevel@tonic-gate lofi_awrite(dev_t dev, struct aio_req *aio, struct cred *credp) 5510Sstevel@tonic-gate { 5520Sstevel@tonic-gate if (getminor(dev) == 0) 5530Sstevel@tonic-gate return (EINVAL); 5540Sstevel@tonic-gate return (aphysio(lofi_strategy, anocancel, dev, B_WRITE, minphys, aio)); 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate /*ARGSUSED*/ 5580Sstevel@tonic-gate static int 5590Sstevel@tonic-gate lofi_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 5600Sstevel@tonic-gate { 5610Sstevel@tonic-gate switch (infocmd) { 5620Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 5630Sstevel@tonic-gate *result = lofi_dip; 5640Sstevel@tonic-gate return (DDI_SUCCESS); 5650Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 5660Sstevel@tonic-gate *result = 0; 5670Sstevel@tonic-gate return (DDI_SUCCESS); 5680Sstevel@tonic-gate } 5690Sstevel@tonic-gate return (DDI_FAILURE); 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate static int 5730Sstevel@tonic-gate lofi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 5740Sstevel@tonic-gate { 5750Sstevel@tonic-gate int error; 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate if (cmd != DDI_ATTACH) 5780Sstevel@tonic-gate return (DDI_FAILURE); 5790Sstevel@tonic-gate error = ddi_soft_state_zalloc(lofi_statep, 0); 5800Sstevel@tonic-gate if (error == DDI_FAILURE) { 5810Sstevel@tonic-gate return (DDI_FAILURE); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate error = ddi_create_minor_node(dip, LOFI_CTL_NODE, S_IFCHR, 0, 5840Sstevel@tonic-gate DDI_PSEUDO, NULL); 5850Sstevel@tonic-gate if (error == DDI_FAILURE) { 5860Sstevel@tonic-gate ddi_soft_state_free(lofi_statep, 0); 5870Sstevel@tonic-gate return (DDI_FAILURE); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate lofi_dip = dip; 5900Sstevel@tonic-gate ddi_report_dev(dip); 5910Sstevel@tonic-gate return (DDI_SUCCESS); 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate static int 5950Sstevel@tonic-gate lofi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 5960Sstevel@tonic-gate { 5970Sstevel@tonic-gate if (cmd != DDI_DETACH) 5980Sstevel@tonic-gate return (DDI_FAILURE); 5990Sstevel@tonic-gate if (lofi_busy()) 6000Sstevel@tonic-gate return (DDI_FAILURE); 6010Sstevel@tonic-gate lofi_dip = NULL; 6020Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 6030Sstevel@tonic-gate ddi_soft_state_free(lofi_statep, 0); 6040Sstevel@tonic-gate return (DDI_SUCCESS); 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate /* 6080Sstevel@tonic-gate * These two just simplify the rest of the ioctls that need to copyin/out 6090Sstevel@tonic-gate * the lofi_ioctl structure. 6100Sstevel@tonic-gate */ 6110Sstevel@tonic-gate struct lofi_ioctl * 6121657Sheppo copy_in_lofi_ioctl(const struct lofi_ioctl *ulip, int flag) 6130Sstevel@tonic-gate { 6140Sstevel@tonic-gate struct lofi_ioctl *klip; 6150Sstevel@tonic-gate int error; 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate klip = kmem_alloc(sizeof (struct lofi_ioctl), KM_SLEEP); 6181657Sheppo error = ddi_copyin(ulip, klip, sizeof (struct lofi_ioctl), flag); 6190Sstevel@tonic-gate if (error) { 6200Sstevel@tonic-gate kmem_free(klip, sizeof (struct lofi_ioctl)); 6210Sstevel@tonic-gate return (NULL); 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate /* make sure filename is always null-terminated */ 6250Sstevel@tonic-gate klip->li_filename[MAXPATHLEN] = '\0'; 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate /* validate minor number */ 6280Sstevel@tonic-gate if (klip->li_minor > lofi_max_files) { 6290Sstevel@tonic-gate kmem_free(klip, sizeof (struct lofi_ioctl)); 6300Sstevel@tonic-gate return (NULL); 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate return (klip); 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate int 6361657Sheppo copy_out_lofi_ioctl(const struct lofi_ioctl *klip, struct lofi_ioctl *ulip, 6371657Sheppo int flag) 6380Sstevel@tonic-gate { 6390Sstevel@tonic-gate int error; 6400Sstevel@tonic-gate 6411657Sheppo error = ddi_copyout(klip, ulip, sizeof (struct lofi_ioctl), flag); 6420Sstevel@tonic-gate if (error) 6430Sstevel@tonic-gate return (EFAULT); 6440Sstevel@tonic-gate return (0); 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate void 6480Sstevel@tonic-gate free_lofi_ioctl(struct lofi_ioctl *klip) 6490Sstevel@tonic-gate { 6500Sstevel@tonic-gate kmem_free(klip, sizeof (struct lofi_ioctl)); 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate /* 6540Sstevel@tonic-gate * Return the minor number 'filename' is mapped to, if it is. 6550Sstevel@tonic-gate */ 6560Sstevel@tonic-gate static int 6570Sstevel@tonic-gate file_to_minor(char *filename) 6580Sstevel@tonic-gate { 6590Sstevel@tonic-gate minor_t minor; 6600Sstevel@tonic-gate struct lofi_state *lsp; 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate ASSERT(mutex_owned(&lofi_lock)); 6630Sstevel@tonic-gate for (minor = 1; minor <= lofi_max_files; minor++) { 6640Sstevel@tonic-gate lsp = ddi_get_soft_state(lofi_statep, minor); 6650Sstevel@tonic-gate if (lsp == NULL) 6660Sstevel@tonic-gate continue; 6670Sstevel@tonic-gate if (strcmp(lsp->ls_filename, filename) == 0) 6680Sstevel@tonic-gate return (minor); 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate return (0); 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate /* 6740Sstevel@tonic-gate * lofiadm does some validation, but since Joe Random (or crashme) could 6750Sstevel@tonic-gate * do our ioctls, we need to do some validation too. 6760Sstevel@tonic-gate */ 6770Sstevel@tonic-gate static int 6780Sstevel@tonic-gate valid_filename(const char *filename) 6790Sstevel@tonic-gate { 6800Sstevel@tonic-gate static char *blkprefix = "/dev/" LOFI_BLOCK_NAME "/"; 6810Sstevel@tonic-gate static char *charprefix = "/dev/" LOFI_CHAR_NAME "/"; 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate /* must be absolute path */ 6840Sstevel@tonic-gate if (filename[0] != '/') 6850Sstevel@tonic-gate return (0); 6860Sstevel@tonic-gate /* must not be lofi */ 6870Sstevel@tonic-gate if (strncmp(filename, blkprefix, strlen(blkprefix)) == 0) 6880Sstevel@tonic-gate return (0); 6890Sstevel@tonic-gate if (strncmp(filename, charprefix, strlen(charprefix)) == 0) 6900Sstevel@tonic-gate return (0); 6910Sstevel@tonic-gate return (1); 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate /* 6950Sstevel@tonic-gate * Fakes up a disk geometry, and one big partition, based on the size 6960Sstevel@tonic-gate * of the file. This is needed because we allow newfs'ing the device, 6970Sstevel@tonic-gate * and newfs will do several disk ioctls to figure out the geometry and 6980Sstevel@tonic-gate * partition information. It uses that information to determine the parameters 6993517Smp204432 * to pass to mkfs. Geometry is pretty much irrelevant these days, but we 7000Sstevel@tonic-gate * have to support it. 7010Sstevel@tonic-gate */ 7020Sstevel@tonic-gate static void 7030Sstevel@tonic-gate fake_disk_geometry(struct lofi_state *lsp) 7040Sstevel@tonic-gate { 7050Sstevel@tonic-gate /* dk_geom - see dkio(7I) */ 7060Sstevel@tonic-gate /* 7070Sstevel@tonic-gate * dkg_ncyl _could_ be set to one here (one big cylinder with gobs 7080Sstevel@tonic-gate * of sectors), but that breaks programs like fdisk which want to 7090Sstevel@tonic-gate * partition a disk by cylinder. With one cylinder, you can't create 7100Sstevel@tonic-gate * an fdisk partition and put pcfs on it for testing (hard to pick 7110Sstevel@tonic-gate * a number between one and one). 7120Sstevel@tonic-gate * 7130Sstevel@tonic-gate * The cheezy floppy test is an attempt to not have too few cylinders 7140Sstevel@tonic-gate * for a small file, or so many on a big file that you waste space 7150Sstevel@tonic-gate * for backup superblocks or cylinder group structures. 7160Sstevel@tonic-gate */ 7170Sstevel@tonic-gate if (lsp->ls_vp_size < (2 * 1024 * 1024)) /* floppy? */ 7180Sstevel@tonic-gate lsp->ls_dkg.dkg_ncyl = lsp->ls_vp_size / (100 * 1024); 7190Sstevel@tonic-gate else 7200Sstevel@tonic-gate lsp->ls_dkg.dkg_ncyl = lsp->ls_vp_size / (300 * 1024); 7210Sstevel@tonic-gate /* in case file file is < 100k */ 7220Sstevel@tonic-gate if (lsp->ls_dkg.dkg_ncyl == 0) 7230Sstevel@tonic-gate lsp->ls_dkg.dkg_ncyl = 1; 7240Sstevel@tonic-gate lsp->ls_dkg.dkg_acyl = 0; 7250Sstevel@tonic-gate lsp->ls_dkg.dkg_bcyl = 0; 7260Sstevel@tonic-gate lsp->ls_dkg.dkg_nhead = 1; 7270Sstevel@tonic-gate lsp->ls_dkg.dkg_obs1 = 0; 7280Sstevel@tonic-gate lsp->ls_dkg.dkg_intrlv = 0; 7290Sstevel@tonic-gate lsp->ls_dkg.dkg_obs2 = 0; 7300Sstevel@tonic-gate lsp->ls_dkg.dkg_obs3 = 0; 7310Sstevel@tonic-gate lsp->ls_dkg.dkg_apc = 0; 7320Sstevel@tonic-gate lsp->ls_dkg.dkg_rpm = 7200; 7330Sstevel@tonic-gate lsp->ls_dkg.dkg_pcyl = lsp->ls_dkg.dkg_ncyl + lsp->ls_dkg.dkg_acyl; 7340Sstevel@tonic-gate lsp->ls_dkg.dkg_nsect = lsp->ls_vp_size / 7350Sstevel@tonic-gate (DEV_BSIZE * lsp->ls_dkg.dkg_ncyl); 7360Sstevel@tonic-gate lsp->ls_dkg.dkg_write_reinstruct = 0; 7370Sstevel@tonic-gate lsp->ls_dkg.dkg_read_reinstruct = 0; 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate /* vtoc - see dkio(7I) */ 7400Sstevel@tonic-gate bzero(&lsp->ls_vtoc, sizeof (struct vtoc)); 7410Sstevel@tonic-gate lsp->ls_vtoc.v_sanity = VTOC_SANE; 7420Sstevel@tonic-gate lsp->ls_vtoc.v_version = V_VERSION; 7430Sstevel@tonic-gate bcopy(LOFI_DRIVER_NAME, lsp->ls_vtoc.v_volume, 7); 7440Sstevel@tonic-gate lsp->ls_vtoc.v_sectorsz = DEV_BSIZE; 7450Sstevel@tonic-gate lsp->ls_vtoc.v_nparts = 1; 7460Sstevel@tonic-gate lsp->ls_vtoc.v_part[0].p_tag = V_UNASSIGNED; 7470Sstevel@tonic-gate lsp->ls_vtoc.v_part[0].p_flag = V_UNMNT; 7480Sstevel@tonic-gate lsp->ls_vtoc.v_part[0].p_start = (daddr_t)0; 7490Sstevel@tonic-gate /* 7500Sstevel@tonic-gate * The partition size cannot just be the number of sectors, because 7510Sstevel@tonic-gate * that might not end on a cylinder boundary. And if that's the case, 7520Sstevel@tonic-gate * newfs/mkfs will print a scary warning. So just figure the size 7530Sstevel@tonic-gate * based on the number of cylinders and sectors/cylinder. 7540Sstevel@tonic-gate */ 7550Sstevel@tonic-gate lsp->ls_vtoc.v_part[0].p_size = lsp->ls_dkg.dkg_pcyl * 7560Sstevel@tonic-gate lsp->ls_dkg.dkg_nsect * lsp->ls_dkg.dkg_nhead; 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate /* dk_cinfo - see dkio(7I) */ 7590Sstevel@tonic-gate bzero(&lsp->ls_ci, sizeof (struct dk_cinfo)); 7600Sstevel@tonic-gate (void) strcpy(lsp->ls_ci.dki_cname, LOFI_DRIVER_NAME); 7610Sstevel@tonic-gate lsp->ls_ci.dki_ctype = DKC_MD; 7620Sstevel@tonic-gate lsp->ls_ci.dki_flags = 0; 7630Sstevel@tonic-gate lsp->ls_ci.dki_cnum = 0; 7640Sstevel@tonic-gate lsp->ls_ci.dki_addr = 0; 7650Sstevel@tonic-gate lsp->ls_ci.dki_space = 0; 7660Sstevel@tonic-gate lsp->ls_ci.dki_prio = 0; 7670Sstevel@tonic-gate lsp->ls_ci.dki_vec = 0; 7680Sstevel@tonic-gate (void) strcpy(lsp->ls_ci.dki_dname, LOFI_DRIVER_NAME); 7690Sstevel@tonic-gate lsp->ls_ci.dki_unit = 0; 7700Sstevel@tonic-gate lsp->ls_ci.dki_slave = 0; 7710Sstevel@tonic-gate lsp->ls_ci.dki_partition = 0; 7720Sstevel@tonic-gate /* 7730Sstevel@tonic-gate * newfs uses this to set maxcontig. Must not be < 16, or it 7740Sstevel@tonic-gate * will be 0 when newfs multiplies it by DEV_BSIZE and divides 7750Sstevel@tonic-gate * it by the block size. Then tunefs doesn't work because 7760Sstevel@tonic-gate * maxcontig is 0. 7770Sstevel@tonic-gate */ 7780Sstevel@tonic-gate lsp->ls_ci.dki_maxtransfer = 16; 7790Sstevel@tonic-gate } 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate /* 7820Sstevel@tonic-gate * map a file to a minor number. Return the minor number. 7830Sstevel@tonic-gate */ 7840Sstevel@tonic-gate static int 7850Sstevel@tonic-gate lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor, 7861657Sheppo int *rvalp, struct cred *credp, int ioctl_flag) 7870Sstevel@tonic-gate { 7880Sstevel@tonic-gate minor_t newminor; 7890Sstevel@tonic-gate struct lofi_state *lsp; 7900Sstevel@tonic-gate struct lofi_ioctl *klip; 7910Sstevel@tonic-gate int error; 7920Sstevel@tonic-gate struct vnode *vp; 7930Sstevel@tonic-gate int64_t Nblocks_prop_val; 7940Sstevel@tonic-gate int64_t Size_prop_val; 7950Sstevel@tonic-gate vattr_t vattr; 7960Sstevel@tonic-gate int flag; 7970Sstevel@tonic-gate enum vtype v_type; 798*4451Seschrock int zalloced = 0; 7990Sstevel@tonic-gate dev_t newdev; 800*4451Seschrock char namebuf[50]; 8010Sstevel@tonic-gate 8021657Sheppo klip = copy_in_lofi_ioctl(ulip, ioctl_flag); 8030Sstevel@tonic-gate if (klip == NULL) 8040Sstevel@tonic-gate return (EFAULT); 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate mutex_enter(&lofi_lock); 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate if (!valid_filename(klip->li_filename)) { 8090Sstevel@tonic-gate error = EINVAL; 8100Sstevel@tonic-gate goto out; 8110Sstevel@tonic-gate } 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate if (file_to_minor(klip->li_filename) != 0) { 8140Sstevel@tonic-gate error = EBUSY; 8150Sstevel@tonic-gate goto out; 8160Sstevel@tonic-gate } 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate if (pickminor) { 8190Sstevel@tonic-gate /* Find a free one */ 8200Sstevel@tonic-gate for (newminor = 1; newminor <= lofi_max_files; newminor++) 8210Sstevel@tonic-gate if (ddi_get_soft_state(lofi_statep, newminor) == NULL) 8220Sstevel@tonic-gate break; 8230Sstevel@tonic-gate if (newminor >= lofi_max_files) { 8240Sstevel@tonic-gate error = EAGAIN; 8250Sstevel@tonic-gate goto out; 8260Sstevel@tonic-gate } 8270Sstevel@tonic-gate } else { 8280Sstevel@tonic-gate newminor = klip->li_minor; 8290Sstevel@tonic-gate if (ddi_get_soft_state(lofi_statep, newminor) != NULL) { 8300Sstevel@tonic-gate error = EEXIST; 8310Sstevel@tonic-gate goto out; 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate /* make sure it's valid */ 8360Sstevel@tonic-gate error = lookupname(klip->li_filename, UIO_SYSSPACE, FOLLOW, 8370Sstevel@tonic-gate NULLVPP, &vp); 8380Sstevel@tonic-gate if (error) { 8390Sstevel@tonic-gate goto out; 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate v_type = vp->v_type; 8420Sstevel@tonic-gate VN_RELE(vp); 8430Sstevel@tonic-gate if (!V_ISLOFIABLE(v_type)) { 8440Sstevel@tonic-gate error = EINVAL; 8450Sstevel@tonic-gate goto out; 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate flag = FREAD | FWRITE | FOFFMAX | FEXCL; 8480Sstevel@tonic-gate error = vn_open(klip->li_filename, UIO_SYSSPACE, flag, 0, &vp, 0, 0); 8490Sstevel@tonic-gate if (error) { 8500Sstevel@tonic-gate /* try read-only */ 8510Sstevel@tonic-gate flag &= ~FWRITE; 8520Sstevel@tonic-gate error = vn_open(klip->li_filename, UIO_SYSSPACE, flag, 0, 8530Sstevel@tonic-gate &vp, 0, 0); 8540Sstevel@tonic-gate if (error) { 8550Sstevel@tonic-gate goto out; 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate vattr.va_mask = AT_SIZE; 8590Sstevel@tonic-gate error = VOP_GETATTR(vp, &vattr, 0, credp); 8600Sstevel@tonic-gate if (error) { 8610Sstevel@tonic-gate goto closeout; 8620Sstevel@tonic-gate } 8630Sstevel@tonic-gate /* the file needs to be a multiple of the block size */ 8640Sstevel@tonic-gate if ((vattr.va_size % DEV_BSIZE) != 0) { 8650Sstevel@tonic-gate error = EINVAL; 8660Sstevel@tonic-gate goto closeout; 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate newdev = makedevice(getmajor(dev), newminor); 8690Sstevel@tonic-gate Size_prop_val = vattr.va_size; 8700Sstevel@tonic-gate if ((ddi_prop_update_int64(newdev, lofi_dip, 8710Sstevel@tonic-gate SIZE_PROP_NAME, Size_prop_val)) != DDI_PROP_SUCCESS) { 8720Sstevel@tonic-gate error = EINVAL; 8730Sstevel@tonic-gate goto closeout; 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate Nblocks_prop_val = vattr.va_size / DEV_BSIZE; 8760Sstevel@tonic-gate if ((ddi_prop_update_int64(newdev, lofi_dip, 8770Sstevel@tonic-gate NBLOCKS_PROP_NAME, Nblocks_prop_val)) != DDI_PROP_SUCCESS) { 8780Sstevel@tonic-gate error = EINVAL; 8790Sstevel@tonic-gate goto propout; 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate error = ddi_soft_state_zalloc(lofi_statep, newminor); 8820Sstevel@tonic-gate if (error == DDI_FAILURE) { 8830Sstevel@tonic-gate error = ENOMEM; 8840Sstevel@tonic-gate goto propout; 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate zalloced = 1; 8870Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%d", newminor); 8880Sstevel@tonic-gate (void) ddi_create_minor_node(lofi_dip, namebuf, S_IFBLK, newminor, 8890Sstevel@tonic-gate DDI_PSEUDO, NULL); 8900Sstevel@tonic-gate if (error != DDI_SUCCESS) { 8910Sstevel@tonic-gate error = ENXIO; 8920Sstevel@tonic-gate goto propout; 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%d,raw", newminor); 8950Sstevel@tonic-gate error = ddi_create_minor_node(lofi_dip, namebuf, S_IFCHR, newminor, 8960Sstevel@tonic-gate DDI_PSEUDO, NULL); 8970Sstevel@tonic-gate if (error != DDI_SUCCESS) { 8980Sstevel@tonic-gate /* remove block node */ 8990Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%d", newminor); 9000Sstevel@tonic-gate ddi_remove_minor_node(lofi_dip, namebuf); 9010Sstevel@tonic-gate error = ENXIO; 9020Sstevel@tonic-gate goto propout; 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate lsp = ddi_get_soft_state(lofi_statep, newminor); 9050Sstevel@tonic-gate lsp->ls_filename_sz = strlen(klip->li_filename) + 1; 9060Sstevel@tonic-gate lsp->ls_filename = kmem_alloc(lsp->ls_filename_sz, KM_SLEEP); 9070Sstevel@tonic-gate (void) snprintf(namebuf, sizeof (namebuf), "%s_taskq_%d", 9080Sstevel@tonic-gate LOFI_DRIVER_NAME, newminor); 9090Sstevel@tonic-gate lsp->ls_taskq = taskq_create(namebuf, lofi_taskq_nthreads, 9100Sstevel@tonic-gate minclsyspri, 1, lofi_taskq_maxalloc, 0); 9110Sstevel@tonic-gate lsp->ls_kstat = kstat_create(LOFI_DRIVER_NAME, newminor, 9120Sstevel@tonic-gate NULL, "disk", KSTAT_TYPE_IO, 1, 0); 9130Sstevel@tonic-gate if (lsp->ls_kstat) { 9140Sstevel@tonic-gate mutex_init(&lsp->ls_kstat_lock, NULL, MUTEX_DRIVER, NULL); 9150Sstevel@tonic-gate lsp->ls_kstat->ks_lock = &lsp->ls_kstat_lock; 9160Sstevel@tonic-gate kstat_install(lsp->ls_kstat); 9170Sstevel@tonic-gate } 918*4451Seschrock cv_init(&lsp->ls_vp_cv, NULL, CV_DRIVER, NULL); 919*4451Seschrock mutex_init(&lsp->ls_vp_lock, NULL, MUTEX_DRIVER, NULL); 920*4451Seschrock 9210Sstevel@tonic-gate /* 9220Sstevel@tonic-gate * save open mode so file can be closed properly and vnode counts 9230Sstevel@tonic-gate * updated correctly. 9240Sstevel@tonic-gate */ 9250Sstevel@tonic-gate lsp->ls_openflag = flag; 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate /* 9280Sstevel@tonic-gate * Try to handle stacked lofs vnodes. 9290Sstevel@tonic-gate */ 9300Sstevel@tonic-gate if (vp->v_type == VREG) { 9310Sstevel@tonic-gate if (VOP_REALVP(vp, &lsp->ls_vp) != 0) { 9320Sstevel@tonic-gate lsp->ls_vp = vp; 9330Sstevel@tonic-gate } else { 9340Sstevel@tonic-gate /* 9350Sstevel@tonic-gate * Even though vp was obtained via vn_open(), we 9360Sstevel@tonic-gate * can't call vn_close() on it, since lofs will 9370Sstevel@tonic-gate * pass the VOP_CLOSE() on down to the realvp 9380Sstevel@tonic-gate * (which we are about to use). Hence we merely 9390Sstevel@tonic-gate * drop the reference to the lofs vnode and hold 9400Sstevel@tonic-gate * the realvp so things behave as if we've 9410Sstevel@tonic-gate * opened the realvp without any interaction 9420Sstevel@tonic-gate * with lofs. 9430Sstevel@tonic-gate */ 9440Sstevel@tonic-gate VN_HOLD(lsp->ls_vp); 9450Sstevel@tonic-gate VN_RELE(vp); 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate } else { 9480Sstevel@tonic-gate lsp->ls_vp = vp; 9490Sstevel@tonic-gate } 9500Sstevel@tonic-gate lsp->ls_vp_size = vattr.va_size; 9510Sstevel@tonic-gate (void) strcpy(lsp->ls_filename, klip->li_filename); 9520Sstevel@tonic-gate if (rvalp) 9530Sstevel@tonic-gate *rvalp = (int)newminor; 9540Sstevel@tonic-gate klip->li_minor = newminor; 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate fake_disk_geometry(lsp); 9570Sstevel@tonic-gate mutex_exit(&lofi_lock); 9581657Sheppo (void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag); 9590Sstevel@tonic-gate free_lofi_ioctl(klip); 9600Sstevel@tonic-gate return (0); 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate propout: 9630Sstevel@tonic-gate (void) ddi_prop_remove(newdev, lofi_dip, SIZE_PROP_NAME); 9640Sstevel@tonic-gate (void) ddi_prop_remove(newdev, lofi_dip, NBLOCKS_PROP_NAME); 9650Sstevel@tonic-gate closeout: 9660Sstevel@tonic-gate (void) VOP_CLOSE(vp, flag, 1, 0, credp); 9670Sstevel@tonic-gate VN_RELE(vp); 9680Sstevel@tonic-gate out: 9690Sstevel@tonic-gate if (zalloced) 9700Sstevel@tonic-gate ddi_soft_state_free(lofi_statep, newminor); 9710Sstevel@tonic-gate mutex_exit(&lofi_lock); 9720Sstevel@tonic-gate free_lofi_ioctl(klip); 9730Sstevel@tonic-gate return (error); 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate /* 9770Sstevel@tonic-gate * unmap a file. 9780Sstevel@tonic-gate */ 9790Sstevel@tonic-gate static int 9800Sstevel@tonic-gate lofi_unmap_file(dev_t dev, struct lofi_ioctl *ulip, int byfilename, 9811657Sheppo struct cred *credp, int ioctl_flag) 9820Sstevel@tonic-gate { 9830Sstevel@tonic-gate struct lofi_state *lsp; 9840Sstevel@tonic-gate struct lofi_ioctl *klip; 9850Sstevel@tonic-gate minor_t minor; 9860Sstevel@tonic-gate 9871657Sheppo klip = copy_in_lofi_ioctl(ulip, ioctl_flag); 9880Sstevel@tonic-gate if (klip == NULL) 9890Sstevel@tonic-gate return (EFAULT); 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate mutex_enter(&lofi_lock); 9920Sstevel@tonic-gate if (byfilename) { 9930Sstevel@tonic-gate minor = file_to_minor(klip->li_filename); 9940Sstevel@tonic-gate } else { 9950Sstevel@tonic-gate minor = klip->li_minor; 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate if (minor == 0) { 9980Sstevel@tonic-gate mutex_exit(&lofi_lock); 9990Sstevel@tonic-gate free_lofi_ioctl(klip); 10000Sstevel@tonic-gate return (ENXIO); 10010Sstevel@tonic-gate } 10020Sstevel@tonic-gate lsp = ddi_get_soft_state(lofi_statep, minor); 1003*4451Seschrock if (lsp == NULL || lsp->ls_vp == NULL) { 10040Sstevel@tonic-gate mutex_exit(&lofi_lock); 10050Sstevel@tonic-gate free_lofi_ioctl(klip); 10060Sstevel@tonic-gate return (ENXIO); 10070Sstevel@tonic-gate } 1008*4451Seschrock 10090Sstevel@tonic-gate if (is_opened(lsp)) { 1010*4451Seschrock /* 1011*4451Seschrock * If the 'force' flag is set, then we forcibly close the 1012*4451Seschrock * underlying file. Subsequent operations will fail, and the 1013*4451Seschrock * DKIOCSTATE ioctl will return DKIO_DEV_GONE. When the device 1014*4451Seschrock * is last closed, the device will be cleaned up appropriately. 1015*4451Seschrock * 1016*4451Seschrock * This is complicated by the fact that we may have outstanding 1017*4451Seschrock * dispatched I/Os. Rather than having a single mutex to 1018*4451Seschrock * serialize all I/O, we keep a count of the number of 1019*4451Seschrock * outstanding I/O requests, as well as a flag to indicate that 1020*4451Seschrock * no new I/Os should be dispatched. We set the flag, wait for 1021*4451Seschrock * the number of outstanding I/Os to reach 0, and then close the 1022*4451Seschrock * underlying vnode. 1023*4451Seschrock */ 1024*4451Seschrock if (klip->li_force) { 1025*4451Seschrock mutex_enter(&lsp->ls_vp_lock); 1026*4451Seschrock lsp->ls_vp_closereq = B_TRUE; 1027*4451Seschrock while (lsp->ls_vp_iocount > 0) 1028*4451Seschrock cv_wait(&lsp->ls_vp_cv, &lsp->ls_vp_lock); 1029*4451Seschrock (void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag, 1, 0, 1030*4451Seschrock credp); 1031*4451Seschrock VN_RELE(lsp->ls_vp); 1032*4451Seschrock lsp->ls_vp = NULL; 1033*4451Seschrock cv_broadcast(&lsp->ls_vp_cv); 1034*4451Seschrock mutex_exit(&lsp->ls_vp_lock); 1035*4451Seschrock mutex_exit(&lofi_lock); 1036*4451Seschrock klip->li_minor = minor; 1037*4451Seschrock (void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag); 1038*4451Seschrock free_lofi_ioctl(klip); 1039*4451Seschrock return (0); 1040*4451Seschrock } 10410Sstevel@tonic-gate mutex_exit(&lofi_lock); 10420Sstevel@tonic-gate free_lofi_ioctl(klip); 10430Sstevel@tonic-gate return (EBUSY); 10440Sstevel@tonic-gate } 10450Sstevel@tonic-gate 1046*4451Seschrock lofi_free_handle(dev, minor, lsp, credp); 10470Sstevel@tonic-gate 10480Sstevel@tonic-gate klip->li_minor = minor; 10490Sstevel@tonic-gate mutex_exit(&lofi_lock); 10501657Sheppo (void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag); 10510Sstevel@tonic-gate free_lofi_ioctl(klip); 10520Sstevel@tonic-gate return (0); 10530Sstevel@tonic-gate } 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate /* 10560Sstevel@tonic-gate * get the filename given the minor number, or the minor number given 10570Sstevel@tonic-gate * the name. 10580Sstevel@tonic-gate */ 1059*4451Seschrock /*ARGSUSED*/ 10600Sstevel@tonic-gate static int 10610Sstevel@tonic-gate lofi_get_info(dev_t dev, struct lofi_ioctl *ulip, int which, 10621657Sheppo struct cred *credp, int ioctl_flag) 10630Sstevel@tonic-gate { 10640Sstevel@tonic-gate struct lofi_state *lsp; 10650Sstevel@tonic-gate struct lofi_ioctl *klip; 10660Sstevel@tonic-gate int error; 10670Sstevel@tonic-gate minor_t minor; 10680Sstevel@tonic-gate 10691657Sheppo klip = copy_in_lofi_ioctl(ulip, ioctl_flag); 10700Sstevel@tonic-gate if (klip == NULL) 10710Sstevel@tonic-gate return (EFAULT); 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate switch (which) { 10740Sstevel@tonic-gate case LOFI_GET_FILENAME: 10750Sstevel@tonic-gate minor = klip->li_minor; 10760Sstevel@tonic-gate if (minor == 0) { 10770Sstevel@tonic-gate free_lofi_ioctl(klip); 10780Sstevel@tonic-gate return (EINVAL); 10790Sstevel@tonic-gate } 10800Sstevel@tonic-gate 10810Sstevel@tonic-gate mutex_enter(&lofi_lock); 10820Sstevel@tonic-gate lsp = ddi_get_soft_state(lofi_statep, minor); 10830Sstevel@tonic-gate if (lsp == NULL) { 10840Sstevel@tonic-gate mutex_exit(&lofi_lock); 10850Sstevel@tonic-gate free_lofi_ioctl(klip); 10860Sstevel@tonic-gate return (ENXIO); 10870Sstevel@tonic-gate } 10880Sstevel@tonic-gate (void) strcpy(klip->li_filename, lsp->ls_filename); 10890Sstevel@tonic-gate mutex_exit(&lofi_lock); 10901657Sheppo error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag); 10910Sstevel@tonic-gate free_lofi_ioctl(klip); 10920Sstevel@tonic-gate return (error); 10930Sstevel@tonic-gate case LOFI_GET_MINOR: 10940Sstevel@tonic-gate mutex_enter(&lofi_lock); 10950Sstevel@tonic-gate klip->li_minor = file_to_minor(klip->li_filename); 10960Sstevel@tonic-gate mutex_exit(&lofi_lock); 10970Sstevel@tonic-gate if (klip->li_minor == 0) { 10980Sstevel@tonic-gate free_lofi_ioctl(klip); 10990Sstevel@tonic-gate return (ENOENT); 11000Sstevel@tonic-gate } 11011657Sheppo error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag); 11020Sstevel@tonic-gate free_lofi_ioctl(klip); 11030Sstevel@tonic-gate return (error); 11040Sstevel@tonic-gate default: 11050Sstevel@tonic-gate free_lofi_ioctl(klip); 11060Sstevel@tonic-gate return (EINVAL); 11070Sstevel@tonic-gate } 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate } 11100Sstevel@tonic-gate 11110Sstevel@tonic-gate static int 11120Sstevel@tonic-gate lofi_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, 11130Sstevel@tonic-gate int *rvalp) 11140Sstevel@tonic-gate { 11150Sstevel@tonic-gate int error; 11160Sstevel@tonic-gate enum dkio_state dkstate; 11170Sstevel@tonic-gate struct lofi_state *lsp; 11180Sstevel@tonic-gate minor_t minor; 11190Sstevel@tonic-gate 11200Sstevel@tonic-gate #ifdef lint 11210Sstevel@tonic-gate credp = credp; 11220Sstevel@tonic-gate #endif 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate minor = getminor(dev); 11250Sstevel@tonic-gate /* lofi ioctls only apply to the master device */ 11260Sstevel@tonic-gate if (minor == 0) { 11270Sstevel@tonic-gate struct lofi_ioctl *lip = (struct lofi_ioctl *)arg; 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate /* 11300Sstevel@tonic-gate * the query command only need read-access - i.e., normal 11310Sstevel@tonic-gate * users are allowed to do those on the ctl device as 11320Sstevel@tonic-gate * long as they can open it read-only. 11330Sstevel@tonic-gate */ 11340Sstevel@tonic-gate switch (cmd) { 11350Sstevel@tonic-gate case LOFI_MAP_FILE: 11360Sstevel@tonic-gate if ((flag & FWRITE) == 0) 11370Sstevel@tonic-gate return (EPERM); 11381657Sheppo return (lofi_map_file(dev, lip, 1, rvalp, credp, flag)); 11390Sstevel@tonic-gate case LOFI_MAP_FILE_MINOR: 11400Sstevel@tonic-gate if ((flag & FWRITE) == 0) 11410Sstevel@tonic-gate return (EPERM); 11421657Sheppo return (lofi_map_file(dev, lip, 0, rvalp, credp, flag)); 11430Sstevel@tonic-gate case LOFI_UNMAP_FILE: 11440Sstevel@tonic-gate if ((flag & FWRITE) == 0) 11450Sstevel@tonic-gate return (EPERM); 11461657Sheppo return (lofi_unmap_file(dev, lip, 1, credp, flag)); 11470Sstevel@tonic-gate case LOFI_UNMAP_FILE_MINOR: 11480Sstevel@tonic-gate if ((flag & FWRITE) == 0) 11490Sstevel@tonic-gate return (EPERM); 11501657Sheppo return (lofi_unmap_file(dev, lip, 0, credp, flag)); 11510Sstevel@tonic-gate case LOFI_GET_FILENAME: 11520Sstevel@tonic-gate return (lofi_get_info(dev, lip, LOFI_GET_FILENAME, 11531657Sheppo credp, flag)); 11540Sstevel@tonic-gate case LOFI_GET_MINOR: 11550Sstevel@tonic-gate return (lofi_get_info(dev, lip, LOFI_GET_MINOR, 11561657Sheppo credp, flag)); 11570Sstevel@tonic-gate case LOFI_GET_MAXMINOR: 11581657Sheppo error = ddi_copyout(&lofi_max_files, &lip->li_minor, 11591657Sheppo sizeof (lofi_max_files), flag); 11600Sstevel@tonic-gate if (error) 11610Sstevel@tonic-gate return (EFAULT); 11620Sstevel@tonic-gate return (0); 11630Sstevel@tonic-gate default: 11640Sstevel@tonic-gate break; 11650Sstevel@tonic-gate } 11660Sstevel@tonic-gate } 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate lsp = ddi_get_soft_state(lofi_statep, minor); 11690Sstevel@tonic-gate if (lsp == NULL) 11700Sstevel@tonic-gate return (ENXIO); 11710Sstevel@tonic-gate 1172*4451Seschrock /* 1173*4451Seschrock * We explicitly allow DKIOCSTATE, but all other ioctls should fail with 1174*4451Seschrock * EIO as if the device was no longer present. 1175*4451Seschrock */ 1176*4451Seschrock if (lsp->ls_vp == NULL && cmd != DKIOCSTATE) 1177*4451Seschrock return (EIO); 1178*4451Seschrock 11790Sstevel@tonic-gate /* these are for faking out utilities like newfs */ 11800Sstevel@tonic-gate switch (cmd) { 11810Sstevel@tonic-gate case DKIOCGVTOC: 11820Sstevel@tonic-gate switch (ddi_model_convert_from(flag & FMODELS)) { 11830Sstevel@tonic-gate case DDI_MODEL_ILP32: { 11840Sstevel@tonic-gate struct vtoc32 vtoc32; 11850Sstevel@tonic-gate 11860Sstevel@tonic-gate vtoctovtoc32(lsp->ls_vtoc, vtoc32); 11870Sstevel@tonic-gate if (ddi_copyout(&vtoc32, (void *)arg, 11880Sstevel@tonic-gate sizeof (struct vtoc32), flag)) 11890Sstevel@tonic-gate return (EFAULT); 11900Sstevel@tonic-gate break; 11910Sstevel@tonic-gate } 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate case DDI_MODEL_NONE: 11940Sstevel@tonic-gate if (ddi_copyout(&lsp->ls_vtoc, (void *)arg, 11950Sstevel@tonic-gate sizeof (struct vtoc), flag)) 11960Sstevel@tonic-gate return (EFAULT); 11970Sstevel@tonic-gate break; 11980Sstevel@tonic-gate } 11990Sstevel@tonic-gate return (0); 12000Sstevel@tonic-gate case DKIOCINFO: 12011657Sheppo error = ddi_copyout(&lsp->ls_ci, (void *)arg, 12021657Sheppo sizeof (struct dk_cinfo), flag); 12030Sstevel@tonic-gate if (error) 12040Sstevel@tonic-gate return (EFAULT); 12050Sstevel@tonic-gate return (0); 12060Sstevel@tonic-gate case DKIOCG_VIRTGEOM: 12070Sstevel@tonic-gate case DKIOCG_PHYGEOM: 12080Sstevel@tonic-gate case DKIOCGGEOM: 12091657Sheppo error = ddi_copyout(&lsp->ls_dkg, (void *)arg, 12101657Sheppo sizeof (struct dk_geom), flag); 12110Sstevel@tonic-gate if (error) 12120Sstevel@tonic-gate return (EFAULT); 12130Sstevel@tonic-gate return (0); 12140Sstevel@tonic-gate case DKIOCSTATE: 1215*4451Seschrock /* 1216*4451Seschrock * Normally, lofi devices are always in the INSERTED state. If 1217*4451Seschrock * a device is forcefully unmapped, then the device transitions 1218*4451Seschrock * to the DKIO_DEV_GONE state. 1219*4451Seschrock */ 1220*4451Seschrock if (ddi_copyin((void *)arg, &dkstate, sizeof (dkstate), 1221*4451Seschrock flag) != 0) 1222*4451Seschrock return (EFAULT); 1223*4451Seschrock 1224*4451Seschrock mutex_enter(&lsp->ls_vp_lock); 1225*4451Seschrock while ((dkstate == DKIO_INSERTED && lsp->ls_vp != NULL) || 1226*4451Seschrock (dkstate == DKIO_DEV_GONE && lsp->ls_vp == NULL)) { 1227*4451Seschrock /* 1228*4451Seschrock * By virtue of having the device open, we know that 1229*4451Seschrock * 'lsp' will remain valid when we return. 1230*4451Seschrock */ 1231*4451Seschrock if (!cv_wait_sig(&lsp->ls_vp_cv, 1232*4451Seschrock &lsp->ls_vp_lock)) { 1233*4451Seschrock mutex_exit(&lsp->ls_vp_lock); 1234*4451Seschrock return (EINTR); 1235*4451Seschrock } 1236*4451Seschrock } 1237*4451Seschrock 1238*4451Seschrock dkstate = (lsp->ls_vp != NULL ? DKIO_INSERTED : DKIO_DEV_GONE); 1239*4451Seschrock mutex_exit(&lsp->ls_vp_lock); 1240*4451Seschrock 1241*4451Seschrock if (ddi_copyout(&dkstate, (void *)arg, 1242*4451Seschrock sizeof (dkstate), flag) != 0) 12430Sstevel@tonic-gate return (EFAULT); 12440Sstevel@tonic-gate return (0); 12450Sstevel@tonic-gate default: 12460Sstevel@tonic-gate return (ENOTTY); 12470Sstevel@tonic-gate } 12480Sstevel@tonic-gate } 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate static struct cb_ops lofi_cb_ops = { 12510Sstevel@tonic-gate lofi_open, /* open */ 12520Sstevel@tonic-gate lofi_close, /* close */ 12530Sstevel@tonic-gate lofi_strategy, /* strategy */ 12540Sstevel@tonic-gate nodev, /* print */ 12550Sstevel@tonic-gate nodev, /* dump */ 12560Sstevel@tonic-gate lofi_read, /* read */ 12570Sstevel@tonic-gate lofi_write, /* write */ 12580Sstevel@tonic-gate lofi_ioctl, /* ioctl */ 12590Sstevel@tonic-gate nodev, /* devmap */ 12600Sstevel@tonic-gate nodev, /* mmap */ 12610Sstevel@tonic-gate nodev, /* segmap */ 12620Sstevel@tonic-gate nochpoll, /* poll */ 12630Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 12640Sstevel@tonic-gate 0, /* streamtab */ 12650Sstevel@tonic-gate D_64BIT | D_NEW | D_MP, /* Driver compatibility flag */ 12660Sstevel@tonic-gate CB_REV, 12670Sstevel@tonic-gate lofi_aread, 12680Sstevel@tonic-gate lofi_awrite 12690Sstevel@tonic-gate }; 12700Sstevel@tonic-gate 12710Sstevel@tonic-gate static struct dev_ops lofi_ops = { 12720Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 12730Sstevel@tonic-gate 0, /* refcnt */ 12740Sstevel@tonic-gate lofi_info, /* info */ 12750Sstevel@tonic-gate nulldev, /* identify */ 12760Sstevel@tonic-gate nulldev, /* probe */ 12770Sstevel@tonic-gate lofi_attach, /* attach */ 12780Sstevel@tonic-gate lofi_detach, /* detach */ 12790Sstevel@tonic-gate nodev, /* reset */ 12800Sstevel@tonic-gate &lofi_cb_ops, /* driver operations */ 12810Sstevel@tonic-gate NULL /* no bus operations */ 12820Sstevel@tonic-gate }; 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate static struct modldrv modldrv = { 12850Sstevel@tonic-gate &mod_driverops, 12860Sstevel@tonic-gate "loopback file driver (%I%)", 12870Sstevel@tonic-gate &lofi_ops, 12880Sstevel@tonic-gate }; 12890Sstevel@tonic-gate 12900Sstevel@tonic-gate static struct modlinkage modlinkage = { 12910Sstevel@tonic-gate MODREV_1, 12920Sstevel@tonic-gate &modldrv, 12930Sstevel@tonic-gate NULL 12940Sstevel@tonic-gate }; 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate int 12970Sstevel@tonic-gate _init(void) 12980Sstevel@tonic-gate { 12990Sstevel@tonic-gate int error; 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate error = ddi_soft_state_init(&lofi_statep, 13020Sstevel@tonic-gate sizeof (struct lofi_state), 0); 13030Sstevel@tonic-gate if (error) 13040Sstevel@tonic-gate return (error); 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate mutex_init(&lofi_lock, NULL, MUTEX_DRIVER, NULL); 13070Sstevel@tonic-gate error = mod_install(&modlinkage); 13080Sstevel@tonic-gate if (error) { 13090Sstevel@tonic-gate mutex_destroy(&lofi_lock); 13100Sstevel@tonic-gate ddi_soft_state_fini(&lofi_statep); 13110Sstevel@tonic-gate } 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate return (error); 13140Sstevel@tonic-gate } 13150Sstevel@tonic-gate 13160Sstevel@tonic-gate int 13170Sstevel@tonic-gate _fini(void) 13180Sstevel@tonic-gate { 13190Sstevel@tonic-gate int error; 13200Sstevel@tonic-gate 13210Sstevel@tonic-gate if (lofi_busy()) 13220Sstevel@tonic-gate return (EBUSY); 13230Sstevel@tonic-gate 13240Sstevel@tonic-gate error = mod_remove(&modlinkage); 13250Sstevel@tonic-gate if (error) 13260Sstevel@tonic-gate return (error); 13270Sstevel@tonic-gate 13280Sstevel@tonic-gate mutex_destroy(&lofi_lock); 13290Sstevel@tonic-gate ddi_soft_state_fini(&lofi_statep); 13300Sstevel@tonic-gate 13310Sstevel@tonic-gate return (error); 13320Sstevel@tonic-gate } 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate int 13350Sstevel@tonic-gate _info(struct modinfo *modinfop) 13360Sstevel@tonic-gate { 13370Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 13380Sstevel@tonic-gate } 1339