vfs_init.c revision 138290
1105197Ssam/*
2105197Ssam * Copyright (c) 1989, 1993
3105197Ssam *	The Regents of the University of California.  All rights reserved.
4139823Simp *
5105197Ssam * This code is derived from software contributed
6105197Ssam * to Berkeley by John Heidemann of the UCLA Ficus project.
7105197Ssam *
8105197Ssam * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project
9105197Ssam *
10105197Ssam * Redistribution and use in source and binary forms, with or without
11105197Ssam * modification, are permitted provided that the following conditions
12105197Ssam * are met:
13105197Ssam * 1. Redistributions of source code must retain the above copyright
14105197Ssam *    notice, this list of conditions and the following disclaimer.
15105197Ssam * 2. Redistributions in binary form must reproduce the above copyright
16105197Ssam *    notice, this list of conditions and the following disclaimer in the
17105197Ssam *    documentation and/or other materials provided with the distribution.
18105197Ssam * 4. Neither the name of the University nor the names of its contributors
19105197Ssam *    may be used to endorse or promote products derived from this software
20105197Ssam *    without specific prior written permission.
21105197Ssam *
22105197Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23105197Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24105197Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25105197Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26105197Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27105197Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28105197Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29105197Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30105197Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31105197Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32105197Ssam * SUCH DAMAGE.
33105197Ssam *
34105197Ssam *	@(#)vfs_init.c	8.3 (Berkeley) 1/4/94
35105197Ssam */
36105197Ssam
37105197Ssam#include <sys/cdefs.h>
38105197Ssam__FBSDID("$FreeBSD: head/sys/kern/vfs_init.c 138290 2004-12-01 23:16:38Z phk $");
39105197Ssam
40105197Ssam#include <sys/param.h>
41105197Ssam#include <sys/systm.h>
42105197Ssam#include <sys/kernel.h>
43105197Ssam#include <sys/mount.h>
44105197Ssam#include <sys/sysctl.h>
45105197Ssam#include <sys/vnode.h>
46105197Ssam#include <sys/malloc.h>
47105197Ssam
48105197Ssam
49105197SsamMALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes");
50105197Ssam
51105197Ssam/*
52105197Ssam * The highest defined VFS number.
53157123Sgnn */
54157123Sgnnint maxvfsconf = VFS_GENERIC + 1;
55105197Ssam
56105197Ssam/*
57105197Ssam * Single-linked list of configured VFSes.
58105197Ssam * New entries are added/deleted by vfs_register()/vfs_unregister()
59 */
60struct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(vfsconf);
61
62/*
63 * A Zen vnode attribute structure.
64 *
65 * Initialized when the first filesystem registers by vfs_register().
66 */
67struct vattr va_null;
68
69/*
70 * vfs_init.c
71 *
72 * Allocate and fill in operations vectors.
73 *
74 * An undocumented feature of this approach to defining operations is that
75 * there can be multiple entries in vfs_opv_descs for the same operations
76 * vector. This allows third parties to extend the set of operations
77 * supported by another layer in a binary compatibile way. For example,
78 * assume that NFS needed to be modified to support Ficus. NFS has an entry
79 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
80 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
81 * listing those new operations Ficus adds to NFS, all without modifying the
82 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
83 * that is a(whole)nother story.) This is a feature.
84 */
85
86/*
87 * Routines having to do with the management of the vnode table.
88 */
89
90/*
91 * XXX: hack alert
92 */
93int
94vcall(struct vnode *vp, u_int off, void *ap)
95{
96	struct vop_vector *vop = vp->v_op;
97	vop_bypass_t **bpt;
98	int rc;
99
100	for(;;) {
101		bpt = (void *)((u_char *)vop + off);
102		if (vop != NULL && *bpt == NULL && vop->vop_bypass == NULL) {
103			vop = vop->vop_default;
104			continue;
105		}
106		break;
107	}
108	KASSERT(vop != NULL, ("No VCALL(%p...)", vp));
109	if (*bpt != NULL)
110		rc = (*bpt)(ap);
111	else
112		rc = vop->vop_bypass(ap);
113	return (rc);
114}
115
116struct vfsconf *
117vfs_byname(const char *name)
118{
119	struct vfsconf *vfsp;
120
121	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list)
122		if (!strcmp(name, vfsp->vfc_name))
123			return (vfsp);
124	return (NULL);
125}
126
127/* Register a new filesystem type in the global table */
128int
129vfs_register(struct vfsconf *vfc)
130{
131	struct sysctl_oid *oidp;
132	struct vfsops *vfsops;
133	static int once;
134
135	if (!once) {
136		vattr_null(&va_null);
137		once = 1;
138	}
139
140	if (vfc->vfc_version != VFS_VERSION) {
141		printf("ERROR: filesystem %s, unsupported ABI version %x\n",
142		    vfc->vfc_name, vfc->vfc_version);
143		return (EINVAL);
144	}
145	if (vfs_byname(vfc->vfc_name) != NULL)
146		return EEXIST;
147
148	vfc->vfc_typenum = maxvfsconf++;
149	TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list);
150
151	/*
152	 * If this filesystem has a sysctl node under vfs
153	 * (i.e. vfs.xxfs), then change the oid number of that node to
154	 * match the filesystem's type number.  This allows user code
155	 * which uses the type number to read sysctl variables defined
156	 * by the filesystem to continue working. Since the oids are
157	 * in a sorted list, we need to make sure the order is
158	 * preserved by re-registering the oid after modifying its
159	 * number.
160	 */
161	SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
162		if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
163			sysctl_unregister_oid(oidp);
164			oidp->oid_number = vfc->vfc_typenum;
165			sysctl_register_oid(oidp);
166		}
167
168	/*
169	 * Initialise unused ``struct vfsops'' fields, to use
170	 * the vfs_std*() functions.  Note, we need the mount
171	 * and unmount operations, at the least.  The check
172	 * for vfsops available is just a debugging aid.
173	 */
174	KASSERT(vfc->vfc_vfsops != NULL,
175	    ("Filesystem %s has no vfsops", vfc->vfc_name));
176	/*
177	 * Check the mount and unmount operations.
178	 */
179	vfsops = vfc->vfc_vfsops;
180	KASSERT(vfsops->vfs_mount != NULL || vfsops->vfs_omount != NULL,
181	    ("Filesystem %s has no (o)mount op", vfc->vfc_name));
182	KASSERT(vfsops->vfs_unmount != NULL,
183	    ("Filesystem %s has no unmount op", vfc->vfc_name));
184
185	if (vfsops->vfs_start == NULL)
186		/* make a file system operational */
187		vfsops->vfs_start =	vfs_stdstart;
188	if (vfsops->vfs_root == NULL)
189		/* return file system's root vnode */
190		vfsops->vfs_root =	vfs_stdroot;
191	if (vfsops->vfs_quotactl == NULL)
192		/* quota control */
193		vfsops->vfs_quotactl =	vfs_stdquotactl;
194	if (vfsops->vfs_statfs == NULL)
195		/* return file system's status */
196		vfsops->vfs_statfs =	vfs_stdstatfs;
197	if (vfsops->vfs_sync == NULL)
198		/*
199		 * flush unwritten data (nosync)
200		 * file systems can use vfs_stdsync
201		 * explicitly by setting it in the
202		 * vfsop vector.
203		 */
204		vfsops->vfs_sync =	vfs_stdnosync;
205	if (vfsops->vfs_vget == NULL)
206		/* convert an inode number to a vnode */
207		vfsops->vfs_vget =	vfs_stdvget;
208	if (vfsops->vfs_fhtovp == NULL)
209		/* turn an NFS file handle into a vnode */
210		vfsops->vfs_fhtovp =	vfs_stdfhtovp;
211	if (vfsops->vfs_checkexp == NULL)
212		/* check if file system is exported */
213		vfsops->vfs_checkexp =	vfs_stdcheckexp;
214	if (vfsops->vfs_vptofh == NULL)
215		/* turn a vnode into an NFS file handle */
216		vfsops->vfs_vptofh =	vfs_stdvptofh;
217	if (vfsops->vfs_init == NULL)
218		/* file system specific initialisation */
219		vfsops->vfs_init =	vfs_stdinit;
220	if (vfsops->vfs_uninit == NULL)
221		/* file system specific uninitialisation */
222		vfsops->vfs_uninit =	vfs_stduninit;
223	if (vfsops->vfs_extattrctl == NULL)
224		/* extended attribute control */
225		vfsops->vfs_extattrctl = vfs_stdextattrctl;
226	if (vfsops->vfs_sysctl == NULL)
227		vfsops->vfs_sysctl = vfs_stdsysctl;
228
229	/*
230	 * Call init function for this VFS...
231	 */
232	(*(vfc->vfc_vfsops->vfs_init))(vfc);
233
234	return 0;
235}
236
237
238/* Remove registration of a filesystem type */
239int
240vfs_unregister(struct vfsconf *vfc)
241{
242	struct vfsconf *vfsp;
243	int error, i, maxtypenum;
244
245	i = vfc->vfc_typenum;
246
247	vfsp = vfs_byname(vfc->vfc_name);
248	if (vfsp == NULL)
249		return EINVAL;
250	if (vfsp->vfc_refcount)
251		return EBUSY;
252	if (vfc->vfc_vfsops->vfs_uninit != NULL) {
253		error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
254		if (error)
255			return (error);
256	}
257	TAILQ_REMOVE(&vfsconf, vfsp, vfc_list);
258	maxtypenum = VFS_GENERIC;
259	TAILQ_FOREACH(vfsp, &vfsconf, vfc_list)
260		if (maxtypenum < vfsp->vfc_typenum)
261			maxtypenum = vfsp->vfc_typenum;
262	maxvfsconf = maxtypenum + 1;
263	return 0;
264}
265
266/*
267 * Standard kernel module handling code for filesystem modules.
268 * Referenced from VFS_SET().
269 */
270int
271vfs_modevent(module_t mod, int type, void *data)
272{
273	struct vfsconf *vfc;
274	int error = 0;
275
276	vfc = (struct vfsconf *)data;
277
278	switch (type) {
279	case MOD_LOAD:
280		if (vfc)
281			error = vfs_register(vfc);
282		break;
283
284	case MOD_UNLOAD:
285		if (vfc)
286			error = vfs_unregister(vfc);
287		break;
288	default:
289		error = EOPNOTSUPP;
290		break;
291	}
292	return (error);
293}
294