vfs_init.c revision 132710
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 132710 2004-07-27 22:32:01Z phk $"); 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 */ 60132710Sphkstruct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(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 352132710Sphkstruct vfsconf * 353132710Sphkvfs_byname(const char *name) 354132710Sphk{ 355132710Sphk struct vfsconf *vfsp; 356132710Sphk 357132710Sphk TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) 358132710Sphk if (!strcmp(name, vfsp->vfc_name)) 359132710Sphk return (vfsp); 360132710Sphk return (NULL); 361132710Sphk} 362132710Sphk 3631541Srgrimes/* 36496755Strhodes * Initialize the vnode structures and initialize each filesystem type. 3651541Srgrimes */ 36610358Sjulian/* ARGSUSED*/ 36710358Sjulianstatic void 36841056Spetervfsinit(void *dummy) 3691541Srgrimes{ 3701541Srgrimes 3711541Srgrimes vattr_null(&va_null); 37240435Speter} 37341056SpeterSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) 37440435Speter 37596755Strhodes/* Register a new filesystem type in the global table */ 37640435Speterint 37741056Spetervfs_register(struct vfsconf *vfc) 37840435Speter{ 37944549Sdfr struct sysctl_oid *oidp; 380116271Sphk struct vfsops *vfsops; 381116271Sphk 382132710Sphk if (vfs_byname(vfc->vfc_name) != NULL) 383132710Sphk return EEXIST; 38440435Speter 38540435Speter vfc->vfc_typenum = maxvfsconf++; 386132710Sphk TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list); 38740435Speter 38840435Speter /* 38944549Sdfr * If this filesystem has a sysctl node under vfs 39044549Sdfr * (i.e. vfs.xxfs), then change the oid number of that node to 39144549Sdfr * match the filesystem's type number. This allows user code 39244549Sdfr * which uses the type number to read sysctl variables defined 39344549Sdfr * by the filesystem to continue working. Since the oids are 39444549Sdfr * in a sorted list, we need to make sure the order is 39544549Sdfr * preserved by re-registering the oid after modifying its 39644549Sdfr * number. 39744549Sdfr */ 39872012Sphk SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) 39944549Sdfr if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 40044549Sdfr sysctl_unregister_oid(oidp); 40144549Sdfr oidp->oid_number = vfc->vfc_typenum; 40244549Sdfr sysctl_register_oid(oidp); 40344549Sdfr } 40444549Sdfr 40544549Sdfr /* 406116271Sphk * Initialise unused ``struct vfsops'' fields, to use 407116271Sphk * the vfs_std*() functions. Note, we need the mount 408116271Sphk * and unmount operations, at the least. The check 409116271Sphk * for vfsops available is just a debugging aid. 410116271Sphk */ 411116271Sphk KASSERT(vfc->vfc_vfsops != NULL, 412116271Sphk ("Filesystem %s has no vfsops", vfc->vfc_name)); 413116271Sphk /* 414116271Sphk * Check the mount and unmount operations. 415116271Sphk */ 416116271Sphk vfsops = vfc->vfc_vfsops; 417116271Sphk KASSERT(vfsops->vfs_mount != NULL || vfsops->vfs_nmount != NULL, 418116271Sphk ("Filesystem %s has no (n)mount op", vfc->vfc_name)); 419116271Sphk KASSERT(vfsops->vfs_unmount != NULL, 420116271Sphk ("Filesystem %s has no unmount op", vfc->vfc_name)); 421116271Sphk 422116271Sphk if (vfsops->vfs_start == NULL) 423116271Sphk /* make a file system operational */ 424116271Sphk vfsops->vfs_start = vfs_stdstart; 425116271Sphk if (vfsops->vfs_root == NULL) 426116271Sphk /* return file system's root vnode */ 427116271Sphk vfsops->vfs_root = vfs_stdroot; 428116271Sphk if (vfsops->vfs_quotactl == NULL) 429116271Sphk /* quota control */ 430116271Sphk vfsops->vfs_quotactl = vfs_stdquotactl; 431116271Sphk if (vfsops->vfs_statfs == NULL) 432116271Sphk /* return file system's status */ 433116271Sphk vfsops->vfs_statfs = vfs_stdstatfs; 434116271Sphk if (vfsops->vfs_sync == NULL) 435116271Sphk /* 436116271Sphk * flush unwritten data (nosync) 437116271Sphk * file systems can use vfs_stdsync 438116271Sphk * explicitly by setting it in the 439116271Sphk * vfsop vector. 440116271Sphk */ 441116271Sphk vfsops->vfs_sync = vfs_stdnosync; 442116271Sphk if (vfsops->vfs_vget == NULL) 443116271Sphk /* convert an inode number to a vnode */ 444116271Sphk vfsops->vfs_vget = vfs_stdvget; 445116271Sphk if (vfsops->vfs_fhtovp == NULL) 446116271Sphk /* turn an NFS file handle into a vnode */ 447116271Sphk vfsops->vfs_fhtovp = vfs_stdfhtovp; 448116271Sphk if (vfsops->vfs_checkexp == NULL) 449116271Sphk /* check if file system is exported */ 450116271Sphk vfsops->vfs_checkexp = vfs_stdcheckexp; 451116271Sphk if (vfsops->vfs_vptofh == NULL) 452116271Sphk /* turn a vnode into an NFS file handle */ 453116271Sphk vfsops->vfs_vptofh = vfs_stdvptofh; 454116271Sphk if (vfsops->vfs_init == NULL) 455116271Sphk /* file system specific initialisation */ 456116271Sphk vfsops->vfs_init = vfs_stdinit; 457116271Sphk if (vfsops->vfs_uninit == NULL) 458116271Sphk /* file system specific uninitialisation */ 459116271Sphk vfsops->vfs_uninit = vfs_stduninit; 460116271Sphk if (vfsops->vfs_extattrctl == NULL) 461116271Sphk /* extended attribute control */ 462116271Sphk vfsops->vfs_extattrctl = vfs_stdextattrctl; 463131733Salfred if (vfsops->vfs_sysctl == NULL) 464131733Salfred vfsops->vfs_sysctl = vfs_stdsysctl; 465116271Sphk 466116271Sphk /* 46740435Speter * Call init function for this VFS... 46840435Speter */ 46940435Speter (*(vfc->vfc_vfsops->vfs_init))(vfc); 47040435Speter 47140435Speter return 0; 4721541Srgrimes} 4732946Swollman 47440435Speter 47596755Strhodes/* Remove registration of a filesystem type */ 47640435Speterint 47741056Spetervfs_unregister(struct vfsconf *vfc) 47840435Speter{ 479132710Sphk struct vfsconf *vfsp; 48040435Speter int error, i, maxtypenum; 48140435Speter 48240435Speter i = vfc->vfc_typenum; 48340435Speter 484132710Sphk vfsp = vfs_byname(vfc->vfc_name); 48540435Speter if (vfsp == NULL) 48640435Speter return EINVAL; 48740435Speter if (vfsp->vfc_refcount) 48840435Speter return EBUSY; 48940435Speter if (vfc->vfc_vfsops->vfs_uninit != NULL) { 49040435Speter error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp); 49140435Speter if (error) 49240435Speter return (error); 49340435Speter } 494132710Sphk TAILQ_REMOVE(&vfsconf, vfsp, vfc_list); 49540435Speter maxtypenum = VFS_GENERIC; 496132710Sphk TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) 49740435Speter if (maxtypenum < vfsp->vfc_typenum) 49840435Speter maxtypenum = vfsp->vfc_typenum; 49940435Speter maxvfsconf = maxtypenum + 1; 50040435Speter return 0; 50140435Speter} 50241056Speter 50391690Seivind/* 50496755Strhodes * Standard kernel module handling code for filesystem modules. 50591690Seivind * Referenced from VFS_SET(). 50691690Seivind */ 50741056Speterint 50841170Sbdevfs_modevent(module_t mod, int type, void *data) 50941056Speter{ 51041056Speter struct vfsconf *vfc; 51141056Speter int error = 0; 51241056Speter 51341056Speter vfc = (struct vfsconf *)data; 51441056Speter 51541056Speter switch (type) { 51641056Speter case MOD_LOAD: 51741056Speter if (vfc) 51841056Speter error = vfs_register(vfc); 51941056Speter break; 52041056Speter 52141056Speter case MOD_UNLOAD: 52241056Speter if (vfc) 52341056Speter error = vfs_unregister(vfc); 52441056Speter break; 525132199Sphk default: 526132199Sphk error = EOPNOTSUPP; 52741056Speter break; 52841056Speter } 52941056Speter return (error); 53041056Speter} 531