xref: /original-bsd/sys/kern/vfs_init.c (revision 3705696b)
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.1 (Berkeley) 06/10/93
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
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
78 vfs_opv_init()
79 {
80 	int i, j, k;
81 	struct vnodeop_defn *defnp;
82 	int (***opv_desc_vector_p)();
83 	int (**opv_desc_vector)();
84 	struct vnodeopv_entry_desc *opve_descp;
85 
86 	/*
87 	 * Allocate the dynamic vectors and fill them in.
88 	 */
89 	for (i=0; vfs_opv_descs[i]; i++) {
90 		opv_desc_vector_p = vfs_opv_descs[i]->opv_desc_vector_p;
91 		/*
92 		 * Allocate and init the vector, if it needs it.
93 		 * Also handle backwards compatibility.
94 		 */
95 		if (*opv_desc_vector_p == NULL) {
96 			/* XXX - shouldn't be M_VNODE */
97 			MALLOC(*opv_desc_vector_p, PFI*,
98 			       vfs_opv_numops*sizeof(PFI), M_VNODE, M_WAITOK);
99 			bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFI));
100 			DODEBUG(printf("vector at %x allocated\n",
101 			    opv_desc_vector_p));
102 		}
103 		opv_desc_vector = *opv_desc_vector_p;
104 		for (j=0; vfs_opv_descs[i]->opv_desc_ops[j].opve_op; j++) {
105 			opve_descp = &(vfs_opv_descs[i]->opv_desc_ops[j]);
106 
107 			/*
108 			 * Sanity check:  is this operation listed
109 			 * in the list of operations?  We check this
110 			 * by seeing if its offest is zero.  Since
111 			 * the default routine should always be listed
112 			 * first, it should be the only one with a zero
113 			 * offset.  Any other operation with a zero
114 			 * offset is probably not listed in
115 			 * vfs_op_descs, and so is probably an error.
116 			 *
117 			 * A panic here means the layer programmer
118 			 * has committed the all-too common bug
119 			 * of adding a new operation to the layer's
120 			 * list of vnode operations but
121 			 * not adding the operation to the system-wide
122 			 * list of supported operations.
123 			 */
124 			if (opve_descp->opve_op->vdesc_offset == 0 &&
125 				    opve_descp->opve_op->vdesc_offset !=
126 				    	VOFFSET(vop_default)) {
127 				printf("operation %s not listed in %s.\n",
128 				    opve_descp->opve_op->vdesc_name,
129 				    "vfs_op_descs");
130 				panic ("vfs_opv_init: bad operation");
131 			}
132 			/*
133 			 * Fill in this entry.
134 			 */
135 			opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
136 					opve_descp->opve_impl;
137 		}
138 	}
139 	/*
140 	 * Finally, go back and replace unfilled routines
141 	 * with their default.  (Sigh, an O(n^3) algorithm.  I
142 	 * could make it better, but that'd be work, and n is small.)
143 	 */
144 	for (i = 0; vfs_opv_descs[i]; i++) {
145 		opv_desc_vector = *(vfs_opv_descs[i]->opv_desc_vector_p);
146 		/*
147 		 * Force every operations vector to have a default routine.
148 		 */
149 		if (opv_desc_vector[VOFFSET(vop_default)]==NULL) {
150 			panic("vfs_opv_init: operation vector without default routine.");
151 		}
152 		for (k = 0; k<vfs_opv_numops; k++)
153 			if (opv_desc_vector[k] == NULL)
154 				opv_desc_vector[k] =
155 					opv_desc_vector[VOFFSET(vop_default)];
156 	}
157 }
158 
159 /*
160  * Initialize known vnode operations vectors.
161  */
162 void
163 vfs_op_init()
164 {
165 	int i, j;
166 
167 	DODEBUG(printf("Vnode_interface_init.\n"));
168 	/*
169 	 * Set all vnode vectors to a well known value.
170 	 */
171 	for (i = 0; vfs_opv_descs[i]; i++)
172 		*(vfs_opv_descs[i]->opv_desc_vector_p) = NULL;
173 	/*
174 	 * Figure out how many ops there are by counting the table,
175 	 * and assign each its offset.
176 	 */
177 	for (vfs_opv_numops = 0, i = 0; vfs_op_descs[i]; i++) {
178 		vfs_op_descs[i]->vdesc_offset = vfs_opv_numops;
179 		vfs_opv_numops++;
180 	}
181 	DODEBUG(printf ("vfs_opv_numops=%d\n", vfs_opv_numops));
182 }
183 
184 /*
185  * Routines having to do with the management of the vnode table.
186  */
187 extern struct vnodeops dead_vnodeops;
188 extern struct vnodeops spec_vnodeops;
189 extern void vclean();
190 struct vattr va_null;
191 
192 /*
193  * Initialize the vnode structures and initialize each file system type.
194  */
195 vfsinit()
196 {
197 	struct vfsops **vfsp;
198 
199 	/*
200 	 * Initialize the vnode name cache
201 	 */
202 	nchinit();
203 	/*
204 	 * Build vnode operation vectors.
205 	 */
206 	vfs_op_init();
207 	vfs_opv_init();   /* finish the job */
208 	/*
209 	 * Initialize each file system type.
210 	 */
211 	vattr_null(&va_null);
212 	for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
213 		if (*vfsp == NULL)
214 			continue;
215 		(*(*vfsp)->vfs_init)();
216 	}
217 }
218