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 */ 603dfe213eSPoul-Henning Kamp struct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(vfsconf); 61b676e48cSMike Smith 62b676e48cSMike Smith /* 63273350adSPoul-Henning Kamp * A Zen vnode attribute structure. 64273350adSPoul-Henning Kamp * 65273350adSPoul-Henning Kamp * Initialized when the first filesystem registers by vfs_register(). 66273350adSPoul-Henning Kamp */ 67273350adSPoul-Henning Kamp struct vattr va_null; 68273350adSPoul-Henning Kamp 69273350adSPoul-Henning Kamp /* 70df8bae1dSRodney W. Grimes * vfs_init.c 71df8bae1dSRodney W. Grimes * 72df8bae1dSRodney W. Grimes * Allocate and fill in operations vectors. 73df8bae1dSRodney W. Grimes * 74df8bae1dSRodney W. Grimes * An undocumented feature of this approach to defining operations is that 75df8bae1dSRodney W. Grimes * there can be multiple entries in vfs_opv_descs for the same operations 76df8bae1dSRodney W. Grimes * vector. This allows third parties to extend the set of operations 77df8bae1dSRodney W. Grimes * supported by another layer in a binary compatibile way. For example, 78df8bae1dSRodney W. Grimes * assume that NFS needed to be modified to support Ficus. NFS has an entry 79df8bae1dSRodney W. Grimes * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by 80df8bae1dSRodney W. Grimes * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions) 81df8bae1dSRodney W. Grimes * listing those new operations Ficus adds to NFS, all without modifying the 82df8bae1dSRodney W. Grimes * NFS code. (Of couse, the OTW NFS protocol still needs to be munged, but 83df8bae1dSRodney W. Grimes * that is a(whole)nother story.) This is a feature. 84df8bae1dSRodney W. Grimes */ 854e61198eSPeter Wemm 864e61198eSPeter Wemm /* Table of known vnodeop vectors (list of VFS vnode vectors) */ 878aef1712SMatthew Dillon static const struct vnodeopv_desc **vnodeopv_descs; 884e61198eSPeter Wemm static int vnodeopv_num; 894e61198eSPeter Wemm 904e61198eSPeter Wemm /* Table of known descs (list of vnode op handlers "vop_access_desc") */ 914e61198eSPeter Wemm static struct vnodeop_desc **vfs_op_descs; 92eb8e6d52SEivind Eklund /* Reference counts for vfs_op_descs */ 93eb8e6d52SEivind Eklund static int *vfs_op_desc_refs; 94eb8e6d52SEivind Eklund /* Number of descriptions */ 954e61198eSPeter Wemm static int num_op_descs; 96eb8e6d52SEivind Eklund /* Number of entries in each description */ 97e6728403SMatthew Dillon static int vfs_opv_numops = 64; 98e6728403SMatthew Dillon 99e6728403SMatthew Dillon /* Allow this number to be tuned at boot */ 100e6728403SMatthew Dillon TUNABLE_INT("vfs.opv_numops", &vfs_opv_numops); 101184dcdc7SMike Silbersack SYSCTL_INT(_vfs, OID_AUTO, opv_numops, CTLFLAG_RDTUN, &vfs_opv_numops, 102e6728403SMatthew Dillon 0, "Maximum number of operations in vop_t vector"); 103e6728403SMatthew Dillon 104e6728403SMatthew Dillon static int int_cmp(const void *a, const void *b); 105e6728403SMatthew Dillon 106e6728403SMatthew Dillon static int 107e6728403SMatthew Dillon int_cmp(const void *a, const void *b) 108e6728403SMatthew Dillon { 109e6728403SMatthew Dillon return(*(const int *)a - *(const int *)b); 110e6728403SMatthew Dillon } 1114e61198eSPeter Wemm 112eb8e6d52SEivind Eklund /* 113eb8e6d52SEivind Eklund * Recalculate the operations vector/description (those parts of it that can 114eb8e6d52SEivind Eklund * be recalculated, that is.) 115e6728403SMatthew Dillon * Always allocate operations vector large enough to hold vfs_opv_numops 116e6728403SMatthew Dillon * entries. The vector is never freed or deallocated once it is initialized, 117e6728403SMatthew Dillon * so that vnodes might safely reference it through their v_op pointer without 118e6728403SMatthew Dillon * vector changing suddenly from under them. 119eb8e6d52SEivind Eklund */ 1204e61198eSPeter Wemm static void 1214e61198eSPeter Wemm vfs_opv_recalc(void) 122df8bae1dSRodney W. Grimes { 123e6728403SMatthew Dillon int i, j, k; 124e6728403SMatthew Dillon int *vfs_op_offsets; 125f57e6547SBruce Evans vop_t ***opv_desc_vector_p; 126f57e6547SBruce Evans vop_t **opv_desc_vector; 127df8bae1dSRodney W. Grimes struct vnodeopv_entry_desc *opve_descp; 1288aef1712SMatthew Dillon const struct vnodeopv_desc *opv; 129df8bae1dSRodney W. Grimes 1304e61198eSPeter Wemm if (vfs_op_descs == NULL) 1314e61198eSPeter Wemm panic("vfs_opv_recalc called with null vfs_op_descs"); 1324e61198eSPeter Wemm 133df8bae1dSRodney W. Grimes /* 134e6728403SMatthew Dillon * Allocate and initialize temporary array to store 135e6728403SMatthew Dillon * offsets. Sort it to put all uninitialized entries 136e6728403SMatthew Dillon * first and to make holes in existing offset sequence 137e6728403SMatthew Dillon * detectable. 138e6728403SMatthew Dillon */ 139e6728403SMatthew Dillon MALLOC(vfs_op_offsets, int *, 140a163d034SWarner Losh num_op_descs * sizeof(int), M_TEMP, M_WAITOK); 141e6728403SMatthew Dillon if (vfs_op_offsets == NULL) 142e6728403SMatthew Dillon panic("vfs_opv_recalc: no memory"); 143e6728403SMatthew Dillon for (i = 0; i < num_op_descs; i++) 144e6728403SMatthew Dillon vfs_op_offsets[i] = vfs_op_descs[i]->vdesc_offset; 145e6728403SMatthew Dillon qsort(vfs_op_offsets, num_op_descs, sizeof(int), int_cmp); 146e6728403SMatthew Dillon 147e6728403SMatthew Dillon /* 148e6728403SMatthew Dillon * Run through and make sure all known descs have an offset. 149e6728403SMatthew Dillon * Use vfs_op_offsets to locate holes in offset sequence and 150e6728403SMatthew Dillon * reuse them. 1514e61198eSPeter Wemm * vop_default_desc is hardwired at offset 1, and offset 0 1524e61198eSPeter Wemm * is a panic sanity check. 153df8bae1dSRodney W. Grimes */ 154e6728403SMatthew Dillon j = 1; k = 1; 155e6728403SMatthew Dillon for (i = 0; i < num_op_descs; i++) { 156e6728403SMatthew Dillon if (vfs_op_descs[i]->vdesc_offset != 0) 157e6728403SMatthew Dillon continue; 158e6728403SMatthew Dillon /* 159e6728403SMatthew Dillon * Look at two adjacent entries vfs_op_offsets[j - 1] and 160e6728403SMatthew Dillon * vfs_op_offsets[j] and see if we can fit a new offset 161e6728403SMatthew Dillon * number in between. If not, look at the next pair until 162e6728403SMatthew Dillon * hole is found or the end of the vfs_op_offsets vector is 163e6728403SMatthew Dillon * reached. j has been initialized to 1 above so that 164e6728403SMatthew Dillon * referencing (j-1)-th element is safe and the loop will 165e6728403SMatthew Dillon * never execute if num_op_descs is 1. For each new value s 166e6728403SMatthew Dillon * of i the j loop pick up from where previous iteration has 167e6728403SMatthew Dillon * left off. When the last hole has been consumed or if no 168e6728403SMatthew Dillon * hole has been found, we will start allocating new numbers 169e6728403SMatthew Dillon * starting from the biggest already available offset + 1. 170e6728403SMatthew Dillon */ 171e6728403SMatthew Dillon for (; j < num_op_descs; j++) { 172e6728403SMatthew Dillon if (vfs_op_offsets[j - 1] < k && vfs_op_offsets[j] > k) 173e6728403SMatthew Dillon break; 174e6728403SMatthew Dillon k = vfs_op_offsets[j] + 1; 175e6728403SMatthew Dillon } 176e6728403SMatthew Dillon vfs_op_descs[i]->vdesc_offset = k++; 177e6728403SMatthew Dillon } 178e6728403SMatthew Dillon FREE(vfs_op_offsets, M_TEMP); 179e6728403SMatthew Dillon 180e6728403SMatthew Dillon /* Panic if new vops will cause vector overflow */ 181e6728403SMatthew Dillon if (k > vfs_opv_numops) 182e6728403SMatthew Dillon panic("VFS: Ran out of vop_t vector entries. %d entries required, only %d available.\n", k, vfs_opv_numops); 183e6728403SMatthew Dillon 1844e61198eSPeter Wemm /* 1854e61198eSPeter Wemm * Allocate and fill in the vectors 1864e61198eSPeter Wemm */ 1874e61198eSPeter Wemm for (i = 0; i < vnodeopv_num; i++) { 1884e61198eSPeter Wemm opv = vnodeopv_descs[i]; 189aa855a59SPeter Wemm opv_desc_vector_p = opv->opv_desc_vector_p; 190e6728403SMatthew Dillon if (*opv_desc_vector_p == NULL) 191f57e6547SBruce Evans MALLOC(*opv_desc_vector_p, vop_t **, 1927cc0979fSDavid Malone vfs_opv_numops * sizeof(vop_t *), M_VNODE, 193a163d034SWarner Losh M_WAITOK | M_ZERO); 1944e61198eSPeter Wemm 195fc611b06SPeter Wemm /* Fill in, with slot 0 being to return EOPNOTSUPP */ 196df8bae1dSRodney W. Grimes opv_desc_vector = *opv_desc_vector_p; 197fc611b06SPeter Wemm opv_desc_vector[0] = (vop_t *)vop_eopnotsupp; 198aa855a59SPeter Wemm for (j = 0; opv->opv_desc_ops[j].opve_op; j++) { 199aa855a59SPeter Wemm opve_descp = &(opv->opv_desc_ops[j]); 200df8bae1dSRodney W. Grimes opv_desc_vector[opve_descp->opve_op->vdesc_offset] = 201df8bae1dSRodney W. Grimes opve_descp->opve_impl; 202df8bae1dSRodney W. Grimes } 2034e61198eSPeter Wemm 2044e61198eSPeter Wemm /* Replace unfilled routines with their default (slot 1). */ 205aa855a59SPeter Wemm opv_desc_vector = *(opv->opv_desc_vector_p); 2064e61198eSPeter Wemm if (opv_desc_vector[1] == NULL) 2074e61198eSPeter Wemm panic("vfs_opv_recalc: vector without a default."); 208ee9d248cSPeter Wemm for (j = 0; j < vfs_opv_numops; j++) 209ee9d248cSPeter Wemm if (opv_desc_vector[j] == NULL) 2104e61198eSPeter Wemm opv_desc_vector[j] = opv_desc_vector[1]; 2114e61198eSPeter Wemm } 212df8bae1dSRodney W. Grimes } 213df8bae1dSRodney W. Grimes 214eb8e6d52SEivind Eklund /* Add a set of vnode operations (a description) to the table above. */ 2154e61198eSPeter Wemm void 2168aef1712SMatthew Dillon vfs_add_vnodeops(const void *data) 217df8bae1dSRodney W. Grimes { 2188aef1712SMatthew Dillon const struct vnodeopv_desc *opv; 2198aef1712SMatthew Dillon const struct vnodeopv_desc **newopv; 2204e61198eSPeter Wemm struct vnodeop_desc **newop; 2214e61198eSPeter Wemm int *newref; 2224e61198eSPeter Wemm struct vnodeop_desc *desc; 223f1d19042SArchie Cobbs int i, j; 224df8bae1dSRodney W. Grimes 2258aef1712SMatthew Dillon opv = (const struct vnodeopv_desc *)data; 2268aef1712SMatthew Dillon MALLOC(newopv, const struct vnodeopv_desc **, 227a163d034SWarner Losh (vnodeopv_num + 1) * sizeof(*newopv), M_VNODE, M_WAITOK); 2284e61198eSPeter Wemm if (vnodeopv_descs) { 2294e61198eSPeter Wemm bcopy(vnodeopv_descs, newopv, vnodeopv_num * sizeof(*newopv)); 2304e61198eSPeter Wemm FREE(vnodeopv_descs, M_VNODE); 2314e61198eSPeter Wemm } 2324e61198eSPeter Wemm newopv[vnodeopv_num] = opv; 2334e61198eSPeter Wemm vnodeopv_descs = newopv; 2344e61198eSPeter Wemm vnodeopv_num++; 2354e61198eSPeter Wemm 2364e61198eSPeter Wemm /* See if we have turned up a new vnode op desc */ 2374e61198eSPeter Wemm for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) { 2384e61198eSPeter Wemm for (j = 0; j < num_op_descs; j++) { 2394e61198eSPeter Wemm if (desc == vfs_op_descs[j]) { 2404e61198eSPeter Wemm /* found it, increase reference count */ 2414e61198eSPeter Wemm vfs_op_desc_refs[j]++; 2424e61198eSPeter Wemm break; 2434e61198eSPeter Wemm } 2444e61198eSPeter Wemm } 2454e61198eSPeter Wemm if (j == num_op_descs) { 2464e61198eSPeter Wemm /* not found, new entry */ 2474e61198eSPeter Wemm MALLOC(newop, struct vnodeop_desc **, 2484e61198eSPeter Wemm (num_op_descs + 1) * sizeof(*newop), 249a163d034SWarner Losh M_VNODE, M_WAITOK); 2504e61198eSPeter Wemm /* new reference count (for unload) */ 2514e61198eSPeter Wemm MALLOC(newref, int *, 2524e61198eSPeter Wemm (num_op_descs + 1) * sizeof(*newref), 253a163d034SWarner Losh M_VNODE, M_WAITOK); 2544e61198eSPeter Wemm if (vfs_op_descs) { 2554e61198eSPeter Wemm bcopy(vfs_op_descs, newop, 2564e61198eSPeter Wemm num_op_descs * sizeof(*newop)); 2574e61198eSPeter Wemm FREE(vfs_op_descs, M_VNODE); 2584e61198eSPeter Wemm } 2594e61198eSPeter Wemm if (vfs_op_desc_refs) { 2604e61198eSPeter Wemm bcopy(vfs_op_desc_refs, newref, 2614e61198eSPeter Wemm num_op_descs * sizeof(*newref)); 2624e61198eSPeter Wemm FREE(vfs_op_desc_refs, M_VNODE); 2634e61198eSPeter Wemm } 2644e61198eSPeter Wemm newop[num_op_descs] = desc; 2654e61198eSPeter Wemm newref[num_op_descs] = 1; 2664e61198eSPeter Wemm vfs_op_descs = newop; 2674e61198eSPeter Wemm vfs_op_desc_refs = newref; 2684e61198eSPeter Wemm num_op_descs++; 2694e61198eSPeter Wemm } 2704e61198eSPeter Wemm } 2714e61198eSPeter Wemm vfs_opv_recalc(); 2724e61198eSPeter Wemm } 2734e61198eSPeter Wemm 274eb8e6d52SEivind Eklund /* Remove a vnode type from the vnode description table above. */ 2754e61198eSPeter Wemm void 2768aef1712SMatthew Dillon vfs_rm_vnodeops(const void *data) 2774e61198eSPeter Wemm { 2788aef1712SMatthew Dillon const struct vnodeopv_desc *opv; 2798aef1712SMatthew Dillon const struct vnodeopv_desc **newopv; 2804e61198eSPeter Wemm struct vnodeop_desc **newop; 2814e61198eSPeter Wemm int *newref; 2824e61198eSPeter Wemm vop_t **opv_desc_vector; 2834e61198eSPeter Wemm struct vnodeop_desc *desc; 2844e61198eSPeter Wemm int i, j, k; 2854e61198eSPeter Wemm 286697457a1SMatthew Dillon opv = (const struct vnodeopv_desc *)data; 2874e61198eSPeter Wemm /* Lower ref counts on descs in the table and release if zero */ 2884e61198eSPeter Wemm for (i = 0; (desc = opv->opv_desc_ops[i].opve_op); i++) { 2894e61198eSPeter Wemm for (j = 0; j < num_op_descs; j++) { 2904e61198eSPeter Wemm if (desc == vfs_op_descs[j]) { 2914e61198eSPeter Wemm /* found it, decrease reference count */ 2924e61198eSPeter Wemm vfs_op_desc_refs[j]--; 2934e61198eSPeter Wemm break; 2944e61198eSPeter Wemm } 2954e61198eSPeter Wemm } 2964e61198eSPeter Wemm for (j = 0; j < num_op_descs; j++) { 2974e61198eSPeter Wemm if (vfs_op_desc_refs[j] > 0) 2984e61198eSPeter Wemm continue; 2994e61198eSPeter Wemm if (vfs_op_desc_refs[j] < 0) 3004e61198eSPeter Wemm panic("vfs_remove_vnodeops: negative refcnt"); 301e6728403SMatthew Dillon /* Entry is going away - replace it with defaultop */ 302e6728403SMatthew Dillon for (k = 0; k < vnodeopv_num; k++) { 303e6728403SMatthew Dillon opv_desc_vector = 304e6728403SMatthew Dillon *(vnodeopv_descs[k]->opv_desc_vector_p); 305e6728403SMatthew Dillon if (opv_desc_vector != NULL) 306e6728403SMatthew Dillon opv_desc_vector[desc->vdesc_offset] = 307e6728403SMatthew Dillon opv_desc_vector[1]; 308e6728403SMatthew Dillon } 3094e61198eSPeter Wemm MALLOC(newop, struct vnodeop_desc **, 3104e61198eSPeter Wemm (num_op_descs - 1) * sizeof(*newop), 311a163d034SWarner Losh M_VNODE, M_WAITOK); 3124e61198eSPeter Wemm /* new reference count (for unload) */ 3134e61198eSPeter Wemm MALLOC(newref, int *, 3144e61198eSPeter Wemm (num_op_descs - 1) * sizeof(*newref), 315a163d034SWarner Losh M_VNODE, M_WAITOK); 3164e61198eSPeter Wemm for (k = j; k < (num_op_descs - 1); k++) { 3174e61198eSPeter Wemm vfs_op_descs[k] = vfs_op_descs[k + 1]; 3184e61198eSPeter Wemm vfs_op_desc_refs[k] = vfs_op_desc_refs[k + 1]; 3194e61198eSPeter Wemm } 3204e61198eSPeter Wemm bcopy(vfs_op_descs, newop, 3214e61198eSPeter Wemm (num_op_descs - 1) * sizeof(*newop)); 3224e61198eSPeter Wemm bcopy(vfs_op_desc_refs, newref, 3234e61198eSPeter Wemm (num_op_descs - 1) * sizeof(*newref)); 3244e61198eSPeter Wemm FREE(vfs_op_descs, M_VNODE); 3254e61198eSPeter Wemm FREE(vfs_op_desc_refs, M_VNODE); 3264e61198eSPeter Wemm vfs_op_descs = newop; 3274e61198eSPeter Wemm vfs_op_desc_refs = newref; 3284e61198eSPeter Wemm num_op_descs--; 3294e61198eSPeter Wemm } 3304e61198eSPeter Wemm } 3314e61198eSPeter Wemm 3324e61198eSPeter Wemm for (i = 0; i < vnodeopv_num; i++) { 3334e61198eSPeter Wemm if (vnodeopv_descs[i] == opv) { 3344e61198eSPeter Wemm for (j = i; j < (vnodeopv_num - 1); j++) 3354e61198eSPeter Wemm vnodeopv_descs[j] = vnodeopv_descs[j + 1]; 3364e61198eSPeter Wemm break; 3374e61198eSPeter Wemm } 3384e61198eSPeter Wemm } 3394e61198eSPeter Wemm if (i == vnodeopv_num) 3404e61198eSPeter Wemm panic("vfs_remove_vnodeops: opv not found"); 341e6728403SMatthew Dillon opv_desc_vector = *(opv->opv_desc_vector_p); 342e6728403SMatthew Dillon if (opv_desc_vector != NULL) 343e6728403SMatthew Dillon FREE(opv_desc_vector, M_VNODE); 3448aef1712SMatthew Dillon MALLOC(newopv, const struct vnodeopv_desc **, 345a163d034SWarner Losh (vnodeopv_num - 1) * sizeof(*newopv), M_VNODE, M_WAITOK); 3464e61198eSPeter Wemm bcopy(vnodeopv_descs, newopv, (vnodeopv_num - 1) * sizeof(*newopv)); 3474e61198eSPeter Wemm FREE(vnodeopv_descs, M_VNODE); 3484e61198eSPeter Wemm vnodeopv_descs = newopv; 3494e61198eSPeter Wemm vnodeopv_num--; 3504e61198eSPeter Wemm 3514e61198eSPeter Wemm vfs_opv_recalc(); 352df8bae1dSRodney W. Grimes } 353df8bae1dSRodney W. Grimes 354df8bae1dSRodney W. Grimes /* 355df8bae1dSRodney W. Grimes * Routines having to do with the management of the vnode table. 356df8bae1dSRodney W. Grimes */ 357df8bae1dSRodney W. Grimes 3583dfe213eSPoul-Henning Kamp struct vfsconf * 3593dfe213eSPoul-Henning Kamp vfs_byname(const char *name) 3603dfe213eSPoul-Henning Kamp { 3613dfe213eSPoul-Henning Kamp struct vfsconf *vfsp; 3623dfe213eSPoul-Henning Kamp 3633dfe213eSPoul-Henning Kamp TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) 3643dfe213eSPoul-Henning Kamp if (!strcmp(name, vfsp->vfc_name)) 3653dfe213eSPoul-Henning Kamp return (vfsp); 3663dfe213eSPoul-Henning Kamp return (NULL); 3673dfe213eSPoul-Henning Kamp } 3683dfe213eSPoul-Henning Kamp 369eb8e6d52SEivind Eklund /* Register a new filesystem type in the global table */ 370aa855a59SPeter Wemm int 3714e61198eSPeter Wemm vfs_register(struct vfsconf *vfc) 372aa855a59SPeter Wemm { 373a199ed3cSDoug Rabson struct sysctl_oid *oidp; 3747652131bSPoul-Henning Kamp struct vfsops *vfsops; 375273350adSPoul-Henning Kamp static int once; 376273350adSPoul-Henning Kamp 377273350adSPoul-Henning Kamp if (!once) { 378273350adSPoul-Henning Kamp vattr_null(&va_null); 379273350adSPoul-Henning Kamp once = 1; 380273350adSPoul-Henning Kamp } 3817652131bSPoul-Henning Kamp 3825e8c582aSPoul-Henning Kamp if (vfc->vfc_version != VFS_VERSION) { 3835e8c582aSPoul-Henning Kamp printf("ERROR: filesystem %s, unsupported ABI version %x\n", 3845e8c582aSPoul-Henning Kamp vfc->vfc_name, vfc->vfc_version); 3855e8c582aSPoul-Henning Kamp return (EINVAL); 3865e8c582aSPoul-Henning Kamp } 3873dfe213eSPoul-Henning Kamp if (vfs_byname(vfc->vfc_name) != NULL) 388aa855a59SPeter Wemm return EEXIST; 389aa855a59SPeter Wemm 390aa855a59SPeter Wemm vfc->vfc_typenum = maxvfsconf++; 3913dfe213eSPoul-Henning Kamp TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list); 392aa855a59SPeter Wemm 393aa855a59SPeter Wemm /* 394a199ed3cSDoug Rabson * If this filesystem has a sysctl node under vfs 395a199ed3cSDoug Rabson * (i.e. vfs.xxfs), then change the oid number of that node to 396a199ed3cSDoug Rabson * match the filesystem's type number. This allows user code 397a199ed3cSDoug Rabson * which uses the type number to read sysctl variables defined 398a199ed3cSDoug Rabson * by the filesystem to continue working. Since the oids are 399a199ed3cSDoug Rabson * in a sorted list, we need to make sure the order is 400a199ed3cSDoug Rabson * preserved by re-registering the oid after modifying its 401a199ed3cSDoug Rabson * number. 402a199ed3cSDoug Rabson */ 40337d40066SPoul-Henning Kamp SLIST_FOREACH(oidp, &sysctl__vfs_children, oid_link) 404a199ed3cSDoug Rabson if (strcmp(oidp->oid_name, vfc->vfc_name) == 0) { 405a199ed3cSDoug Rabson sysctl_unregister_oid(oidp); 406a199ed3cSDoug Rabson oidp->oid_number = vfc->vfc_typenum; 407a199ed3cSDoug Rabson sysctl_register_oid(oidp); 408a199ed3cSDoug Rabson } 409a199ed3cSDoug Rabson 410a199ed3cSDoug Rabson /* 4117652131bSPoul-Henning Kamp * Initialise unused ``struct vfsops'' fields, to use 4127652131bSPoul-Henning Kamp * the vfs_std*() functions. Note, we need the mount 4137652131bSPoul-Henning Kamp * and unmount operations, at the least. The check 4147652131bSPoul-Henning Kamp * for vfsops available is just a debugging aid. 4157652131bSPoul-Henning Kamp */ 4167652131bSPoul-Henning Kamp KASSERT(vfc->vfc_vfsops != NULL, 4177652131bSPoul-Henning Kamp ("Filesystem %s has no vfsops", vfc->vfc_name)); 4187652131bSPoul-Henning Kamp /* 4197652131bSPoul-Henning Kamp * Check the mount and unmount operations. 4207652131bSPoul-Henning Kamp */ 4217652131bSPoul-Henning Kamp vfsops = vfc->vfc_vfsops; 4225e8c582aSPoul-Henning Kamp KASSERT(vfsops->vfs_mount != NULL || vfsops->vfs_omount != NULL, 4235e8c582aSPoul-Henning Kamp ("Filesystem %s has no (o)mount op", vfc->vfc_name)); 4247652131bSPoul-Henning Kamp KASSERT(vfsops->vfs_unmount != NULL, 4257652131bSPoul-Henning Kamp ("Filesystem %s has no unmount op", vfc->vfc_name)); 4267652131bSPoul-Henning Kamp 4277652131bSPoul-Henning Kamp if (vfsops->vfs_start == NULL) 4287652131bSPoul-Henning Kamp /* make a file system operational */ 4297652131bSPoul-Henning Kamp vfsops->vfs_start = vfs_stdstart; 4307652131bSPoul-Henning Kamp if (vfsops->vfs_root == NULL) 4317652131bSPoul-Henning Kamp /* return file system's root vnode */ 4327652131bSPoul-Henning Kamp vfsops->vfs_root = vfs_stdroot; 4337652131bSPoul-Henning Kamp if (vfsops->vfs_quotactl == NULL) 4347652131bSPoul-Henning Kamp /* quota control */ 4357652131bSPoul-Henning Kamp vfsops->vfs_quotactl = vfs_stdquotactl; 4367652131bSPoul-Henning Kamp if (vfsops->vfs_statfs == NULL) 4377652131bSPoul-Henning Kamp /* return file system's status */ 4387652131bSPoul-Henning Kamp vfsops->vfs_statfs = vfs_stdstatfs; 4397652131bSPoul-Henning Kamp if (vfsops->vfs_sync == NULL) 4407652131bSPoul-Henning Kamp /* 4417652131bSPoul-Henning Kamp * flush unwritten data (nosync) 4427652131bSPoul-Henning Kamp * file systems can use vfs_stdsync 4437652131bSPoul-Henning Kamp * explicitly by setting it in the 4447652131bSPoul-Henning Kamp * vfsop vector. 4457652131bSPoul-Henning Kamp */ 4467652131bSPoul-Henning Kamp vfsops->vfs_sync = vfs_stdnosync; 4477652131bSPoul-Henning Kamp if (vfsops->vfs_vget == NULL) 4487652131bSPoul-Henning Kamp /* convert an inode number to a vnode */ 4497652131bSPoul-Henning Kamp vfsops->vfs_vget = vfs_stdvget; 4507652131bSPoul-Henning Kamp if (vfsops->vfs_fhtovp == NULL) 4517652131bSPoul-Henning Kamp /* turn an NFS file handle into a vnode */ 4527652131bSPoul-Henning Kamp vfsops->vfs_fhtovp = vfs_stdfhtovp; 4537652131bSPoul-Henning Kamp if (vfsops->vfs_checkexp == NULL) 4547652131bSPoul-Henning Kamp /* check if file system is exported */ 4557652131bSPoul-Henning Kamp vfsops->vfs_checkexp = vfs_stdcheckexp; 4567652131bSPoul-Henning Kamp if (vfsops->vfs_vptofh == NULL) 4577652131bSPoul-Henning Kamp /* turn a vnode into an NFS file handle */ 4587652131bSPoul-Henning Kamp vfsops->vfs_vptofh = vfs_stdvptofh; 4597652131bSPoul-Henning Kamp if (vfsops->vfs_init == NULL) 4607652131bSPoul-Henning Kamp /* file system specific initialisation */ 4617652131bSPoul-Henning Kamp vfsops->vfs_init = vfs_stdinit; 4627652131bSPoul-Henning Kamp if (vfsops->vfs_uninit == NULL) 4637652131bSPoul-Henning Kamp /* file system specific uninitialisation */ 4647652131bSPoul-Henning Kamp vfsops->vfs_uninit = vfs_stduninit; 4657652131bSPoul-Henning Kamp if (vfsops->vfs_extattrctl == NULL) 4667652131bSPoul-Henning Kamp /* extended attribute control */ 4677652131bSPoul-Henning Kamp vfsops->vfs_extattrctl = vfs_stdextattrctl; 46881d16e2dSAlfred Perlstein if (vfsops->vfs_sysctl == NULL) 46981d16e2dSAlfred Perlstein vfsops->vfs_sysctl = vfs_stdsysctl; 4707652131bSPoul-Henning Kamp 4717652131bSPoul-Henning Kamp /* 472aa855a59SPeter Wemm * Call init function for this VFS... 473aa855a59SPeter Wemm */ 474aa855a59SPeter Wemm (*(vfc->vfc_vfsops->vfs_init))(vfc); 475aa855a59SPeter Wemm 476aa855a59SPeter Wemm return 0; 477aa855a59SPeter Wemm } 478aa855a59SPeter Wemm 479aa855a59SPeter Wemm 480eb8e6d52SEivind Eklund /* Remove registration of a filesystem type */ 481aa855a59SPeter Wemm int 4824e61198eSPeter Wemm vfs_unregister(struct vfsconf *vfc) 483aa855a59SPeter Wemm { 4843dfe213eSPoul-Henning Kamp struct vfsconf *vfsp; 485aa855a59SPeter Wemm int error, i, maxtypenum; 486aa855a59SPeter Wemm 487aa855a59SPeter Wemm i = vfc->vfc_typenum; 488aa855a59SPeter Wemm 4893dfe213eSPoul-Henning Kamp vfsp = vfs_byname(vfc->vfc_name); 490aa855a59SPeter Wemm if (vfsp == NULL) 491aa855a59SPeter Wemm return EINVAL; 492aa855a59SPeter Wemm if (vfsp->vfc_refcount) 493aa855a59SPeter Wemm return EBUSY; 494aa855a59SPeter Wemm if (vfc->vfc_vfsops->vfs_uninit != NULL) { 495aa855a59SPeter Wemm error = (*vfc->vfc_vfsops->vfs_uninit)(vfsp); 496aa855a59SPeter Wemm if (error) 497aa855a59SPeter Wemm return (error); 498aa855a59SPeter Wemm } 4993dfe213eSPoul-Henning Kamp TAILQ_REMOVE(&vfsconf, vfsp, vfc_list); 500aa855a59SPeter Wemm maxtypenum = VFS_GENERIC; 5013dfe213eSPoul-Henning Kamp TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) 502aa855a59SPeter Wemm if (maxtypenum < vfsp->vfc_typenum) 503aa855a59SPeter Wemm maxtypenum = vfsp->vfc_typenum; 504aa855a59SPeter Wemm maxvfsconf = maxtypenum + 1; 505aa855a59SPeter Wemm return 0; 506aa855a59SPeter Wemm } 5074e61198eSPeter Wemm 508eb8e6d52SEivind Eklund /* 509eb8e6d52SEivind Eklund * Standard kernel module handling code for filesystem modules. 510eb8e6d52SEivind Eklund * Referenced from VFS_SET(). 511eb8e6d52SEivind Eklund */ 5124e61198eSPeter Wemm int 5134ae860afSBruce Evans vfs_modevent(module_t mod, int type, void *data) 5144e61198eSPeter Wemm { 5154e61198eSPeter Wemm struct vfsconf *vfc; 5164e61198eSPeter Wemm int error = 0; 5174e61198eSPeter Wemm 5184e61198eSPeter Wemm vfc = (struct vfsconf *)data; 5194e61198eSPeter Wemm 5204e61198eSPeter Wemm switch (type) { 5214e61198eSPeter Wemm case MOD_LOAD: 5224e61198eSPeter Wemm if (vfc) 5234e61198eSPeter Wemm error = vfs_register(vfc); 5244e61198eSPeter Wemm break; 5254e61198eSPeter Wemm 5264e61198eSPeter Wemm case MOD_UNLOAD: 5274e61198eSPeter Wemm if (vfc) 5284e61198eSPeter Wemm error = vfs_unregister(vfc); 5294e61198eSPeter Wemm break; 5303e019deaSPoul-Henning Kamp default: 5313e019deaSPoul-Henning Kamp error = EOPNOTSUPP; 5324e61198eSPeter Wemm break; 5334e61198eSPeter Wemm } 5344e61198eSPeter Wemm return (error); 5354e61198eSPeter Wemm } 536