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 /* 22*11958SGeorge.Wilson@Sun.COM * Copyright 2010 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 38*11958SGeorge.Wilson@Sun.COM static void 39*11958SGeorge.Wilson@Sun.COM vdev_file_hold(vdev_t *vd) 40*11958SGeorge.Wilson@Sun.COM { 41*11958SGeorge.Wilson@Sun.COM ASSERT(vd->vdev_path != NULL); 42*11958SGeorge.Wilson@Sun.COM } 43*11958SGeorge.Wilson@Sun.COM 44*11958SGeorge.Wilson@Sun.COM static void 45*11958SGeorge.Wilson@Sun.COM vdev_file_rele(vdev_t *vd) 46*11958SGeorge.Wilson@Sun.COM { 47*11958SGeorge.Wilson@Sun.COM ASSERT(vd->vdev_path != NULL); 48*11958SGeorge.Wilson@Sun.COM } 49*11958SGeorge.Wilson@Sun.COM 50789Sahrens static int 517754SJeff.Bonwick@Sun.COM vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) 52789Sahrens { 53789Sahrens vdev_file_t *vf; 54789Sahrens vnode_t *vp; 557754SJeff.Bonwick@Sun.COM vattr_t vattr; 56789Sahrens int error; 57789Sahrens 58789Sahrens /* 59789Sahrens * We must have a pathname, and it must be absolute. 60789Sahrens */ 61789Sahrens if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { 62789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 63789Sahrens return (EINVAL); 64789Sahrens } 65789Sahrens 6610850SGeorge.Wilson@Sun.COM /* 6710850SGeorge.Wilson@Sun.COM * Reopen the device if it's not currently open. Otherwise, 6810850SGeorge.Wilson@Sun.COM * just update the physical size of the device. 6910850SGeorge.Wilson@Sun.COM */ 7010850SGeorge.Wilson@Sun.COM if (vd->vdev_tsd != NULL) { 7110850SGeorge.Wilson@Sun.COM ASSERT(vd->vdev_reopening); 7210850SGeorge.Wilson@Sun.COM vf = vd->vdev_tsd; 7310850SGeorge.Wilson@Sun.COM goto skip_open; 7410850SGeorge.Wilson@Sun.COM } 7510850SGeorge.Wilson@Sun.COM 76789Sahrens vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); 77789Sahrens 78789Sahrens /* 79789Sahrens * We always open the files from the root of the global zone, even if 80789Sahrens * we're in a local zone. If the user has gotten to this point, the 81789Sahrens * administrator has already decided that the pool should be available 82789Sahrens * to local zone users, so the underlying devices should be as well. 83789Sahrens */ 84789Sahrens ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); 855329Sgw25295 error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, 868241SJeff.Bonwick@Sun.COM spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir, -1); 87789Sahrens 88789Sahrens if (error) { 89789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 90789Sahrens return (error); 91789Sahrens } 92789Sahrens 93789Sahrens vf->vf_vnode = vp; 94789Sahrens 95789Sahrens #ifdef _KERNEL 96789Sahrens /* 97789Sahrens * Make sure it's a regular file. 98789Sahrens */ 99789Sahrens if (vp->v_type != VREG) { 100789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 101789Sahrens return (ENODEV); 102789Sahrens } 103789Sahrens #endif 10410850SGeorge.Wilson@Sun.COM 10510850SGeorge.Wilson@Sun.COM skip_open: 106789Sahrens /* 107789Sahrens * Determine the physical size of the file. 108789Sahrens */ 109789Sahrens vattr.va_mask = AT_SIZE; 1105331Samw error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL); 111789Sahrens if (error) { 112789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 113789Sahrens return (error); 114789Sahrens } 115789Sahrens 116789Sahrens *psize = vattr.va_size; 117789Sahrens *ashift = SPA_MINBLOCKSHIFT; 118789Sahrens 119789Sahrens return (0); 120789Sahrens } 121789Sahrens 122789Sahrens static void 123789Sahrens vdev_file_close(vdev_t *vd) 124789Sahrens { 125789Sahrens vdev_file_t *vf = vd->vdev_tsd; 126789Sahrens 12710850SGeorge.Wilson@Sun.COM if (vd->vdev_reopening || vf == NULL) 128789Sahrens return; 129789Sahrens 130789Sahrens if (vf->vf_vnode != NULL) { 1315331Samw (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL); 1328241SJeff.Bonwick@Sun.COM (void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0, 1338241SJeff.Bonwick@Sun.COM kcred, NULL); 134789Sahrens VN_RELE(vf->vf_vnode); 135789Sahrens } 136789Sahrens 137789Sahrens kmem_free(vf, sizeof (vdev_file_t)); 138789Sahrens vd->vdev_tsd = NULL; 139789Sahrens } 140789Sahrens 1415329Sgw25295 static int 142789Sahrens vdev_file_io_start(zio_t *zio) 143789Sahrens { 144789Sahrens vdev_t *vd = zio->io_vd; 145789Sahrens vdev_file_t *vf = vd->vdev_tsd; 146789Sahrens ssize_t resid; 147789Sahrens 148789Sahrens if (zio->io_type == ZIO_TYPE_IOCTL) { 149789Sahrens /* XXPOLICY */ 1505329Sgw25295 if (!vdev_readable(vd)) { 151789Sahrens zio->io_error = ENXIO; 1525530Sbonwick return (ZIO_PIPELINE_CONTINUE); 153789Sahrens } 154789Sahrens 155789Sahrens switch (zio->io_cmd) { 156789Sahrens case DKIOCFLUSHWRITECACHE: 157789Sahrens zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC, 1585331Samw kcred, NULL); 159789Sahrens break; 160789Sahrens default: 161789Sahrens zio->io_error = ENOTSUP; 162789Sahrens } 163789Sahrens 1645530Sbonwick return (ZIO_PIPELINE_CONTINUE); 165789Sahrens } 166789Sahrens 167789Sahrens zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ? 168789Sahrens UIO_READ : UIO_WRITE, vf->vf_vnode, zio->io_data, 169789Sahrens zio->io_size, zio->io_offset, UIO_SYSSPACE, 170789Sahrens 0, RLIM64_INFINITY, kcred, &resid); 171789Sahrens 172789Sahrens if (resid != 0 && zio->io_error == 0) 173789Sahrens zio->io_error = ENOSPC; 174789Sahrens 1755530Sbonwick zio_interrupt(zio); 1765530Sbonwick 1775530Sbonwick return (ZIO_PIPELINE_STOP); 178789Sahrens } 179789Sahrens 1807754SJeff.Bonwick@Sun.COM /* ARGSUSED */ 1817754SJeff.Bonwick@Sun.COM static void 182789Sahrens vdev_file_io_done(zio_t *zio) 183789Sahrens { 184789Sahrens } 185789Sahrens 186789Sahrens vdev_ops_t vdev_file_ops = { 187789Sahrens vdev_file_open, 188789Sahrens vdev_file_close, 189789Sahrens vdev_default_asize, 190789Sahrens vdev_file_io_start, 191789Sahrens vdev_file_io_done, 192789Sahrens NULL, 193*11958SGeorge.Wilson@Sun.COM vdev_file_hold, 194*11958SGeorge.Wilson@Sun.COM vdev_file_rele, 195789Sahrens VDEV_TYPE_FILE, /* name of this vdev type */ 196789Sahrens B_TRUE /* leaf vdev */ 197789Sahrens }; 198789Sahrens 199789Sahrens /* 200789Sahrens * From userland we access disks just like files. 201789Sahrens */ 202789Sahrens #ifndef _KERNEL 203789Sahrens 204789Sahrens vdev_ops_t vdev_disk_ops = { 205789Sahrens vdev_file_open, 206789Sahrens vdev_file_close, 207789Sahrens vdev_default_asize, 208789Sahrens vdev_file_io_start, 209789Sahrens vdev_file_io_done, 210789Sahrens NULL, 211*11958SGeorge.Wilson@Sun.COM vdev_file_hold, 212*11958SGeorge.Wilson@Sun.COM vdev_file_rele, 213789Sahrens VDEV_TYPE_DISK, /* name of this vdev type */ 214789Sahrens B_TRUE /* leaf vdev */ 215789Sahrens }; 216789Sahrens 217789Sahrens #endif 218