vdev_file.c revision 209962
1234353Sdim/* 2204642Srdivacky * CDDL HEADER START 3204642Srdivacky * 4204642Srdivacky * The contents of this file are subject to the terms of the 5204642Srdivacky * Common Development and Distribution License (the "License"). 6204642Srdivacky * You may not use this file except in compliance with the License. 7204642Srdivacky * 8204642Srdivacky * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9204642Srdivacky * or http://www.opensolaris.org/os/licensing. 10204642Srdivacky * See the License for the specific language governing permissions 11204642Srdivacky * and limitations under the License. 12204642Srdivacky * 13204642Srdivacky * When distributing Covered Code, include this CDDL HEADER in each 14204642Srdivacky * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15204642Srdivacky * If applicable, add the following below this CDDL HEADER, with the 16204642Srdivacky * fields enclosed by brackets "[]" replaced with your own identifying 17218893Sdim * information: Portions Copyright [yyyy] [name of copyright owner] 18204642Srdivacky * 19249423Sdim * CDDL HEADER END 20204642Srdivacky */ 21204642Srdivacky/* 22204642Srdivacky * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23204642Srdivacky * Use is subject to license terms. 24204642Srdivacky */ 25204642Srdivacky 26204642Srdivacky#include <sys/zfs_context.h> 27234353Sdim#include <sys/spa.h> 28204642Srdivacky#include <sys/vdev_file.h> 29218893Sdim#include <sys/vdev_impl.h> 30204642Srdivacky#include <sys/zio.h> 31204642Srdivacky#include <sys/fs/zfs.h> 32204642Srdivacky#include <sys/fm/fs/zfs.h> 33218893Sdim 34204642Srdivacky/* 35204642Srdivacky * Virtual device vector for files. 36204642Srdivacky */ 37204642Srdivacky 38204642Srdivackystatic int 39204642Srdivackyvdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift) 40204642Srdivacky{ 41204642Srdivacky vdev_file_t *vf; 42204642Srdivacky vnode_t *vp; 43204642Srdivacky vattr_t vattr; 44204642Srdivacky int error, vfslocked; 45204642Srdivacky 46204642Srdivacky /* 47218893Sdim * We must have a pathname, and it must be absolute. 48218893Sdim */ 49218893Sdim if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { 50204642Srdivacky vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 51204642Srdivacky return (EINVAL); 52204642Srdivacky } 53204642Srdivacky 54218893Sdim vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); 55218893Sdim 56204642Srdivacky /* 57204642Srdivacky * We always open the files from the root of the global zone, even if 58204642Srdivacky * we're in a local zone. If the user has gotten to this point, the 59218893Sdim * administrator has already decided that the pool should be available 60218893Sdim * to local zone users, so the underlying devices should be as well. 61204642Srdivacky */ 62218893Sdim ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); 63204642Srdivacky error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, 64204642Srdivacky spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir, -1); 65204642Srdivacky 66218893Sdim if (error) { 67218893Sdim vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 68218893Sdim return (error); 69218893Sdim } 70218893Sdim 71204642Srdivacky vf->vf_vnode = vp; 72204642Srdivacky 73204642Srdivacky#ifdef _KERNEL 74204642Srdivacky /* 75204642Srdivacky * Make sure it's a regular file. 76204642Srdivacky */ 77204642Srdivacky if (vp->v_type != VREG) { 78204642Srdivacky (void) VOP_CLOSE(vp, spa_mode(vd->vdev_spa), 1, 0, kcred, NULL); 79204642Srdivacky vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 80204642Srdivacky return (ENODEV); 81207618Srdivacky } 82207618Srdivacky#endif 83207618Srdivacky /* 84218893Sdim * Determine the physical size of the file. 85218893Sdim */ 86218893Sdim vattr.va_mask = AT_SIZE; 87218893Sdim vfslocked = VFS_LOCK_GIANT(vp->v_mount); 88204642Srdivacky vn_lock(vp, LK_SHARED | LK_RETRY); 89218893Sdim error = VOP_GETATTR(vp, &vattr, kcred); 90218893Sdim VOP_UNLOCK(vp, 0); 91218893Sdim VFS_UNLOCK_GIANT(vfslocked); 92218893Sdim if (error) { 93204642Srdivacky (void) VOP_CLOSE(vp, spa_mode(vd->vdev_spa), 1, 0, kcred, NULL); 94204642Srdivacky vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 95204642Srdivacky return (error); 96204642Srdivacky } 97204642Srdivacky 98204642Srdivacky *psize = vattr.va_size; 99204642Srdivacky *ashift = SPA_MINBLOCKSHIFT; 100204642Srdivacky 101204642Srdivacky return (0); 102204642Srdivacky} 103204642Srdivacky 104204642Srdivackystatic void 105204642Srdivackyvdev_file_close(vdev_t *vd) 106204642Srdivacky{ 107204642Srdivacky vdev_file_t *vf = vd->vdev_tsd; 108218893Sdim 109204642Srdivacky if (vf == NULL) 110218893Sdim return; 111218893Sdim 112218893Sdim if (vf->vf_vnode != NULL) 113218893Sdim (void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0, 114218893Sdim kcred, NULL); 115218893Sdim kmem_free(vf, sizeof (vdev_file_t)); 116218893Sdim vd->vdev_tsd = NULL; 117218893Sdim} 118218893Sdim 119218893Sdimstatic int 120218893Sdimvdev_file_io_start(zio_t *zio) 121218893Sdim{ 122218893Sdim vdev_t *vd = zio->io_vd; 123218893Sdim vdev_file_t *vf = vd->vdev_tsd; 124218893Sdim vnode_t *vp = vf->vf_vnode; 125218893Sdim ssize_t resid; 126218893Sdim 127218893Sdim if (zio->io_type == ZIO_TYPE_IOCTL) { 128218893Sdim /* XXPOLICY */ 129218893Sdim if (!vdev_readable(vd)) { 130218893Sdim zio->io_error = ENXIO; 131218893Sdim return (ZIO_PIPELINE_CONTINUE); 132218893Sdim } 133218893Sdim 134218893Sdim switch (zio->io_cmd) { 135204642Srdivacky case DKIOCFLUSHWRITECACHE: 136204642Srdivacky zio->io_error = VOP_FSYNC(vp, FSYNC | FDSYNC, 137204642Srdivacky kcred, NULL); 138204642Srdivacky break; 139218893Sdim default: 140204642Srdivacky zio->io_error = ENOTSUP; 141204642Srdivacky } 142204642Srdivacky 143204642Srdivacky return (ZIO_PIPELINE_CONTINUE); 144204642Srdivacky } 145204642Srdivacky 146204642Srdivacky zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ? 147218893Sdim UIO_READ : UIO_WRITE, vp, zio->io_data, zio->io_size, 148218893Sdim zio->io_offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid); 149204642Srdivacky 150218893Sdim if (resid != 0 && zio->io_error == 0) 151204642Srdivacky zio->io_error = ENOSPC; 152218893Sdim 153218893Sdim zio_interrupt(zio); 154218893Sdim 155204642Srdivacky return (ZIO_PIPELINE_STOP); 156204642Srdivacky} 157204642Srdivacky 158204642Srdivacky/* ARGSUSED */ 159204642Srdivackystatic void 160204642Srdivackyvdev_file_io_done(zio_t *zio) 161204642Srdivacky{ 162207618Srdivacky} 163207618Srdivacky 164207618Srdivackyvdev_ops_t vdev_file_ops = { 165204642Srdivacky vdev_file_open, 166204642Srdivacky vdev_file_close, 167204642Srdivacky vdev_default_asize, 168204642Srdivacky vdev_file_io_start, 169204642Srdivacky vdev_file_io_done, 170 NULL, 171 VDEV_TYPE_FILE, /* name of this vdev type */ 172 B_TRUE /* leaf vdev */ 173}; 174 175/* 176 * From userland we access disks just like files. 177 */ 178#ifndef _KERNEL 179 180vdev_ops_t vdev_disk_ops = { 181 vdev_file_open, 182 vdev_file_close, 183 vdev_default_asize, 184 vdev_file_io_start, 185 vdev_file_io_done, 186 NULL, 187 VDEV_TYPE_DISK, /* name of this vdev type */ 188 B_TRUE /* leaf vdev */ 189}; 190 191#endif 192