]> git.saurik.com Git - apple/xnu.git/blame - bsd/miscfs/mockfs/mockfs_vfsops.c
xnu-2782.30.5.tar.gz
[apple/xnu.git] / bsd / miscfs / mockfs / mockfs_vfsops.c
CommitLineData
39236c6e
A
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
42lck_attr_t * mockfs_mtx_attr = (lck_attr_t *) 0;
43lck_grp_attr_t * mockfs_grp_attr = (lck_grp_attr_t *) 0;
44lck_grp_t * mockfs_mtx_grp = (lck_grp_t *) 0;
45
46int 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 */
51int mockfs_unmount(__unused struct mount *mp, __unused int mntflags, __unused vfs_context_t ctx);
52int mockfs_root(mount_t mp, vnode_t * vpp, __unused vfs_context_t ctx);
53int mockfs_sync(__unused struct mount *mp, __unused int waitfor, __unused vfs_context_t ctx);
54int 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 */
66int 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
128done:
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 */
151int 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 */
200int 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 */
214int 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 */
226int 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
243struct vfsops mockfs_vfsops = {
244 NULL, /* mount */
245 NULL, /* start */
246 mockfs_unmount, /* unmount */
247 mockfs_root, /* root */
248 NULL, /* quotactl */
249 NULL, /* getattr */
250 mockfs_sync, /* sync */
251 NULL, /* vget */
252 NULL, /* fhtovp */
253 NULL, /* vptofh */
254 mockfs_init, /* init */
255 NULL, /* sysctl */
256 NULL, /* setattr */
257 {NULL}
258};
259