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 http://www.opensolaris.org/os/licensing. 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 unsigned long vdev_file_logical_ashift = SPA_MINBLOCKSHIFT; 44 unsigned long 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 if (resid != 0 && zio->io_error == 0) 238 zio->io_error = ENOSPC; 239 240 vdev_file_io_intr(zio); 241 } 242 243 static void 244 vdev_file_io_start(zio_t *zio) 245 { 246 vdev_t *vd = zio->io_vd; 247 vdev_file_t *vf = vd->vdev_tsd; 248 249 if (zio->io_type == ZIO_TYPE_IOCTL) { 250 /* XXPOLICY */ 251 if (!vdev_readable(vd)) { 252 zio->io_error = SET_ERROR(ENXIO); 253 zio_interrupt(zio); 254 return; 255 } 256 257 switch (zio->io_cmd) { 258 case DKIOCFLUSHWRITECACHE: 259 zio->io_error = zfs_file_fsync(vf->vf_file, 260 O_SYNC|O_DSYNC); 261 break; 262 default: 263 zio->io_error = SET_ERROR(ENOTSUP); 264 } 265 266 zio_execute(zio); 267 return; 268 } else if (zio->io_type == ZIO_TYPE_TRIM) { 269 #ifdef notyet 270 int mode = 0; 271 272 ASSERT3U(zio->io_size, !=, 0); 273 274 /* XXX FreeBSD has no fallocate routine in file ops */ 275 zio->io_error = zfs_file_fallocate(vf->vf_file, 276 mode, zio->io_offset, zio->io_size); 277 #endif 278 zio->io_error = SET_ERROR(ENOTSUP); 279 zio_execute(zio); 280 return; 281 } 282 ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE); 283 zio->io_target_timestamp = zio_handle_io_delay(zio); 284 285 VERIFY3U(taskq_dispatch(vdev_file_taskq, vdev_file_io_strategy, zio, 286 TQ_SLEEP), !=, 0); 287 } 288 289 /* ARGSUSED */ 290 static void 291 vdev_file_io_done(zio_t *zio) 292 { 293 } 294 295 vdev_ops_t vdev_file_ops = { 296 .vdev_op_init = NULL, 297 .vdev_op_fini = NULL, 298 .vdev_op_open = vdev_file_open, 299 .vdev_op_close = vdev_file_close, 300 .vdev_op_asize = vdev_default_asize, 301 .vdev_op_min_asize = vdev_default_min_asize, 302 .vdev_op_min_alloc = NULL, 303 .vdev_op_io_start = vdev_file_io_start, 304 .vdev_op_io_done = vdev_file_io_done, 305 .vdev_op_state_change = NULL, 306 .vdev_op_need_resilver = NULL, 307 .vdev_op_hold = vdev_file_hold, 308 .vdev_op_rele = vdev_file_rele, 309 .vdev_op_remap = NULL, 310 .vdev_op_xlate = vdev_default_xlate, 311 .vdev_op_rebuild_asize = NULL, 312 .vdev_op_metaslab_init = NULL, 313 .vdev_op_config_generate = NULL, 314 .vdev_op_nparity = NULL, 315 .vdev_op_ndisks = NULL, 316 .vdev_op_type = VDEV_TYPE_FILE, /* name of this vdev type */ 317 .vdev_op_leaf = B_TRUE /* leaf vdev */ 318 }; 319 320 /* 321 * From userland we access disks just like files. 322 */ 323 #ifndef _KERNEL 324 325 vdev_ops_t vdev_disk_ops = { 326 .vdev_op_init = NULL, 327 .vdev_op_fini = NULL, 328 .vdev_op_open = vdev_file_open, 329 .vdev_op_close = vdev_file_close, 330 .vdev_op_asize = vdev_default_asize, 331 .vdev_op_min_asize = vdev_default_min_asize, 332 .vdev_op_min_alloc = NULL, 333 .vdev_op_io_start = vdev_file_io_start, 334 .vdev_op_io_done = vdev_file_io_done, 335 .vdev_op_state_change = NULL, 336 .vdev_op_need_resilver = NULL, 337 .vdev_op_hold = vdev_file_hold, 338 .vdev_op_rele = vdev_file_rele, 339 .vdev_op_remap = NULL, 340 .vdev_op_xlate = vdev_default_xlate, 341 .vdev_op_rebuild_asize = NULL, 342 .vdev_op_metaslab_init = NULL, 343 .vdev_op_config_generate = NULL, 344 .vdev_op_nparity = NULL, 345 .vdev_op_ndisks = NULL, 346 .vdev_op_type = VDEV_TYPE_DISK, /* name of this vdev type */ 347 .vdev_op_leaf = B_TRUE /* leaf vdev */ 348 }; 349 350 #endif 351 352 ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, logical_ashift, ULONG, ZMOD_RW, 353 "Logical ashift for file-based devices"); 354 ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, physical_ashift, ULONG, ZMOD_RW, 355 "Physical ashift for file-based devices"); 356