1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or https://opensource.org/licenses/CDDL-1.0. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2011, 2020 by Delphix. All rights reserved. 24 */ 25 26 #include <sys/zfs_context.h> 27 #include <sys/spa.h> 28 #include <sys/file.h> 29 #include <sys/vdev_file.h> 30 #include <sys/vdev_impl.h> 31 #include <sys/zio.h> 32 #include <sys/fs/zfs.h> 33 #include <sys/fm/fs/zfs.h> 34 #include <sys/abd.h> 35 #include <sys/stat.h> 36 37 /* 38 * Virtual device vector for files. 39 */ 40 41 static taskq_t *vdev_file_taskq; 42 43 static uint_t vdev_file_logical_ashift = SPA_MINBLOCKSHIFT; 44 static uint_t vdev_file_physical_ashift = SPA_MINBLOCKSHIFT; 45 46 void 47 vdev_file_init(void) 48 { 49 vdev_file_taskq = taskq_create("z_vdev_file", MAX(max_ncpus, 16), 50 minclsyspri, max_ncpus, INT_MAX, 0); 51 } 52 53 void 54 vdev_file_fini(void) 55 { 56 taskq_destroy(vdev_file_taskq); 57 } 58 59 static void 60 vdev_file_hold(vdev_t *vd) 61 { 62 ASSERT3P(vd->vdev_path, !=, NULL); 63 } 64 65 static void 66 vdev_file_rele(vdev_t *vd) 67 { 68 ASSERT3P(vd->vdev_path, !=, NULL); 69 } 70 71 static mode_t 72 vdev_file_open_mode(spa_mode_t spa_mode) 73 { 74 mode_t mode = 0; 75 76 if ((spa_mode & SPA_MODE_READ) && (spa_mode & SPA_MODE_WRITE)) { 77 mode = O_RDWR; 78 } else if (spa_mode & SPA_MODE_READ) { 79 mode = O_RDONLY; 80 } else if (spa_mode & SPA_MODE_WRITE) { 81 mode = O_WRONLY; 82 } 83 84 return (mode | O_LARGEFILE); 85 } 86 87 static int 88 vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, 89 uint64_t *logical_ashift, uint64_t *physical_ashift) 90 { 91 vdev_file_t *vf; 92 zfs_file_t *fp; 93 zfs_file_attr_t zfa; 94 int error; 95 96 /* 97 * Rotational optimizations only make sense on block devices. 98 */ 99 vd->vdev_nonrot = B_TRUE; 100 101 /* 102 * Allow TRIM on file based vdevs. This may not always be supported, 103 * since it depends on your kernel version and underlying filesystem 104 * type but it is always safe to attempt. 105 */ 106 vd->vdev_has_trim = B_TRUE; 107 108 /* 109 * Disable secure TRIM on file based vdevs. There is no way to 110 * request this behavior from the underlying filesystem. 111 */ 112 vd->vdev_has_securetrim = B_FALSE; 113 114 /* 115 * We must have a pathname, and it must be absolute. 116 */ 117 if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') { 118 vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; 119 return (SET_ERROR(EINVAL)); 120 } 121 122 /* 123 * Reopen the device if it's not currently open. Otherwise, 124 * just update the physical size of the device. 125 */ 126 if (vd->vdev_tsd != NULL) { 127 ASSERT(vd->vdev_reopening); 128 vf = vd->vdev_tsd; 129 goto skip_open; 130 } 131 132 vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); 133 134 /* 135 * We always open the files from the root of the global zone, even if 136 * we're in a local zone. If the user has gotten to this point, the 137 * administrator has already decided that the pool should be available 138 * to local zone users, so the underlying devices should be as well. 139 */ 140 ASSERT3P(vd->vdev_path, !=, NULL); 141 ASSERT(vd->vdev_path[0] == '/'); 142 143 error = zfs_file_open(vd->vdev_path, 144 vdev_file_open_mode(spa_mode(vd->vdev_spa)), 0, &fp); 145 if (error) { 146 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 147 return (error); 148 } 149 150 vf->vf_file = fp; 151 152 #ifdef _KERNEL 153 /* 154 * Make sure it's a regular file. 155 */ 156 if (zfs_file_getattr(fp, &zfa)) { 157 return (SET_ERROR(ENODEV)); 158 } 159 if (!S_ISREG(zfa.zfa_mode)) { 160 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 161 return (SET_ERROR(ENODEV)); 162 } 163 #endif 164 165 skip_open: 166 167 error = zfs_file_getattr(vf->vf_file, &zfa); 168 if (error) { 169 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 170 return (error); 171 } 172 173 *max_psize = *psize = zfa.zfa_size; 174 *logical_ashift = vdev_file_logical_ashift; 175 *physical_ashift = vdev_file_physical_ashift; 176 177 return (0); 178 } 179 180 static void 181 vdev_file_close(vdev_t *vd) 182 { 183 vdev_file_t *vf = vd->vdev_tsd; 184 185 if (vd->vdev_reopening || vf == NULL) 186 return; 187 188 if (vf->vf_file != NULL) { 189 zfs_file_close(vf->vf_file); 190 } 191 192 vd->vdev_delayed_close = B_FALSE; 193 kmem_free(vf, sizeof (vdev_file_t)); 194 vd->vdev_tsd = NULL; 195 } 196 197 /* 198 * Implements the interrupt side for file vdev types. This routine will be 199 * called when the I/O completes allowing us to transfer the I/O to the 200 * interrupt taskqs. For consistency, the code structure mimics disk vdev 201 * types. 202 */ 203 static void 204 vdev_file_io_intr(zio_t *zio) 205 { 206 zio_delay_interrupt(zio); 207 } 208 209 static void 210 vdev_file_io_strategy(void *arg) 211 { 212 zio_t *zio = arg; 213 vdev_t *vd = zio->io_vd; 214 vdev_file_t *vf; 215 void *buf; 216 ssize_t resid; 217 loff_t off; 218 ssize_t size; 219 int err; 220 221 off = zio->io_offset; 222 size = zio->io_size; 223 resid = 0; 224 225 vf = vd->vdev_tsd; 226 227 ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE); 228 if (zio->io_type == ZIO_TYPE_READ) { 229 buf = abd_borrow_buf(zio->io_abd, zio->io_size); 230 err = zfs_file_pread(vf->vf_file, buf, size, off, &resid); 231 abd_return_buf_copy(zio->io_abd, buf, size); 232 } else { 233 buf = abd_borrow_buf_copy(zio->io_abd, zio->io_size); 234 err = zfs_file_pwrite(vf->vf_file, buf, size, off, &resid); 235 abd_return_buf(zio->io_abd, buf, size); 236 } 237 zio->io_error = err; 238 if (resid != 0 && zio->io_error == 0) 239 zio->io_error = ENOSPC; 240 241 vdev_file_io_intr(zio); 242 } 243 244 static void 245 vdev_file_io_start(zio_t *zio) 246 { 247 vdev_t *vd = zio->io_vd; 248 vdev_file_t *vf = vd->vdev_tsd; 249 250 if (zio->io_type == ZIO_TYPE_FLUSH) { 251 /* XXPOLICY */ 252 if (!vdev_readable(vd)) { 253 zio->io_error = SET_ERROR(ENXIO); 254 zio_interrupt(zio); 255 return; 256 } 257 258 zio->io_error = zfs_file_fsync(vf->vf_file, O_SYNC|O_DSYNC); 259 260 zio_execute(zio); 261 return; 262 } else if (zio->io_type == ZIO_TYPE_TRIM) { 263 #ifdef notyet 264 int mode = 0; 265 266 ASSERT3U(zio->io_size, !=, 0); 267 268 /* XXX FreeBSD has no fallocate routine in file ops */ 269 zio->io_error = zfs_file_fallocate(vf->vf_file, 270 mode, zio->io_offset, zio->io_size); 271 #endif 272 zio->io_error = SET_ERROR(ENOTSUP); 273 zio_execute(zio); 274 return; 275 } 276 ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE); 277 zio->io_target_timestamp = zio_handle_io_delay(zio); 278 279 VERIFY3U(taskq_dispatch(vdev_file_taskq, vdev_file_io_strategy, zio, 280 TQ_SLEEP), !=, 0); 281 } 282 283 static void 284 vdev_file_io_done(zio_t *zio) 285 { 286 (void) zio; 287 } 288 289 vdev_ops_t vdev_file_ops = { 290 .vdev_op_init = NULL, 291 .vdev_op_fini = NULL, 292 .vdev_op_open = vdev_file_open, 293 .vdev_op_close = vdev_file_close, 294 .vdev_op_asize = vdev_default_asize, 295 .vdev_op_min_asize = vdev_default_min_asize, 296 .vdev_op_min_alloc = NULL, 297 .vdev_op_io_start = vdev_file_io_start, 298 .vdev_op_io_done = vdev_file_io_done, 299 .vdev_op_state_change = NULL, 300 .vdev_op_need_resilver = NULL, 301 .vdev_op_hold = vdev_file_hold, 302 .vdev_op_rele = vdev_file_rele, 303 .vdev_op_remap = NULL, 304 .vdev_op_xlate = vdev_default_xlate, 305 .vdev_op_rebuild_asize = NULL, 306 .vdev_op_metaslab_init = NULL, 307 .vdev_op_config_generate = NULL, 308 .vdev_op_nparity = NULL, 309 .vdev_op_ndisks = NULL, 310 .vdev_op_type = VDEV_TYPE_FILE, /* name of this vdev type */ 311 .vdev_op_leaf = B_TRUE /* leaf vdev */ 312 }; 313 314 /* 315 * From userland we access disks just like files. 316 */ 317 #ifndef _KERNEL 318 319 vdev_ops_t vdev_disk_ops = { 320 .vdev_op_init = NULL, 321 .vdev_op_fini = NULL, 322 .vdev_op_open = vdev_file_open, 323 .vdev_op_close = vdev_file_close, 324 .vdev_op_asize = vdev_default_asize, 325 .vdev_op_min_asize = vdev_default_min_asize, 326 .vdev_op_min_alloc = NULL, 327 .vdev_op_io_start = vdev_file_io_start, 328 .vdev_op_io_done = vdev_file_io_done, 329 .vdev_op_state_change = NULL, 330 .vdev_op_need_resilver = NULL, 331 .vdev_op_hold = vdev_file_hold, 332 .vdev_op_rele = vdev_file_rele, 333 .vdev_op_remap = NULL, 334 .vdev_op_xlate = vdev_default_xlate, 335 .vdev_op_rebuild_asize = NULL, 336 .vdev_op_metaslab_init = NULL, 337 .vdev_op_config_generate = NULL, 338 .vdev_op_nparity = NULL, 339 .vdev_op_ndisks = NULL, 340 .vdev_op_type = VDEV_TYPE_DISK, /* name of this vdev type */ 341 .vdev_op_leaf = B_TRUE /* leaf vdev */ 342 }; 343 344 #endif 345 346 ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, logical_ashift, UINT, ZMOD_RW, 347 "Logical ashift for file-based devices"); 348 ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, physical_ashift, UINT, ZMOD_RW, 349 "Physical ashift for file-based devices"); 350