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*10850SGeorge.Wilson@Sun.COM * Copyright 2009 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 54*10850SGeorge.Wilson@Sun.COM /* 55*10850SGeorge.Wilson@Sun.COM * Reopen the device if it's not currently open. Otherwise, 56*10850SGeorge.Wilson@Sun.COM * just update the physical size of the device. 57*10850SGeorge.Wilson@Sun.COM */ 58*10850SGeorge.Wilson@Sun.COM if (vd->vdev_tsd != NULL) { 59*10850SGeorge.Wilson@Sun.COM ASSERT(vd->vdev_reopening); 60*10850SGeorge.Wilson@Sun.COM vf = vd->vdev_tsd; 61*10850SGeorge.Wilson@Sun.COM goto skip_open; 62*10850SGeorge.Wilson@Sun.COM } 63*10850SGeorge.Wilson@Sun.COM 64789Sahrens vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); 65789Sahrens 66789Sahrens /* 67789Sahrens * We always open the files from the root of the global zone, even if 68789Sahrens * we're in a local zone. If the user has gotten to this point, the 69789Sahrens * administrator has already decided that the pool should be available 70789Sahrens * to local zone users, so the underlying devices should be as well. 71789Sahrens */ 72789Sahrens ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); 735329Sgw25295 error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, 748241SJeff.Bonwick@Sun.COM spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir, -1); 75789Sahrens 76789Sahrens if (error) { 77789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 78789Sahrens return (error); 79789Sahrens } 80789Sahrens 81789Sahrens vf->vf_vnode = vp; 82789Sahrens 83789Sahrens #ifdef _KERNEL 84789Sahrens /* 85789Sahrens * Make sure it's a regular file. 86789Sahrens */ 87789Sahrens if (vp->v_type != VREG) { 88789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 89789Sahrens return (ENODEV); 90789Sahrens } 91789Sahrens #endif 92*10850SGeorge.Wilson@Sun.COM 93*10850SGeorge.Wilson@Sun.COM skip_open: 94789Sahrens /* 95789Sahrens * Determine the physical size of the file. 96789Sahrens */ 97789Sahrens vattr.va_mask = AT_SIZE; 985331Samw error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL); 99789Sahrens if (error) { 100789Sahrens vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 101789Sahrens return (error); 102789Sahrens } 103789Sahrens 104789Sahrens *psize = vattr.va_size; 105789Sahrens *ashift = SPA_MINBLOCKSHIFT; 106789Sahrens 107789Sahrens return (0); 108789Sahrens } 109789Sahrens 110789Sahrens static void 111789Sahrens vdev_file_close(vdev_t *vd) 112789Sahrens { 113789Sahrens vdev_file_t *vf = vd->vdev_tsd; 114789Sahrens 115*10850SGeorge.Wilson@Sun.COM if (vd->vdev_reopening || vf == NULL) 116789Sahrens return; 117789Sahrens 118789Sahrens if (vf->vf_vnode != NULL) { 1195331Samw (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL); 1208241SJeff.Bonwick@Sun.COM (void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0, 1218241SJeff.Bonwick@Sun.COM kcred, NULL); 122789Sahrens VN_RELE(vf->vf_vnode); 123789Sahrens } 124789Sahrens 125789Sahrens kmem_free(vf, sizeof (vdev_file_t)); 126789Sahrens vd->vdev_tsd = NULL; 127789Sahrens } 128789Sahrens 1295329Sgw25295 static int 130789Sahrens vdev_file_io_start(zio_t *zio) 131789Sahrens { 132789Sahrens vdev_t *vd = zio->io_vd; 133789Sahrens vdev_file_t *vf = vd->vdev_tsd; 134789Sahrens ssize_t resid; 135789Sahrens 136789Sahrens if (zio->io_type == ZIO_TYPE_IOCTL) { 137789Sahrens /* XXPOLICY */ 1385329Sgw25295 if (!vdev_readable(vd)) { 139789Sahrens zio->io_error = ENXIO; 1405530Sbonwick return (ZIO_PIPELINE_CONTINUE); 141789Sahrens } 142789Sahrens 143789Sahrens switch (zio->io_cmd) { 144789Sahrens case DKIOCFLUSHWRITECACHE: 145789Sahrens zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC, 1465331Samw kcred, NULL); 147789Sahrens break; 148789Sahrens default: 149789Sahrens zio->io_error = ENOTSUP; 150789Sahrens } 151789Sahrens 1525530Sbonwick return (ZIO_PIPELINE_CONTINUE); 153789Sahrens } 154789Sahrens 155789Sahrens zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ? 156789Sahrens UIO_READ : UIO_WRITE, vf->vf_vnode, zio->io_data, 157789Sahrens zio->io_size, zio->io_offset, UIO_SYSSPACE, 158789Sahrens 0, RLIM64_INFINITY, kcred, &resid); 159789Sahrens 160789Sahrens if (resid != 0 && zio->io_error == 0) 161789Sahrens zio->io_error = ENOSPC; 162789Sahrens 1635530Sbonwick zio_interrupt(zio); 1645530Sbonwick 1655530Sbonwick return (ZIO_PIPELINE_STOP); 166789Sahrens } 167789Sahrens 1687754SJeff.Bonwick@Sun.COM /* ARGSUSED */ 1697754SJeff.Bonwick@Sun.COM static void 170789Sahrens vdev_file_io_done(zio_t *zio) 171789Sahrens { 172789Sahrens } 173789Sahrens 174789Sahrens vdev_ops_t vdev_file_ops = { 175789Sahrens vdev_file_open, 176789Sahrens vdev_file_close, 177789Sahrens vdev_default_asize, 178789Sahrens vdev_file_io_start, 179789Sahrens vdev_file_io_done, 180789Sahrens NULL, 181789Sahrens VDEV_TYPE_FILE, /* name of this vdev type */ 182789Sahrens B_TRUE /* leaf vdev */ 183789Sahrens }; 184789Sahrens 185789Sahrens /* 186789Sahrens * From userland we access disks just like files. 187789Sahrens */ 188789Sahrens #ifndef _KERNEL 189789Sahrens 190789Sahrens vdev_ops_t vdev_disk_ops = { 191789Sahrens vdev_file_open, 192789Sahrens vdev_file_close, 193789Sahrens vdev_default_asize, 194789Sahrens vdev_file_io_start, 195789Sahrens vdev_file_io_done, 196789Sahrens NULL, 197789Sahrens VDEV_TYPE_DISK, /* name of this vdev type */ 198789Sahrens B_TRUE /* leaf vdev */ 199789Sahrens }; 200789Sahrens 201789Sahrens #endif 202