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 ASSERT(vd->vdev_path != NULL); 63 } 64 65 static void 66 vdev_file_rele(vdev_t *vd) 67 { 68 ASSERT(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 ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/'); 141 142 error = zfs_file_open(vd->vdev_path, 143 vdev_file_open_mode(spa_mode(vd->vdev_spa)), 0, &fp); 144 if (error) { 145 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 146 return (error); 147 } 148 149 vf->vf_file = fp; 150 151 #ifdef _KERNEL 152 /* 153 * Make sure it's a regular file. 154 */ 155 if (zfs_file_getattr(fp, &zfa)) { 156 return (SET_ERROR(ENODEV)); 157 } 158 if (!S_ISREG(zfa.zfa_mode)) { 159 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 160 return (SET_ERROR(ENODEV)); 161 } 162 #endif 163 164 skip_open: 165 166 error = zfs_file_getattr(vf->vf_file, &zfa); 167 if (error) { 168 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; 169 return (error); 170 } 171 172 *max_psize = *psize = zfa.zfa_size; 173 *logical_ashift = vdev_file_logical_ashift; 174 *physical_ashift = vdev_file_physical_ashift; 175 176 return (0); 177 } 178 179 static void 180 vdev_file_close(vdev_t *vd) 181 { 182 vdev_file_t *vf = vd->vdev_tsd; 183 184 if (vd->vdev_reopening || vf == NULL) 185 return; 186 187 if (vf->vf_file != NULL) { 188 zfs_file_close(vf->vf_file); 189 } 190 191 vd->vdev_delayed_close = B_FALSE; 192 kmem_free(vf, sizeof (vdev_file_t)); 193 vd->vdev_tsd = NULL; 194 } 195 196 /* 197 * Implements the interrupt side for file vdev types. This routine will be 198 * called when the I/O completes allowing us to transfer the I/O to the 199 * interrupt taskqs. For consistency, the code structure mimics disk vdev 200 * types. 201 */ 202 static void 203 vdev_file_io_intr(zio_t *zio) 204 { 205 zio_delay_interrupt(zio); 206 } 207 208 static void 209 vdev_file_io_strategy(void *arg) 210 { 211 zio_t *zio = arg; 212 vdev_t *vd = zio->io_vd; 213 vdev_file_t *vf; 214 void *buf; 215 ssize_t resid; 216 loff_t off; 217 ssize_t size; 218 int err; 219 220 off = zio->io_offset; 221 size = zio->io_size; 222 resid = 0; 223 224 vf = vd->vdev_tsd; 225 226 ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE); 227 if (zio->io_type == ZIO_TYPE_READ) { 228 buf = abd_borrow_buf(zio->io_abd, zio->io_size); 229 err = zfs_file_pread(vf->vf_file, buf, size, off, &resid); 230 abd_return_buf_copy(zio->io_abd, buf, size); 231 } else { 232 buf = abd_borrow_buf_copy(zio->io_abd, zio->io_size); 233 err = zfs_file_pwrite(vf->vf_file, buf, size, off, &resid); 234 abd_return_buf(zio->io_abd, buf, size); 235 } 236 if (resid != 0 && zio->io_error == 0) 237 zio->io_error = ENOSPC; 238 239 vdev_file_io_intr(zio); 240 } 241 242 static void 243 vdev_file_io_start(zio_t *zio) 244 { 245 vdev_t *vd = zio->io_vd; 246 vdev_file_t *vf = vd->vdev_tsd; 247 248 if (zio->io_type == ZIO_TYPE_IOCTL) { 249 /* XXPOLICY */ 250 if (!vdev_readable(vd)) { 251 zio->io_error = SET_ERROR(ENXIO); 252 zio_interrupt(zio); 253 return; 254 } 255 256 switch (zio->io_cmd) { 257 case DKIOCFLUSHWRITECACHE: 258 zio->io_error = zfs_file_fsync(vf->vf_file, 259 O_SYNC|O_DSYNC); 260 break; 261 default: 262 zio->io_error = SET_ERROR(ENOTSUP); 263 } 264 265 zio_execute(zio); 266 return; 267 } else if (zio->io_type == ZIO_TYPE_TRIM) { 268 #ifdef notyet 269 int mode = 0; 270 271 ASSERT3U(zio->io_size, !=, 0); 272 273 /* XXX FreeBSD has no fallocate routine in file ops */ 274 zio->io_error = zfs_file_fallocate(vf->vf_file, 275 mode, zio->io_offset, zio->io_size); 276 #endif 277 zio->io_error = SET_ERROR(ENOTSUP); 278 zio_execute(zio); 279 return; 280 } 281 ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE); 282 zio->io_target_timestamp = zio_handle_io_delay(zio); 283 284 VERIFY3U(taskq_dispatch(vdev_file_taskq, vdev_file_io_strategy, zio, 285 TQ_SLEEP), !=, 0); 286 } 287 288 /* ARGSUSED */ 289 static void 290 vdev_file_io_done(zio_t *zio) 291 { 292 } 293 294 vdev_ops_t vdev_file_ops = { 295 vdev_file_open, 296 vdev_file_close, 297 vdev_default_asize, 298 vdev_file_io_start, 299 vdev_file_io_done, 300 NULL, 301 NULL, 302 vdev_file_hold, 303 vdev_file_rele, 304 NULL, 305 vdev_default_xlate, 306 VDEV_TYPE_FILE, /* name of this vdev type */ 307 B_TRUE /* leaf vdev */ 308 }; 309 310 /* 311 * From userland we access disks just like files. 312 */ 313 #ifndef _KERNEL 314 315 vdev_ops_t vdev_disk_ops = { 316 vdev_file_open, 317 vdev_file_close, 318 vdev_default_asize, 319 vdev_file_io_start, 320 vdev_file_io_done, 321 NULL, 322 NULL, 323 vdev_file_hold, 324 vdev_file_rele, 325 NULL, 326 vdev_default_xlate, 327 VDEV_TYPE_DISK, /* name of this vdev type */ 328 B_TRUE /* leaf vdev */ 329 }; 330 331 #endif 332 333 ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, logical_ashift, ULONG, ZMOD_RW, 334 "Logical ashift for file-based devices"); 335 ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, physical_ashift, ULONG, ZMOD_RW, 336 "Physical ashift for file-based devices"); 337