]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/mockfs/mockfs_vfsops.c
xnu-4903.241.1.tar.gz
[apple/xnu.git] / bsd / miscfs / mockfs / mockfs_vfsops.c
1 /*
2 * Copyright (c) 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <kern/assert.h>
30 #include <kern/debug.h>
31 #include <libkern/libkern.h>
32 #include <miscfs/mockfs/mockfs.h>
33 #include <miscfs/mockfs/mockfs_fsnode.h>
34 #include <miscfs/mockfs/mockfs_vnops.h>
35 #include <miscfs/specfs/specdev.h>
36 #include <sys/disk.h>
37 #include <sys/errno.h>
38 #include <sys/malloc.h>
39 #include <sys/mount_internal.h>
40 #include <sys/vnode_internal.h>
41
42 lck_attr_t * mockfs_mtx_attr = (lck_attr_t *) 0;
43 lck_grp_attr_t * mockfs_grp_attr = (lck_grp_attr_t *) 0;
44 lck_grp_t * mockfs_mtx_grp = (lck_grp_t *) 0;
45
46 int mockfs_mountroot(mount_t mp, vnode_t rvp, __unused vfs_context_t ctx);
47
48 /*
49 * Functions that are part of the mockfs_vfsops structure.
50 */
51 int mockfs_unmount(__unused struct mount *mp, __unused int mntflags, __unused vfs_context_t ctx);
52 int mockfs_root(mount_t mp, vnode_t * vpp, __unused vfs_context_t ctx);
53 int mockfs_sync(__unused struct mount *mp, __unused int waitfor, __unused vfs_context_t ctx);
54 int mockfs_init(__unused struct vfsconf * vfsc);
55
56 /*
57 * mockfs_mountroot:
58 * Given a mount (mp) and a vnode for the root device (rvp), builds a fake filesystem for rvp. This consists
59 * of three nodes; a directory node (to serve as a mountpoint for devfs), a file node meant to serve as an
60 * executable frontend for rootvp (we will assume that rootvp is an executable, that the kernel can subsequently
61 * run), and the root node for the mockfs filesystem. The structure of mockfs is memory-backed; only the
62 * contents of the file node refer to the backing device.
63 *
64 * Returns 0 on success, or an error.
65 */
66 int mockfs_mountroot(mount_t mp, vnode_t rvp, __unused vfs_context_t ctx)
67 {
68 int rvalue = 0;
69 mockfs_fsnode_t root_fsnode = NULL;
70 mockfs_fsnode_t dev_fsnode = NULL;
71 mockfs_fsnode_t file_fsnode = NULL;
72 mockfs_mount_t mockfs_mount_data = NULL;
73 dk_memdev_info_t memdev_info;
74
75 /*
76 * TODO: Validate that the device at least LOOKS like a mach-o (has a sane header); this would prevent us
77 * from causing EBADMACHO panics further along the boot path.
78 */
79
80 /*
81 * There are no M_MOCKFS* definitions at the moment, just use M_TEMP.
82 */
83
84 MALLOC(mockfs_mount_data, mockfs_mount_t, sizeof(*mockfs_mount_data), M_TEMP, M_WAITOK | M_ZERO);
85 mockfs_fsnode_create(mp, MOCKFS_ROOT, &root_fsnode);
86 mockfs_fsnode_create(mp, MOCKFS_DEV, &dev_fsnode);
87 mockfs_fsnode_create(mp, MOCKFS_FILE, &file_fsnode);
88
89 if (!mockfs_mount_data || !root_fsnode || !dev_fsnode || !file_fsnode) {
90 rvalue = ENOMEM;
91 goto done;
92 }
93
94 /*
95 * If rvp is a memory device (with a few caveats), we can point to the same physical memory as the device
96 * and avoid pointless paging/copying; query the device node for the information we need to determine
97 * if we can do this.
98 */
99 bzero(&memdev_info, sizeof(memdev_info));
100
101 if (!VNOP_IOCTL(rvp, DKIOCGETMEMDEVINFO, (caddr_t)&memdev_info, 0, NULL)) {
102 /*
103 * For the moment, we won't try to optimize when mi_phys is true.
104 */
105 if (!mockfs_mount_data->mockfs_physical_memory) {
106 mockfs_mount_data->mockfs_memory_backed = memdev_info.mi_mdev;
107 mockfs_mount_data->mockfs_physical_memory = memdev_info.mi_phys;
108 mockfs_mount_data->mockfs_memdev_base = memdev_info.mi_base;
109 mockfs_mount_data->mockfs_memdev_size = memdev_info.mi_size;
110 }
111 }
112
113 lck_mtx_init(&mockfs_mount_data->mockfs_mnt_mtx, mockfs_mtx_grp, mockfs_mtx_attr);
114
115 /*
116 * All of the needed nodes/structures have been set up; now we just need to establish the relationships
117 * between the various mockfs nodes.
118 */
119 if ((rvalue = mockfs_fsnode_adopt(root_fsnode, dev_fsnode)))
120 goto done;
121
122 if ((rvalue = mockfs_fsnode_adopt(root_fsnode, file_fsnode)))
123 goto done;
124
125 mockfs_mount_data->mockfs_root = root_fsnode;
126 mp->mnt_data = (typeof(mp->mnt_data)) mockfs_mount_data;
127
128 done:
129 if (rvalue) {
130 if (file_fsnode)
131 mockfs_fsnode_destroy(file_fsnode);
132 if (dev_fsnode)
133 mockfs_fsnode_destroy(dev_fsnode);
134 if (root_fsnode)
135 mockfs_fsnode_destroy(root_fsnode);
136 if (mockfs_mount_data) {
137 lck_mtx_destroy(&mockfs_mount_data->mockfs_mnt_mtx, mockfs_mtx_grp);
138 FREE(mockfs_mount_data, M_TEMP);
139 }
140 }
141
142 return rvalue;
143 }
144
145 /*
146 * mockfs_unmount:
147 * Given a mount (mp), and associated flags (mntflags), performs the necessary teardown to destroy the mount.
148 *
149 * Returns 0 on success, or an error.
150 */
151 int mockfs_unmount(struct mount *mp, int mntflags, __unused vfs_context_t ctx)
152 {
153 int rvalue;
154 int vflush_flags;
155 mockfs_fsnode_t root_fsnode;
156 mockfs_mount_t mockfs_mnt;
157
158 vflush_flags = 0;
159 mockfs_mnt = (mockfs_mount_t) mp->mnt_data;
160
161 /*
162 * Reclaim the vnodes for the mount (forcibly, if requested; given that mockfs only support mountroot
163 * at the moment, this should ALWAYS be forced),
164 */
165 if (mntflags & MNT_FORCE) {
166 vflush_flags |= FORCECLOSE;
167 }
168
169 rvalue = vflush(mp, NULL, vflush_flags);
170
171 if (rvalue)
172 return rvalue;
173
174 /*
175 * Past this point, errors are likely to be unrecoverable, so panic if we're given any excuse; we
176 * need to teardown the mockfs_mnt data now, so that VFS can cleanup the mount structure. Note
177 * that clearing mockfs_root before destroying the fsnode tree is related to an implementation
178 * detail of mockfs_fsnode_destroy (which will refuse to destroy the root node).
179 */
180 root_fsnode = mockfs_mnt->mockfs_root;
181 mockfs_mnt->mockfs_root = NULL;
182 rvalue = mockfs_fsnode_destroy(root_fsnode);
183
184 if (rvalue)
185 panic("mockfs_unmount: Failed to destroy the fsnode tree");
186
187 lck_mtx_destroy(&mockfs_mnt->mockfs_mnt_mtx, mockfs_mtx_grp);
188 FREE(mockfs_mnt, M_TEMP);
189 mp->mnt_data = NULL;
190
191 return rvalue;
192 }
193
194 /*
195 * mockfs_root:
196 * Given a mount (mp), returns the root vnode (*vpp) for that mount with an iocount.
197 *
198 * Returns 0 on success, or an error.
199 */
200 int mockfs_root(mount_t mp, vnode_t * vpp, __unused vfs_context_t ctx)
201 {
202 int rvalue;
203
204 rvalue = mockfs_fsnode_vnode(((mockfs_mount_t) mp->mnt_data)->mockfs_root, vpp);
205 return rvalue;
206 }
207
208 /*
209 * mockfs_sync:
210 * Returns success because we're a read-only filesystem.
211 *
212 * Returns 0.
213 */
214 int mockfs_sync(__unused struct mount *mp, __unused int waitfor, __unused vfs_context_t ctx)
215 {
216 return (0);
217 }
218
219 /*
220 * mockfs_init:
221 * Run once (during VFS initialization); takes care of generic mockfs initialization (which for now, means
222 * global lock information).
223 *
224 * Returns 0 on success, or an error.
225 */
226 int mockfs_init(__unused struct vfsconf * vfsc)
227 {
228 mockfs_mtx_attr = lck_attr_alloc_init();
229 mockfs_grp_attr = lck_grp_attr_alloc_init();
230 mockfs_mtx_grp = lck_grp_alloc_init("mockfs-mutex", mockfs_grp_attr);
231
232 /*
233 * If we've failed to allocate this early in boot, something is horrendously wrong; it should be fine to
234 * panic (for now).
235 */
236 if (!mockfs_mtx_attr || !mockfs_grp_attr || !mockfs_mtx_grp) {
237 panic("mockfs_init failed to allocate lock information");
238 }
239
240 return (0);
241 }
242
243 struct vfsops mockfs_vfsops = {
244 .vfs_unmount = mockfs_unmount,
245 .vfs_root = mockfs_root,
246 .vfs_sync = mockfs_sync,
247 .vfs_init = mockfs_init,
248 };