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