1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed
6 * to Berkeley by John Heidemann of the UCLA Ficus project.
7 *
8 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
9 *
10 * %sccs.include.redist.c%
11 *
12 * @(#)vfs_init.c 8.5 (Berkeley) 05/11/95
13 */
14
15
16 #include <sys/param.h>
17 #include <sys/mount.h>
18 #include <sys/time.h>
19 #include <sys/vnode.h>
20 #include <sys/stat.h>
21 #include <sys/namei.h>
22 #include <sys/ucred.h>
23 #include <sys/buf.h>
24 #include <sys/errno.h>
25 #include <sys/malloc.h>
26
27 /*
28 * Sigh, such primitive tools are these...
29 */
30 #if 0
31 #define DODEBUG(A) A
32 #else
33 #define DODEBUG(A)
34 #endif
35
36 extern struct vnodeopv_desc *vfs_opv_descs[];
37 /* a list of lists of vnodeops defns */
38 extern struct vnodeop_desc *vfs_op_descs[];
39 /* and the operations they perform */
40 /*
41 * This code doesn't work if the defn is **vnodop_defns with cc.
42 * The problem is because of the compiler sometimes putting in an
43 * extra level of indirection for arrays. It's an interesting
44 * "feature" of C.
45 */
46 int vfs_opv_numops;
47
48 typedef (*PFI)(); /* the standard Pointer to a Function returning an Int */
49
50 /*
51 * A miscellaneous routine.
52 * A generic "default" routine that just returns an error.
53 */
54 int
vn_default_error()55 vn_default_error()
56 {
57
58 return (EOPNOTSUPP);
59 }
60
61 /*
62 * vfs_init.c
63 *
64 * Allocate and fill in operations vectors.
65 *
66 * An undocumented feature of this approach to defining operations is that
67 * there can be multiple entries in vfs_opv_descs for the same operations
68 * vector. This allows third parties to extend the set of operations
69 * supported by another layer in a binary compatibile way. For example,
70 * assume that NFS needed to be modified to support Ficus. NFS has an entry
71 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
72 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
73 * listing those new operations Ficus adds to NFS, all without modifying the
74 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
75 * that is a(whole)nother story.) This is a feature.
76 */
77 void
vfs_opv_init()78 vfs_opv_init()
79 {
80 int i, j, k;
81 int (***opv_desc_vector_p)();
82 int (**opv_desc_vector)();
83 struct vnodeopv_entry_desc *opve_descp;
84
85 /*
86 * Allocate the dynamic vectors and fill them in.
87 */
88 for (i=0; vfs_opv_descs[i]; i++) {
89 opv_desc_vector_p = vfs_opv_descs[i]->opv_desc_vector_p;
90 /*
91 * Allocate and init the vector, if it needs it.
92 * Also handle backwards compatibility.
93 */
94 if (*opv_desc_vector_p == NULL) {
95 /* XXX - shouldn't be M_VNODE */
96 MALLOC(*opv_desc_vector_p, PFI*,
97 vfs_opv_numops*sizeof(PFI), M_VNODE, M_WAITOK);
98 bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFI));
99 DODEBUG(printf("vector at %x allocated\n",
100 opv_desc_vector_p));
101 }
102 opv_desc_vector = *opv_desc_vector_p;
103 for (j=0; vfs_opv_descs[i]->opv_desc_ops[j].opve_op; j++) {
104 opve_descp = &(vfs_opv_descs[i]->opv_desc_ops[j]);
105
106 /*
107 * Sanity check: is this operation listed
108 * in the list of operations? We check this
109 * by seeing if its offest is zero. Since
110 * the default routine should always be listed
111 * first, it should be the only one with a zero
112 * offset. Any other operation with a zero
113 * offset is probably not listed in
114 * vfs_op_descs, and so is probably an error.
115 *
116 * A panic here means the layer programmer
117 * has committed the all-too common bug
118 * of adding a new operation to the layer's
119 * list of vnode operations but
120 * not adding the operation to the system-wide
121 * list of supported operations.
122 */
123 if (opve_descp->opve_op->vdesc_offset == 0 &&
124 opve_descp->opve_op->vdesc_offset !=
125 VOFFSET(vop_default)) {
126 printf("operation %s not listed in %s.\n",
127 opve_descp->opve_op->vdesc_name,
128 "vfs_op_descs");
129 panic ("vfs_opv_init: bad operation");
130 }
131 /*
132 * Fill in this entry.
133 */
134 opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
135 opve_descp->opve_impl;
136 }
137 }
138 /*
139 * Finally, go back and replace unfilled routines
140 * with their default. (Sigh, an O(n^3) algorithm. I
141 * could make it better, but that'd be work, and n is small.)
142 */
143 for (i = 0; vfs_opv_descs[i]; i++) {
144 opv_desc_vector = *(vfs_opv_descs[i]->opv_desc_vector_p);
145 /*
146 * Force every operations vector to have a default routine.
147 */
148 if (opv_desc_vector[VOFFSET(vop_default)]==NULL) {
149 panic("vfs_opv_init: operation vector without default routine.");
150 }
151 for (k = 0; k<vfs_opv_numops; k++)
152 if (opv_desc_vector[k] == NULL)
153 opv_desc_vector[k] =
154 opv_desc_vector[VOFFSET(vop_default)];
155 }
156 }
157
158 /*
159 * Initialize known vnode operations vectors.
160 */
161 void
vfs_op_init()162 vfs_op_init()
163 {
164 int i;
165
166 DODEBUG(printf("Vnode_interface_init.\n"));
167 /*
168 * Set all vnode vectors to a well known value.
169 */
170 for (i = 0; vfs_opv_descs[i]; i++)
171 *(vfs_opv_descs[i]->opv_desc_vector_p) = NULL;
172 /*
173 * Figure out how many ops there are by counting the table,
174 * and assign each its offset.
175 */
176 for (vfs_opv_numops = 0, i = 0; vfs_op_descs[i]; i++) {
177 vfs_op_descs[i]->vdesc_offset = vfs_opv_numops;
178 vfs_opv_numops++;
179 }
180 DODEBUG(printf ("vfs_opv_numops=%d\n", vfs_opv_numops));
181 }
182
183 /*
184 * Routines having to do with the management of the vnode table.
185 */
186 extern struct vnodeops dead_vnodeops;
187 extern struct vnodeops spec_vnodeops;
188 struct vattr va_null;
189
190 /*
191 * Initialize the vnode structures and initialize each file system type.
192 */
vfsinit()193 vfsinit()
194 {
195 struct vfsconf *vfsp;
196 int i, maxtypenum;
197
198 /*
199 * Initialize the vnode table
200 */
201 vntblinit();
202 /*
203 * Initialize the vnode name cache
204 */
205 nchinit();
206 /*
207 * Build vnode operation vectors.
208 */
209 vfs_op_init();
210 vfs_opv_init(); /* finish the job */
211 /*
212 * Initialize each file system type.
213 */
214 vattr_null(&va_null);
215 maxtypenum = 0;
216 for (vfsp = vfsconf, i = 1; i <= maxvfsconf; i++, vfsp++) {
217 if (i < maxvfsconf)
218 vfsp->vfc_next = vfsp + 1;
219 if (maxtypenum <= vfsp->vfc_typenum)
220 maxtypenum = vfsp->vfc_typenum + 1;
221 (*vfsp->vfc_vfsops->vfs_init)(vfsp);
222 }
223 /* next vfc_typenum to be used */
224 maxvfsconf = maxtypenum;
225 }
226