1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 5*1544Seschrock * Common Development and Distribution License (the "License"). 6*1544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 22*1544Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <sys/zfs_context.h> 29789Sahrens #include <sys/spa.h> 30789Sahrens #include <sys/vdev_file.h> 31789Sahrens #include <sys/vdev_impl.h> 32789Sahrens #include <sys/zio.h> 33789Sahrens #include <sys/fs/zfs.h> 34789Sahrens 35789Sahrens /* 36789Sahrens * Virtual device vector for files. 37789Sahrens */ 38789Sahrens 39789Sahrens static int 40789Sahrens vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) 41789Sahrens { 42789Sahrens vdev_file_t *vf; 43789Sahrens vnode_t *vp; 44789Sahrens vattr_t vattr; 45789Sahrens int error; 46789Sahrens 47789Sahrens /* 48789Sahrens * We must have a pathname, and it must be absolute. 49789Sahrens */ 50789Sahrens if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { 51789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 52789Sahrens return (EINVAL); 53789Sahrens } 54789Sahrens 55789Sahrens vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); 56789Sahrens 57789Sahrens #ifdef _KERNEL 58789Sahrens /* 59789Sahrens * When using a file vdev in kernel context, the underlying filesystem 60789Sahrens * will already be caching the data. Don't cache it again here. 61789Sahrens */ 62789Sahrens vd->vdev_cache.vc_size = 0; 63789Sahrens #endif 64789Sahrens 65789Sahrens /* 66789Sahrens * We always open the files from the root of the global zone, even if 67789Sahrens * we're in a local zone. If the user has gotten to this point, the 68789Sahrens * administrator has already decided that the pool should be available 69789Sahrens * to local zone users, so the underlying devices should be as well. 70789Sahrens */ 71789Sahrens ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); 72789Sahrens error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, spa_mode | FOFFMAX, 73789Sahrens 0, &vp, 0, 0, rootdir); 74789Sahrens 75789Sahrens if (error) { 76789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 77789Sahrens return (error); 78789Sahrens } 79789Sahrens 80789Sahrens vf->vf_vnode = vp; 81789Sahrens 82789Sahrens #ifdef _KERNEL 83789Sahrens /* 84789Sahrens * Make sure it's a regular file. 85789Sahrens */ 86789Sahrens if (vp->v_type != VREG) { 87789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 88789Sahrens return (ENODEV); 89789Sahrens } 90789Sahrens #endif 91789Sahrens 92789Sahrens /* 93789Sahrens * Determine the physical size of the file. 94789Sahrens */ 95789Sahrens vattr.va_mask = AT_SIZE; 96789Sahrens error = VOP_GETATTR(vp, &vattr, 0, kcred); 97789Sahrens if (error) { 98789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 99789Sahrens return (error); 100789Sahrens } 101789Sahrens 102789Sahrens *psize = vattr.va_size; 103789Sahrens *ashift = SPA_MINBLOCKSHIFT; 104789Sahrens 105789Sahrens return (0); 106789Sahrens } 107789Sahrens 108789Sahrens static void 109789Sahrens vdev_file_close(vdev_t *vd) 110789Sahrens { 111789Sahrens vdev_file_t *vf = vd->vdev_tsd; 112789Sahrens 113789Sahrens if (vf == NULL) 114789Sahrens return; 115789Sahrens 116789Sahrens if (vf->vf_vnode != NULL) { 117789Sahrens (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred); 118789Sahrens (void) VOP_CLOSE(vf->vf_vnode, spa_mode, 1, 0, kcred); 119789Sahrens VN_RELE(vf->vf_vnode); 120789Sahrens } 121789Sahrens 122789Sahrens kmem_free(vf, sizeof (vdev_file_t)); 123789Sahrens vd->vdev_tsd = NULL; 124789Sahrens } 125789Sahrens 126789Sahrens static void 127789Sahrens vdev_file_io_start(zio_t *zio) 128789Sahrens { 129789Sahrens vdev_t *vd = zio->io_vd; 130789Sahrens vdev_file_t *vf = vd->vdev_tsd; 131789Sahrens ssize_t resid; 132789Sahrens int error; 133789Sahrens 134789Sahrens if (zio->io_type == ZIO_TYPE_IOCTL) { 135789Sahrens zio_vdev_io_bypass(zio); 136789Sahrens 137789Sahrens /* XXPOLICY */ 138789Sahrens if (vdev_is_dead(vd)) { 139789Sahrens zio->io_error = ENXIO; 140789Sahrens zio_next_stage_async(zio); 141789Sahrens return; 142789Sahrens } 143789Sahrens 144789Sahrens switch (zio->io_cmd) { 145789Sahrens case DKIOCFLUSHWRITECACHE: 146789Sahrens zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC, 147789Sahrens kcred); 148789Sahrens dprintf("fsync(%s) = %d\n", vdev_description(vd), 149789Sahrens zio->io_error); 150789Sahrens break; 151789Sahrens default: 152789Sahrens zio->io_error = ENOTSUP; 153789Sahrens } 154789Sahrens 155789Sahrens zio_next_stage_async(zio); 156789Sahrens return; 157789Sahrens } 158789Sahrens 159789Sahrens if (zio->io_type == ZIO_TYPE_READ && vdev_cache_read(zio) == 0) 160789Sahrens return; 161789Sahrens 162789Sahrens if ((zio = vdev_queue_io(zio)) == NULL) 163789Sahrens return; 164789Sahrens 165789Sahrens /* XXPOLICY */ 166789Sahrens error = vdev_is_dead(vd) ? ENXIO : vdev_error_inject(vd, zio); 167789Sahrens if (error) { 168789Sahrens zio->io_error = error; 169789Sahrens zio_next_stage_async(zio); 170789Sahrens return; 171789Sahrens } 172789Sahrens 173789Sahrens zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ? 174789Sahrens UIO_READ : UIO_WRITE, vf->vf_vnode, zio->io_data, 175789Sahrens zio->io_size, zio->io_offset, UIO_SYSSPACE, 176789Sahrens 0, RLIM64_INFINITY, kcred, &resid); 177789Sahrens 178789Sahrens if (resid != 0 && zio->io_error == 0) 179789Sahrens zio->io_error = ENOSPC; 180789Sahrens 181789Sahrens zio_next_stage_async(zio); 182789Sahrens } 183789Sahrens 184789Sahrens static void 185789Sahrens vdev_file_io_done(zio_t *zio) 186789Sahrens { 187789Sahrens vdev_queue_io_done(zio); 188789Sahrens 189789Sahrens if (zio->io_type == ZIO_TYPE_WRITE) 190789Sahrens vdev_cache_write(zio); 191789Sahrens 192*1544Seschrock if (zio_injection_enabled && zio->io_error == 0) 193*1544Seschrock zio->io_error = zio_handle_device_injection(zio->io_vd, EIO); 194*1544Seschrock 195789Sahrens zio_next_stage(zio); 196789Sahrens } 197789Sahrens 198789Sahrens vdev_ops_t vdev_file_ops = { 199789Sahrens vdev_file_open, 200789Sahrens vdev_file_close, 201789Sahrens vdev_default_asize, 202789Sahrens vdev_file_io_start, 203789Sahrens vdev_file_io_done, 204789Sahrens NULL, 205789Sahrens VDEV_TYPE_FILE, /* name of this vdev type */ 206789Sahrens B_TRUE /* leaf vdev */ 207789Sahrens }; 208789Sahrens 209789Sahrens /* 210789Sahrens * From userland we access disks just like files. 211789Sahrens */ 212789Sahrens #ifndef _KERNEL 213789Sahrens 214789Sahrens vdev_ops_t vdev_disk_ops = { 215789Sahrens vdev_file_open, 216789Sahrens vdev_file_close, 217789Sahrens vdev_default_asize, 218789Sahrens vdev_file_io_start, 219789Sahrens vdev_file_io_done, 220789Sahrens NULL, 221789Sahrens VDEV_TYPE_DISK, /* name of this vdev type */ 222789Sahrens B_TRUE /* leaf vdev */ 223789Sahrens }; 224789Sahrens 225789Sahrens #endif 226