1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1989, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * This code is derived from software contributed 6df8bae1dSRodney W. Grimes * to Berkeley by John Heidemann of the UCLA Ficus project. 7df8bae1dSRodney W. Grimes * 8df8bae1dSRodney W. Grimes * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 19df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 20df8bae1dSRodney W. Grimes * without specific prior written permission. 21df8bae1dSRodney W. Grimes * 22df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32df8bae1dSRodney W. Grimes * SUCH DAMAGE. 33df8bae1dSRodney W. Grimes * 34df8bae1dSRodney W. Grimes * @(#)vfs_init.c 8.3 (Berkeley) 1/4/94 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37677b542eSDavid E. O'Brien #include <sys/cdefs.h> 38677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 39df8bae1dSRodney W. Grimes 40df8bae1dSRodney W. Grimes #include <sys/param.h> 41f23b4c91SGarrett Wollman #include <sys/systm.h> 42c901836cSGarrett Wollman #include <sys/kernel.h> 43df8bae1dSRodney W. Grimes #include <sys/mount.h> 44e99ea9ecSBruce Evans #include <sys/sysctl.h> 45df8bae1dSRodney W. Grimes #include <sys/vnode.h> 46df8bae1dSRodney W. Grimes #include <sys/malloc.h> 47df8bae1dSRodney W. Grimes 482b14f991SJulian Elischer 49a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_VNODE, "vnodes", "Dynamically allocated vnodes"); 50a1c995b6SPoul-Henning Kamp 512b14f991SJulian Elischer /* 52138e514cSPeter Wemm * The highest defined VFS number. 5399448ed1SJohn Dyson */ 54138e514cSPeter Wemm int maxvfsconf = VFS_GENERIC + 1; 55eb8e6d52SEivind Eklund 56eb8e6d52SEivind Eklund /* 57eb8e6d52SEivind Eklund * Single-linked list of configured VFSes. 58eb8e6d52SEivind Eklund * New entries are added/deleted by vfs_register()/vfs_unregister() 59eb8e6d52SEivind Eklund */ 60b676e48cSMike Smith struct vfsconf *vfsconf; 61b676e48cSMike Smith 62b676e48cSMike Smith /* 63df8bae1dSRodney W. Grimes * vfs_init.c 64df8bae1dSRodney W. Grimes * 65df8bae1dSRodney W. Grimes * Allocate and fill in operations vectors. 66df8bae1dSRodney W. Grimes * 67df8bae1dSRodney W. Grimes * An undocumented feature of this approach to defining operations is that 68df8bae1dSRodney W. Grimes * there can be multiple entries in vfs_opv_descs for the same operations 69df8bae1dSRodney W. Grimes * vector. This allows third parties to extend the set of operations 70df8bae1dSRodney W. Grimes * supported by another layer in a binary compatibile way. For example, 71df8bae1dSRodney W. Grimes * assume that NFS needed to be modified to support Ficus. NFS has an entry 72df8bae1dSRodney W. Grimes * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by 73df8bae1dSRodney W. Grimes * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions) 74df8bae1dSRodney W. Grimes * listing those new operations Ficus adds to NFS, all without modifying the 75df8bae1dSRodney W. Grimes * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but 76df8bae1dSRodney W. Grimes * that is a(whole)nother story.) This is a feature. 77df8bae1dSRodney W. Grimes */ 784e61198eSPeter Wemm 794e61198eSPeter Wemm /* Table of known vnodeop vectors (list of VFS vnode vectors) */ 808aef1712SMatthew Dillon static const struct vnodeopv_desc **vnodeopv_descs; 814e61198eSPeter Wemm static int vnodeopv_num; 824e61198eSPeter Wemm 834e61198eSPeter Wemm /* Table of known descs (list of vnode op handlers "vop_access_desc") */ 844e61198eSPeter Wemm static struct vnodeop_desc **vfs_op_descs; 85eb8e6d52SEivind Eklund /* Reference counts for vfs_op_descs */ 86eb8e6d52SEivind Eklund static int *vfs_op_desc_refs; 87eb8e6d52SEivind Eklund /* Number of descriptions */ 884e61198eSPeter Wemm static int num_op_descs; 89eb8e6d52SEivind Eklund /* Number of entries in each description */ 90e6728403SMatthew Dillon static int vfs_opv_numops = 64; 91e6728403SMatthew Dillon 92e6728403SMatthew Dillon /* Allow this number to be tuned at boot */ 93e6728403SMatthew Dillon TUNABLE_INT("vfs.opv_numops", &vfs_opv_numops); 94184dcdc7SMike Silbersack SYSCTL_INT(_vfs, OID_AUTO, opv_numops, CTLFLAG_RDTUN, &vfs_opv_numops, 95e6728403SMatthew Dillon 0, "Maximum number of operations in vop_t vector"); 96e6728403SMatthew Dillon 97e6728403SMatthew Dillon static int int_cmp(const void *a, const void *b); 98e6728403SMatthew Dillon 99e6728403SMatthew Dillon static int 100e6728403SMatthew Dillon int_cmp(const void *a, const void *b) 101e6728403SMatthew Dillon { 102e6728403SMatthew Dillon return(*(const int *)a - *(const int *)b); 103e6728403SMatthew Dillon } 1044e61198eSPeter Wemm 105eb8e6d52SEivind Eklund /* 106eb8e6d52SEivind Eklund * Recalculate the operations vector/description (those parts of it that can 107eb8e6d52SEivind Eklund * be recalculated, that is.) 108e6728403SMatthew Dillon * Always allocate operations vector large enough to hold vfs_opv_numops 109e6728403SMatthew Dillon * entries. The vector is never freed or deallocated once it is initialized, 110e6728403SMatthew Dillon * so that vnodes might safely reference it through their v_op pointer without 111e6728403SMatthew Dillon * vector changing suddenly from under them. 112eb8e6d52SEivind Eklund */ 1134e61198eSPeter Wemm static void 1144e61198eSPeter Wemm vfs_opv_recalc(void) 115df8bae1dSRodney W. Grimes { 116e6728403SMatthew Dillon int i, j, k; 117e6728403SMatthew Dillon int *vfs_op_offsets; 118f57e6547SBruce Evans vop_t ***opv_desc_vector_p; 119f57e6547SBruce Evans vop_t **opv_desc_vector; 120df8bae1dSRodney W. Grimes struct vnodeopv_entry_desc *opve_descp; 1218aef1712SMatthew Dillon const struct vnodeopv_desc *opv; 122df8bae1dSRodney W. Grimes 1234e61198eSPeter Wemm if (vfs_op_descs == NULL) 1244e61198eSPeter Wemm panic("vfs_opv_recalc called with null vfs_op_descs"); 1254e61198eSPeter Wemm 126df8bae1dSRodney W. Grimes /* 127e6728403SMatthew Dillon * Allocate and initialize temporary array to store 128e6728403SMatthew Dillon * offsets. Sort it to put all uninitialized entries 129e6728403SMatthew Dillon * first and to make holes in existing offset sequence 130e6728403SMatthew Dillon * detectable. 131e6728403SMatthew Dillon */ 132e6728403SMatthew Dillon MALLOC(vfs_op_offsets, int *, 133a163d034SWarner Losh num_op_descs * sizeof(int), M_TEMP, M_WAITOK); 134e6728403SMatthew Dillon if (vfs_op_offsets == NULL) 135e6728403SMatthew Dillon panic("vfs_opv_recalc: no memory"); 136e6728403SMatthew Dillon for (i = 0; i < num_op_descs; i++) 137e6728403SMatthew Dillon vfs_op_offsets[i] = vfs_op_descs[i]->vdesc_offset; 138e6728403SMatthew Dillon qsort(vfs_op_offsets, num_op_descs, sizeof(int), int_cmp); 139e6728403SMatthew Dillon 140e6728403SMatthew Dillon /* 141e6728403SMatthew Dillon * Run through and make sure all known descs have an offset. 142e6728403SMatthew Dillon * Use vfs_op_offsets to locate holes in offset sequence and 143e6728403SMatthew Dillon * reuse them. 1444e61198eSPeter Wemm * vop_default_desc is hardwired at offset 1, and offset 0 1454e61198eSPeter Wemm * is a panic sanity check. 146df8bae1dSRodney W. Grimes */ 147e6728403SMatthew Dillon j = 1; k = 1; 148e6728403SMatthew Dillon for (i = 0; i < num_op_descs; i++) { 149e6728403SMatthew Dillon if (vfs_op_descs[i]->vdesc_offset != 0) 150e6728403SMatthew Dillon continue; 151e6728403SMatthew Dillon /* 152e6728403SMatthew Dillon * Look at two adjacent entries vfs_op_offsets[j - 1] and 153e6728403SMatthew Dillon * vfs_op_offsets[j] and see if we can fit a new offset 154e6728403SMatthew Dillon * number in between. If not, look at the next pair until 155e6728403SMatthew Dillon * hole is found or the end of the vfs_op_offsets vector is 156e6728403SMatthew Dillon * reached. j has been initialized to 1 above so that 157e6728403SMatthew Dillon * referencing (j-1)-th element is safe and the loop will 158e6728403SMatthew Dillon * never execute if num_op_descs is 1. For each new value s 159e6728403SMatthew Dillon * of i the j loop pick up from where previous iteration has 160e6728403SMatthew Dillon * left off. When the last hole has been consumed or if no 161e6728403SMatthew Dillon * hole has been found, we will start allocating new numbers 162e6728403SMatthew Dillon * starting from the biggest already available offset + 1. 163e6728403SMatthew Dillon */ 164e6728403SMatthew Dillon for (; j < num_op_descs; j++) { 165e6728403SMatthew Dillon if (vfs_op_offsets[j - 1] < k && vfs_op_offsets[j] > k) 166e6728403SMatthew Dillon break; 167e6728403SMatthew Dillon k = vfs_op_offsets[j] + 1; 168e6728403SMatthew Dillon } 169e6728403SMatthew Dillon vfs_op_descs[i]->vdesc_offset = k++; 170e6728403SMatthew Dillon } 171e6728403SMatthew Dillon FREE(vfs_op_offsets, M_TEMP); 172e6728403SMatthew Dillon 173e6728403SMatthew Dillon /* Panic if new vops will cause vector overflow */ 174e6728403SMatthew Dillon if (k > vfs_opv_numops) 175e6728403SMatthew Dillon panic("VFS: Ran out of vop_t vector entries. %d entries required, only %d available.\n", k, vfs_opv_numops); 176e6728403SMatthew Dillon 1774e61198eSPeter Wemm /* 1784e61198eSPeter Wemm * Allocate and fill in the vectors 1794e61198eSPeter Wemm */ 1804e61198eSPeter Wemm for (i = 0; i < vnodeopv_num; i++) { 1814e61198eSPeter Wemm opv = vnodeopv_descs[i]; 182aa855a59SPeter Wemm opv_desc_vector_p = opv->opv_desc_vector_p; 183e6728403SMatthew Dillon if (*opv_desc_vector_p == NULL) 184f57e6547SBruce Evans MALLOC(*opv_desc_vector_p, vop_t **, 1857cc0979fSDavid Malone vfs_opv_numops * sizeof(vop_t *), M_VNODE, 186a163d034SWarner Losh M_WAITOK | M_ZERO); 1874e61198eSPeter Wemm 188fc611b06SPeter Wemm /* Fill in, with slot 0 being to return EOPNOTSUPP */ 189df8bae1dSRodney W. Grimes opv_desc_vector = *opv_desc_vector_p; 190fc611b06SPeter Wemm opv_desc_vector[0] = (vop_t *)vop_eopnotsupp; 191aa855a59SPeter Wemm for (j = 0; opv->opv_desc_ops[j].opve_op; j++) { 192aa855a59SPeter Wemm opve_descp = &(opv->opv_desc_ops[j]); 193df8bae1dSRodney W. Grimes opv_desc_vector[opve_descp->opve_op->vdesc_offset] = 194df8bae1dSRodney W. Grimes opve_descp->opve_impl; 195df8bae1dSRodney W. Grimes } 1964e61198eSPeter Wemm 1974e61198eSPeter Wemm /* Replace unfilled routines with their default (slot 1). */ 198aa855a59SPeter Wemm opv_desc_vector = *(opv->opv_desc_vector_p); 1994e61198eSPeter Wemm if (opv_desc_vector[1] == NULL) 2004e61198eSPeter Wemm panic("vfs_opv_recalc: vector without a default."); 201ee9d248cSPeter Wemm for (j = 0; j < vfs_opv_numops; j++) 202ee9d248cSPeter Wemm if (opv_desc_vector[j] == NULL) 2034e61198eSPeter Wemm opv_desc_vector[j] = opv_desc_vector[1]; 2044e61198eSPeter Wemm } 205df8bae1dSRodney W. Grimes } 206df8bae1dSRodney W. Grimes 207eb8e6d52SEivind Eklund /* Add a set of vnode operations (a description) to the table above. */ 2084e61198eSPeter Wemm void 2098aef1712SMatthew Dillon vfs_add_vnodeops(const void *data) 210df8bae1dSRodney W. Grimes { 2118aef1712SMatthew Dillon const struct vnodeopv_desc *opv; 2128aef1712SMatthew Dillon const struct vnodeopv_desc **newopv; 2134e61198eSPeter Wemm struct vnodeop_desc **newop; 2144e61198eSPeter Wemm int *newref; 2154e61198eSPeter Wemm struct vnodeop_desc *desc; 216f1d19042SArchie Cobbs int i, j; 217df8bae1dSRodney W. Grimes 2188aef1712SMatthew Dillon opv = (const struct vnodeopv_desc *)data; 2198aef1712SMatthew Dillon MALLOC(newopv, const struct vnodeopv_desc **, 220a163d034SWarner Losh (vnodeopv_num + 1) * sizeof(*newopv), M_VNODE, M_WAITOK); 2214e61198eSPeter Wemm if (vnodeopv_descs) { 2224e61198eSPeter Wemm bcopy(vnodeopv_descs, newopv, vnodeopv_num * sizeof(*newopv)); 2234e61198eSPeter Wemm FREE(vnodeopv_descs, M_VNODE); 2244e61198eSPeter Wemm } 2254e61198eSPeter Wemm newopv[vnodeopv_num] = opv; 2264e61198eSPeter Wemm vnodeopv_descs = newopv; 2274e61198eSPeter Wemm vnodeopv_num++; 2284e61198eSPeter Wemm 2294e61198eSPeter Wemm /* See if we have turned up a new vnode op desc */ 2304e61198eSPeter Wemm for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) { 2314e61198eSPeter Wemm for (j = 0; j < num_op_descs; j++) { 2324e61198eSPeter Wemm if (desc == vfs_op_descs[j]) { 2334e61198eSPeter Wemm /* found it, increase reference count */ 2344e61198eSPeter Wemm vfs_op_desc_refs[j]++; 2354e61198eSPeter Wemm break; 2364e61198eSPeter Wemm } 2374e61198eSPeter Wemm } 2384e61198eSPeter Wemm if (j == num_op_descs) { 2394e61198eSPeter Wemm /* not found, new entry */ 2404e61198eSPeter Wemm MALLOC(newop, struct vnodeop_desc **, 2414e61198eSPeter Wemm (num_op_descs + 1) * sizeof(*newop), 242a163d034SWarner Losh M_VNODE, M_WAITOK); 2434e61198eSPeter Wemm /* new reference count (for unload) */ 2444e61198eSPeter Wemm MALLOC(newref, int *, 2454e61198eSPeter Wemm (num_op_descs + 1) * sizeof(*newref), 246a163d034SWarner Losh M_VNODE, M_WAITOK); 2474e61198eSPeter Wemm if (vfs_op_descs) { 2484e61198eSPeter Wemm bcopy(vfs_op_descs, newop, 2494e61198eSPeter Wemm num_op_descs * sizeof(*newop)); 2504e61198eSPeter Wemm FREE(vfs_op_descs, M_VNODE); 2514e61198eSPeter Wemm } 2524e61198eSPeter Wemm if (vfs_op_desc_refs) { 2534e61198eSPeter Wemm bcopy(vfs_op_desc_refs, newref, 2544e61198eSPeter Wemm num_op_descs * sizeof(*newref)); 2554e61198eSPeter Wemm FREE(vfs_op_desc_refs, M_VNODE); 2564e61198eSPeter Wemm } 2574e61198eSPeter Wemm newop[num_op_descs] = desc; 2584e61198eSPeter Wemm newref[num_op_descs] = 1; 2594e61198eSPeter Wemm vfs_op_descs = newop; 2604e61198eSPeter Wemm vfs_op_desc_refs = newref; 2614e61198eSPeter Wemm num_op_descs++; 2624e61198eSPeter Wemm } 2634e61198eSPeter Wemm } 2644e61198eSPeter Wemm vfs_opv_recalc(); 2654e61198eSPeter Wemm } 2664e61198eSPeter Wemm 267eb8e6d52SEivind Eklund /* Remove a vnode type from the vnode description table above. */ 2684e61198eSPeter Wemm void 2698aef1712SMatthew Dillon vfs_rm_vnodeops(const void *data) 2704e61198eSPeter Wemm { 2718aef1712SMatthew Dillon const struct vnodeopv_desc *opv; 2728aef1712SMatthew Dillon const struct vnodeopv_desc **newopv; 2734e61198eSPeter Wemm struct vnodeop_desc **newop; 2744e61198eSPeter Wemm int *newref; 2754e61198eSPeter Wemm vop_t **opv_desc_vector; 2764e61198eSPeter Wemm struct vnodeop_desc *desc; 2774e61198eSPeter Wemm int i, j, k; 2784e61198eSPeter Wemm 279697457a1SMatthew Dillon opv = (const struct vnodeopv_desc *)data; 2804e61198eSPeter Wemm /* Lower ref counts on descs in the table and release if zero */ 2814e61198eSPeter Wemm for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) { 2824e61198eSPeter Wemm for (j = 0; j < num_op_descs; j++) { 2834e61198eSPeter Wemm if (desc == vfs_op_descs[j]) { 2844e61198eSPeter Wemm /* found it, decrease reference count */ 2854e61198eSPeter Wemm vfs_op_desc_refs[j]--; 2864e61198eSPeter Wemm break; 2874e61198eSPeter Wemm } 2884e61198eSPeter Wemm } 2894e61198eSPeter Wemm for (j = 0; j < num_op_descs; j++) { 2904e61198eSPeter Wemm if (vfs_op_desc_refs[j] > 0) 2914e61198eSPeter Wemm continue; 2924e61198eSPeter Wemm if (vfs_op_desc_refs[j] < 0) 2934e61198eSPeter Wemm panic("vfs_remove_vnodeops: negative refcnt"); 294e6728403SMatthew Dillon /* Entry is going away - replace it with defaultop */ 295e6728403SMatthew Dillon for (k = 0; k < vnodeopv_num; k++) { 296e6728403SMatthew Dillon opv_desc_vector = 297e6728403SMatthew Dillon *(vnodeopv_descs[k]->opv_desc_vector_p); 298e6728403SMatthew Dillon if (opv_desc_vector != NULL) 299e6728403SMatthew Dillon opv_desc_vector[desc->vdesc_offset] = 300e6728403SMatthew Dillon opv_desc_vector[1]; 301e6728403SMatthew Dillon } 3024e61198eSPeter Wemm MALLOC(newop, struct vnodeop_desc **, 3034e61198eSPeter Wemm (num_op_descs - 1) * sizeof(*newop), 304a163d034SWarner Losh M_VNODE, M_WAITOK); 3054e61198eSPeter Wemm /* new reference count (for unload) */ 3064e61198eSPeter Wemm MALLOC(newref, int *, 3074e61198eSPeter Wemm (num_op_descs - 1) * sizeof(*newref), 308a163d034SWarner Losh M_VNODE, M_WAITOK); 3094e61198eSPeter Wemm for (k = j; k < (num_op_descs - 1); k++) { 3104e61198eSPeter Wemm vfs_op_descs[k] = vfs_op_descs[k + 1]; 3114e61198eSPeter Wemm vfs_op_desc_refs[k] = vfs_op_desc_refs[k + 1]; 3124e61198eSPeter Wemm } 3134e61198eSPeter Wemm bcopy(vfs_op_descs, newop, 3144e61198eSPeter Wemm (num_op_descs - 1) * sizeof(*newop)); 3154e61198eSPeter Wemm bcopy(vfs_op_desc_refs, newref, 3164e61198eSPeter Wemm (num_op_descs - 1) * sizeof(*newref)); 3174e61198eSPeter Wemm FREE(vfs_op_descs, M_VNODE); 3184e61198eSPeter Wemm FREE(vfs_op_desc_refs, M_VNODE); 3194e61198eSPeter Wemm vfs_op_descs = newop; 3204e61198eSPeter Wemm vfs_op_desc_refs = newref; 3214e61198eSPeter Wemm num_op_descs--; 3224e61198eSPeter Wemm } 3234e61198eSPeter Wemm } 3244e61198eSPeter Wemm 3254e61198eSPeter Wemm for (i = 0; i < vnodeopv_num; i++) { 3264e61198eSPeter Wemm if (vnodeopv_descs[i] == opv) { 3274e61198eSPeter Wemm for (j = i; j < (vnodeopv_num - 1); j++) 3284e61198eSPeter Wemm vnodeopv_descs[j] = vnodeopv_descs[j + 1]; 3294e61198eSPeter Wemm break; 3304e61198eSPeter Wemm } 3314e61198eSPeter Wemm } 3324e61198eSPeter Wemm if (i == vnodeopv_num) 3334e61198eSPeter Wemm panic("vfs_remove_vnodeops: opv not found"); 334e6728403SMatthew Dillon opv_desc_vector = *(opv->opv_desc_vector_p); 335e6728403SMatthew Dillon if (opv_desc_vector != NULL) 336e6728403SMatthew Dillon FREE(opv_desc_vector, M_VNODE); 3378aef1712SMatthew Dillon MALLOC(newopv, const struct vnodeopv_desc **, 338a163d034SWarner Losh (vnodeopv_num - 1) * sizeof(*newopv), M_VNODE, M_WAITOK); 3394e61198eSPeter Wemm bcopy(vnodeopv_descs, newopv, (vnodeopv_num - 1) * sizeof(*newopv)); 3404e61198eSPeter Wemm FREE(vnodeopv_descs, M_VNODE); 3414e61198eSPeter Wemm vnodeopv_descs = newopv; 3424e61198eSPeter Wemm vnodeopv_num--; 3434e61198eSPeter Wemm 3444e61198eSPeter Wemm vfs_opv_recalc(); 345df8bae1dSRodney W. Grimes } 346df8bae1dSRodney W. Grimes 347df8bae1dSRodney W. Grimes /* 348df8bae1dSRodney W. Grimes * Routines having to do with the management of the vnode table. 349df8bae1dSRodney W. Grimes */ 350df8bae1dSRodney W. Grimes struct vattr va_null; 351df8bae1dSRodney W. Grimes 352df8bae1dSRodney W. Grimes /* 353df8bae1dSRodney W. Grimes * Initialize the vnode structures and initialize each filesystem type. 354df8bae1dSRodney W. Grimes */ 3552b14f991SJulian Elischer /* ARGSUSED*/ 3562b14f991SJulian Elischer static void 3574e61198eSPeter Wemm vfsinit(void *dummy) 358df8bae1dSRodney W. Grimes { 359df8bae1dSRodney W. Grimes 360df8bae1dSRodney W. Grimes vattr_null(&va_null); 361df8bae1dSRodney W. Grimes } 3624e61198eSPeter Wemm SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_FIRST, vfsinit, NULL) 363c901836cSGarrett Wollman 364eb8e6d52SEivind Eklund /* Register a new filesystem type in the global table */ 365aa855a59SPeter Wemm int 3664e61198eSPeter Wemm vfs_register(struct vfsconf *vfc) 367aa855a59SPeter Wemm { 368a199ed3cSDoug Rabson struct sysctl_oid *oidp; 369aa855a59SPeter Wemm struct vfsconf *vfsp; 370aa855a59SPeter Wemm 3717652131bSPoul-Henning Kamp struct vfsops *vfsops; 3727652131bSPoul-Henning Kamp 373aa855a59SPeter Wemm vfsp = NULL; 374aa855a59SPeter Wemm if (vfsconf) 375aa855a59SPeter Wemm for (vfsp = vfsconf; vfsp->vfc_next; vfsp = vfsp->vfc_next) 376a199ed3cSDoug Rabson if (strcmp(vfc->vfc_name, vfsp->vfc_name) == 0) 377aa855a59SPeter Wemm return EEXIST; 378aa855a59SPeter Wemm 379aa855a59SPeter Wemm vfc->vfc_typenum = maxvfsconf++; 380aa855a59SPeter Wemm if (vfsp) 381aa855a59SPeter Wemm vfsp->vfc_next = vfc; 382aa855a59SPeter Wemm else 383aa855a59SPeter Wemm vfsconf = vfc; 384aa855a59SPeter Wemm vfc->vfc_next = NULL; 385aa855a59SPeter Wemm 386aa855a59SPeter Wemm /* 387a199ed3cSDoug Rabson * If this filesystem has a sysctl node under vfs 388a199ed3cSDoug Rabson * (i.e. vfs.xxfs), then change the oid number of that node to 389a199ed3cSDoug Rabson * match the filesystem's type number. This allows user code 390a199ed3cSDoug Rabson * which uses the type number to read sysctl variables defined 391a199ed3cSDoug Rabson * by the filesystem to continue working. Since the oids are 392a199ed3cSDoug Rabson * in a sorted list, we need to make sure the order is 393a199ed3cSDoug Rabson * preserved by re-registering the oid after modifying its 394a199ed3cSDoug Rabson * number. 395a199ed3cSDoug Rabson */ 39637d40066SPoul-Henning Kamp SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) 397a199ed3cSDoug Rabson if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 398a199ed3cSDoug Rabson sysctl_unregister_oid(oidp); 399a199ed3cSDoug Rabson oidp->oid_number = vfc->vfc_typenum; 400a199ed3cSDoug Rabson sysctl_register_oid(oidp); 401a199ed3cSDoug Rabson } 402a199ed3cSDoug Rabson 403a199ed3cSDoug Rabson /* 4047652131bSPoul-Henning Kamp * Initialise unused ``struct vfsops'' fields, to use 4057652131bSPoul-Henning Kamp * the vfs_std*() functions. Note, we need the mount 4067652131bSPoul-Henning Kamp * and unmount operations, at the least. The check 4077652131bSPoul-Henning Kamp * for vfsops available is just a debugging aid. 4087652131bSPoul-Henning Kamp */ 4097652131bSPoul-Henning Kamp KASSERT(vfc->vfc_vfsops != NULL, 4107652131bSPoul-Henning Kamp ("Filesystem %s has no vfsops", vfc->vfc_name)); 4117652131bSPoul-Henning Kamp /* 4127652131bSPoul-Henning Kamp * Check the mount and unmount operations. 4137652131bSPoul-Henning Kamp */ 4147652131bSPoul-Henning Kamp vfsops = vfc->vfc_vfsops; 4157652131bSPoul-Henning Kamp KASSERT(vfsops->vfs_mount != NULL || vfsops->vfs_nmount != NULL, 4167652131bSPoul-Henning Kamp ("Filesystem %s has no (n)mount op", vfc->vfc_name)); 4177652131bSPoul-Henning Kamp KASSERT(vfsops->vfs_unmount != NULL, 4187652131bSPoul-Henning Kamp ("Filesystem %s has no unmount op", vfc->vfc_name)); 4197652131bSPoul-Henning Kamp 4207652131bSPoul-Henning Kamp if (vfsops->vfs_start == NULL) 4217652131bSPoul-Henning Kamp /* make a file system operational */ 4227652131bSPoul-Henning Kamp vfsops->vfs_start = vfs_stdstart; 4237652131bSPoul-Henning Kamp if (vfsops->vfs_root == NULL) 4247652131bSPoul-Henning Kamp /* return file system's root vnode */ 4257652131bSPoul-Henning Kamp vfsops->vfs_root = vfs_stdroot; 4267652131bSPoul-Henning Kamp if (vfsops->vfs_quotactl == NULL) 4277652131bSPoul-Henning Kamp /* quota control */ 4287652131bSPoul-Henning Kamp vfsops->vfs_quotactl = vfs_stdquotactl; 4297652131bSPoul-Henning Kamp if (vfsops->vfs_statfs == NULL) 4307652131bSPoul-Henning Kamp /* return file system's status */ 4317652131bSPoul-Henning Kamp vfsops->vfs_statfs = vfs_stdstatfs; 4327652131bSPoul-Henning Kamp if (vfsops->vfs_sync == NULL) 4337652131bSPoul-Henning Kamp /* 4347652131bSPoul-Henning Kamp * flush unwritten data (nosync) 4357652131bSPoul-Henning Kamp * file systems can use vfs_stdsync 4367652131bSPoul-Henning Kamp * explicitly by setting it in the 4377652131bSPoul-Henning Kamp * vfsop vector. 4387652131bSPoul-Henning Kamp */ 4397652131bSPoul-Henning Kamp vfsops->vfs_sync = vfs_stdnosync; 4407652131bSPoul-Henning Kamp if (vfsops->vfs_vget == NULL) 4417652131bSPoul-Henning Kamp /* convert an inode number to a vnode */ 4427652131bSPoul-Henning Kamp vfsops->vfs_vget = vfs_stdvget; 4437652131bSPoul-Henning Kamp if (vfsops->vfs_fhtovp == NULL) 4447652131bSPoul-Henning Kamp /* turn an NFS file handle into a vnode */ 4457652131bSPoul-Henning Kamp vfsops->vfs_fhtovp = vfs_stdfhtovp; 4467652131bSPoul-Henning Kamp if (vfsops->vfs_checkexp == NULL) 4477652131bSPoul-Henning Kamp /* check if file system is exported */ 4487652131bSPoul-Henning Kamp vfsops->vfs_checkexp = vfs_stdcheckexp; 4497652131bSPoul-Henning Kamp if (vfsops->vfs_vptofh == NULL) 4507652131bSPoul-Henning Kamp /* turn a vnode into an NFS file handle */ 4517652131bSPoul-Henning Kamp vfsops->vfs_vptofh = vfs_stdvptofh; 4527652131bSPoul-Henning Kamp if (vfsops->vfs_init == NULL) 4537652131bSPoul-Henning Kamp /* file system specific initialisation */ 4547652131bSPoul-Henning Kamp vfsops->vfs_init = vfs_stdinit; 4557652131bSPoul-Henning Kamp if (vfsops->vfs_uninit == NULL) 4567652131bSPoul-Henning Kamp /* file system specific uninitialisation */ 4577652131bSPoul-Henning Kamp vfsops->vfs_uninit = vfs_stduninit; 4587652131bSPoul-Henning Kamp if (vfsops->vfs_extattrctl == NULL) 4597652131bSPoul-Henning Kamp /* extended attribute control */ 4607652131bSPoul-Henning Kamp vfsops->vfs_extattrctl = vfs_stdextattrctl; 46181d16e2dSAlfred Perlstein if (vfsops->vfs_sysctl == NULL) 46281d16e2dSAlfred Perlstein vfsops->vfs_sysctl = vfs_stdsysctl; 4637652131bSPoul-Henning Kamp 4647652131bSPoul-Henning Kamp /* 465aa855a59SPeter Wemm * Call init function for this VFS... 466aa855a59SPeter Wemm */ 467aa855a59SPeter Wemm (*(vfc->vfc_vfsops->vfs_init))(vfc); 468aa855a59SPeter Wemm 469aa855a59SPeter Wemm return 0; 470aa855a59SPeter Wemm } 471aa855a59SPeter Wemm 472aa855a59SPeter Wemm 473eb8e6d52SEivind Eklund /* Remove registration of a filesystem type */ 474aa855a59SPeter Wemm int 4754e61198eSPeter Wemm vfs_unregister(struct vfsconf *vfc) 476aa855a59SPeter Wemm { 477aa855a59SPeter Wemm struct vfsconf *vfsp, *prev_vfsp; 478aa855a59SPeter Wemm int error, i, maxtypenum; 479aa855a59SPeter Wemm 480aa855a59SPeter Wemm i = vfc->vfc_typenum; 481aa855a59SPeter Wemm 482aa855a59SPeter Wemm prev_vfsp = NULL; 483aa855a59SPeter Wemm for (vfsp = vfsconf; vfsp; 484aa855a59SPeter Wemm prev_vfsp = vfsp, vfsp = vfsp->vfc_next) { 485aa855a59SPeter Wemm if (!strcmp(vfc->vfc_name, vfsp->vfc_name)) 486aa855a59SPeter Wemm break; 487aa855a59SPeter Wemm } 488aa855a59SPeter Wemm if (vfsp == NULL) 489aa855a59SPeter Wemm return EINVAL; 490aa855a59SPeter Wemm if (vfsp->vfc_refcount) 491aa855a59SPeter Wemm return EBUSY; 492aa855a59SPeter Wemm if (vfc->vfc_vfsops->vfs_uninit != NULL) { 493aa855a59SPeter Wemm error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp); 494aa855a59SPeter Wemm if (error) 495aa855a59SPeter Wemm return (error); 496aa855a59SPeter Wemm } 497aa855a59SPeter Wemm if (prev_vfsp) 498aa855a59SPeter Wemm prev_vfsp->vfc_next = vfsp->vfc_next; 499aa855a59SPeter Wemm else 500aa855a59SPeter Wemm vfsconf = vfsp->vfc_next; 501aa855a59SPeter Wemm maxtypenum = VFS_GENERIC; 502aa855a59SPeter Wemm for (vfsp = vfsconf; vfsp != NULL; vfsp = vfsp->vfc_next) 503aa855a59SPeter Wemm if (maxtypenum < vfsp->vfc_typenum) 504aa855a59SPeter Wemm maxtypenum = vfsp->vfc_typenum; 505aa855a59SPeter Wemm maxvfsconf = maxtypenum + 1; 506aa855a59SPeter Wemm return 0; 507aa855a59SPeter Wemm } 5084e61198eSPeter Wemm 509eb8e6d52SEivind Eklund /* 510eb8e6d52SEivind Eklund * Standard kernel module handling code for filesystem modules. 511eb8e6d52SEivind Eklund * Referenced from VFS_SET(). 512eb8e6d52SEivind Eklund */ 5134e61198eSPeter Wemm int 5144ae860afSBruce Evans vfs_modevent(module_t mod, int type, void *data) 5154e61198eSPeter Wemm { 5164e61198eSPeter Wemm struct vfsconf *vfc; 5174e61198eSPeter Wemm int error = 0; 5184e61198eSPeter Wemm 5194e61198eSPeter Wemm vfc = (struct vfsconf *)data; 5204e61198eSPeter Wemm 5214e61198eSPeter Wemm switch (type) { 5224e61198eSPeter Wemm case MOD_LOAD: 5234e61198eSPeter Wemm if (vfc) 5244e61198eSPeter Wemm error = vfs_register(vfc); 5254e61198eSPeter Wemm break; 5264e61198eSPeter Wemm 5274e61198eSPeter Wemm case MOD_UNLOAD: 5284e61198eSPeter Wemm if (vfc) 5294e61198eSPeter Wemm error = vfs_unregister(vfc); 5304e61198eSPeter Wemm break; 5314e61198eSPeter Wemm default: /* including MOD_SHUTDOWN */ 5324e61198eSPeter Wemm break; 5334e61198eSPeter Wemm } 5344e61198eSPeter Wemm return (error); 5354e61198eSPeter Wemm } 536