1 /* 2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * 35 * Copyright (c) 1989, 1993 36 * The Regents of the University of California. All rights reserved. 37 * 38 * This code is derived from software contributed 39 * to Berkeley by John Heidemann of the UCLA Ficus project. 40 * 41 * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgement: 53 * This product includes software developed by the University of 54 * California, Berkeley and its contributors. 55 * 4. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94 72 * $FreeBSD: src/sys/kern/vfs_init.c,v 1.59 2002/04/30 18:44:32 dillon Exp $ 73 * $DragonFly: src/sys/kern/vfs_init.c,v 1.8 2004/12/17 00:18:07 dillon Exp $ 74 */ 75 /* 76 * Manage vnode VOP operations vectors 77 */ 78 #include <sys/param.h> 79 #include <sys/systm.h> 80 #include <sys/kernel.h> 81 #include <sys/mount.h> 82 #include <sys/sysctl.h> 83 #include <sys/vnode.h> 84 #include <sys/malloc.h> 85 #include <vm/vm_zone.h> 86 87 static MALLOC_DEFINE(M_VNODEOP, "vnodeops", "vnode operations vectors"); 88 89 /* 90 * Zone for namei 91 */ 92 struct vm_zone *namei_zone; 93 94 /* 95 * vfs_init() will set maxvfsconf 96 * to the highest defined type number. 97 */ 98 int maxvfsconf; 99 struct vfsconf *vfsconf; 100 101 static TAILQ_HEAD(, vnodeopv_node) vnodeopv_list; 102 static void vfs_recalc_vnodeops(void); 103 104 /* 105 * Add a vnode operations (vnops) vector to the global list. 106 */ 107 void 108 vfs_add_vnodeops_sysinit(const void *data) 109 { 110 const struct vnodeopv_desc *vdesc = data; 111 112 vfs_add_vnodeops(NULL, vdesc->opv_desc_vector, vdesc->opv_desc_ops); 113 } 114 115 /* 116 * Unlink previously added vnode operations vector. 117 */ 118 void 119 vfs_rm_vnodeops_sysinit(const void *data) 120 { 121 const struct vnodeopv_desc *vdesc = data; 122 123 vfs_rm_vnodeops(vdesc->opv_desc_vector); 124 } 125 126 void 127 vfs_add_vnodeops(struct mount *mp, struct vop_ops **vops_pp, 128 struct vnodeopv_entry_desc *descs) 129 { 130 struct vnodeopv_node *node; 131 struct vop_ops *ops; 132 133 node = malloc(sizeof(*node), M_VNODEOP, M_ZERO|M_WAITOK); 134 if ((ops = *vops_pp) == NULL) { 135 ops = malloc(sizeof(struct vop_ops), 136 M_VNODEOP, M_ZERO|M_WAITOK); 137 *vops_pp = ops; 138 } 139 node->ops = ops; 140 node->descs = descs; 141 ops->vv_mount = mp; 142 ++ops->vv_refs; 143 TAILQ_INSERT_TAIL(&vnodeopv_list, node, entry); 144 vfs_recalc_vnodeops(); 145 if (mp) { 146 if (mp->mnt_vn_coherency_ops) 147 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops; 148 else if (mp->mnt_vn_journal_ops) 149 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops; 150 else 151 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops; 152 } 153 } 154 155 void 156 vfs_rm_vnodeops(struct vop_ops **vops_pp) 157 { 158 struct vop_ops *ops = *vops_pp; 159 struct vnodeopv_node *node; 160 struct mount *mp; 161 162 if (ops == NULL) 163 return; 164 165 TAILQ_FOREACH(node, &vnodeopv_list, entry) { 166 if (node->ops == ops) 167 break; 168 } 169 if (node == NULL) { 170 printf("vfs_rm_vnodeops: unable to find ops: %p\n", ops); 171 return; 172 } 173 TAILQ_REMOVE(&vnodeopv_list, node, entry); 174 free(node, M_VNODEOP); 175 KKASSERT(ops != NULL && ops->vv_refs > 0); 176 if (--ops->vv_refs == 0) { 177 *vops_pp = NULL; 178 if ((mp = ops->vv_mount) != NULL) { 179 if (mp->mnt_vn_coherency_ops) 180 mp->mnt_vn_use_ops = mp->mnt_vn_coherency_ops; 181 else if (mp->mnt_vn_journal_ops) 182 mp->mnt_vn_use_ops = mp->mnt_vn_journal_ops; 183 else 184 mp->mnt_vn_use_ops = mp->mnt_vn_norm_ops; 185 } 186 free(ops, M_VNODEOP); 187 } 188 vfs_recalc_vnodeops(); 189 } 190 191 /* 192 * Recalculate VFS operations vectors 193 */ 194 static void 195 vfs_recalc_vnodeops(void) 196 { 197 struct vnodeopv_node *node; 198 struct vnodeopv_entry_desc *desc; 199 struct vop_ops *ops; 200 struct vop_ops *vnew; 201 int off; 202 203 /* 204 * Because vop_ops may be active we can't just blow them away, we 205 * have to generate new vop_ops and then copy them into the running 206 * vop_ops. Any missing entries will be assigned to the default 207 * entry. If the default entry itself is missing it will be assigned 208 * to vop_eopnotsupp. 209 */ 210 TAILQ_FOREACH(node, &vnodeopv_list, entry) { 211 ops = node->ops; 212 if ((vnew = ops->vv_new) == NULL) { 213 vnew = malloc(sizeof(struct vop_ops), 214 M_VNODEOP, M_ZERO|M_WAITOK); 215 ops->vv_new = vnew; 216 vnew->vop_default = vop_eopnotsupp; 217 } 218 for (desc = node->descs; desc->opve_op; ++desc) { 219 off = desc->opve_op->vdesc_offset; 220 *(void **)((char *)vnew + off) = desc->opve_func; 221 } 222 for (off = __offsetof(struct vop_ops, vop_ops_first_field); 223 off <= __offsetof(struct vop_ops, vop_ops_last_field); 224 off += sizeof(void **) 225 ) { 226 if (*(void **)((char *)vnew + off) == NULL) 227 *(void **)((char *)vnew + off) = vnew->vop_default; 228 } 229 } 230 231 /* 232 * Copy the temporary ops into the running configuration and then 233 * delete them. 234 */ 235 TAILQ_FOREACH(node, &vnodeopv_list, entry) { 236 ops = node->ops; 237 if ((vnew = ops->vv_new) == NULL) 238 continue; 239 for (off = __offsetof(struct vop_ops, vop_ops_first_field); 240 off <= __offsetof(struct vop_ops, vop_ops_last_field); 241 off += sizeof(void **) 242 ) { 243 *(void **)((char *)ops + off) = 244 *(void **)((char *)vnew + off); 245 } 246 ops->vv_new = NULL; 247 free(vnew, M_VNODEOP); 248 } 249 } 250 251 /* 252 * Routines having to do with the management of the vnode table. 253 */ 254 struct vattr va_null; 255 256 /* 257 * Initialize the vnode structures and initialize each file system type. 258 */ 259 /* ARGSUSED*/ 260 static void 261 vfsinit(void *dummy) 262 { 263 TAILQ_INIT(&vnodeopv_list); 264 namei_zone = zinit("NAMEI", MAXPATHLEN, 0, 0, 2); 265 266 /* 267 * Initialize the vnode table 268 */ 269 vfs_subr_init(); 270 vfs_mount_init(); 271 vfs_lock_init(); 272 vfs_sync_init(); 273 /* 274 * Initialize the vnode name cache 275 */ 276 nchinit(); 277 /* 278 * Initialize each file system type. 279 * Vfs type numbers must be distinct from VFS_GENERIC (and VFS_VFSCONF). 280 */ 281 vattr_null(&va_null); 282 maxvfsconf = VFS_GENERIC + 1; 283 } 284 SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) 285 286 /* 287 * Register a VFS. 288 * 289 * After doing general initialisation, this function will 290 * call the filesystem specific initialisation vector op, 291 * i.e. vfsops->vfs_init(). 292 */ 293 int 294 vfs_register(struct vfsconf *vfc) 295 { 296 struct sysctl_oid *oidp; 297 struct vfsconf *vfsp; 298 299 vfsp = NULL; 300 if (vfsconf) 301 for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next) 302 if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0) 303 return EEXIST; 304 305 vfc->vfc_typenum = maxvfsconf++; 306 if (vfsp) 307 vfsp->vfc_next = vfc; 308 else 309 vfsconf = vfc; 310 vfc->vfc_next = NULL; 311 312 /* 313 * If this filesystem has a sysctl node under vfs 314 * (i.e. vfs.xxfs), then change the oid number of that node to 315 * match the filesystem's type number. This allows user code 316 * which uses the type number to read sysctl variables defined 317 * by the filesystem to continue working. Since the oids are 318 * in a sorted list, we need to make sure the order is 319 * preserved by re-registering the oid after modifying its 320 * number. 321 */ 322 SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) 323 if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 324 sysctl_unregister_oid(oidp); 325 oidp->oid_number = vfc->vfc_typenum; 326 sysctl_register_oid(oidp); 327 } 328 329 /* 330 * Call init function for this VFS... 331 */ 332 (*(vfc->vfc_vfsops->vfs_init))(vfc); 333 334 return 0; 335 } 336 337 338 /* 339 * Remove previously registered VFS. 340 * 341 * After doing general de-registration like removing sysctl 342 * nodes etc, it will call the filesystem specific vector 343 * op, i.e. vfsops->vfs_uninit(). 344 * 345 */ 346 int 347 vfs_unregister(struct vfsconf *vfc) 348 { 349 struct vfsconf *vfsp, *prev_vfsp; 350 int error, i, maxtypenum; 351 352 i = vfc->vfc_typenum; 353 354 prev_vfsp = NULL; 355 for (vfsp = vfsconf; vfsp; 356 prev_vfsp = vfsp, vfsp = vfsp->vfc_next) { 357 if (!strcmp(vfc->vfc_name, vfsp->vfc_name)) 358 break; 359 } 360 if (vfsp == NULL) 361 return EINVAL; 362 if (vfsp->vfc_refcount) 363 return EBUSY; 364 if (vfc->vfc_vfsops->vfs_uninit != NULL) { 365 error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp); 366 if (error) 367 return (error); 368 } 369 if (prev_vfsp) 370 prev_vfsp->vfc_next = vfsp->vfc_next; 371 else 372 vfsconf = vfsp->vfc_next; 373 maxtypenum = VFS_GENERIC; 374 for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next) 375 if (maxtypenum < vfsp->vfc_typenum) 376 maxtypenum = vfsp->vfc_typenum; 377 maxvfsconf = maxtypenum + 1; 378 return 0; 379 } 380 381 int 382 vfs_modevent(module_t mod, int type, void *data) 383 { 384 struct vfsconf *vfc; 385 int error = 0; 386 387 vfc = (struct vfsconf *)data; 388 389 switch (type) { 390 case MOD_LOAD: 391 if (vfc) 392 error = vfs_register(vfc); 393 break; 394 395 case MOD_UNLOAD: 396 if (vfc) 397 error = vfs_unregister(vfc); 398 break; 399 default: /* including MOD_SHUTDOWN */ 400 break; 401 } 402 return (error); 403 } 404