xref: /freebsd/sys/kern/vfs_init.c (revision 3e0f6b97b257a96f7275e4442204263e44b16686)
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  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)vfs_init.c	8.3 (Berkeley) 1/4/94
39  * $FreeBSD$
40  */
41 
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/mount.h>
47 #include <sys/time.h>
48 #include <sys/vnode.h>
49 #include <sys/stat.h>
50 #include <sys/namei.h>
51 #include <sys/ucred.h>
52 #include <sys/buf.h>
53 #include <sys/errno.h>
54 #include <sys/malloc.h>
55 #include <sys/proc.h>
56 #include <vm/vm.h>
57 #include <sys/sysctl.h>
58 
59 static void	vfs_op_init __P((void));
60 
61 static void vfsinit __P((void *));
62 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL)
63 
64 /*
65  * Sigh, such primitive tools are these...
66  */
67 #if 0
68 #define DODEBUG(A) A
69 #else
70 #define DODEBUG(A)
71 #endif
72 
73 struct vfsconf void_vfsconf;
74 
75 extern struct linker_set vfs_opv_descs_;
76 #define vfs_opv_descs ((struct vnodeopv_desc **)vfs_opv_descs_.ls_items)
77 
78 extern struct linker_set vfs_set;
79 
80 extern struct vnodeop_desc *vfs_op_descs[];
81 				/* and the operations they perform */
82 /*
83  * This code doesn't work if the defn is **vnodop_defns with cc.
84  * The problem is because of the compiler sometimes putting in an
85  * extra level of indirection for arrays.  It's an interesting
86  * "feature" of C.
87  */
88 static int vfs_opv_numops;
89 
90 /*
91  * A miscellaneous routine.
92  * A generic "default" routine that just returns an error.
93  */
94 int
95 vn_default_error()
96 {
97 
98 	return (EOPNOTSUPP);
99 }
100 
101 /*
102  * vfs_init.c
103  *
104  * Allocate and fill in operations vectors.
105  *
106  * An undocumented feature of this approach to defining operations is that
107  * there can be multiple entries in vfs_opv_descs for the same operations
108  * vector. This allows third parties to extend the set of operations
109  * supported by another layer in a binary compatibile way. For example,
110  * assume that NFS needed to be modified to support Ficus. NFS has an entry
111  * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
112  * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
113  * listing those new operations Ficus adds to NFS, all without modifying the
114  * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
115  * that is a(whole)nother story.) This is a feature.
116  */
117 void
118 vfs_opv_init(struct vnodeopv_desc **them)
119 {
120 	int i, j, k;
121 	vop_t ***opv_desc_vector_p;
122 	vop_t **opv_desc_vector;
123 	struct vnodeopv_entry_desc *opve_descp;
124 
125 	/*
126 	 * Allocate the dynamic vectors and fill them in.
127 	 */
128 	for (i=0; them[i]; i++) {
129 		opv_desc_vector_p = them[i]->opv_desc_vector_p;
130 		/*
131 		 * Allocate and init the vector, if it needs it.
132 		 * Also handle backwards compatibility.
133 		 */
134 		if (*opv_desc_vector_p == NULL) {
135 			/* XXX - shouldn't be M_VNODE */
136 			MALLOC(*opv_desc_vector_p, vop_t **,
137 			       vfs_opv_numops * sizeof(vop_t *), M_VNODE,
138 			       M_WAITOK);
139 			bzero(*opv_desc_vector_p,
140 			      vfs_opv_numops * sizeof(vop_t *));
141 			DODEBUG(printf("vector at %x allocated\n",
142 			    opv_desc_vector_p));
143 		}
144 		opv_desc_vector = *opv_desc_vector_p;
145 		for (j=0; them[i]->opv_desc_ops[j].opve_op; j++) {
146 			opve_descp = &(them[i]->opv_desc_ops[j]);
147 
148 			/*
149 			 * Sanity check:  is this operation listed
150 			 * in the list of operations?  We check this
151 			 * by seeing if its offest is zero.  Since
152 			 * the default routine should always be listed
153 			 * first, it should be the only one with a zero
154 			 * offset.  Any other operation with a zero
155 			 * offset is probably not listed in
156 			 * vfs_op_descs, and so is probably an error.
157 			 *
158 			 * A panic here means the layer programmer
159 			 * has committed the all-too common bug
160 			 * of adding a new operation to the layer's
161 			 * list of vnode operations but
162 			 * not adding the operation to the system-wide
163 			 * list of supported operations.
164 			 */
165 			if (opve_descp->opve_op->vdesc_offset == 0 &&
166 				    opve_descp->opve_op->vdesc_offset !=
167 				    	VOFFSET(vop_default)) {
168 				printf("operation %s not listed in %s.\n",
169 				    opve_descp->opve_op->vdesc_name,
170 				    "vfs_op_descs");
171 				panic ("vfs_opv_init: bad operation");
172 			}
173 			/*
174 			 * Fill in this entry.
175 			 */
176 			opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
177 					opve_descp->opve_impl;
178 		}
179 	}
180 	/*
181 	 * Finally, go back and replace unfilled routines
182 	 * with their default.  (Sigh, an O(n^3) algorithm.  I
183 	 * could make it better, but that'd be work, and n is small.)
184 	 */
185 	for (i = 0; them[i]; i++) {
186 		opv_desc_vector = *(them[i]->opv_desc_vector_p);
187 		/*
188 		 * Force every operations vector to have a default routine.
189 		 */
190 		if (opv_desc_vector[VOFFSET(vop_default)]==NULL) {
191 			panic("vfs_opv_init: operation vector without default routine.");
192 		}
193 		for (k = 0; k<vfs_opv_numops; k++)
194 			if (opv_desc_vector[k] == NULL)
195 				opv_desc_vector[k] =
196 					opv_desc_vector[VOFFSET(vop_default)];
197 	}
198 }
199 
200 /*
201  * Initialize known vnode operations vectors.
202  */
203 static void
204 vfs_op_init()
205 {
206 	int i;
207 
208 	DODEBUG(printf("Vnode_interface_init.\n"));
209 	/*
210 	 * Set all vnode vectors to a well known value.
211 	 */
212 	for (i = 0; vfs_opv_descs[i]; i++)
213 		*(vfs_opv_descs[i]->opv_desc_vector_p) = NULL;
214 	/*
215 	 * Figure out how many ops there are by counting the table,
216 	 * and assign each its offset.
217 	 */
218 	for (vfs_opv_numops = 0, i = 0; vfs_op_descs[i]; i++) {
219 		vfs_op_descs[i]->vdesc_offset = vfs_opv_numops;
220 		vfs_opv_numops++;
221 	}
222 	DODEBUG(printf ("vfs_opv_numops=%d\n", vfs_opv_numops));
223 }
224 
225 /*
226  * Routines having to do with the management of the vnode table.
227  */
228 extern struct vnodeops dead_vnodeops;
229 extern struct vnodeops spec_vnodeops;
230 struct vattr va_null;
231 
232 /*
233  * Initialize the vnode structures and initialize each file system type.
234  */
235 /* ARGSUSED*/
236 static void
237 vfsinit(dummy)
238 	void *dummy;
239 {
240 	struct vfsconf **vfc;
241 	int maxtypenum;
242 
243 	/*
244 	 * Initialize the vnode table
245 	 */
246 	vntblinit();
247 	/*
248 	 * Initialize the vnode name cache
249 	 */
250 	nchinit();
251 	/*
252 	 * Build vnode operation vectors.
253 	 */
254 	vfs_op_init();
255 	vfs_opv_init(vfs_opv_descs);   /* finish the job */
256 	/*
257 	 * Initialize each file system type.
258 	 */
259 	vattr_null(&va_null);
260 	maxtypenum = 0;
261 	vfc = (struct vfsconf **)vfs_set.ls_items;
262 	vfsconf = *vfc;		/* simulate Lite2 vfsconf array */
263 	while (*vfc) {
264 		struct vfsconf *vfsp = *vfc;
265 
266 		vfc++;
267 		vfsp->vfc_next = *vfc;
268 		if (maxtypenum <= vfsp->vfc_typenum)
269 			maxtypenum = vfsp->vfc_typenum + 1;
270 		(*vfsp->vfc_vfsops->vfs_init)(vfsp);
271 	}
272 	/* next vfc_typenum to be used */
273 	maxvfsconf = maxtypenum;
274 }
275 
276 /*
277  * kernel related system variables.
278  */
279 
280 static int
281 sysctl_vfs_conf SYSCTL_HANDLER_ARGS
282 {
283 	int error;
284 	struct vfsconf *vfsp;
285 
286 	if (req->newptr)
287 		return EINVAL;
288 	for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
289 		error = SYSCTL_OUT(req, vfsp, sizeof *vfsp);
290 		if (error)
291 			return error;
292 	}
293 	return 0;
294 }
295 
296 SYSCTL_PROC(_vfs, VFS_VFSCONF, vfsconf, CTLTYPE_OPAQUE|CTLFLAG_RD,
297 	0, 0, sysctl_vfs_conf, "S,vfsconf", "");
298 
299 #ifdef COMPAT_PRELITE2
300 
301 #define OVFS_MAXNAMELEN 32
302 struct ovfsconf {
303 	void *vfc_vfsops;
304 	char vfc_name[OVFS_MAXNAMELEN];
305 	int vfc_index;
306 	int vfc_refcount;
307 	int vfc_flags;
308 };
309 
310 static int
311 sysctl_ovfs_conf SYSCTL_HANDLER_ARGS
312 {
313 	int error;
314 	struct vfsconf *vfsp;
315 
316 	if (req->newptr)
317 		return EINVAL;
318 	for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
319 		struct ovfsconf ovfs;
320 		ovfs.vfc_vfsops = NULL;
321 		strcpy(ovfs.vfc_name, vfsp->vfc_name);
322 		ovfs.vfc_index = vfsp->vfc_typenum;
323 		ovfs.vfc_refcount = vfsp->vfc_refcount;
324 		ovfs.vfc_flags = vfsp->vfc_flags;
325 		error = SYSCTL_OUT(req, &ovfs, sizeof ovfs);
326 		if (error)
327 			return error;
328 	}
329 	return 0;
330 }
331 
332 SYSCTL_PROC(_vfs, VFS_OVFSCONF, ovfsconf, CTLTYPE_OPAQUE|CTLFLAG_RD,
333 	0, 0, sysctl_ovfs_conf, "S,ovfsconf", "");
334 
335 #endif /* COMPAT_PRELITE2 */
336 
337 /*
338  * This goop is here to support a loadable NFS module... grumble...
339  */
340 int (*lease_check_hook) __P((struct vop_lease_args *))
341      = 0;
342 void (*lease_updatetime) __P((int))
343      = 0;
344 
345 int
346 lease_check(ap)
347 	struct vop_lease_args /* {
348 		struct vnode *a_vp;
349 		struct proc *a_p;
350 		struct ucred *a_cred;
351 		int a_flag;
352 	} */ *ap;
353 {
354     if (lease_check_hook)
355 	return (*lease_check_hook)(ap);
356     else
357 	return 0;
358 }
359