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. 23296510Smav * Copyright (c) 2011, 2015 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 132274619Ssmh vd->vdev_notrim = B_TRUE; 133274619Ssmh 134236155Smm *max_psize = *psize = vattr.va_size; 135254591Sgibbs *logical_ashift = SPA_MINBLOCKSHIFT; 136254591Sgibbs *physical_ashift = SPA_MINBLOCKSHIFT; 137168404Spjd 138168404Spjd return (0); 139168404Spjd} 140168404Spjd 141168404Spjdstatic void 142168404Spjdvdev_file_close(vdev_t *vd) 143168404Spjd{ 144168404Spjd vdev_file_t *vf = vd->vdev_tsd; 145168404Spjd 146219089Spjd if (vd->vdev_reopening || vf == NULL) 147168404Spjd return; 148168404Spjd 149219089Spjd if (vf->vf_vnode != NULL) { 150209962Smm (void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0, 151209962Smm kcred, NULL); 152219089Spjd } 153219089Spjd 154219089Spjd vd->vdev_delayed_close = B_FALSE; 155168404Spjd kmem_free(vf, sizeof (vdev_file_t)); 156168404Spjd vd->vdev_tsd = NULL; 157168404Spjd} 158168404Spjd 159274304Sdelphijstatic void 160168404Spjdvdev_file_io_start(zio_t *zio) 161168404Spjd{ 162168404Spjd vdev_t *vd = zio->io_vd; 163226617Spjd vdev_file_t *vf; 164226617Spjd vnode_t *vp; 165168404Spjd ssize_t resid; 166168404Spjd 167226617Spjd if (!vdev_readable(vd)) { 168249195Smm zio->io_error = SET_ERROR(ENXIO); 169269407Ssmh zio_interrupt(zio); 170274304Sdelphij return; 171226617Spjd } 172226617Spjd 173226617Spjd vf = vd->vdev_tsd; 174226617Spjd vp = vf->vf_vnode; 175226617Spjd 176168404Spjd if (zio->io_type == ZIO_TYPE_IOCTL) { 177168404Spjd switch (zio->io_cmd) { 178168404Spjd case DKIOCFLUSHWRITECACHE: 179185319Spjd zio->io_error = VOP_FSYNC(vp, FSYNC | FDSYNC, 180185029Spjd kcred, NULL); 181168404Spjd break; 182168404Spjd default: 183249195Smm zio->io_error = SET_ERROR(ENOTSUP); 184168404Spjd } 185168404Spjd 186274304Sdelphij zio_execute(zio); 187274304Sdelphij return; 188168404Spjd } 189168404Spjd 190274619Ssmh ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE); 191296510Smav zio->io_target_timestamp = zio_handle_io_delay(zio); 192274619Ssmh 193168404Spjd zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ? 194185319Spjd UIO_READ : UIO_WRITE, vp, zio->io_data, zio->io_size, 195185319Spjd zio->io_offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid); 196168404Spjd 197168404Spjd if (resid != 0 && zio->io_error == 0) 198168404Spjd zio->io_error = ENOSPC; 199168404Spjd 200296510Smav zio_delay_interrupt(zio); 201185029Spjd 202274304Sdelphij#ifdef illumos 203274304Sdelphij VERIFY3U(taskq_dispatch(system_taskq, vdev_file_io_strategy, bp, 204274304Sdelphij TQ_SLEEP), !=, 0); 205274304Sdelphij#endif 206168404Spjd} 207168404Spjd 208185029Spjd/* ARGSUSED */ 209168404Spjdstatic void 210168404Spjdvdev_file_io_done(zio_t *zio) 211168404Spjd{ 212168404Spjd} 213168404Spjd 214168404Spjdvdev_ops_t vdev_file_ops = { 215168404Spjd vdev_file_open, 216168404Spjd vdev_file_close, 217168404Spjd vdev_default_asize, 218168404Spjd vdev_file_io_start, 219168404Spjd vdev_file_io_done, 220168404Spjd NULL, 221219089Spjd vdev_file_hold, 222219089Spjd vdev_file_rele, 223168404Spjd VDEV_TYPE_FILE, /* name of this vdev type */ 224168404Spjd B_TRUE /* leaf vdev */ 225168404Spjd}; 226168404Spjd 227168404Spjd/* 228168404Spjd * From userland we access disks just like files. 229168404Spjd */ 230168404Spjd#ifndef _KERNEL 231168404Spjd 232168404Spjdvdev_ops_t vdev_disk_ops = { 233168404Spjd vdev_file_open, 234168404Spjd vdev_file_close, 235168404Spjd vdev_default_asize, 236168404Spjd vdev_file_io_start, 237168404Spjd vdev_file_io_done, 238168404Spjd NULL, 239219089Spjd vdev_file_hold, 240219089Spjd vdev_file_rele, 241168404Spjd VDEV_TYPE_DISK, /* name of this vdev type */ 242168404Spjd B_TRUE /* leaf vdev */ 243168404Spjd}; 244168404Spjd 245168404Spjd#endif 246