FreeBSD ZFS
The Zettabyte File System
|
00001 /* 00002 * CDDL HEADER START 00003 * 00004 * The contents of this file are subject to the terms of the 00005 * Common Development and Distribution License (the "License"). 00006 * You may not use this file except in compliance with the License. 00007 * 00008 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 00009 * or http://www.opensolaris.org/os/licensing. 00010 * See the License for the specific language governing permissions 00011 * and limitations under the License. 00012 * 00013 * When distributing Covered Code, include this CDDL HEADER in each 00014 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 00015 * If applicable, add the following below this CDDL HEADER, with the 00016 * fields enclosed by brackets "[]" replaced with your own identifying 00017 * information: Portions Copyright [yyyy] [name of copyright owner] 00018 * 00019 * CDDL HEADER END 00020 */ 00021 /* 00022 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 00023 * Copyright (c) 2012 by Delphix. All rights reserved. 00024 */ 00025 00026 #include <sys/zfs_context.h> 00027 #include <sys/spa.h> 00028 #include <sys/vdev_file.h> 00029 #include <sys/vdev_impl.h> 00030 #include <sys/zio.h> 00031 #include <sys/fs/zfs.h> 00032 #include <sys/fm/fs/zfs.h> 00033 00039 static void 00040 vdev_file_hold(vdev_t *vd) 00041 { 00042 ASSERT(vd->vdev_path != NULL); 00043 } 00044 00045 static void 00046 vdev_file_rele(vdev_t *vd) 00047 { 00048 ASSERT(vd->vdev_path != NULL); 00049 } 00050 00051 static int 00052 vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, 00053 uint64_t *ashift) 00054 { 00055 vdev_file_t *vf; 00056 vnode_t *vp; 00057 vattr_t vattr; 00058 int error; 00059 00060 /* 00061 * We must have a pathname, and it must be absolute. 00062 */ 00063 if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { 00064 vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 00065 return (EINVAL); 00066 } 00067 00068 /* 00069 * Reopen the device if it's not currently open. Otherwise, 00070 * just update the physical size of the device. 00071 */ 00072 if (vd->vdev_tsd != NULL) { 00073 ASSERT(vd->vdev_reopening); 00074 vf = vd->vdev_tsd; 00075 vp = vf->vf_vnode; 00076 goto skip_open; 00077 } 00078 00079 vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); 00080 00081 /* 00082 * We always open the files from the root of the global zone, even if 00083 * we're in a local zone. If the user has gotten to this point, the 00084 * administrator has already decided that the pool should be available 00085 * to local zone users, so the underlying devices should be as well. 00086 */ 00087 ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); 00088 error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, 00089 spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir, -1); 00090 00091 if (error) { 00092 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 00093 kmem_free(vd->vdev_tsd, sizeof (vdev_file_t)); 00094 vd->vdev_tsd = NULL; 00095 return (error); 00096 } 00097 00098 vf->vf_vnode = vp; 00099 00100 #ifdef _KERNEL 00101 /* 00102 * Make sure it's a regular file. 00103 */ 00104 if (vp->v_type != VREG) { 00105 (void) VOP_CLOSE(vp, spa_mode(vd->vdev_spa), 1, 0, kcred, NULL); 00106 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 00107 kmem_free(vd->vdev_tsd, sizeof (vdev_file_t)); 00108 vd->vdev_tsd = NULL; 00109 return (ENODEV); 00110 } 00111 #endif 00112 00113 skip_open: 00114 /* 00115 * Determine the physical size of the file. 00116 */ 00117 vattr.va_mask = AT_SIZE; 00118 vn_lock(vp, LK_SHARED | LK_RETRY); 00119 error = VOP_GETATTR(vp, &vattr, kcred); 00120 VOP_UNLOCK(vp, 0); 00121 if (error) { 00122 (void) VOP_CLOSE(vp, spa_mode(vd->vdev_spa), 1, 0, kcred, NULL); 00123 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 00124 kmem_free(vd->vdev_tsd, sizeof (vdev_file_t)); 00125 vd->vdev_tsd = NULL; 00126 return (error); 00127 } 00128 00129 *max_psize = *psize = vattr.va_size; 00130 *ashift = SPA_MINBLOCKSHIFT; 00131 00132 return (0); 00133 } 00134 00135 static void 00136 vdev_file_close(vdev_t *vd) 00137 { 00138 vdev_file_t *vf = vd->vdev_tsd; 00139 00140 if (vd->vdev_reopening || vf == NULL) 00141 return; 00142 00143 if (vf->vf_vnode != NULL) { 00144 (void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0, 00145 kcred, NULL); 00146 } 00147 00148 vd->vdev_delayed_close = B_FALSE; 00149 kmem_free(vf, sizeof (vdev_file_t)); 00150 vd->vdev_tsd = NULL; 00151 } 00152 00153 static int 00154 vdev_file_io_start(zio_t *zio) 00155 { 00156 vdev_t *vd = zio->io_vd; 00157 vdev_file_t *vf; 00158 vnode_t *vp; 00159 ssize_t resid; 00160 00161 if (!vdev_readable(vd)) { 00162 zio->io_error = ENXIO; 00163 return (ZIO_PIPELINE_CONTINUE); 00164 } 00165 00166 vf = vd->vdev_tsd; 00167 vp = vf->vf_vnode; 00168 00169 if (zio->io_type == ZIO_TYPE_IOCTL) { 00170 switch (zio->io_cmd) { 00171 case DKIOCFLUSHWRITECACHE: 00172 zio->io_error = VOP_FSYNC(vp, FSYNC | FDSYNC, 00173 kcred, NULL); 00174 break; 00175 default: 00176 zio->io_error = ENOTSUP; 00177 } 00178 00179 return (ZIO_PIPELINE_CONTINUE); 00180 } 00181 00182 zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ? 00183 UIO_READ : UIO_WRITE, vp, zio->io_data, zio->io_size, 00184 zio->io_offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid); 00185 00186 if (resid != 0 && zio->io_error == 0) 00187 zio->io_error = ENOSPC; 00188 00189 zio_interrupt(zio); 00190 00191 return (ZIO_PIPELINE_STOP); 00192 } 00193 00194 /* ARGSUSED */ 00195 static void 00196 vdev_file_io_done(zio_t *zio) 00197 { 00198 } 00199 00200 vdev_ops_t vdev_file_ops = { 00201 vdev_file_open, 00202 vdev_file_close, 00203 vdev_default_asize, 00204 vdev_file_io_start, 00205 vdev_file_io_done, 00206 NULL, 00207 vdev_file_hold, 00208 vdev_file_rele, 00209 VDEV_TYPE_FILE, /* name of this vdev type */ 00210 B_TRUE /* leaf vdev */ 00211 }; 00212 00213 /* 00214 * From userland we access disks just like files. 00215 */ 00216 #ifndef _KERNEL 00217 00218 vdev_ops_t vdev_disk_ops = { 00219 vdev_file_open, 00220 vdev_file_close, 00221 vdev_default_asize, 00222 vdev_file_io_start, 00223 vdev_file_io_done, 00224 NULL, 00225 vdev_file_hold, 00226 vdev_file_rele, 00227 VDEV_TYPE_DISK, /* name of this vdev type */ 00228 B_TRUE /* leaf vdev */ 00229 }; 00230 00231 #endif