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