1*54289Smckusick /* 2*54289Smckusick * Copyright (c) 1989 The Regents of the University of California. 3*54289Smckusick * All rights reserved. 4*54289Smckusick * 5*54289Smckusick * This code is derived from software contributed 6*54289Smckusick * to Berkeley by John Heidemann of the UCLA Ficus project. 7*54289Smckusick * 8*54289Smckusick * Source: * @(#)i405_init.c 2.10 92/04/27 UCLA Ficus project 9*54289Smckusick * 10*54289Smckusick * %sccs.include.redist.c% 11*54289Smckusick * 12*54289Smckusick * @(#)vfs_init.c 7.1 (Berkeley) 06/23/92 13*54289Smckusick */ 14*54289Smckusick 15*54289Smckusick 16*54289Smckusick #include <sys/param.h> 17*54289Smckusick #include <sys/mount.h> 18*54289Smckusick #include <sys/time.h> 19*54289Smckusick #include <sys/vnode.h> 20*54289Smckusick #include <sys/stat.h> 21*54289Smckusick #include <sys/specdev.h> 22*54289Smckusick #include <sys/namei.h> 23*54289Smckusick #include <sys/ucred.h> 24*54289Smckusick #include <sys/buf.h> 25*54289Smckusick #include <sys/errno.h> 26*54289Smckusick #include <sys/malloc.h> 27*54289Smckusick 28*54289Smckusick 29*54289Smckusick /* Sigh, such primitive tools are these... */ 30*54289Smckusick #if 0 31*54289Smckusick #define DODEBUG(A) A 32*54289Smckusick #else 33*54289Smckusick #define DODEBUG(A) 34*54289Smckusick #endif 35*54289Smckusick 36*54289Smckusick 37*54289Smckusick 38*54289Smckusick extern struct vnodeopv_desc *vfs_opv_descs[]; 39*54289Smckusick /* a list of lists of vnodeops defns */ 40*54289Smckusick extern struct vnodeop_desc *vfs_op_descs[]; 41*54289Smckusick /* and the operations they perform */ 42*54289Smckusick /* 43*54289Smckusick * This code doesn't work if the defn is **vnodop_defns with cc. 44*54289Smckusick * The problem is because of the compiler sometimes putting in an 45*54289Smckusick * extra level of indirection for arrays. It's an interesting 46*54289Smckusick * "feature" of C. 47*54289Smckusick */ 48*54289Smckusick int vfs_opv_numops; 49*54289Smckusick 50*54289Smckusick typedef (*PFI)(); /* the standard Pointer to a Function returning an Int */ 51*54289Smckusick 52*54289Smckusick 53*54289Smckusick 54*54289Smckusick /* 55*54289Smckusick * A miscellaneous routine. 56*54289Smckusick * A generic "default" routine that just returns an error. 57*54289Smckusick */ 58*54289Smckusick int 59*54289Smckusick vn_default_error() 60*54289Smckusick { 61*54289Smckusick return EOPNOTSUPP; 62*54289Smckusick } 63*54289Smckusick 64*54289Smckusick 65*54289Smckusick 66*54289Smckusick 67*54289Smckusick /* 68*54289Smckusick * vfs_init.c 69*54289Smckusick * 70*54289Smckusick * Allocate and fill in operations vectors. 71*54289Smckusick * 72*54289Smckusick * An undocumented feature of this approach to defining 73*54289Smckusick * operations is that there can be multiple entries in 74*54289Smckusick * vfs_opv_descs for the same operations vector. 75*54289Smckusick * This allows third parties to extend the set of operations 76*54289Smckusick * supported by another layer in a binary compatibile way. 77*54289Smckusick * For example, assume that NFS needed to be modified to support 78*54289Smckusick * Ficus. NFS has an entry (probably nfs_vnopdeop_decls) 79*54289Smckusick * declaring all the operations NFS supports by default. 80*54289Smckusick * Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions) 81*54289Smckusick * listing those new operations Ficus adds to NFS, all without 82*54289Smckusick * modifying the NFS code. (Of couse, the OTW NFS protocol 83*54289Smckusick * still needs to be munged, but that's a(whole)nother story.) 84*54289Smckusick * This is a feature. 85*54289Smckusick */ 86*54289Smckusick 87*54289Smckusick void 88*54289Smckusick vfs_opv_init() 89*54289Smckusick { 90*54289Smckusick int i, j, k; 91*54289Smckusick struct vnodeop_defn *defnp; 92*54289Smckusick int (***opv_desc_vector_p)(); 93*54289Smckusick int (**opv_desc_vector)(); 94*54289Smckusick struct vnodeopv_entry_desc *opve_descp; 95*54289Smckusick 96*54289Smckusick /* 97*54289Smckusick * Allocate the dynamic vectors and fill them in. 98*54289Smckusick */ 99*54289Smckusick for (i=0; vfs_opv_descs[i]; i++) { 100*54289Smckusick opv_desc_vector_p = vfs_opv_descs[i]->opv_desc_vector_p; 101*54289Smckusick /* 102*54289Smckusick * Allocate and init the vector, if it needs it. 103*54289Smckusick * Also handle backwards compatibility. 104*54289Smckusick */ 105*54289Smckusick if (*opv_desc_vector_p == NULL) { 106*54289Smckusick /* XXX - shouldn't be M_VNODE */ 107*54289Smckusick MALLOC(*opv_desc_vector_p, PFI*, 108*54289Smckusick vfs_opv_numops*sizeof(PFI), M_VNODE, M_WAITOK); 109*54289Smckusick bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFI)); 110*54289Smckusick DODEBUG(printf("vector at %x allocated\n", opv_desc_vector_p)); 111*54289Smckusick }; 112*54289Smckusick opv_desc_vector = *opv_desc_vector_p; 113*54289Smckusick for (j=0; vfs_opv_descs[i]->opv_desc_ops[j].opve_op; j++) { 114*54289Smckusick opve_descp = &(vfs_opv_descs[i]->opv_desc_ops[j]); 115*54289Smckusick 116*54289Smckusick /* 117*54289Smckusick * Sanity check: is this operation listed 118*54289Smckusick * in the list of operations? We check this 119*54289Smckusick * by seeing if its offest is zero. Since 120*54289Smckusick * the default routine should always be listed 121*54289Smckusick * first, it should be the only one with a zero 122*54289Smckusick * offset. Any other operation with a zero 123*54289Smckusick * offset is probably not listed in 124*54289Smckusick * vfs_op_descs, 125*54289Smckusick * and so is probably an error. 126*54289Smckusick * 127*54289Smckusick * A panic here means the layer programmer 128*54289Smckusick * has committed the all-too common bug 129*54289Smckusick * of adding a new operation to the layer's 130*54289Smckusick * list of vnode operations but 131*54289Smckusick * not adding the operation to the system-wide 132*54289Smckusick * list of supported operations. 133*54289Smckusick */ 134*54289Smckusick if (opve_descp->opve_op->vdesc_offset == 0 && 135*54289Smckusick opve_descp->opve_op->vdesc_offset != 136*54289Smckusick VOFFSET(vop_default)) { 137*54289Smckusick printf ("error: operation %s not listed in vfs_op_descs.\n", opve_descp->opve_op->vdesc_name); 138*54289Smckusick panic ("vfs_opv_init: bad operation"); 139*54289Smckusick }; 140*54289Smckusick /* 141*54289Smckusick * Fill in this entry. 142*54289Smckusick */ 143*54289Smckusick opv_desc_vector[opve_descp->opve_op->vdesc_offset]= 144*54289Smckusick opve_descp->opve_impl; 145*54289Smckusick }; 146*54289Smckusick }; 147*54289Smckusick 148*54289Smckusick /* 149*54289Smckusick * Finally, go back and replace unfilled routines 150*54289Smckusick * with their default. (Sigh, an O(n^3) algorithm. I 151*54289Smckusick * could make it better, but that'd be work, and n is small.) 152*54289Smckusick */ 153*54289Smckusick for (i=0; vfs_opv_descs[i]; i++) { 154*54289Smckusick opv_desc_vector = *(vfs_opv_descs[i]->opv_desc_vector_p); 155*54289Smckusick /* 156*54289Smckusick * Force every operations vector to have a default routine. 157*54289Smckusick */ 158*54289Smckusick if (opv_desc_vector[VOFFSET(vop_default)]==NULL) { 159*54289Smckusick panic("vfs_opv_init: operation vector without default routine."); 160*54289Smckusick }; 161*54289Smckusick for (k=0; k<vfs_opv_numops; k++) 162*54289Smckusick if (opv_desc_vector[k] == NULL) 163*54289Smckusick opv_desc_vector[k] = 164*54289Smckusick opv_desc_vector[VOFFSET(vop_default)]; 165*54289Smckusick }; 166*54289Smckusick } 167*54289Smckusick 168*54289Smckusick 169*54289Smckusick 170*54289Smckusick 171*54289Smckusick void 172*54289Smckusick vfs_op_init() 173*54289Smckusick { 174*54289Smckusick int i, j; 175*54289Smckusick 176*54289Smckusick DODEBUG(printf ("Vnode_interface_init.\n")); 177*54289Smckusick 178*54289Smckusick /* 179*54289Smckusick * Set all vnode vectors to a well known value. 180*54289Smckusick */ 181*54289Smckusick for (i=0; vfs_opv_descs[i]; i++) 182*54289Smckusick *(vfs_opv_descs[i]->opv_desc_vector_p) = NULL; 183*54289Smckusick 184*54289Smckusick vfs_opv_numops = 0; 185*54289Smckusick 186*54289Smckusick /* 187*54289Smckusick * Figure out how many ops there are by counting the table, 188*54289Smckusick * and assign each its offset. 189*54289Smckusick */ 190*54289Smckusick for (i=0; vfs_op_descs[i]; i++) { 191*54289Smckusick vfs_op_descs[i]->vdesc_offset = vfs_opv_numops; 192*54289Smckusick vfs_opv_numops++; 193*54289Smckusick }; 194*54289Smckusick 195*54289Smckusick DODEBUG(printf ("vfs_opv_numops=%d\n", vfs_opv_numops)); 196*54289Smckusick } 197*54289Smckusick 198*54289Smckusick 199*54289Smckusick 200*54289Smckusick 201*54289Smckusick 202*54289Smckusick 203*54289Smckusick 204*54289Smckusick /* 205*54289Smckusick * Routines having to do with the management of the vnode table. 206*54289Smckusick */ 207*54289Smckusick struct vnode *vfreeh, **vfreet; 208*54289Smckusick extern struct vnodeops dead_vnodeops; 209*54289Smckusick extern struct vnodeops spec_vnodeops; 210*54289Smckusick extern void vclean(); 211*54289Smckusick struct vattr va_null; 212*54289Smckusick 213*54289Smckusick /* 214*54289Smckusick * Initialize the vnode structures and initialize each file system type. 215*54289Smckusick */ 216*54289Smckusick vfsinit() 217*54289Smckusick { 218*54289Smckusick struct vfsops **vfsp; 219*54289Smckusick 220*54289Smckusick /* 221*54289Smckusick * Initialize the vnode name cache 222*54289Smckusick */ 223*54289Smckusick nchinit(); 224*54289Smckusick /* 225*54289Smckusick * Build vnode operation vectors. 226*54289Smckusick */ 227*54289Smckusick vfs_op_init(); 228*54289Smckusick vfs_opv_init(); /* finish the job */ 229*54289Smckusick /* 230*54289Smckusick * Initialize each file system type. 231*54289Smckusick */ 232*54289Smckusick vattr_null(&va_null); 233*54289Smckusick for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) { 234*54289Smckusick if (*vfsp == NULL) 235*54289Smckusick continue; 236*54289Smckusick (*(*vfsp)->vfs_init)(); 237*54289Smckusick } 238*54289Smckusick } 239