1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * 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 /* 226523Sek110237 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #include <sys/zfs_context.h> 27789Sahrens #include <sys/spa.h> 28789Sahrens #include <sys/vdev_file.h> 29789Sahrens #include <sys/vdev_impl.h> 30789Sahrens #include <sys/zio.h> 31789Sahrens #include <sys/fs/zfs.h> 326976Seschrock #include <sys/fm/fs/zfs.h> 33789Sahrens 34789Sahrens /* 35789Sahrens * Virtual device vector for files. 36789Sahrens */ 37789Sahrens 38789Sahrens static int 397754SJeff.Bonwick@Sun.COM vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) 40789Sahrens { 41789Sahrens vdev_file_t *vf; 42789Sahrens vnode_t *vp; 437754SJeff.Bonwick@Sun.COM vattr_t vattr; 44789Sahrens int error; 45789Sahrens 46789Sahrens /* 47789Sahrens * We must have a pathname, and it must be absolute. 48789Sahrens */ 49789Sahrens if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { 50789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 51789Sahrens return (EINVAL); 52789Sahrens } 53789Sahrens 54789Sahrens vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); 55789Sahrens 56789Sahrens /* 57789Sahrens * We always open the files from the root of the global zone, even if 58789Sahrens * we're in a local zone. If the user has gotten to this point, the 59789Sahrens * administrator has already decided that the pool should be available 60789Sahrens * to local zone users, so the underlying devices should be as well. 61789Sahrens */ 62789Sahrens ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); 635329Sgw25295 error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, 64*8241SJeff.Bonwick@Sun.COM spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir, -1); 65789Sahrens 66789Sahrens if (error) { 67789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 68789Sahrens return (error); 69789Sahrens } 70789Sahrens 71789Sahrens vf->vf_vnode = vp; 72789Sahrens 73789Sahrens #ifdef _KERNEL 74789Sahrens /* 75789Sahrens * Make sure it's a regular file. 76789Sahrens */ 77789Sahrens if (vp->v_type != VREG) { 78789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 79789Sahrens return (ENODEV); 80789Sahrens } 81789Sahrens #endif 82789Sahrens /* 83789Sahrens * Determine the physical size of the file. 84789Sahrens */ 85789Sahrens vattr.va_mask = AT_SIZE; 865331Samw error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL); 87789Sahrens if (error) { 88789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 89789Sahrens return (error); 90789Sahrens } 91789Sahrens 92789Sahrens *psize = vattr.va_size; 93789Sahrens *ashift = SPA_MINBLOCKSHIFT; 94789Sahrens 95789Sahrens return (0); 96789Sahrens } 97789Sahrens 98789Sahrens static void 99789Sahrens vdev_file_close(vdev_t *vd) 100789Sahrens { 101789Sahrens vdev_file_t *vf = vd->vdev_tsd; 102789Sahrens 103789Sahrens if (vf == NULL) 104789Sahrens return; 105789Sahrens 106789Sahrens if (vf->vf_vnode != NULL) { 1075331Samw (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL); 108*8241SJeff.Bonwick@Sun.COM (void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0, 109*8241SJeff.Bonwick@Sun.COM kcred, NULL); 110789Sahrens VN_RELE(vf->vf_vnode); 111789Sahrens } 112789Sahrens 113789Sahrens kmem_free(vf, sizeof (vdev_file_t)); 114789Sahrens vd->vdev_tsd = NULL; 115789Sahrens } 116789Sahrens 1175329Sgw25295 static int 118789Sahrens vdev_file_io_start(zio_t *zio) 119789Sahrens { 120789Sahrens vdev_t *vd = zio->io_vd; 121789Sahrens vdev_file_t *vf = vd->vdev_tsd; 122789Sahrens ssize_t resid; 123789Sahrens 124789Sahrens if (zio->io_type == ZIO_TYPE_IOCTL) { 125789Sahrens /* XXPOLICY */ 1265329Sgw25295 if (!vdev_readable(vd)) { 127789Sahrens zio->io_error = ENXIO; 1285530Sbonwick return (ZIO_PIPELINE_CONTINUE); 129789Sahrens } 130789Sahrens 131789Sahrens switch (zio->io_cmd) { 132789Sahrens case DKIOCFLUSHWRITECACHE: 133789Sahrens zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC, 1345331Samw kcred, NULL); 135789Sahrens break; 136789Sahrens default: 137789Sahrens zio->io_error = ENOTSUP; 138789Sahrens } 139789Sahrens 1405530Sbonwick return (ZIO_PIPELINE_CONTINUE); 141789Sahrens } 142789Sahrens 143789Sahrens zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ? 144789Sahrens UIO_READ : UIO_WRITE, vf->vf_vnode, zio->io_data, 145789Sahrens zio->io_size, zio->io_offset, UIO_SYSSPACE, 146789Sahrens 0, RLIM64_INFINITY, kcred, &resid); 147789Sahrens 148789Sahrens if (resid != 0 && zio->io_error == 0) 149789Sahrens zio->io_error = ENOSPC; 150789Sahrens 1515530Sbonwick zio_interrupt(zio); 1525530Sbonwick 1535530Sbonwick return (ZIO_PIPELINE_STOP); 154789Sahrens } 155789Sahrens 1567754SJeff.Bonwick@Sun.COM /* ARGSUSED */ 1577754SJeff.Bonwick@Sun.COM static void 158789Sahrens vdev_file_io_done(zio_t *zio) 159789Sahrens { 160789Sahrens } 161789Sahrens 162789Sahrens vdev_ops_t vdev_file_ops = { 163789Sahrens vdev_file_open, 164789Sahrens vdev_file_close, 165789Sahrens vdev_default_asize, 166789Sahrens vdev_file_io_start, 167789Sahrens vdev_file_io_done, 168789Sahrens NULL, 169789Sahrens VDEV_TYPE_FILE, /* name of this vdev type */ 170789Sahrens B_TRUE /* leaf vdev */ 171789Sahrens }; 172789Sahrens 173789Sahrens /* 174789Sahrens * From userland we access disks just like files. 175789Sahrens */ 176789Sahrens #ifndef _KERNEL 177789Sahrens 178789Sahrens vdev_ops_t vdev_disk_ops = { 179789Sahrens vdev_file_open, 180789Sahrens vdev_file_close, 181789Sahrens vdev_default_asize, 182789Sahrens vdev_file_io_start, 183789Sahrens vdev_file_io_done, 184789Sahrens NULL, 185789Sahrens VDEV_TYPE_DISK, /* name of this vdev type */ 186789Sahrens B_TRUE /* leaf vdev */ 187789Sahrens }; 188789Sahrens 189789Sahrens #endif 190