]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_init.c
a94a965472ae42b53798019ff0b0a1f0dead788c
[apple/xnu.git] / bsd / vfs / vfs_init.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
31 /*
32 * Copyright (c) 1989, 1993
33 * The Regents of the University of California. All rights reserved.
34 *
35 * This code is derived from software contributed
36 * to Berkeley by John Heidemann of the UCLA Ficus project.
37 *
38 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 * must display the following acknowledgement:
50 * This product includes software developed by the University of
51 * California, Berkeley and its contributors.
52 * 4. Neither the name of the University nor the names of its contributors
53 * may be used to endorse or promote products derived from this software
54 * without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 *
68 * @(#)vfs_init.c 8.5 (Berkeley) 5/11/95
69 */
70
71
72 #include <sys/param.h>
73 #include <sys/mount_internal.h>
74 #include <sys/time.h>
75 #include <sys/vm.h>
76 #include <sys/vnode_internal.h>
77 #include <sys/stat.h>
78 #include <sys/namei.h>
79 #include <sys/ucred.h>
80 #include <sys/errno.h>
81 #include <sys/malloc.h>
82
83
84 /*
85 * Sigh, such primitive tools are these...
86 */
87 #if 0
88 #define DODEBUG(A) A
89 #else
90 #define DODEBUG(A)
91 #endif
92
93 extern uid_t console_user;
94 extern struct vnodeopv_desc *vfs_opv_descs[];
95 /* a list of lists of vnodeops defns */
96 extern struct vnodeop_desc *vfs_op_descs[];
97 /* and the operations they perform */
98 /*
99 * This code doesn't work if the defn is **vnodop_defns with cc.
100 * The problem is because of the compiler sometimes putting in an
101 * extra level of indirection for arrays. It's an interesting
102 * "feature" of C.
103 */
104 int vfs_opv_numops;
105
106 typedef (*PFI)(); /* the standard Pointer to a Function returning an Int */
107
108 /*
109 * A miscellaneous routine.
110 * A generic "default" routine that just returns an error.
111 */
112 int
113 vn_default_error()
114 {
115
116 return (ENOTSUP);
117 }
118
119 /*
120 * vfs_init.c
121 *
122 * Allocate and fill in operations vectors.
123 *
124 * An undocumented feature of this approach to defining operations is that
125 * there can be multiple entries in vfs_opv_descs for the same operations
126 * vector. This allows third parties to extend the set of operations
127 * supported by another layer in a binary compatibile way. For example,
128 * assume that NFS needed to be modified to support Ficus. NFS has an entry
129 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
130 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
131 * listing those new operations Ficus adds to NFS, all without modifying the
132 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
133 * that is a(whole)nother story.) This is a feature.
134 */
135 void
136 vfs_opv_init()
137 {
138 int i, j, k;
139 int (***opv_desc_vector_p)(void *);
140 int (**opv_desc_vector)(void *);
141 struct vnodeopv_entry_desc *opve_descp;
142
143 /*
144 * Allocate the dynamic vectors and fill them in.
145 */
146 for (i=0; vfs_opv_descs[i]; i++) {
147 opv_desc_vector_p = vfs_opv_descs[i]->opv_desc_vector_p;
148 /*
149 * Allocate and init the vector, if it needs it.
150 * Also handle backwards compatibility.
151 */
152 if (*opv_desc_vector_p == NULL) {
153 MALLOC(*opv_desc_vector_p, PFI*,
154 vfs_opv_numops*sizeof(PFI), M_TEMP, M_WAITOK);
155 bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFI));
156 DODEBUG(printf("vector at %x allocated\n",
157 opv_desc_vector_p));
158 }
159 opv_desc_vector = *opv_desc_vector_p;
160 for (j=0; vfs_opv_descs[i]->opv_desc_ops[j].opve_op; j++) {
161 opve_descp = &(vfs_opv_descs[i]->opv_desc_ops[j]);
162
163 /*
164 * Sanity check: is this operation listed
165 * in the list of operations? We check this
166 * by seeing if its offest is zero. Since
167 * the default routine should always be listed
168 * first, it should be the only one with a zero
169 * offset. Any other operation with a zero
170 * offset is probably not listed in
171 * vfs_op_descs, and so is probably an error.
172 *
173 * A panic here means the layer programmer
174 * has committed the all-too common bug
175 * of adding a new operation to the layer's
176 * list of vnode operations but
177 * not adding the operation to the system-wide
178 * list of supported operations.
179 */
180 if (opve_descp->opve_op->vdesc_offset == 0 &&
181 opve_descp->opve_op->vdesc_offset !=
182 VOFFSET(vnop_default)) {
183 printf("operation %s not listed in %s.\n",
184 opve_descp->opve_op->vdesc_name,
185 "vfs_op_descs");
186 panic ("vfs_opv_init: bad operation");
187 }
188 /*
189 * Fill in this entry.
190 */
191 opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
192 opve_descp->opve_impl;
193 }
194 }
195 /*
196 * Finally, go back and replace unfilled routines
197 * with their default. (Sigh, an O(n^3) algorithm. I
198 * could make it better, but that'd be work, and n is small.)
199 */
200 for (i = 0; vfs_opv_descs[i]; i++) {
201 opv_desc_vector = *(vfs_opv_descs[i]->opv_desc_vector_p);
202 /*
203 * Force every operations vector to have a default routine.
204 */
205 if (opv_desc_vector[VOFFSET(vnop_default)]==NULL) {
206 panic("vfs_opv_init: operation vector without default routine.");
207 }
208 for (k = 0; k<vfs_opv_numops; k++)
209 if (opv_desc_vector[k] == NULL)
210 opv_desc_vector[k] =
211 opv_desc_vector[VOFFSET(vnop_default)];
212 }
213 }
214
215 /*
216 * Initialize known vnode operations vectors.
217 */
218 void
219 vfs_op_init()
220 {
221 int i;
222
223 DODEBUG(printf("Vnode_interface_init.\n"));
224 /*
225 * Set all vnode vectors to a well known value.
226 */
227 for (i = 0; vfs_opv_descs[i]; i++)
228 *(vfs_opv_descs[i]->opv_desc_vector_p) = NULL;
229 /*
230 * Figure out how many ops there are by counting the table,
231 * and assign each its offset.
232 */
233 for (vfs_opv_numops = 0, i = 0; vfs_op_descs[i]; i++) {
234 vfs_op_descs[i]->vdesc_offset = vfs_opv_numops;
235 vfs_opv_numops++;
236 }
237 DODEBUG(printf ("vfs_opv_numops=%d\n", vfs_opv_numops));
238 }
239
240 /*
241 * Routines having to do with the management of the vnode table.
242 */
243 extern struct vnodeops dead_vnodeops;
244 extern struct vnodeops spec_vnodeops;
245
246 /* vars for vnode lock */
247 lck_grp_t * vnode_lck_grp;
248 lck_grp_attr_t * vnode_lck_grp_attr;
249 lck_attr_t * vnode_lck_attr;
250
251
252 /* vars for vnode list lock */
253 lck_grp_t * vnode_list_lck_grp;
254 lck_grp_attr_t * vnode_list_lck_grp_attr;
255 lck_attr_t * vnode_list_lck_attr;
256 lck_mtx_t * vnode_list_mtx_lock;
257 lck_mtx_t * spechash_mtx_lock;
258 /* Routine to lock and unlock the vnode lists */
259 void vnode_list_lock(void);
260 void vnode_list_unlock(void);
261
262 /* vars for vfsconf lock */
263 lck_grp_t * fsconf_lck_grp;
264 lck_grp_attr_t * fsconf_lck_grp_attr;
265 lck_attr_t * fsconf_lck_attr;
266
267
268 /* vars for mount lock */
269 lck_grp_t * mnt_lck_grp;
270 lck_grp_attr_t * mnt_lck_grp_attr;
271 lck_attr_t * mnt_lck_attr;
272
273 /* vars for mount list lock */
274 lck_grp_t * mnt_list_lck_grp;
275 lck_grp_attr_t * mnt_list_lck_grp_attr;
276 lck_attr_t * mnt_list_lck_attr;
277 lck_mtx_t * mnt_list_mtx_lock;
278
279 extern void journal_init();
280
281 struct mount * dead_mountp;
282 /*
283 * Initialize the vnode structures and initialize each file system type.
284 */
285 void
286 vfsinit()
287 {
288 struct vfstable *vfsp;
289 int i, maxtypenum;
290 struct mount * mp;
291
292 /* Allocate vnode list lock group attribute and group */
293 vnode_list_lck_grp_attr= lck_grp_attr_alloc_init();
294 lck_grp_attr_setstat(vnode_list_lck_grp_attr);
295
296 vnode_list_lck_grp = lck_grp_alloc_init("vnode list", vnode_list_lck_grp_attr);
297
298 /* Allocate vnode list lock attribute */
299 vnode_list_lck_attr = lck_attr_alloc_init();
300 //lck_attr_setdebug(vnode_list_lck_attr);
301
302 /* Allocate vnode list lock */
303 vnode_list_mtx_lock = lck_mtx_alloc_init(vnode_list_lck_grp, vnode_list_lck_attr);
304
305 /* Allocate spec hash list lock */
306 spechash_mtx_lock = lck_mtx_alloc_init(vnode_list_lck_grp, vnode_list_lck_attr);
307
308 /* allocate vnode lock group attribute and group */
309 vnode_lck_grp_attr= lck_grp_attr_alloc_init();
310 lck_grp_attr_setstat(vnode_lck_grp_attr);
311
312 vnode_lck_grp = lck_grp_alloc_init("vnode", vnode_lck_grp_attr);
313
314 /* Allocate vnode lock attribute */
315 vnode_lck_attr = lck_attr_alloc_init();
316 //lck_attr_setdebug(vnode_lck_attr);
317
318 /* Allocate fs config lock group attribute and group */
319 fsconf_lck_grp_attr= lck_grp_attr_alloc_init();
320 lck_grp_attr_setstat(fsconf_lck_grp_attr);
321
322 fsconf_lck_grp = lck_grp_alloc_init("fs conf", fsconf_lck_grp_attr);
323
324 /* Allocate fs config lock attribute */
325 fsconf_lck_attr = lck_attr_alloc_init();
326 //lck_attr_setdebug(fsconf_lck_attr);
327
328
329 /* Allocate mount point related lock structures */
330
331 /* Allocate mount list lock group attribute and group */
332 mnt_list_lck_grp_attr= lck_grp_attr_alloc_init();
333 lck_grp_attr_setstat(mnt_list_lck_grp_attr);
334
335 mnt_list_lck_grp = lck_grp_alloc_init("mount list", mnt_list_lck_grp_attr);
336
337 /* Allocate mount list lock attribute */
338 mnt_list_lck_attr = lck_attr_alloc_init();
339 //lck_attr_setdebug(mnt_list_lck_attr);
340
341 /* Allocate mount list lock */
342 mnt_list_mtx_lock = lck_mtx_alloc_init(mnt_list_lck_grp, mnt_list_lck_attr);
343
344
345 /* allocate mount lock group attribute and group */
346 mnt_lck_grp_attr= lck_grp_attr_alloc_init();
347 lck_grp_attr_setstat(mnt_lck_grp_attr);
348
349 mnt_lck_grp = lck_grp_alloc_init("mount", mnt_lck_grp_attr);
350
351 /* Allocate mount lock attribute */
352 mnt_lck_attr = lck_attr_alloc_init();
353 //lck_attr_setdebug(mnt_lck_attr);
354
355 /*
356 * Initialize the "console user" for access purposes:
357 */
358 console_user = (uid_t)0;
359
360 /*
361 * Initialize the vnode table
362 */
363 vntblinit();
364 /*
365 * Initialize the filesystem event mechanism.
366 */
367 vfs_event_init();
368 /*
369 * Initialize the vnode name cache
370 */
371 nchinit();
372 /*
373 * Initialize the journaling locks
374 */
375 journal_init();
376 /*
377 * Build vnode operation vectors.
378 */
379 vfs_op_init();
380 vfs_opv_init(); /* finish the job */
381 /*
382 * Initialize each file system type in the static list,
383 * until the first NULL ->vfs_vfsops is encountered.
384 */
385 numused_vfsslots = maxtypenum = 0;
386 for (vfsp = vfsconf, i = 0; i < maxvfsconf; i++, vfsp++) {
387 if (vfsp->vfc_vfsops == (struct vfsops *)0)
388 break;
389 if (i) vfsconf[i-1].vfc_next = vfsp;
390 if (maxtypenum <= vfsp->vfc_typenum)
391 maxtypenum = vfsp->vfc_typenum + 1;
392 (*vfsp->vfc_vfsops->vfs_init)(vfsp);
393
394 lck_mtx_init(&vfsp->vfc_lock, fsconf_lck_grp, fsconf_lck_attr);
395
396 numused_vfsslots++;
397 }
398 /* next vfc_typenum to be used */
399 maxvfsconf = maxtypenum;
400
401 /*
402 * Initialize the vnop authorization scope.
403 */
404 vnode_authorize_init();
405
406 /*
407 * create a mount point for dead vnodes
408 */
409 MALLOC_ZONE(mp, struct mount *, (u_long)sizeof(struct mount),
410 M_MOUNT, M_WAITOK);
411 bzero((char *)mp, (u_long)sizeof(struct mount));
412 /* Initialize the default IO constraints */
413 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
414 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
415 mp->mnt_maxsegreadsize = mp->mnt_maxreadcnt;
416 mp->mnt_maxsegwritesize = mp->mnt_maxwritecnt;
417 mp->mnt_devblocksize = DEV_BSIZE;
418
419 TAILQ_INIT(&mp->mnt_vnodelist);
420 TAILQ_INIT(&mp->mnt_workerqueue);
421 TAILQ_INIT(&mp->mnt_newvnodes);
422 mp->mnt_flag = MNT_LOCAL;
423 mp->mnt_lflag = MNT_LDEAD;
424 mount_lock_init(mp);
425 dead_mountp = mp;
426 }
427
428 void
429 vnode_list_lock()
430 {
431 lck_mtx_lock(vnode_list_mtx_lock);
432 }
433
434 void
435 vnode_list_unlock()
436 {
437 lck_mtx_unlock(vnode_list_mtx_lock);
438 }
439
440 void
441 mount_list_lock()
442 {
443 lck_mtx_lock(mnt_list_mtx_lock);
444 }
445
446 void
447 mount_list_unlock()
448 {
449 lck_mtx_unlock(mnt_list_mtx_lock);
450 }
451
452 void
453 mount_lock_init(mount_t mp)
454 {
455 lck_mtx_init(&mp->mnt_mlock, mnt_lck_grp, mnt_lck_attr);
456 lck_mtx_init(&mp->mnt_renamelock, mnt_lck_grp, mnt_lck_attr);
457 lck_rw_init(&mp->mnt_rwlock, mnt_lck_grp, mnt_lck_attr);
458 }
459
460 void
461 mount_lock_destroy(mount_t mp)
462 {
463 lck_mtx_destroy(&mp->mnt_mlock, mnt_lck_grp);
464 lck_mtx_destroy(&mp->mnt_renamelock, mnt_lck_grp);
465 lck_rw_destroy(&mp->mnt_rwlock, mnt_lck_grp);
466 }
467
468
469 /*
470 * Name: vfstable_add
471 *
472 * Description: Add a filesystem to the vfsconf list at the first
473 * unused slot. If no slots are available, return an
474 * error.
475 *
476 * Parameter: nvfsp vfsconf for VFS to add
477 *
478 * Returns: 0 Success
479 * -1 Failure
480 *
481 * Notes: The vfsconf should be treated as a linked list by
482 * all external references, as the implementation is
483 * expected to change in the future. The linkage is
484 * through ->vfc_next, and the list is NULL terminated.
485 *
486 * Warning: This code assumes that vfsconf[0] is non-empty.
487 */
488 struct vfstable *
489 vfstable_add(struct vfstable *nvfsp)
490 {
491 int slot;
492 struct vfstable *slotp;
493
494 /*
495 * Find the next empty slot; we recognize an empty slot by a
496 * NULL-valued ->vfc_vfsops, so if we delete a VFS, we must
497 * ensure we set the entry back to NULL.
498 */
499 for (slot = 0; slot < maxvfsslots; slot++) {
500 if (vfsconf[slot].vfc_vfsops == NULL)
501 break;
502 }
503 if (slot == maxvfsslots) {
504 /* out of static slots; allocate one instead */
505 MALLOC(slotp, struct vfstable *, sizeof(struct vfstable),
506 M_TEMP, M_WAITOK);
507 } else {
508 slotp = &vfsconf[slot];
509 }
510
511 /*
512 * Replace the contents of the next empty slot with the contents
513 * of the provided nvfsp.
514 *
515 * Note; Takes advantage of the fact that 'slot' was left
516 * with the value of 'maxvfslots' in the allocation case.
517 */
518 bcopy(nvfsp, slotp, sizeof(struct vfstable));
519 lck_mtx_init(&slotp->vfc_lock, fsconf_lck_grp, fsconf_lck_attr);
520 if (slot != 0) {
521 slotp->vfc_next = vfsconf[slot - 1].vfc_next;
522 vfsconf[slot - 1].vfc_next = slotp;
523 } else {
524 slotp->vfc_next = NULL;
525 }
526 numused_vfsslots++;
527
528 return(slotp);
529 }
530
531 /*
532 * Name: vfstable_del
533 *
534 * Description: Remove a filesystem from the vfsconf list by name.
535 * If no such filesystem exists, return an error.
536 *
537 * Parameter: fs_name name of VFS to remove
538 *
539 * Returns: 0 Success
540 * -1 Failure
541 *
542 * Notes: Hopefully all filesystems have unique names.
543 */
544 int
545 vfstable_del(struct vfstable * vtbl)
546 {
547 struct vfstable **vcpp;
548 struct vfstable *vcdelp;
549
550 /*
551 * Traverse the list looking for vtbl; if found, *vcpp
552 * will contain the address of the pointer to the entry to
553 * be removed.
554 */
555 for( vcpp = &vfsconf; *vcpp; vcpp = &(*vcpp)->vfc_next) {
556 if (*vcpp == vtbl)
557 break;
558 }
559
560 if (*vcpp == NULL)
561 return(ESRCH); /* vtbl not on vfsconf list */
562
563 /* Unlink entry */
564 vcdelp = *vcpp;
565 *vcpp = (*vcpp)->vfc_next;
566
567 lck_mtx_destroy(&vcdelp->vfc_lock, fsconf_lck_grp);
568
569 /*
570 * Is this an entry from our static table? We find out by
571 * seeing if the pointer to the object to be deleted places
572 * the object in the address space containing the table (or not).
573 */
574 if (vcdelp >= vfsconf && vcdelp < (vfsconf + maxvfsslots)) { /* Y */
575 /* Mark as empty for vfscon_add() */
576 bzero(vcdelp, sizeof(struct vfstable));
577 numused_vfsslots--;
578 } else { /* N */
579 /*
580 * This entry was dynamically allocated; we must free it;
581 * we would prefer to have just linked the caller's
582 * vfsconf onto our list, but it may not be persistent
583 * because of the previous (copying) implementation.
584 */
585 FREE(vcdelp, M_TEMP);
586 }
587
588 return(0);
589 }
590
591 void
592 SPECHASH_LOCK(void)
593 {
594 lck_mtx_lock(spechash_mtx_lock);
595 }
596
597 void
598 SPECHASH_UNLOCK(void)
599 {
600 lck_mtx_unlock(spechash_mtx_lock);
601 }
602