xref: /freebsd/sys/contrib/openzfs/module/zfs/vdev_file.c (revision d2a8fad3579763bd288260c8c465ab9eb448d465)
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