1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5*ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6*ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 22*ea8dc4b6Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27fa9e4066Sahrens 28fa9e4066Sahrens #include <sys/zfs_context.h> 29fa9e4066Sahrens #include <sys/spa.h> 30fa9e4066Sahrens #include <sys/vdev_file.h> 31fa9e4066Sahrens #include <sys/vdev_impl.h> 32fa9e4066Sahrens #include <sys/zio.h> 33fa9e4066Sahrens #include <sys/fs/zfs.h> 34fa9e4066Sahrens 35fa9e4066Sahrens /* 36fa9e4066Sahrens * Virtual device vector for files. 37fa9e4066Sahrens */ 38fa9e4066Sahrens 39fa9e4066Sahrens static int 40fa9e4066Sahrens vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) 41fa9e4066Sahrens { 42fa9e4066Sahrens vdev_file_t *vf; 43fa9e4066Sahrens vnode_t *vp; 44fa9e4066Sahrens vattr_t vattr; 45fa9e4066Sahrens int error; 46fa9e4066Sahrens 47fa9e4066Sahrens /* 48fa9e4066Sahrens * We must have a pathname, and it must be absolute. 49fa9e4066Sahrens */ 50fa9e4066Sahrens if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { 51fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 52fa9e4066Sahrens return (EINVAL); 53fa9e4066Sahrens } 54fa9e4066Sahrens 55fa9e4066Sahrens vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); 56fa9e4066Sahrens 57fa9e4066Sahrens #ifdef _KERNEL 58fa9e4066Sahrens /* 59fa9e4066Sahrens * When using a file vdev in kernel context, the underlying filesystem 60fa9e4066Sahrens * will already be caching the data. Don't cache it again here. 61fa9e4066Sahrens */ 62fa9e4066Sahrens vd->vdev_cache.vc_size = 0; 63fa9e4066Sahrens #endif 64fa9e4066Sahrens 65fa9e4066Sahrens /* 66fa9e4066Sahrens * We always open the files from the root of the global zone, even if 67fa9e4066Sahrens * we're in a local zone. If the user has gotten to this point, the 68fa9e4066Sahrens * administrator has already decided that the pool should be available 69fa9e4066Sahrens * to local zone users, so the underlying devices should be as well. 70fa9e4066Sahrens */ 71fa9e4066Sahrens ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); 72fa9e4066Sahrens error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, spa_mode | FOFFMAX, 73fa9e4066Sahrens 0, &vp, 0, 0, rootdir); 74fa9e4066Sahrens 75fa9e4066Sahrens if (error) { 76fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 77fa9e4066Sahrens return (error); 78fa9e4066Sahrens } 79fa9e4066Sahrens 80fa9e4066Sahrens vf->vf_vnode = vp; 81fa9e4066Sahrens 82fa9e4066Sahrens #ifdef _KERNEL 83fa9e4066Sahrens /* 84fa9e4066Sahrens * Make sure it's a regular file. 85fa9e4066Sahrens */ 86fa9e4066Sahrens if (vp->v_type != VREG) { 87fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 88fa9e4066Sahrens return (ENODEV); 89fa9e4066Sahrens } 90fa9e4066Sahrens #endif 91fa9e4066Sahrens 92fa9e4066Sahrens /* 93fa9e4066Sahrens * Determine the physical size of the file. 94fa9e4066Sahrens */ 95fa9e4066Sahrens vattr.va_mask = AT_SIZE; 96fa9e4066Sahrens error = VOP_GETATTR(vp, &vattr, 0, kcred); 97fa9e4066Sahrens if (error) { 98fa9e4066Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 99fa9e4066Sahrens return (error); 100fa9e4066Sahrens } 101fa9e4066Sahrens 102fa9e4066Sahrens *psize = vattr.va_size; 103fa9e4066Sahrens *ashift = SPA_MINBLOCKSHIFT; 104fa9e4066Sahrens 105fa9e4066Sahrens return (0); 106fa9e4066Sahrens } 107fa9e4066Sahrens 108fa9e4066Sahrens static void 109fa9e4066Sahrens vdev_file_close(vdev_t *vd) 110fa9e4066Sahrens { 111fa9e4066Sahrens vdev_file_t *vf = vd->vdev_tsd; 112fa9e4066Sahrens 113fa9e4066Sahrens if (vf == NULL) 114fa9e4066Sahrens return; 115fa9e4066Sahrens 116fa9e4066Sahrens if (vf->vf_vnode != NULL) { 117fa9e4066Sahrens (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred); 118fa9e4066Sahrens (void) VOP_CLOSE(vf->vf_vnode, spa_mode, 1, 0, kcred); 119fa9e4066Sahrens VN_RELE(vf->vf_vnode); 120fa9e4066Sahrens } 121fa9e4066Sahrens 122fa9e4066Sahrens kmem_free(vf, sizeof (vdev_file_t)); 123fa9e4066Sahrens vd->vdev_tsd = NULL; 124fa9e4066Sahrens } 125fa9e4066Sahrens 126fa9e4066Sahrens static void 127fa9e4066Sahrens vdev_file_io_start(zio_t *zio) 128fa9e4066Sahrens { 129fa9e4066Sahrens vdev_t *vd = zio->io_vd; 130fa9e4066Sahrens vdev_file_t *vf = vd->vdev_tsd; 131fa9e4066Sahrens ssize_t resid; 132fa9e4066Sahrens int error; 133fa9e4066Sahrens 134fa9e4066Sahrens if (zio->io_type == ZIO_TYPE_IOCTL) { 135fa9e4066Sahrens zio_vdev_io_bypass(zio); 136fa9e4066Sahrens 137fa9e4066Sahrens /* XXPOLICY */ 138fa9e4066Sahrens if (vdev_is_dead(vd)) { 139fa9e4066Sahrens zio->io_error = ENXIO; 140fa9e4066Sahrens zio_next_stage_async(zio); 141fa9e4066Sahrens return; 142fa9e4066Sahrens } 143fa9e4066Sahrens 144fa9e4066Sahrens switch (zio->io_cmd) { 145fa9e4066Sahrens case DKIOCFLUSHWRITECACHE: 146fa9e4066Sahrens zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC, 147fa9e4066Sahrens kcred); 148fa9e4066Sahrens dprintf("fsync(%s) = %d\n", vdev_description(vd), 149fa9e4066Sahrens zio->io_error); 150fa9e4066Sahrens break; 151fa9e4066Sahrens default: 152fa9e4066Sahrens zio->io_error = ENOTSUP; 153fa9e4066Sahrens } 154fa9e4066Sahrens 155fa9e4066Sahrens zio_next_stage_async(zio); 156fa9e4066Sahrens return; 157fa9e4066Sahrens } 158fa9e4066Sahrens 159fa9e4066Sahrens if (zio->io_type == ZIO_TYPE_READ && vdev_cache_read(zio) == 0) 160fa9e4066Sahrens return; 161fa9e4066Sahrens 162fa9e4066Sahrens if ((zio = vdev_queue_io(zio)) == NULL) 163fa9e4066Sahrens return; 164fa9e4066Sahrens 165fa9e4066Sahrens /* XXPOLICY */ 166fa9e4066Sahrens error = vdev_is_dead(vd) ? ENXIO : vdev_error_inject(vd, zio); 167fa9e4066Sahrens if (error) { 168fa9e4066Sahrens zio->io_error = error; 169fa9e4066Sahrens zio_next_stage_async(zio); 170fa9e4066Sahrens return; 171fa9e4066Sahrens } 172fa9e4066Sahrens 173fa9e4066Sahrens zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ? 174fa9e4066Sahrens UIO_READ : UIO_WRITE, vf->vf_vnode, zio->io_data, 175fa9e4066Sahrens zio->io_size, zio->io_offset, UIO_SYSSPACE, 176fa9e4066Sahrens 0, RLIM64_INFINITY, kcred, &resid); 177fa9e4066Sahrens 178fa9e4066Sahrens if (resid != 0 && zio->io_error == 0) 179fa9e4066Sahrens zio->io_error = ENOSPC; 180fa9e4066Sahrens 181fa9e4066Sahrens zio_next_stage_async(zio); 182fa9e4066Sahrens } 183fa9e4066Sahrens 184fa9e4066Sahrens static void 185fa9e4066Sahrens vdev_file_io_done(zio_t *zio) 186fa9e4066Sahrens { 187fa9e4066Sahrens vdev_queue_io_done(zio); 188fa9e4066Sahrens 189fa9e4066Sahrens if (zio->io_type == ZIO_TYPE_WRITE) 190fa9e4066Sahrens vdev_cache_write(zio); 191fa9e4066Sahrens 192*ea8dc4b6Seschrock if (zio_injection_enabled && zio->io_error == 0) 193*ea8dc4b6Seschrock zio->io_error = zio_handle_device_injection(zio->io_vd, EIO); 194*ea8dc4b6Seschrock 195fa9e4066Sahrens zio_next_stage(zio); 196fa9e4066Sahrens } 197fa9e4066Sahrens 198fa9e4066Sahrens vdev_ops_t vdev_file_ops = { 199fa9e4066Sahrens vdev_file_open, 200fa9e4066Sahrens vdev_file_close, 201fa9e4066Sahrens vdev_default_asize, 202fa9e4066Sahrens vdev_file_io_start, 203fa9e4066Sahrens vdev_file_io_done, 204fa9e4066Sahrens NULL, 205fa9e4066Sahrens VDEV_TYPE_FILE, /* name of this vdev type */ 206fa9e4066Sahrens B_TRUE /* leaf vdev */ 207fa9e4066Sahrens }; 208fa9e4066Sahrens 209fa9e4066Sahrens /* 210fa9e4066Sahrens * From userland we access disks just like files. 211fa9e4066Sahrens */ 212fa9e4066Sahrens #ifndef _KERNEL 213fa9e4066Sahrens 214fa9e4066Sahrens vdev_ops_t vdev_disk_ops = { 215fa9e4066Sahrens vdev_file_open, 216fa9e4066Sahrens vdev_file_close, 217fa9e4066Sahrens vdev_default_asize, 218fa9e4066Sahrens vdev_file_io_start, 219fa9e4066Sahrens vdev_file_io_done, 220fa9e4066Sahrens NULL, 221fa9e4066Sahrens VDEV_TYPE_DISK, /* name of this vdev type */ 222fa9e4066Sahrens B_TRUE /* leaf vdev */ 223fa9e4066Sahrens }; 224fa9e4066Sahrens 225fa9e4066Sahrens #endif 226