Deleted Added
full compact
vfs_init.c (139804) vfs_init.c (140165)
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 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94
35 */
36
37#include <sys/cdefs.h>
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 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/sys/kern/vfs_init.c 139804 2005-01-06 23:35:40Z imp $");
38__FBSDID("$FreeBSD: head/sys/kern/vfs_init.c 140165 2005-01-13 07:53:01Z phk $");
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/linker.h>
44#include <sys/mount.h>
45#include <sys/proc.h>
46#include <sys/sysctl.h>
47#include <sys/vnode.h>
48#include <sys/malloc.h>
49
50
51MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes");
52
53/*
54 * The highest defined VFS number.
55 */
56int maxvfsconf = VFS_GENERIC + 1;
57
58/*
59 * Single-linked list of configured VFSes.
60 * New entries are added/deleted by vfs_register()/vfs_unregister()
61 */
62struct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(vfsconf);
63
64/*
65 * A Zen vnode attribute structure.
66 *
67 * Initialized when the first filesystem registers by vfs_register().
68 */
69struct vattr va_null;
70
71/*
72 * vfs_init.c
73 *
74 * Allocate and fill in operations vectors.
75 *
76 * An undocumented feature of this approach to defining operations is that
77 * there can be multiple entries in vfs_opv_descs for the same operations
78 * vector. This allows third parties to extend the set of operations
79 * supported by another layer in a binary compatibile way. For example,
80 * assume that NFS needed to be modified to support Ficus. NFS has an entry
81 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
82 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
83 * listing those new operations Ficus adds to NFS, all without modifying the
84 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
85 * that is a(whole)nother story.) This is a feature.
86 */
87
88/*
89 * Routines having to do with the management of the vnode table.
90 */
91
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/linker.h>
44#include <sys/mount.h>
45#include <sys/proc.h>
46#include <sys/sysctl.h>
47#include <sys/vnode.h>
48#include <sys/malloc.h>
49
50
51MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes");
52
53/*
54 * The highest defined VFS number.
55 */
56int maxvfsconf = VFS_GENERIC + 1;
57
58/*
59 * Single-linked list of configured VFSes.
60 * New entries are added/deleted by vfs_register()/vfs_unregister()
61 */
62struct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(vfsconf);
63
64/*
65 * A Zen vnode attribute structure.
66 *
67 * Initialized when the first filesystem registers by vfs_register().
68 */
69struct vattr va_null;
70
71/*
72 * vfs_init.c
73 *
74 * Allocate and fill in operations vectors.
75 *
76 * An undocumented feature of this approach to defining operations is that
77 * there can be multiple entries in vfs_opv_descs for the same operations
78 * vector. This allows third parties to extend the set of operations
79 * supported by another layer in a binary compatibile way. For example,
80 * assume that NFS needed to be modified to support Ficus. NFS has an entry
81 * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
82 * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
83 * listing those new operations Ficus adds to NFS, all without modifying the
84 * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but
85 * that is a(whole)nother story.) This is a feature.
86 */
87
88/*
89 * Routines having to do with the management of the vnode table.
90 */
91
92/*
93 * XXX: hack alert
94 */
95int
96vcall(struct vnode *vp, u_int off, void *ap)
97{
98 struct vop_vector *vop = vp->v_op;
99 vop_bypass_t **bpt;
100 int rc;
101
102 for(;;) {
103 bpt = (void *)((u_char *)vop + off);
104 if (vop != NULL && *bpt == NULL && vop->vop_bypass == NULL) {
105 vop = vop->vop_default;
106 continue;
107 }
108 break;
109 }
110 KASSERT(vop != NULL, ("No VCALL(%p...)", vp));
111 if (*bpt != NULL)
112 rc = (*bpt)(ap);
113 else
114 rc = vop->vop_bypass(ap);
115 return (rc);
116}
117
118struct vfsconf *
119vfs_byname(const char *name)
120{
121 struct vfsconf *vfsp;
122
123 if (!strcmp(name, "ffs"))
124 name = "ufs";
125 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list)
126 if (!strcmp(name, vfsp->vfc_name))
127 return (vfsp);
128 return (NULL);
129}
130
131struct vfsconf *
132vfs_byname_kld(const char *fstype, struct thread *td, int *error)
133{
134 struct vfsconf *vfsp;
135 linker_file_t lf;
136
137 vfsp = vfs_byname(fstype);
138 if (vfsp != NULL)
139 return (vfsp);
140
141 /* Only load modules for root (very important!). */
142 *error = suser(td);
143 if (*error)
144 return (NULL);
145 *error = securelevel_gt(td->td_ucred, 0);
146 if (*error)
147 return (NULL);
148 *error = linker_load_module(NULL, fstype, NULL, NULL, &lf);
149 if (lf == NULL)
150 *error = ENODEV;
151 if (*error)
152 return (NULL);
153 lf->userrefs++;
154 /* Look up again to see if the VFS was loaded. */
155 vfsp = vfs_byname(fstype);
156 if (vfsp == NULL) {
157 lf->userrefs--;
158 linker_file_unload(lf, LINKER_UNLOAD_FORCE);
159 *error = ENODEV;
160 return (NULL);
161 }
162 return (vfsp);
163}
164
165
166/* Register a new filesystem type in the global table */
167int
168vfs_register(struct vfsconf *vfc)
169{
170 struct sysctl_oid *oidp;
171 struct vfsops *vfsops;
172 static int once;
173
174 if (!once) {
175 vattr_null(&va_null);
176 once = 1;
177 }
178
179 if (vfc->vfc_version != VFS_VERSION) {
180 printf("ERROR: filesystem %s, unsupported ABI version %x\n",
181 vfc->vfc_name, vfc->vfc_version);
182 return (EINVAL);
183 }
184 if (vfs_byname(vfc->vfc_name) != NULL)
185 return EEXIST;
186
187 vfc->vfc_typenum = maxvfsconf++;
188 TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list);
189
190 /*
191 * If this filesystem has a sysctl node under vfs
192 * (i.e. vfs.xxfs), then change the oid number of that node to
193 * match the filesystem's type number. This allows user code
194 * which uses the type number to read sysctl variables defined
195 * by the filesystem to continue working. Since the oids are
196 * in a sorted list, we need to make sure the order is
197 * preserved by re-registering the oid after modifying its
198 * number.
199 */
200 SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
201 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
202 sysctl_unregister_oid(oidp);
203 oidp->oid_number = vfc->vfc_typenum;
204 sysctl_register_oid(oidp);
205 }
206
207 /*
208 * Initialise unused ``struct vfsops'' fields, to use
209 * the vfs_std*() functions. Note, we need the mount
210 * and unmount operations, at the least. The check
211 * for vfsops available is just a debugging aid.
212 */
213 KASSERT(vfc->vfc_vfsops != NULL,
214 ("Filesystem %s has no vfsops", vfc->vfc_name));
215 /*
216 * Check the mount and unmount operations.
217 */
218 vfsops = vfc->vfc_vfsops;
219 KASSERT(vfsops->vfs_mount != NULL,
220 ("Filesystem %s has no mount op", vfc->vfc_name));
221 KASSERT(vfsops->vfs_unmount != NULL,
222 ("Filesystem %s has no unmount op", vfc->vfc_name));
223
224 if (vfsops->vfs_start == NULL)
225 /* make a file system operational */
226 vfsops->vfs_start = vfs_stdstart;
227 if (vfsops->vfs_root == NULL)
228 /* return file system's root vnode */
229 vfsops->vfs_root = vfs_stdroot;
230 if (vfsops->vfs_quotactl == NULL)
231 /* quota control */
232 vfsops->vfs_quotactl = vfs_stdquotactl;
233 if (vfsops->vfs_statfs == NULL)
234 /* return file system's status */
235 vfsops->vfs_statfs = vfs_stdstatfs;
236 if (vfsops->vfs_sync == NULL)
237 /*
238 * flush unwritten data (nosync)
239 * file systems can use vfs_stdsync
240 * explicitly by setting it in the
241 * vfsop vector.
242 */
243 vfsops->vfs_sync = vfs_stdnosync;
244 if (vfsops->vfs_vget == NULL)
245 /* convert an inode number to a vnode */
246 vfsops->vfs_vget = vfs_stdvget;
247 if (vfsops->vfs_fhtovp == NULL)
248 /* turn an NFS file handle into a vnode */
249 vfsops->vfs_fhtovp = vfs_stdfhtovp;
250 if (vfsops->vfs_checkexp == NULL)
251 /* check if file system is exported */
252 vfsops->vfs_checkexp = vfs_stdcheckexp;
253 if (vfsops->vfs_vptofh == NULL)
254 /* turn a vnode into an NFS file handle */
255 vfsops->vfs_vptofh = vfs_stdvptofh;
256 if (vfsops->vfs_init == NULL)
257 /* file system specific initialisation */
258 vfsops->vfs_init = vfs_stdinit;
259 if (vfsops->vfs_uninit == NULL)
260 /* file system specific uninitialisation */
261 vfsops->vfs_uninit = vfs_stduninit;
262 if (vfsops->vfs_extattrctl == NULL)
263 /* extended attribute control */
264 vfsops->vfs_extattrctl = vfs_stdextattrctl;
265 if (vfsops->vfs_sysctl == NULL)
266 vfsops->vfs_sysctl = vfs_stdsysctl;
267
268 /*
269 * Call init function for this VFS...
270 */
271 (*(vfc->vfc_vfsops->vfs_init))(vfc);
272
273 return 0;
274}
275
276
277/* Remove registration of a filesystem type */
278int
279vfs_unregister(struct vfsconf *vfc)
280{
281 struct vfsconf *vfsp;
282 int error, i, maxtypenum;
283
284 i = vfc->vfc_typenum;
285
286 vfsp = vfs_byname(vfc->vfc_name);
287 if (vfsp == NULL)
288 return EINVAL;
289 if (vfsp->vfc_refcount)
290 return EBUSY;
291 if (vfc->vfc_vfsops->vfs_uninit != NULL) {
292 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
293 if (error)
294 return (error);
295 }
296 TAILQ_REMOVE(&vfsconf, vfsp, vfc_list);
297 maxtypenum = VFS_GENERIC;
298 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list)
299 if (maxtypenum < vfsp->vfc_typenum)
300 maxtypenum = vfsp->vfc_typenum;
301 maxvfsconf = maxtypenum + 1;
302 return 0;
303}
304
305/*
306 * Standard kernel module handling code for filesystem modules.
307 * Referenced from VFS_SET().
308 */
309int
310vfs_modevent(module_t mod, int type, void *data)
311{
312 struct vfsconf *vfc;
313 int error = 0;
314
315 vfc = (struct vfsconf *)data;
316
317 switch (type) {
318 case MOD_LOAD:
319 if (vfc)
320 error = vfs_register(vfc);
321 break;
322
323 case MOD_UNLOAD:
324 if (vfc)
325 error = vfs_unregister(vfc);
326 break;
327 default:
328 error = EOPNOTSUPP;
329 break;
330 }
331 return (error);
332}
92struct vfsconf *
93vfs_byname(const char *name)
94{
95 struct vfsconf *vfsp;
96
97 if (!strcmp(name, "ffs"))
98 name = "ufs";
99 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list)
100 if (!strcmp(name, vfsp->vfc_name))
101 return (vfsp);
102 return (NULL);
103}
104
105struct vfsconf *
106vfs_byname_kld(const char *fstype, struct thread *td, int *error)
107{
108 struct vfsconf *vfsp;
109 linker_file_t lf;
110
111 vfsp = vfs_byname(fstype);
112 if (vfsp != NULL)
113 return (vfsp);
114
115 /* Only load modules for root (very important!). */
116 *error = suser(td);
117 if (*error)
118 return (NULL);
119 *error = securelevel_gt(td->td_ucred, 0);
120 if (*error)
121 return (NULL);
122 *error = linker_load_module(NULL, fstype, NULL, NULL, &lf);
123 if (lf == NULL)
124 *error = ENODEV;
125 if (*error)
126 return (NULL);
127 lf->userrefs++;
128 /* Look up again to see if the VFS was loaded. */
129 vfsp = vfs_byname(fstype);
130 if (vfsp == NULL) {
131 lf->userrefs--;
132 linker_file_unload(lf, LINKER_UNLOAD_FORCE);
133 *error = ENODEV;
134 return (NULL);
135 }
136 return (vfsp);
137}
138
139
140/* Register a new filesystem type in the global table */
141int
142vfs_register(struct vfsconf *vfc)
143{
144 struct sysctl_oid *oidp;
145 struct vfsops *vfsops;
146 static int once;
147
148 if (!once) {
149 vattr_null(&va_null);
150 once = 1;
151 }
152
153 if (vfc->vfc_version != VFS_VERSION) {
154 printf("ERROR: filesystem %s, unsupported ABI version %x\n",
155 vfc->vfc_name, vfc->vfc_version);
156 return (EINVAL);
157 }
158 if (vfs_byname(vfc->vfc_name) != NULL)
159 return EEXIST;
160
161 vfc->vfc_typenum = maxvfsconf++;
162 TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list);
163
164 /*
165 * If this filesystem has a sysctl node under vfs
166 * (i.e. vfs.xxfs), then change the oid number of that node to
167 * match the filesystem's type number. This allows user code
168 * which uses the type number to read sysctl variables defined
169 * by the filesystem to continue working. Since the oids are
170 * in a sorted list, we need to make sure the order is
171 * preserved by re-registering the oid after modifying its
172 * number.
173 */
174 SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link)
175 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) {
176 sysctl_unregister_oid(oidp);
177 oidp->oid_number = vfc->vfc_typenum;
178 sysctl_register_oid(oidp);
179 }
180
181 /*
182 * Initialise unused ``struct vfsops'' fields, to use
183 * the vfs_std*() functions. Note, we need the mount
184 * and unmount operations, at the least. The check
185 * for vfsops available is just a debugging aid.
186 */
187 KASSERT(vfc->vfc_vfsops != NULL,
188 ("Filesystem %s has no vfsops", vfc->vfc_name));
189 /*
190 * Check the mount and unmount operations.
191 */
192 vfsops = vfc->vfc_vfsops;
193 KASSERT(vfsops->vfs_mount != NULL,
194 ("Filesystem %s has no mount op", vfc->vfc_name));
195 KASSERT(vfsops->vfs_unmount != NULL,
196 ("Filesystem %s has no unmount op", vfc->vfc_name));
197
198 if (vfsops->vfs_start == NULL)
199 /* make a file system operational */
200 vfsops->vfs_start = vfs_stdstart;
201 if (vfsops->vfs_root == NULL)
202 /* return file system's root vnode */
203 vfsops->vfs_root = vfs_stdroot;
204 if (vfsops->vfs_quotactl == NULL)
205 /* quota control */
206 vfsops->vfs_quotactl = vfs_stdquotactl;
207 if (vfsops->vfs_statfs == NULL)
208 /* return file system's status */
209 vfsops->vfs_statfs = vfs_stdstatfs;
210 if (vfsops->vfs_sync == NULL)
211 /*
212 * flush unwritten data (nosync)
213 * file systems can use vfs_stdsync
214 * explicitly by setting it in the
215 * vfsop vector.
216 */
217 vfsops->vfs_sync = vfs_stdnosync;
218 if (vfsops->vfs_vget == NULL)
219 /* convert an inode number to a vnode */
220 vfsops->vfs_vget = vfs_stdvget;
221 if (vfsops->vfs_fhtovp == NULL)
222 /* turn an NFS file handle into a vnode */
223 vfsops->vfs_fhtovp = vfs_stdfhtovp;
224 if (vfsops->vfs_checkexp == NULL)
225 /* check if file system is exported */
226 vfsops->vfs_checkexp = vfs_stdcheckexp;
227 if (vfsops->vfs_vptofh == NULL)
228 /* turn a vnode into an NFS file handle */
229 vfsops->vfs_vptofh = vfs_stdvptofh;
230 if (vfsops->vfs_init == NULL)
231 /* file system specific initialisation */
232 vfsops->vfs_init = vfs_stdinit;
233 if (vfsops->vfs_uninit == NULL)
234 /* file system specific uninitialisation */
235 vfsops->vfs_uninit = vfs_stduninit;
236 if (vfsops->vfs_extattrctl == NULL)
237 /* extended attribute control */
238 vfsops->vfs_extattrctl = vfs_stdextattrctl;
239 if (vfsops->vfs_sysctl == NULL)
240 vfsops->vfs_sysctl = vfs_stdsysctl;
241
242 /*
243 * Call init function for this VFS...
244 */
245 (*(vfc->vfc_vfsops->vfs_init))(vfc);
246
247 return 0;
248}
249
250
251/* Remove registration of a filesystem type */
252int
253vfs_unregister(struct vfsconf *vfc)
254{
255 struct vfsconf *vfsp;
256 int error, i, maxtypenum;
257
258 i = vfc->vfc_typenum;
259
260 vfsp = vfs_byname(vfc->vfc_name);
261 if (vfsp == NULL)
262 return EINVAL;
263 if (vfsp->vfc_refcount)
264 return EBUSY;
265 if (vfc->vfc_vfsops->vfs_uninit != NULL) {
266 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp);
267 if (error)
268 return (error);
269 }
270 TAILQ_REMOVE(&vfsconf, vfsp, vfc_list);
271 maxtypenum = VFS_GENERIC;
272 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list)
273 if (maxtypenum < vfsp->vfc_typenum)
274 maxtypenum = vfsp->vfc_typenum;
275 maxvfsconf = maxtypenum + 1;
276 return 0;
277}
278
279/*
280 * Standard kernel module handling code for filesystem modules.
281 * Referenced from VFS_SET().
282 */
283int
284vfs_modevent(module_t mod, int type, void *data)
285{
286 struct vfsconf *vfc;
287 int error = 0;
288
289 vfc = (struct vfsconf *)data;
290
291 switch (type) {
292 case MOD_LOAD:
293 if (vfc)
294 error = vfs_register(vfc);
295 break;
296
297 case MOD_UNLOAD:
298 if (vfc)
299 error = vfs_unregister(vfc);
300 break;
301 default:
302 error = EOPNOTSUPP;
303 break;
304 }
305 return (error);
306}