vdev_file.c revision 209962
1234353Sdim/*
2204642Srdivacky * CDDL HEADER START
3204642Srdivacky *
4204642Srdivacky * The contents of this file are subject to the terms of the
5204642Srdivacky * Common Development and Distribution License (the "License").
6204642Srdivacky * You may not use this file except in compliance with the License.
7204642Srdivacky *
8204642Srdivacky * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9204642Srdivacky * or http://www.opensolaris.org/os/licensing.
10204642Srdivacky * See the License for the specific language governing permissions
11204642Srdivacky * and limitations under the License.
12204642Srdivacky *
13204642Srdivacky * When distributing Covered Code, include this CDDL HEADER in each
14204642Srdivacky * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15204642Srdivacky * If applicable, add the following below this CDDL HEADER, with the
16204642Srdivacky * fields enclosed by brackets "[]" replaced with your own identifying
17218893Sdim * information: Portions Copyright [yyyy] [name of copyright owner]
18204642Srdivacky *
19249423Sdim * CDDL HEADER END
20204642Srdivacky */
21204642Srdivacky/*
22204642Srdivacky * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23204642Srdivacky * Use is subject to license terms.
24204642Srdivacky */
25204642Srdivacky
26204642Srdivacky#include <sys/zfs_context.h>
27234353Sdim#include <sys/spa.h>
28204642Srdivacky#include <sys/vdev_file.h>
29218893Sdim#include <sys/vdev_impl.h>
30204642Srdivacky#include <sys/zio.h>
31204642Srdivacky#include <sys/fs/zfs.h>
32204642Srdivacky#include <sys/fm/fs/zfs.h>
33218893Sdim
34204642Srdivacky/*
35204642Srdivacky * Virtual device vector for files.
36204642Srdivacky */
37204642Srdivacky
38204642Srdivackystatic int
39204642Srdivackyvdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift)
40204642Srdivacky{
41204642Srdivacky	vdev_file_t *vf;
42204642Srdivacky	vnode_t *vp;
43204642Srdivacky	vattr_t vattr;
44204642Srdivacky	int error, vfslocked;
45204642Srdivacky
46204642Srdivacky	/*
47218893Sdim	 * We must have a pathname, and it must be absolute.
48218893Sdim	 */
49218893Sdim	if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') {
50204642Srdivacky		vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
51204642Srdivacky		return (EINVAL);
52204642Srdivacky	}
53204642Srdivacky
54218893Sdim	vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP);
55218893Sdim
56204642Srdivacky	/*
57204642Srdivacky	 * We always open the files from the root of the global zone, even if
58204642Srdivacky	 * we're in a local zone.  If the user has gotten to this point, the
59218893Sdim	 * administrator has already decided that the pool should be available
60218893Sdim	 * to local zone users, so the underlying devices should be as well.
61204642Srdivacky	 */
62218893Sdim	ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/');
63204642Srdivacky	error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE,
64204642Srdivacky	    spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir, -1);
65204642Srdivacky
66218893Sdim	if (error) {
67218893Sdim		vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
68218893Sdim		return (error);
69218893Sdim	}
70218893Sdim
71204642Srdivacky	vf->vf_vnode = vp;
72204642Srdivacky
73204642Srdivacky#ifdef _KERNEL
74204642Srdivacky	/*
75204642Srdivacky	 * Make sure it's a regular file.
76204642Srdivacky	 */
77204642Srdivacky	if (vp->v_type != VREG) {
78204642Srdivacky		(void) VOP_CLOSE(vp, spa_mode(vd->vdev_spa), 1, 0, kcred, NULL);
79204642Srdivacky		vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
80204642Srdivacky		return (ENODEV);
81207618Srdivacky	}
82207618Srdivacky#endif
83207618Srdivacky	/*
84218893Sdim	 * Determine the physical size of the file.
85218893Sdim	 */
86218893Sdim	vattr.va_mask = AT_SIZE;
87218893Sdim	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
88204642Srdivacky	vn_lock(vp, LK_SHARED | LK_RETRY);
89218893Sdim	error = VOP_GETATTR(vp, &vattr, kcred);
90218893Sdim	VOP_UNLOCK(vp, 0);
91218893Sdim	VFS_UNLOCK_GIANT(vfslocked);
92218893Sdim	if (error) {
93204642Srdivacky		(void) VOP_CLOSE(vp, spa_mode(vd->vdev_spa), 1, 0, kcred, NULL);
94204642Srdivacky		vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
95204642Srdivacky		return (error);
96204642Srdivacky	}
97204642Srdivacky
98204642Srdivacky	*psize = vattr.va_size;
99204642Srdivacky	*ashift = SPA_MINBLOCKSHIFT;
100204642Srdivacky
101204642Srdivacky	return (0);
102204642Srdivacky}
103204642Srdivacky
104204642Srdivackystatic void
105204642Srdivackyvdev_file_close(vdev_t *vd)
106204642Srdivacky{
107204642Srdivacky	vdev_file_t *vf = vd->vdev_tsd;
108218893Sdim
109204642Srdivacky	if (vf == NULL)
110218893Sdim		return;
111218893Sdim
112218893Sdim	if (vf->vf_vnode != NULL)
113218893Sdim		(void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0,
114218893Sdim		    kcred, NULL);
115218893Sdim	kmem_free(vf, sizeof (vdev_file_t));
116218893Sdim	vd->vdev_tsd = NULL;
117218893Sdim}
118218893Sdim
119218893Sdimstatic int
120218893Sdimvdev_file_io_start(zio_t *zio)
121218893Sdim{
122218893Sdim	vdev_t *vd = zio->io_vd;
123218893Sdim	vdev_file_t *vf = vd->vdev_tsd;
124218893Sdim	vnode_t *vp = vf->vf_vnode;
125218893Sdim	ssize_t resid;
126218893Sdim
127218893Sdim	if (zio->io_type == ZIO_TYPE_IOCTL) {
128218893Sdim		/* XXPOLICY */
129218893Sdim		if (!vdev_readable(vd)) {
130218893Sdim			zio->io_error = ENXIO;
131218893Sdim			return (ZIO_PIPELINE_CONTINUE);
132218893Sdim		}
133218893Sdim
134218893Sdim		switch (zio->io_cmd) {
135204642Srdivacky		case DKIOCFLUSHWRITECACHE:
136204642Srdivacky			zio->io_error = VOP_FSYNC(vp, FSYNC | FDSYNC,
137204642Srdivacky			    kcred, NULL);
138204642Srdivacky			break;
139218893Sdim		default:
140204642Srdivacky			zio->io_error = ENOTSUP;
141204642Srdivacky		}
142204642Srdivacky
143204642Srdivacky		return (ZIO_PIPELINE_CONTINUE);
144204642Srdivacky	}
145204642Srdivacky
146204642Srdivacky	zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ?
147218893Sdim	    UIO_READ : UIO_WRITE, vp, zio->io_data, zio->io_size,
148218893Sdim	    zio->io_offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid);
149204642Srdivacky
150218893Sdim	if (resid != 0 && zio->io_error == 0)
151204642Srdivacky		zio->io_error = ENOSPC;
152218893Sdim
153218893Sdim	zio_interrupt(zio);
154218893Sdim
155204642Srdivacky	return (ZIO_PIPELINE_STOP);
156204642Srdivacky}
157204642Srdivacky
158204642Srdivacky/* ARGSUSED */
159204642Srdivackystatic void
160204642Srdivackyvdev_file_io_done(zio_t *zio)
161204642Srdivacky{
162207618Srdivacky}
163207618Srdivacky
164207618Srdivackyvdev_ops_t vdev_file_ops = {
165204642Srdivacky	vdev_file_open,
166204642Srdivacky	vdev_file_close,
167204642Srdivacky	vdev_default_asize,
168204642Srdivacky	vdev_file_io_start,
169204642Srdivacky	vdev_file_io_done,
170	NULL,
171	VDEV_TYPE_FILE,		/* name of this vdev type */
172	B_TRUE			/* leaf vdev */
173};
174
175/*
176 * From userland we access disks just like files.
177 */
178#ifndef _KERNEL
179
180vdev_ops_t vdev_disk_ops = {
181	vdev_file_open,
182	vdev_file_close,
183	vdev_default_asize,
184	vdev_file_io_start,
185	vdev_file_io_done,
186	NULL,
187	VDEV_TYPE_DISK,		/* name of this vdev type */
188	B_TRUE			/* leaf vdev */
189};
190
191#endif
192