]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_init.c
xnu-201.19.3.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_init.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23 /*
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * This code is derived from software contributed
28 * to Berkeley by John Heidemann of the UCLA Ficus project.
29 *
30 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)vfs_init.c 8.5 (Berkeley) 5/11/95
61 */
62
63
64 #include <sys/param.h>
65 #include <sys/mount.h>
66 #include <sys/time.h>
67 #include <sys/vm.h>
68 #include <sys/vnode.h>
69 #include <sys/stat.h>
70 #include <sys/namei.h>
71 #include <sys/ucred.h>
72 #include <sys/buf.h>
73 #include <sys/errno.h>
74 #include <sys/malloc.h>
75
76
77 /*
78 * Sigh, such primitive tools are these...
79 */
80 #if 0
81 #define DODEBUG(A) A
82 #else
83 #define DODEBUG(A)
84 #endif
85
86 extern uid_t console_user;
87 extern struct vnodeopv_desc *vfs_opv_descs[];
88 /* a list of lists of vnodeops defns */
89 extern struct vnodeop_desc *vfs_op_descs[];
90 /* and the operations they perform */
91 /*
92 * This code doesn't work if the defn is **vnodop_defns with cc.
93 * The problem is because of the compiler sometimes putting in an
94 * extra level of indirection for arrays. It's an interesting
95 * "feature" of C.
96 */
97 int vfs_opv_numops;
98
99 typedef (*PFI)(); /* the standard Pointer to a Function returning an Int */
100
101 /*
102 * A miscellaneous routine.
103 * A generic "default" routine that just returns an error.
104 */
105 int
106 vn_default_error()
107 {
108
109 return (EOPNOTSUPP);
110 }
111
112 /*
113 * vfs_init.c
114 *
115 * Allocate and fill in operations vectors.
116 *
117 * An undocumented feature of this approach to defining operations is that
118 * there can be multiple entries in vfs_opv_descs for the same operations
119 * vector. This allows third parties to extend the set of operations
120 * supported by another layer in a binary compatibile way. For example,
121 * assume that NFS needed to be modified to support Ficus. NFS has an entry
122 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
123 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
124 * listing those new operations Ficus adds to NFS, all without modifying the
125 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
126 * that is a(whole)nother story.) This is a feature.
127 */
128 void
129 vfs_opv_init()
130 {
131 int i, j, k;
132 int (***opv_desc_vector_p)(void *);
133 int (**opv_desc_vector)(void *);
134 struct vnodeopv_entry_desc *opve_descp;
135
136 /*
137 * Allocate the dynamic vectors and fill them in.
138 */
139 for (i=0; vfs_opv_descs[i]; i++) {
140 opv_desc_vector_p = vfs_opv_descs[i]->opv_desc_vector_p;
141 /*
142 * Allocate and init the vector, if it needs it.
143 * Also handle backwards compatibility.
144 */
145 if (*opv_desc_vector_p == NULL) {
146 /* XXX - shouldn't be M_VNODE */
147 MALLOC(*opv_desc_vector_p, PFI*,
148 vfs_opv_numops*sizeof(PFI), M_VNODE, M_WAITOK);
149 bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFI));
150 DODEBUG(printf("vector at %x allocated\n",
151 opv_desc_vector_p));
152 }
153 opv_desc_vector = *opv_desc_vector_p;
154 for (j=0; vfs_opv_descs[i]->opv_desc_ops[j].opve_op; j++) {
155 opve_descp = &(vfs_opv_descs[i]->opv_desc_ops[j]);
156
157 /*
158 * Sanity check: is this operation listed
159 * in the list of operations? We check this
160 * by seeing if its offest is zero. Since
161 * the default routine should always be listed
162 * first, it should be the only one with a zero
163 * offset. Any other operation with a zero
164 * offset is probably not listed in
165 * vfs_op_descs, and so is probably an error.
166 *
167 * A panic here means the layer programmer
168 * has committed the all-too common bug
169 * of adding a new operation to the layer's
170 * list of vnode operations but
171 * not adding the operation to the system-wide
172 * list of supported operations.
173 */
174 if (opve_descp->opve_op->vdesc_offset == 0 &&
175 opve_descp->opve_op->vdesc_offset !=
176 VOFFSET(vop_default)) {
177 printf("operation %s not listed in %s.\n",
178 opve_descp->opve_op->vdesc_name,
179 "vfs_op_descs");
180 panic ("vfs_opv_init: bad operation");
181 }
182 /*
183 * Fill in this entry.
184 */
185 opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
186 opve_descp->opve_impl;
187 }
188 }
189 /*
190 * Finally, go back and replace unfilled routines
191 * with their default. (Sigh, an O(n^3) algorithm. I
192 * could make it better, but that'd be work, and n is small.)
193 */
194 for (i = 0; vfs_opv_descs[i]; i++) {
195 opv_desc_vector = *(vfs_opv_descs[i]->opv_desc_vector_p);
196 /*
197 * Force every operations vector to have a default routine.
198 */
199 if (opv_desc_vector[VOFFSET(vop_default)]==NULL) {
200 panic("vfs_opv_init: operation vector without default routine.");
201 }
202 for (k = 0; k<vfs_opv_numops; k++)
203 if (opv_desc_vector[k] == NULL)
204 opv_desc_vector[k] =
205 opv_desc_vector[VOFFSET(vop_default)];
206 }
207 }
208
209 /*
210 * Initialize known vnode operations vectors.
211 */
212 void
213 vfs_op_init()
214 {
215 int i;
216
217 DODEBUG(printf("Vnode_interface_init.\n"));
218 /*
219 * Set all vnode vectors to a well known value.
220 */
221 for (i = 0; vfs_opv_descs[i]; i++)
222 *(vfs_opv_descs[i]->opv_desc_vector_p) = NULL;
223 /*
224 * Figure out how many ops there are by counting the table,
225 * and assign each its offset.
226 */
227 for (vfs_opv_numops = 0, i = 0; vfs_op_descs[i]; i++) {
228 vfs_op_descs[i]->vdesc_offset = vfs_opv_numops;
229 vfs_opv_numops++;
230 }
231 DODEBUG(printf ("vfs_opv_numops=%d\n", vfs_opv_numops));
232 }
233
234 /*
235 * Routines having to do with the management of the vnode table.
236 */
237 extern struct vnodeops dead_vnodeops;
238 extern struct vnodeops spec_vnodeops;
239 struct vattr va_null;
240
241 /*
242 * Initialize the vnode structures and initialize each file system type.
243 */
244 vfsinit()
245 {
246 struct vfsconf *vfsp;
247 int i, maxtypenum;
248
249 /*
250 * Initialize the "console user" for access purposes:
251 */
252 console_user = (uid_t)0;
253
254 /*
255 * Initialize the vnode table
256 */
257 vntblinit();
258 /*
259 * Initialize the vnode name cache
260 */
261 nchinit();
262 /*
263 * Build vnode operation vectors.
264 */
265 vfs_op_init();
266 vfs_opv_init(); /* finish the job */
267 /*
268 * Initialize each file system type.
269 */
270 vattr_null(&va_null);
271 numused_vfsslots = maxtypenum = 0;
272 for (vfsp = vfsconf, i = 0; i < maxvfsconf; i++, vfsp++) {
273 if (vfsp->vfc_vfsops == (struct vfsops *)0)
274 break;
275 if (i) vfsconf[i-1].vfc_next = vfsp;
276 if (maxtypenum <= vfsp->vfc_typenum)
277 maxtypenum = vfsp->vfc_typenum + 1;
278 (*vfsp->vfc_vfsops->vfs_init)(vfsp);
279 numused_vfsslots++;
280 }
281 /* next vfc_typenum to be used */
282 maxvfsconf = maxtypenum;
283 }
284
285 int
286 vfsconf_add(struct vfsconf *nvfsp)
287 {
288 struct vfsconf *vfsp;
289
290 if ((numused_vfsslots >= maxvfsslots) || (nvfsp == (struct vfsconf *)0))
291 return (-1);
292 bcopy(nvfsp, &vfsconf[numused_vfsslots], sizeof(struct vfsconf));
293 vfsconf[numused_vfsslots-1].vfc_next = &vfsconf[numused_vfsslots];
294
295 if (nvfsp->vfc_typenum <= maxvfsconf )
296 maxvfsconf = nvfsp->vfc_typenum + 1;
297 numused_vfsslots++;
298 if (nvfsp->vfc_vfsops->vfs_init)
299 (*nvfsp->vfc_vfsops->vfs_init)(nvfsp);
300 return(0);
301 }
302
303 int
304 vfsconf_del(char * fs_name)
305 {
306 int entriesRemaining;
307 struct vfsconf *vfsconflistentry;
308 struct vfsconf *prevconf = NULL;
309 struct vfsconf *targetconf = NULL;
310
311 prevconf = vfsconflistentry = vfsconf;
312 for (entriesRemaining = maxvfsslots;
313 (entriesRemaining > 0) && (vfsconflistentry != NULL);
314 --entriesRemaining) {
315 if ((vfsconflistentry->vfc_vfsops != NULL) && (strcmp(vfsconflistentry->vfc_name, fs_name) == 0)) {
316 targetconf = vfsconflistentry;
317 break;
318 };
319 prevconf = vfsconflistentry;
320 vfsconflistentry = vfsconflistentry->vfc_next;
321 };
322
323 if (targetconf != NULL) {
324 if (prevconf != NULL) {
325 /* Unlink the target entry from the list:
326 and decrement our count */
327 prevconf->vfc_next = targetconf->vfc_next;
328 numused_vfsslots--;
329 } else {
330 /* XXX need real error code for no previous entry in list */
331 return(-1);
332 }
333 } else {
334 /* XXX need real error code for entry not found */
335 return(-1);
336 };
337 return(0);
338 }