vfs_init.c revision 131733
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software contributed 61541Srgrimes * to Berkeley by John Heidemann of the UCLA Ficus project. 71541Srgrimes * 81541Srgrimes * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project 91541Srgrimes * 101541Srgrimes * Redistribution and use in source and binary forms, with or without 111541Srgrimes * modification, are permitted provided that the following conditions 121541Srgrimes * are met: 131541Srgrimes * 1. Redistributions of source code must retain the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer. 151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161541Srgrimes * notice, this list of conditions and the following disclaimer in the 171541Srgrimes * documentation and/or other materials provided with the distribution. 181541Srgrimes * 4. Neither the name of the University nor the names of its contributors 191541Srgrimes * may be used to endorse or promote products derived from this software 201541Srgrimes * without specific prior written permission. 211541Srgrimes * 221541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321541Srgrimes * SUCH DAMAGE. 331541Srgrimes * 341541Srgrimes * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94 351541Srgrimes */ 361541Srgrimes 37116182Sobrien#include <sys/cdefs.h> 38116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/vfs_init.c 131733 2004-07-07 06:58:29Z alfred $"); 391541Srgrimes 401541Srgrimes#include <sys/param.h> 412112Swollman#include <sys/systm.h> 422946Swollman#include <sys/kernel.h> 431541Srgrimes#include <sys/mount.h> 4438869Sbde#include <sys/sysctl.h> 451541Srgrimes#include <sys/vnode.h> 461541Srgrimes#include <sys/malloc.h> 471541Srgrimes 4812577Sbde 4930354SphkMALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes"); 5030354Sphk 5110358Sjulian/* 5269664Speter * The highest defined VFS number. 5329653Sdyson */ 5469664Speterint maxvfsconf = VFS_GENERIC + 1; 5591690Seivind 5691690Seivind/* 5791690Seivind * Single-linked list of configured VFSes. 5891690Seivind * New entries are added/deleted by vfs_register()/vfs_unregister() 5991690Seivind */ 6052780Smsmithstruct vfsconf *vfsconf; 6152780Smsmith 6252780Smsmith/* 631541Srgrimes * vfs_init.c 641541Srgrimes * 651541Srgrimes * Allocate and fill in operations vectors. 661541Srgrimes * 671541Srgrimes * An undocumented feature of this approach to defining operations is that 681541Srgrimes * there can be multiple entries in vfs_opv_descs for the same operations 691541Srgrimes * vector. This allows third parties to extend the set of operations 701541Srgrimes * supported by another layer in a binary compatibile way. For example, 711541Srgrimes * assume that NFS needed to be modified to support Ficus. NFS has an entry 721541Srgrimes * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by 731541Srgrimes * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions) 741541Srgrimes * listing those new operations Ficus adds to NFS, all without modifying the 751541Srgrimes * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but 761541Srgrimes * that is a(whole)nother story.) This is a feature. 771541Srgrimes */ 7841056Speter 7941056Speter/* Table of known vnodeop vectors (list of VFS vnode vectors) */ 8043311Sdillonstatic const struct vnodeopv_desc **vnodeopv_descs; 8141056Speterstatic int vnodeopv_num; 8241056Speter 8341056Speter/* Table of known descs (list of vnode op handlers "vop_access_desc") */ 8441056Speterstatic struct vnodeop_desc **vfs_op_descs; 8591690Seivind/* Reference counts for vfs_op_descs */ 8691690Seivindstatic int *vfs_op_desc_refs; 8791690Seivind/* Number of descriptions */ 8841056Speterstatic int num_op_descs; 8991690Seivind/* Number of entries in each description */ 9095813Sdillonstatic int vfs_opv_numops = 64; 9141056Speter 9295813Sdillon/* Allow this number to be tuned at boot */ 9395813SdillonTUNABLE_INT("vfs.opv_numops", &vfs_opv_numops); 94121307SsilbySYSCTL_INT(_vfs, OID_AUTO, opv_numops, CTLFLAG_RDTUN, &vfs_opv_numops, 9595813Sdillon 0, "Maximum number of operations in vop_t vector"); 9695813Sdillon 9795813Sdillonstatic int int_cmp(const void *a, const void *b); 9895813Sdillon 9995813Sdillonstatic int 10095813Sdillonint_cmp(const void *a, const void *b) 10195813Sdillon{ 10295813Sdillon return(*(const int *)a - *(const int *)b); 10395813Sdillon} 10495813Sdillon 10591690Seivind/* 10691690Seivind * Recalculate the operations vector/description (those parts of it that can 10791690Seivind * be recalculated, that is.) 10895813Sdillon * Always allocate operations vector large enough to hold vfs_opv_numops 10995813Sdillon * entries. The vector is never freed or deallocated once it is initialized, 11095813Sdillon * so that vnodes might safely reference it through their v_op pointer without 11195813Sdillon * vector changing suddenly from under them. 11291690Seivind */ 11341056Speterstatic void 11441056Spetervfs_opv_recalc(void) 1151541Srgrimes{ 11695813Sdillon int i, j, k; 11795813Sdillon int *vfs_op_offsets; 11812158Sbde vop_t ***opv_desc_vector_p; 11912158Sbde vop_t **opv_desc_vector; 1201541Srgrimes struct vnodeopv_entry_desc *opve_descp; 12143311Sdillon const struct vnodeopv_desc *opv; 1221541Srgrimes 12341056Speter if (vfs_op_descs == NULL) 12441056Speter panic("vfs_opv_recalc called with null vfs_op_descs"); 12541056Speter 1261541Srgrimes /* 12795813Sdillon * Allocate and initialize temporary array to store 12895813Sdillon * offsets. Sort it to put all uninitialized entries 12995813Sdillon * first and to make holes in existing offset sequence 13095813Sdillon * detectable. 13195813Sdillon */ 13295813Sdillon MALLOC(vfs_op_offsets, int *, 133111119Simp num_op_descs * sizeof(int), M_TEMP, M_WAITOK); 13495813Sdillon if (vfs_op_offsets == NULL) 13595813Sdillon panic("vfs_opv_recalc: no memory"); 13695813Sdillon for (i = 0; i < num_op_descs; i++) 13795813Sdillon vfs_op_offsets[i] = vfs_op_descs[i]->vdesc_offset; 13895813Sdillon qsort(vfs_op_offsets, num_op_descs, sizeof(int), int_cmp); 13995813Sdillon 14095813Sdillon /* 14195813Sdillon * Run through and make sure all known descs have an offset. 14295813Sdillon * Use vfs_op_offsets to locate holes in offset sequence and 14395813Sdillon * reuse them. 14441056Speter * vop_default_desc is hardwired at offset 1, and offset 0 14541056Speter * is a panic sanity check. 1461541Srgrimes */ 14795813Sdillon j = 1; k = 1; 14895813Sdillon for (i = 0; i < num_op_descs; i++) { 14995813Sdillon if (vfs_op_descs[i]->vdesc_offset != 0) 15095813Sdillon continue; 15195813Sdillon /* 15295813Sdillon * Look at two adjacent entries vfs_op_offsets[j - 1] and 15395813Sdillon * vfs_op_offsets[j] and see if we can fit a new offset 15495813Sdillon * number in between. If not, look at the next pair until 15595813Sdillon * hole is found or the end of the vfs_op_offsets vector is 15695813Sdillon * reached. j has been initialized to 1 above so that 15795813Sdillon * referencing (j-1)-th element is safe and the loop will 15895813Sdillon * never execute if num_op_descs is 1. For each new value s 15995813Sdillon * of i the j loop pick up from where previous iteration has 16095813Sdillon * left off. When the last hole has been consumed or if no 16195813Sdillon * hole has been found, we will start allocating new numbers 16295813Sdillon * starting from the biggest already available offset + 1. 16395813Sdillon */ 16495813Sdillon for (; j < num_op_descs; j++) { 16595813Sdillon if (vfs_op_offsets[j - 1] < k && vfs_op_offsets[j] > k) 16695813Sdillon break; 16795813Sdillon k = vfs_op_offsets[j] + 1; 16895813Sdillon } 16995813Sdillon vfs_op_descs[i]->vdesc_offset = k++; 17095813Sdillon } 17195813Sdillon FREE(vfs_op_offsets, M_TEMP); 17295813Sdillon 17395813Sdillon /* Panic if new vops will cause vector overflow */ 17495813Sdillon if (k > vfs_opv_numops) 17595813Sdillon panic("VFS: Ran out of vop_t vector entries. %d entries required, only %d available.\n", k, vfs_opv_numops); 17695813Sdillon 17740435Speter /* 17841056Speter * Allocate and fill in the vectors 17940435Speter */ 18041056Speter for (i = 0; i < vnodeopv_num; i++) { 18141056Speter opv = vnodeopv_descs[i]; 18241056Speter opv_desc_vector_p = opv->opv_desc_vector_p; 18341056Speter if (*opv_desc_vector_p == NULL) 18495813Sdillon MALLOC(*opv_desc_vector_p, vop_t **, 18595813Sdillon vfs_opv_numops * sizeof(vop_t *), M_VNODE, 186111119Simp M_WAITOK | M_ZERO); 18741056Speter 18865527Speter /* Fill in, with slot 0 being to return EOPNOTSUPP */ 18941056Speter opv_desc_vector = *opv_desc_vector_p; 19065527Speter opv_desc_vector[0] = (vop_t *)vop_eopnotsupp; 19141056Speter for (j = 0; opv->opv_desc_ops[j].opve_op; j++) { 19241056Speter opve_descp = &(opv->opv_desc_ops[j]); 19341056Speter opv_desc_vector[opve_descp->opve_op->vdesc_offset] = 19441056Speter opve_descp->opve_impl; 19541056Speter } 19641056Speter 19741056Speter /* Replace unfilled routines with their default (slot 1). */ 19841056Speter opv_desc_vector = *(opv->opv_desc_vector_p); 19941056Speter if (opv_desc_vector[1] == NULL) 20041056Speter panic("vfs_opv_recalc: vector without a default."); 20141056Speter for (j = 0; j < vfs_opv_numops; j++) 20241056Speter if (opv_desc_vector[j] == NULL) 20341056Speter opv_desc_vector[j] = opv_desc_vector[1]; 20440435Speter } 20541056Speter} 20640435Speter 20791690Seivind/* Add a set of vnode operations (a description) to the table above. */ 20841056Spetervoid 20943311Sdillonvfs_add_vnodeops(const void *data) 21041056Speter{ 21143311Sdillon const struct vnodeopv_desc *opv; 21243311Sdillon const struct vnodeopv_desc **newopv; 21341056Speter struct vnodeop_desc **newop; 21441056Speter int *newref; 21541056Speter struct vnodeop_desc *desc; 21641591Sarchie int i, j; 21741056Speter 21843311Sdillon opv = (const struct vnodeopv_desc *)data; 21943311Sdillon MALLOC(newopv, const struct vnodeopv_desc **, 220111119Simp (vnodeopv_num + 1) * sizeof(*newopv), M_VNODE, M_WAITOK); 22141056Speter if (vnodeopv_descs) { 22241056Speter bcopy(vnodeopv_descs, newopv, vnodeopv_num * sizeof(*newopv)); 22341056Speter FREE(vnodeopv_descs, M_VNODE); 22441056Speter } 22541056Speter newopv[vnodeopv_num] = opv; 22641056Speter vnodeopv_descs = newopv; 22741056Speter vnodeopv_num++; 22841056Speter 22941056Speter /* See if we have turned up a new vnode op desc */ 23041056Speter for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) { 23141056Speter for (j = 0; j < num_op_descs; j++) { 23241056Speter if (desc == vfs_op_descs[j]) { 23341056Speter /* found it, increase reference count */ 23441056Speter vfs_op_desc_refs[j]++; 23541056Speter break; 23641056Speter } 2371541Srgrimes } 23841056Speter if (j == num_op_descs) { 23941056Speter /* not found, new entry */ 24041056Speter MALLOC(newop, struct vnodeop_desc **, 24141056Speter (num_op_descs + 1) * sizeof(*newop), 242111119Simp M_VNODE, M_WAITOK); 24341056Speter /* new reference count (for unload) */ 24441056Speter MALLOC(newref, int *, 24541056Speter (num_op_descs + 1) * sizeof(*newref), 246111119Simp M_VNODE, M_WAITOK); 24741056Speter if (vfs_op_descs) { 24841056Speter bcopy(vfs_op_descs, newop, 24941056Speter num_op_descs * sizeof(*newop)); 25041056Speter FREE(vfs_op_descs, M_VNODE); 25141056Speter } 25241056Speter if (vfs_op_desc_refs) { 25341056Speter bcopy(vfs_op_desc_refs, newref, 25441056Speter num_op_descs * sizeof(*newref)); 25541056Speter FREE(vfs_op_desc_refs, M_VNODE); 25641056Speter } 25741056Speter newop[num_op_descs] = desc; 25841056Speter newref[num_op_descs] = 1; 25941056Speter vfs_op_descs = newop; 26041056Speter vfs_op_desc_refs = newref; 26141056Speter num_op_descs++; 26241056Speter } 2631541Srgrimes } 26441056Speter vfs_opv_recalc(); 2651541Srgrimes} 2661541Srgrimes 26791690Seivind/* Remove a vnode type from the vnode description table above. */ 26841056Spetervoid 26943311Sdillonvfs_rm_vnodeops(const void *data) 2701541Srgrimes{ 27143311Sdillon const struct vnodeopv_desc *opv; 27243311Sdillon const struct vnodeopv_desc **newopv; 27341056Speter struct vnodeop_desc **newop; 27441056Speter int *newref; 27541056Speter vop_t **opv_desc_vector; 27641056Speter struct vnodeop_desc *desc; 27741056Speter int i, j, k; 2781541Srgrimes 27943351Sdillon opv = (const struct vnodeopv_desc *)data; 28041056Speter /* Lower ref counts on descs in the table and release if zero */ 28141056Speter for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) { 28241056Speter for (j = 0; j < num_op_descs; j++) { 28341056Speter if (desc == vfs_op_descs[j]) { 28441056Speter /* found it, decrease reference count */ 28541056Speter vfs_op_desc_refs[j]--; 28641056Speter break; 28741056Speter } 28841056Speter } 28941056Speter for (j = 0; j < num_op_descs; j++) { 29041056Speter if (vfs_op_desc_refs[j] > 0) 29141056Speter continue; 29241056Speter if (vfs_op_desc_refs[j] < 0) 29341056Speter panic("vfs_remove_vnodeops: negative refcnt"); 29495813Sdillon /* Entry is going away - replace it with defaultop */ 29595813Sdillon for (k = 0; k < vnodeopv_num; k++) { 29695813Sdillon opv_desc_vector = 29795813Sdillon *(vnodeopv_descs[k]->opv_desc_vector_p); 29895813Sdillon if (opv_desc_vector != NULL) 29995813Sdillon opv_desc_vector[desc->vdesc_offset] = 30095813Sdillon opv_desc_vector[1]; 30195813Sdillon } 30241056Speter MALLOC(newop, struct vnodeop_desc **, 30341056Speter (num_op_descs - 1) * sizeof(*newop), 304111119Simp M_VNODE, M_WAITOK); 30541056Speter /* new reference count (for unload) */ 30641056Speter MALLOC(newref, int *, 30741056Speter (num_op_descs - 1) * sizeof(*newref), 308111119Simp M_VNODE, M_WAITOK); 30941056Speter for (k = j; k < (num_op_descs - 1); k++) { 31041056Speter vfs_op_descs[k] = vfs_op_descs[k + 1]; 31141056Speter vfs_op_desc_refs[k] = vfs_op_desc_refs[k + 1]; 31241056Speter } 31341056Speter bcopy(vfs_op_descs, newop, 31441056Speter (num_op_descs - 1) * sizeof(*newop)); 31541056Speter bcopy(vfs_op_desc_refs, newref, 31641056Speter (num_op_descs - 1) * sizeof(*newref)); 31741056Speter FREE(vfs_op_descs, M_VNODE); 31841056Speter FREE(vfs_op_desc_refs, M_VNODE); 31941056Speter vfs_op_descs = newop; 32041056Speter vfs_op_desc_refs = newref; 32141056Speter num_op_descs--; 32241056Speter } 32341056Speter } 32441056Speter 32541056Speter for (i = 0; i < vnodeopv_num; i++) { 32641056Speter if (vnodeopv_descs[i] == opv) { 32741056Speter for (j = i; j < (vnodeopv_num - 1); j++) 32841056Speter vnodeopv_descs[j] = vnodeopv_descs[j + 1]; 32941056Speter break; 33041056Speter } 33141056Speter } 33241056Speter if (i == vnodeopv_num) 33341056Speter panic("vfs_remove_vnodeops: opv not found"); 33495813Sdillon opv_desc_vector = *(opv->opv_desc_vector_p); 33595813Sdillon if (opv_desc_vector != NULL) 33695813Sdillon FREE(opv_desc_vector, M_VNODE); 33743311Sdillon MALLOC(newopv, const struct vnodeopv_desc **, 338111119Simp (vnodeopv_num - 1) * sizeof(*newopv), M_VNODE, M_WAITOK); 33941056Speter bcopy(vnodeopv_descs, newopv, (vnodeopv_num - 1) * sizeof(*newopv)); 34041056Speter FREE(vnodeopv_descs, M_VNODE); 34141056Speter vnodeopv_descs = newopv; 34241056Speter vnodeopv_num--; 34341056Speter 34441056Speter vfs_opv_recalc(); 3451541Srgrimes} 3461541Srgrimes 3471541Srgrimes/* 3481541Srgrimes * Routines having to do with the management of the vnode table. 3491541Srgrimes */ 3501541Srgrimesstruct vattr va_null; 3511541Srgrimes 3521541Srgrimes/* 35396755Strhodes * Initialize the vnode structures and initialize each filesystem type. 3541541Srgrimes */ 35510358Sjulian/* ARGSUSED*/ 35610358Sjulianstatic void 35741056Spetervfsinit(void *dummy) 3581541Srgrimes{ 3591541Srgrimes 3601541Srgrimes vattr_null(&va_null); 36140435Speter} 36241056SpeterSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) 36340435Speter 36496755Strhodes/* Register a new filesystem type in the global table */ 36540435Speterint 36641056Spetervfs_register(struct vfsconf *vfc) 36740435Speter{ 36844549Sdfr struct sysctl_oid *oidp; 36940435Speter struct vfsconf *vfsp; 37040435Speter 371116271Sphk struct vfsops *vfsops; 372116271Sphk 37340435Speter vfsp = NULL; 37440435Speter if (vfsconf) 37540435Speter for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next) 37644549Sdfr if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0) 37740435Speter return EEXIST; 37840435Speter 37940435Speter vfc->vfc_typenum = maxvfsconf++; 38040435Speter if (vfsp) 38140435Speter vfsp->vfc_next = vfc; 38240435Speter else 38340435Speter vfsconf = vfc; 38440435Speter vfc->vfc_next = NULL; 38540435Speter 38640435Speter /* 38744549Sdfr * If this filesystem has a sysctl node under vfs 38844549Sdfr * (i.e. vfs.xxfs), then change the oid number of that node to 38944549Sdfr * match the filesystem's type number. This allows user code 39044549Sdfr * which uses the type number to read sysctl variables defined 39144549Sdfr * by the filesystem to continue working. Since the oids are 39244549Sdfr * in a sorted list, we need to make sure the order is 39344549Sdfr * preserved by re-registering the oid after modifying its 39444549Sdfr * number. 39544549Sdfr */ 39672012Sphk SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) 39744549Sdfr if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 39844549Sdfr sysctl_unregister_oid(oidp); 39944549Sdfr oidp->oid_number = vfc->vfc_typenum; 40044549Sdfr sysctl_register_oid(oidp); 40144549Sdfr } 40244549Sdfr 40344549Sdfr /* 404116271Sphk * Initialise unused ``struct vfsops'' fields, to use 405116271Sphk * the vfs_std*() functions. Note, we need the mount 406116271Sphk * and unmount operations, at the least. The check 407116271Sphk * for vfsops available is just a debugging aid. 408116271Sphk */ 409116271Sphk KASSERT(vfc->vfc_vfsops != NULL, 410116271Sphk ("Filesystem %s has no vfsops", vfc->vfc_name)); 411116271Sphk /* 412116271Sphk * Check the mount and unmount operations. 413116271Sphk */ 414116271Sphk vfsops = vfc->vfc_vfsops; 415116271Sphk KASSERT(vfsops->vfs_mount != NULL || vfsops->vfs_nmount != NULL, 416116271Sphk ("Filesystem %s has no (n)mount op", vfc->vfc_name)); 417116271Sphk KASSERT(vfsops->vfs_unmount != NULL, 418116271Sphk ("Filesystem %s has no unmount op", vfc->vfc_name)); 419116271Sphk 420116271Sphk if (vfsops->vfs_start == NULL) 421116271Sphk /* make a file system operational */ 422116271Sphk vfsops->vfs_start = vfs_stdstart; 423116271Sphk if (vfsops->vfs_root == NULL) 424116271Sphk /* return file system's root vnode */ 425116271Sphk vfsops->vfs_root = vfs_stdroot; 426116271Sphk if (vfsops->vfs_quotactl == NULL) 427116271Sphk /* quota control */ 428116271Sphk vfsops->vfs_quotactl = vfs_stdquotactl; 429116271Sphk if (vfsops->vfs_statfs == NULL) 430116271Sphk /* return file system's status */ 431116271Sphk vfsops->vfs_statfs = vfs_stdstatfs; 432116271Sphk if (vfsops->vfs_sync == NULL) 433116271Sphk /* 434116271Sphk * flush unwritten data (nosync) 435116271Sphk * file systems can use vfs_stdsync 436116271Sphk * explicitly by setting it in the 437116271Sphk * vfsop vector. 438116271Sphk */ 439116271Sphk vfsops->vfs_sync = vfs_stdnosync; 440116271Sphk if (vfsops->vfs_vget == NULL) 441116271Sphk /* convert an inode number to a vnode */ 442116271Sphk vfsops->vfs_vget = vfs_stdvget; 443116271Sphk if (vfsops->vfs_fhtovp == NULL) 444116271Sphk /* turn an NFS file handle into a vnode */ 445116271Sphk vfsops->vfs_fhtovp = vfs_stdfhtovp; 446116271Sphk if (vfsops->vfs_checkexp == NULL) 447116271Sphk /* check if file system is exported */ 448116271Sphk vfsops->vfs_checkexp = vfs_stdcheckexp; 449116271Sphk if (vfsops->vfs_vptofh == NULL) 450116271Sphk /* turn a vnode into an NFS file handle */ 451116271Sphk vfsops->vfs_vptofh = vfs_stdvptofh; 452116271Sphk if (vfsops->vfs_init == NULL) 453116271Sphk /* file system specific initialisation */ 454116271Sphk vfsops->vfs_init = vfs_stdinit; 455116271Sphk if (vfsops->vfs_uninit == NULL) 456116271Sphk /* file system specific uninitialisation */ 457116271Sphk vfsops->vfs_uninit = vfs_stduninit; 458116271Sphk if (vfsops->vfs_extattrctl == NULL) 459116271Sphk /* extended attribute control */ 460116271Sphk vfsops->vfs_extattrctl = vfs_stdextattrctl; 461131733Salfred if (vfsops->vfs_sysctl == NULL) 462131733Salfred vfsops->vfs_sysctl = vfs_stdsysctl; 463116271Sphk 464116271Sphk /* 46540435Speter * Call init function for this VFS... 46640435Speter */ 46740435Speter (*(vfc->vfc_vfsops->vfs_init))(vfc); 46840435Speter 46940435Speter return 0; 4701541Srgrimes} 4712946Swollman 47240435Speter 47396755Strhodes/* Remove registration of a filesystem type */ 47440435Speterint 47541056Spetervfs_unregister(struct vfsconf *vfc) 47640435Speter{ 47740435Speter struct vfsconf *vfsp, *prev_vfsp; 47840435Speter int error, i, maxtypenum; 47940435Speter 48040435Speter i = vfc->vfc_typenum; 48140435Speter 48240435Speter prev_vfsp = NULL; 48340435Speter for (vfsp = vfsconf; vfsp; 48440435Speter prev_vfsp = vfsp, vfsp = vfsp->vfc_next) { 48540435Speter if (!strcmp(vfc->vfc_name, vfsp->vfc_name)) 48640435Speter break; 48740435Speter } 48840435Speter if (vfsp == NULL) 48940435Speter return EINVAL; 49040435Speter if (vfsp->vfc_refcount) 49140435Speter return EBUSY; 49240435Speter if (vfc->vfc_vfsops->vfs_uninit != NULL) { 49340435Speter error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp); 49440435Speter if (error) 49540435Speter return (error); 49640435Speter } 49740435Speter if (prev_vfsp) 49840435Speter prev_vfsp->vfc_next = vfsp->vfc_next; 49940435Speter else 50040435Speter vfsconf = vfsp->vfc_next; 50140435Speter maxtypenum = VFS_GENERIC; 50240435Speter for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next) 50340435Speter if (maxtypenum < vfsp->vfc_typenum) 50440435Speter maxtypenum = vfsp->vfc_typenum; 50540435Speter maxvfsconf = maxtypenum + 1; 50640435Speter return 0; 50740435Speter} 50841056Speter 50991690Seivind/* 51096755Strhodes * Standard kernel module handling code for filesystem modules. 51191690Seivind * Referenced from VFS_SET(). 51291690Seivind */ 51341056Speterint 51441170Sbdevfs_modevent(module_t mod, int type, void *data) 51541056Speter{ 51641056Speter struct vfsconf *vfc; 51741056Speter int error = 0; 51841056Speter 51941056Speter vfc = (struct vfsconf *)data; 52041056Speter 52141056Speter switch (type) { 52241056Speter case MOD_LOAD: 52341056Speter if (vfc) 52441056Speter error = vfs_register(vfc); 52541056Speter break; 52641056Speter 52741056Speter case MOD_UNLOAD: 52841056Speter if (vfc) 52941056Speter error = vfs_unregister(vfc); 53041056Speter break; 53141056Speter default: /* including MOD_SHUTDOWN */ 53241056Speter break; 53341056Speter } 53441056Speter return (error); 53541056Speter} 536