]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_file.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / cddl / contrib / opensolaris / uts / common / fs / zfs / vdev_file.c
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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25
26 #pragma ident   "%Z%%M% %I%     %E% SMI"
27
28 #include <sys/zfs_context.h>
29 #include <sys/spa.h>
30 #include <sys/vdev_file.h>
31 #include <sys/vdev_impl.h>
32 #include <sys/zio.h>
33 #include <sys/fs/zfs.h>
34
35 /*
36  * Virtual device vector for files.
37  */
38
39 static int
40 vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift)
41 {
42         vdev_file_t *vf;
43         vnode_t *vp;
44         vattr_t vattr;
45         int error;
46
47         /*
48          * We must have a pathname, and it must be absolute.
49          */
50         if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') {
51                 vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
52                 return (EINVAL);
53         }
54
55         vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP);
56
57         /*
58          * We always open the files from the root of the global zone, even if
59          * we're in a local zone.  If the user has gotten to this point, the
60          * administrator has already decided that the pool should be available
61          * to local zone users, so the underlying devices should be as well.
62          */
63         ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/');
64         error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE, spa_mode | FOFFMAX,
65             0, &vp, 0, 0, rootdir);
66
67         if (error) {
68                 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
69                 return (error);
70         }
71
72         vf->vf_vnode = vp;
73
74 #ifdef _KERNEL
75         /*
76          * Make sure it's a regular file.
77          */
78         if (vp->v_type != VREG) {
79                 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
80                 return (ENODEV);
81         }
82 #endif
83
84         /*
85          * Determine the physical size of the file.
86          */
87         vattr.va_mask = AT_SIZE;
88         error = VOP_GETATTR(vp, &vattr, 0, kcred);
89         if (error) {
90                 vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
91                 return (error);
92         }
93
94         *psize = vattr.va_size;
95         *ashift = SPA_MINBLOCKSHIFT;
96
97         return (0);
98 }
99
100 static void
101 vdev_file_close(vdev_t *vd)
102 {
103         vdev_file_t *vf = vd->vdev_tsd;
104
105         if (vf == NULL)
106                 return;
107
108         if (vf->vf_vnode != NULL) {
109                 (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred);
110                 (void) VOP_CLOSE(vf->vf_vnode, spa_mode, 1, 0, kcred);
111                 VN_RELE(vf->vf_vnode);
112         }
113
114         kmem_free(vf, sizeof (vdev_file_t));
115         vd->vdev_tsd = NULL;
116 }
117
118 static void
119 vdev_file_io_start(zio_t *zio)
120 {
121         vdev_t *vd = zio->io_vd;
122         vdev_file_t *vf = vd->vdev_tsd;
123         ssize_t resid;
124         int error;
125
126         if (zio->io_type == ZIO_TYPE_IOCTL) {
127                 zio_vdev_io_bypass(zio);
128
129                 /* XXPOLICY */
130                 if (vdev_is_dead(vd)) {
131                         zio->io_error = ENXIO;
132                         zio_next_stage_async(zio);
133                         return;
134                 }
135
136                 switch (zio->io_cmd) {
137                 case DKIOCFLUSHWRITECACHE:
138                         zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC,
139                             kcred);
140                         dprintf("fsync(%s) = %d\n", vdev_description(vd),
141                             zio->io_error);
142                         break;
143                 default:
144                         zio->io_error = ENOTSUP;
145                 }
146
147                 zio_next_stage_async(zio);
148                 return;
149         }
150
151         /*
152          * In the kernel, don't bother double-caching, but in userland,
153          * we want to test the vdev_cache code.
154          */
155 #ifndef _KERNEL
156         if (zio->io_type == ZIO_TYPE_READ && vdev_cache_read(zio) == 0)
157                 return;
158 #endif
159
160         if ((zio = vdev_queue_io(zio)) == NULL)
161                 return;
162
163         /* XXPOLICY */
164         error = vdev_is_dead(vd) ? ENXIO : vdev_error_inject(vd, zio);
165         if (error) {
166                 zio->io_error = error;
167                 zio_next_stage_async(zio);
168                 return;
169         }
170
171         zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ?
172             UIO_READ : UIO_WRITE, vf->vf_vnode, zio->io_data,
173             zio->io_size, zio->io_offset, UIO_SYSSPACE,
174             0, RLIM64_INFINITY, kcred, &resid);
175
176         if (resid != 0 && zio->io_error == 0)
177                 zio->io_error = ENOSPC;
178
179         zio_next_stage_async(zio);
180 }
181
182 static void
183 vdev_file_io_done(zio_t *zio)
184 {
185         vdev_queue_io_done(zio);
186
187 #ifndef _KERNEL
188         if (zio->io_type == ZIO_TYPE_WRITE)
189                 vdev_cache_write(zio);
190 #endif
191
192         if (zio_injection_enabled && zio->io_error == 0)
193                 zio->io_error = zio_handle_device_injection(zio->io_vd, EIO);
194
195         zio_next_stage(zio);
196 }
197
198 vdev_ops_t vdev_file_ops = {
199         vdev_file_open,
200         vdev_file_close,
201         vdev_default_asize,
202         vdev_file_io_start,
203         vdev_file_io_done,
204         NULL,
205         VDEV_TYPE_FILE,         /* name of this vdev type */
206         B_TRUE                  /* leaf vdev */
207 };
208
209 /*
210  * From userland we access disks just like files.
211  */
212 #ifndef _KERNEL
213
214 vdev_ops_t vdev_disk_ops = {
215         vdev_file_open,
216         vdev_file_close,
217         vdev_default_asize,
218         vdev_file_io_start,
219         vdev_file_io_done,
220         NULL,
221         VDEV_TYPE_DISK,         /* name of this vdev type */
222         B_TRUE                  /* leaf vdev */
223 };
224
225 #endif