vdev_file.c revision 269407
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd/* 22219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23249195Smm * Copyright (c) 2013 by Delphix. All rights reserved. 24168404Spjd */ 25168404Spjd 26168404Spjd#include <sys/zfs_context.h> 27168404Spjd#include <sys/spa.h> 28168404Spjd#include <sys/vdev_file.h> 29168404Spjd#include <sys/vdev_impl.h> 30168404Spjd#include <sys/zio.h> 31168404Spjd#include <sys/fs/zfs.h> 32185029Spjd#include <sys/fm/fs/zfs.h> 33168404Spjd 34168404Spjd/* 35168404Spjd * Virtual device vector for files. 36168404Spjd */ 37168404Spjd 38219089Spjdstatic void 39219089Spjdvdev_file_hold(vdev_t *vd) 40219089Spjd{ 41219089Spjd ASSERT(vd->vdev_path != NULL); 42219089Spjd} 43219089Spjd 44219089Spjdstatic void 45219089Spjdvdev_file_rele(vdev_t *vd) 46219089Spjd{ 47219089Spjd ASSERT(vd->vdev_path != NULL); 48219089Spjd} 49219089Spjd 50168404Spjdstatic int 51236155Smmvdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, 52254591Sgibbs uint64_t *logical_ashift, uint64_t *physical_ashift) 53168404Spjd{ 54168404Spjd vdev_file_t *vf; 55168404Spjd vnode_t *vp; 56168404Spjd vattr_t vattr; 57241896Skib int error; 58168404Spjd 59168404Spjd /* 60168404Spjd * We must have a pathname, and it must be absolute. 61168404Spjd */ 62168404Spjd if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { 63168404Spjd vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 64249195Smm return (SET_ERROR(EINVAL)); 65168404Spjd } 66168404Spjd 67219089Spjd /* 68219089Spjd * Reopen the device if it's not currently open. Otherwise, 69219089Spjd * just update the physical size of the device. 70219089Spjd */ 71219089Spjd if (vd->vdev_tsd != NULL) { 72219089Spjd ASSERT(vd->vdev_reopening); 73219089Spjd vf = vd->vdev_tsd; 74219089Spjd vp = vf->vf_vnode; 75219089Spjd goto skip_open; 76219089Spjd } 77219089Spjd 78168404Spjd vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); 79168404Spjd 80168404Spjd /* 81168404Spjd * We always open the files from the root of the global zone, even if 82168404Spjd * we're in a local zone. If the user has gotten to this point, the 83168404Spjd * administrator has already decided that the pool should be available 84168404Spjd * to local zone users, so the underlying devices should be as well. 85168404Spjd */ 86168404Spjd ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); 87185029Spjd error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, 88209962Smm spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir, -1); 89168404Spjd 90168404Spjd if (error) { 91168404Spjd vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 92219089Spjd kmem_free(vd->vdev_tsd, sizeof (vdev_file_t)); 93219089Spjd vd->vdev_tsd = NULL; 94168404Spjd return (error); 95168404Spjd } 96168404Spjd 97168404Spjd vf->vf_vnode = vp; 98168404Spjd 99168404Spjd#ifdef _KERNEL 100168404Spjd /* 101168404Spjd * Make sure it's a regular file. 102168404Spjd */ 103168404Spjd if (vp->v_type != VREG) { 104249195Smm#ifdef __FreeBSD__ 105209962Smm (void) VOP_CLOSE(vp, spa_mode(vd->vdev_spa), 1, 0, kcred, NULL); 106249195Smm#endif 107168404Spjd vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 108249195Smm#ifdef __FreeBSD__ 109219089Spjd kmem_free(vd->vdev_tsd, sizeof (vdev_file_t)); 110219089Spjd vd->vdev_tsd = NULL; 111249195Smm#endif 112249195Smm return (SET_ERROR(ENODEV)); 113168404Spjd } 114249195Smm#endif /* _KERNEL */ 115219089Spjd 116219089Spjdskip_open: 117168404Spjd /* 118168404Spjd * Determine the physical size of the file. 119168404Spjd */ 120168404Spjd vattr.va_mask = AT_SIZE; 121185029Spjd vn_lock(vp, LK_SHARED | LK_RETRY); 122185029Spjd error = VOP_GETATTR(vp, &vattr, kcred); 123185029Spjd VOP_UNLOCK(vp, 0); 124168404Spjd if (error) { 125209962Smm (void) VOP_CLOSE(vp, spa_mode(vd->vdev_spa), 1, 0, kcred, NULL); 126168404Spjd vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 127219089Spjd kmem_free(vd->vdev_tsd, sizeof (vdev_file_t)); 128219089Spjd vd->vdev_tsd = NULL; 129168404Spjd return (error); 130168404Spjd } 131168404Spjd 132236155Smm *max_psize = *psize = vattr.va_size; 133254591Sgibbs *logical_ashift = SPA_MINBLOCKSHIFT; 134254591Sgibbs *physical_ashift = SPA_MINBLOCKSHIFT; 135168404Spjd 136168404Spjd return (0); 137168404Spjd} 138168404Spjd 139168404Spjdstatic void 140168404Spjdvdev_file_close(vdev_t *vd) 141168404Spjd{ 142168404Spjd vdev_file_t *vf = vd->vdev_tsd; 143168404Spjd 144219089Spjd if (vd->vdev_reopening || vf == NULL) 145168404Spjd return; 146168404Spjd 147219089Spjd if (vf->vf_vnode != NULL) { 148209962Smm (void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0, 149209962Smm kcred, NULL); 150219089Spjd } 151219089Spjd 152219089Spjd vd->vdev_delayed_close = B_FALSE; 153168404Spjd kmem_free(vf, sizeof (vdev_file_t)); 154168404Spjd vd->vdev_tsd = NULL; 155168404Spjd} 156168404Spjd 157185029Spjdstatic int 158168404Spjdvdev_file_io_start(zio_t *zio) 159168404Spjd{ 160168404Spjd vdev_t *vd = zio->io_vd; 161226617Spjd vdev_file_t *vf; 162226617Spjd vnode_t *vp; 163168404Spjd ssize_t resid; 164168404Spjd 165226617Spjd if (!vdev_readable(vd)) { 166249195Smm zio->io_error = SET_ERROR(ENXIO); 167269407Ssmh zio_interrupt(zio); 168269407Ssmh return (ZIO_PIPELINE_STOP); 169226617Spjd } 170226617Spjd 171226617Spjd vf = vd->vdev_tsd; 172226617Spjd vp = vf->vf_vnode; 173226617Spjd 174168404Spjd if (zio->io_type == ZIO_TYPE_IOCTL) { 175168404Spjd switch (zio->io_cmd) { 176168404Spjd case DKIOCFLUSHWRITECACHE: 177185319Spjd zio->io_error = VOP_FSYNC(vp, FSYNC | FDSYNC, 178185029Spjd kcred, NULL); 179168404Spjd break; 180168404Spjd default: 181249195Smm zio->io_error = SET_ERROR(ENOTSUP); 182168404Spjd } 183168404Spjd 184269407Ssmh zio_interrupt(zio); 185269407Ssmh return (ZIO_PIPELINE_STOP); 186168404Spjd } 187168404Spjd 188168404Spjd zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ? 189185319Spjd UIO_READ : UIO_WRITE, vp, zio->io_data, zio->io_size, 190185319Spjd zio->io_offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid); 191168404Spjd 192168404Spjd if (resid != 0 && zio->io_error == 0) 193168404Spjd zio->io_error = ENOSPC; 194168404Spjd 195185029Spjd zio_interrupt(zio); 196185029Spjd 197185029Spjd return (ZIO_PIPELINE_STOP); 198168404Spjd} 199168404Spjd 200185029Spjd/* ARGSUSED */ 201168404Spjdstatic void 202168404Spjdvdev_file_io_done(zio_t *zio) 203168404Spjd{ 204168404Spjd} 205168404Spjd 206168404Spjdvdev_ops_t vdev_file_ops = { 207168404Spjd vdev_file_open, 208168404Spjd vdev_file_close, 209168404Spjd vdev_default_asize, 210168404Spjd vdev_file_io_start, 211168404Spjd vdev_file_io_done, 212168404Spjd NULL, 213219089Spjd vdev_file_hold, 214219089Spjd vdev_file_rele, 215168404Spjd VDEV_TYPE_FILE, /* name of this vdev type */ 216168404Spjd B_TRUE /* leaf vdev */ 217168404Spjd}; 218168404Spjd 219168404Spjd/* 220168404Spjd * From userland we access disks just like files. 221168404Spjd */ 222168404Spjd#ifndef _KERNEL 223168404Spjd 224168404Spjdvdev_ops_t vdev_disk_ops = { 225168404Spjd vdev_file_open, 226168404Spjd vdev_file_close, 227168404Spjd vdev_default_asize, 228168404Spjd vdev_file_io_start, 229168404Spjd vdev_file_io_done, 230168404Spjd NULL, 231219089Spjd vdev_file_hold, 232219089Spjd vdev_file_rele, 233168404Spjd VDEV_TYPE_DISK, /* name of this vdev type */ 234168404Spjd B_TRUE /* leaf vdev */ 235168404Spjd}; 236168404Spjd 237168404Spjd#endif 238