xref: /xnu-10063.121.3/bsd/miscfs/mockfs/mockfs_vfsops.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
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 static LCK_GRP_DECLARE(mockfs_mtx_grp, "mockfs-mutex");
43 
44 int mockfs_mountroot(mount_t mp, vnode_t rvp, __unused vfs_context_t ctx);
45 
46 /*
47  * Functions that are part of the mockfs_vfsops structure.
48  */
49 int mockfs_unmount(__unused struct mount *mp, __unused int mntflags, __unused vfs_context_t ctx);
50 int mockfs_root(mount_t mp, vnode_t * vpp, __unused vfs_context_t ctx);
51 int mockfs_sync(__unused struct mount *mp, __unused int waitfor, __unused vfs_context_t ctx);
52 int mockfs_init(__unused struct vfsconf * vfsc);
53 
54 /*
55  * mockfs_mountroot:
56  *   Given a mount (mp) and a vnode for the root device (rvp), builds a fake filesystem for rvp.  This consists
57  *   of three nodes; a directory node (to serve as a mountpoint for devfs), a file node meant to serve as an
58  *   executable frontend for rootvp (we will assume that rootvp is an executable, that the kernel can subsequently
59  *   run), and the root node for the mockfs filesystem.  The structure of mockfs is memory-backed; only the
60  *   contents of the file node refer to the backing device.
61  *
62  * Returns 0 on success, or an error.
63  */
64 int
mockfs_mountroot(mount_t mp,vnode_t rvp,__unused vfs_context_t ctx)65 mockfs_mountroot(mount_t mp, vnode_t rvp, __unused vfs_context_t ctx)
66 {
67 	int rvalue = 0;
68 	mockfs_fsnode_t root_fsnode = NULL;
69 	mockfs_fsnode_t dev_fsnode = NULL;
70 	mockfs_fsnode_t file_fsnode = NULL;
71 	mockfs_mount_t mockfs_mount_data = NULL;
72 	dk_memdev_info_t memdev_info;
73 
74 	/*
75 	 * TODO: Validate that the device at least LOOKS like a mach-o (has a sane header); this would prevent us
76 	 *   from causing EBADMACHO panics further along the boot path.
77 	 */
78 
79 	/*
80 	 * There are no M_MOCKFS* definitions at the moment, just use M_TEMP.
81 	 */
82 
83 	mockfs_mount_data = kalloc_type(struct mockfs_mount, Z_WAITOK | Z_ZERO);
84 	mockfs_fsnode_create(mp, MOCKFS_ROOT, &root_fsnode);
85 	mockfs_fsnode_create(mp, MOCKFS_DEV, &dev_fsnode);
86 	mockfs_fsnode_create(mp, MOCKFS_FILE, &file_fsnode);
87 
88 	if (!root_fsnode || !dev_fsnode || !file_fsnode) {
89 		rvalue = ENOMEM;
90 		goto done;
91 	}
92 
93 	/*
94 	 * If rvp is a memory device (with a few caveats), we can point to the same physical memory as the device
95 	 *   and avoid pointless paging/copying; query the device node for the information we need to determine
96 	 *   if we can do this.
97 	 */
98 	bzero(&memdev_info, sizeof(memdev_info));
99 
100 	if (!VNOP_IOCTL(rvp, DKIOCGETMEMDEVINFO, (caddr_t)&memdev_info, 0, NULL)) {
101 		/*
102 		 * For the moment, we won't try to optimize when mi_phys is true.
103 		 */
104 		if (!mockfs_mount_data->mockfs_physical_memory) {
105 			mockfs_mount_data->mockfs_memory_backed = memdev_info.mi_mdev;
106 			mockfs_mount_data->mockfs_physical_memory = memdev_info.mi_phys;
107 			mockfs_mount_data->mockfs_memdev_base = memdev_info.mi_base;
108 			mockfs_mount_data->mockfs_memdev_size = memdev_info.mi_size;
109 		}
110 	}
111 
112 	lck_mtx_init(&mockfs_mount_data->mockfs_mnt_mtx, &mockfs_mtx_grp, LCK_ATTR_NULL);
113 
114 	/*
115 	 * All of the needed nodes/structures have been set up; now we just need to establish the relationships
116 	 *   between the various mockfs nodes.
117 	 */
118 	if ((rvalue = mockfs_fsnode_adopt(root_fsnode, dev_fsnode))) {
119 		goto done;
120 	}
121 
122 	if ((rvalue = mockfs_fsnode_adopt(root_fsnode, file_fsnode))) {
123 		goto done;
124 	}
125 
126 	mockfs_mount_data->mockfs_root = root_fsnode;
127 	mp->mnt_data = (typeof(mp->mnt_data))mockfs_mount_data;
128 
129 done:
130 	if (rvalue) {
131 		if (file_fsnode) {
132 			mockfs_fsnode_destroy(file_fsnode);
133 		}
134 		if (dev_fsnode) {
135 			mockfs_fsnode_destroy(dev_fsnode);
136 		}
137 		if (root_fsnode) {
138 			mockfs_fsnode_destroy(root_fsnode);
139 		}
140 		if (mockfs_mount_data) {
141 			lck_mtx_destroy(&mockfs_mount_data->mockfs_mnt_mtx, &mockfs_mtx_grp);
142 			kfree_type(struct mockfs_mount, mockfs_mount_data);
143 		}
144 	}
145 
146 	return rvalue;
147 }
148 
149 /*
150  * mockfs_unmount:
151  *   Given a mount (mp), and associated flags (mntflags), performs the necessary teardown to destroy the mount.
152  *
153  * Returns 0 on success, or an error.
154  */
155 int
mockfs_unmount(struct mount * mp,int mntflags,__unused vfs_context_t ctx)156 mockfs_unmount(struct mount *mp, int mntflags, __unused vfs_context_t ctx)
157 {
158 	int rvalue;
159 	int vflush_flags;
160 	mockfs_fsnode_t root_fsnode;
161 	mockfs_mount_t mockfs_mnt;
162 
163 	vflush_flags = 0;
164 	mockfs_mnt = (mockfs_mount_t) mp->mnt_data;
165 
166 	/*
167 	 * Reclaim the vnodes for the mount (forcibly, if requested; given that mockfs only support mountroot
168 	 *   at the moment, this should ALWAYS be forced),
169 	 */
170 	if (mntflags & MNT_FORCE) {
171 		vflush_flags |= FORCECLOSE;
172 	}
173 
174 	rvalue = vflush(mp, NULL, vflush_flags);
175 
176 	if (rvalue) {
177 		return rvalue;
178 	}
179 
180 	/*
181 	 * Past this point, errors are likely to be unrecoverable, so panic if we're given any excuse; we
182 	 *   need to teardown the mockfs_mnt data now, so that VFS can cleanup the mount structure.  Note
183 	 *   that clearing mockfs_root before destroying the fsnode tree is related to an implementation
184 	 *   detail of mockfs_fsnode_destroy (which will refuse to destroy the root node).
185 	 */
186 	root_fsnode = mockfs_mnt->mockfs_root;
187 	mockfs_mnt->mockfs_root = NULL;
188 	rvalue = mockfs_fsnode_destroy(root_fsnode);
189 
190 	if (rvalue) {
191 		panic("mockfs_unmount: Failed to destroy the fsnode tree");
192 	}
193 
194 	lck_mtx_destroy(&mockfs_mnt->mockfs_mnt_mtx, &mockfs_mtx_grp);
195 	kfree_type(struct mockfs_mount, mockfs_mnt);
196 	mp->mnt_data = NULL;
197 
198 	return rvalue;
199 }
200 
201 /*
202  * mockfs_root:
203  *   Given a mount (mp), returns the root vnode (*vpp) for that mount with an iocount.
204  *
205  * Returns 0 on success, or an error.
206  */
207 int
mockfs_root(mount_t mp,vnode_t * vpp,__unused vfs_context_t ctx)208 mockfs_root(mount_t mp, vnode_t * vpp, __unused vfs_context_t ctx)
209 {
210 	int rvalue;
211 
212 	rvalue = mockfs_fsnode_vnode(((mockfs_mount_t) mp->mnt_data)->mockfs_root, vpp);
213 	return rvalue;
214 }
215 
216 /*
217  * mockfs_sync:
218  *  Returns success because we're a read-only filesystem.
219  *
220  * Returns 0.
221  */
222 int
mockfs_sync(__unused struct mount * mp,__unused int waitfor,__unused vfs_context_t ctx)223 mockfs_sync(__unused struct mount *mp, __unused int waitfor, __unused vfs_context_t ctx)
224 {
225 	return 0;
226 }
227 
228 int
mockfs_init(__unused struct vfsconf * vfsc)229 mockfs_init(__unused struct vfsconf * vfsc)
230 {
231 	return 0;
232 }
233 
234 struct vfsops mockfs_vfsops = {
235 	.vfs_unmount = mockfs_unmount,
236 	.vfs_root = mockfs_root,
237 	.vfs_sync = mockfs_sync,
238 	.vfs_init = mockfs_init,
239 };
240