137488Smckusick /* 237488Smckusick * Copyright (c) 1989 The Regents of the University of California. 337488Smckusick * All rights reserved. 437488Smckusick * 537488Smckusick * Redistribution and use in source and binary forms are permitted 637488Smckusick * provided that the above copyright notice and this paragraph are 737488Smckusick * duplicated in all such forms and that any documentation, 837488Smckusick * advertising materials, and other materials related to such 937488Smckusick * distribution and use acknowledge that the software was developed 1037488Smckusick * by the University of California, Berkeley. The name of the 1137488Smckusick * University may not be used to endorse or promote products derived 1237488Smckusick * from this software without specific prior written permission. 1337488Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437488Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537488Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637488Smckusick * 17*39397Smckusick * @(#)vfs_subr.c 7.8 (Berkeley) 10/24/89 1837488Smckusick */ 1937488Smckusick 2037488Smckusick /* 2137488Smckusick * External virtual filesystem routines 2237488Smckusick */ 2337488Smckusick 2437488Smckusick #include "param.h" 2537488Smckusick #include "mount.h" 2637488Smckusick #include "time.h" 2737488Smckusick #include "vnode.h" 2838265Smckusick #include "namei.h" 2938265Smckusick #include "ucred.h" 3037488Smckusick #include "errno.h" 3137488Smckusick 3237488Smckusick /* 3337488Smckusick * Remove a mount point from the list of mounted filesystems. 3437488Smckusick * Unmount of the root is illegal. 3537488Smckusick */ 3637488Smckusick void 3737488Smckusick vfs_remove(mp) 3837488Smckusick register struct mount *mp; 3937488Smckusick { 4037488Smckusick 4137488Smckusick if (mp == rootfs) 4237488Smckusick panic("vfs_remove: unmounting root"); 4337488Smckusick mp->m_prev->m_next = mp->m_next; 4437488Smckusick mp->m_next->m_prev = mp->m_prev; 4537488Smckusick mp->m_vnodecovered->v_mountedhere = (struct mount *)0; 4637488Smckusick vfs_unlock(mp); 4737488Smckusick } 4837488Smckusick 4937488Smckusick /* 5037488Smckusick * Lock a filesystem. 5137488Smckusick * Used to prevent access to it while mounting and unmounting. 5237488Smckusick */ 5337488Smckusick vfs_lock(mp) 5437488Smckusick register struct mount *mp; 5537488Smckusick { 5637488Smckusick 5739045Smckusick while(mp->m_flag & M_MLOCK) { 5839045Smckusick mp->m_flag |= M_MWAIT; 5939045Smckusick sleep((caddr_t)mp, PVFS); 6039045Smckusick } 6137488Smckusick mp->m_flag |= M_MLOCK; 6237488Smckusick return (0); 6337488Smckusick } 6437488Smckusick 6537488Smckusick /* 6637488Smckusick * Unlock a locked filesystem. 6737488Smckusick * Panic if filesystem is not locked. 6837488Smckusick */ 6937488Smckusick void 7037488Smckusick vfs_unlock(mp) 7137488Smckusick register struct mount *mp; 7237488Smckusick { 7337488Smckusick 7437488Smckusick if ((mp->m_flag & M_MLOCK) == 0) 7537488Smckusick panic("vfs_unlock: locked fs"); 7637488Smckusick mp->m_flag &= ~M_MLOCK; 7737488Smckusick if (mp->m_flag & M_MWAIT) { 7837488Smckusick mp->m_flag &= ~M_MWAIT; 7937488Smckusick wakeup((caddr_t)mp); 8037488Smckusick } 8137488Smckusick } 8237488Smckusick 8337488Smckusick /* 8437488Smckusick * Lookup a mount point by filesystem identifier. 8537488Smckusick */ 8637488Smckusick struct mount * 8737488Smckusick getvfs(fsid) 8837488Smckusick fsid_t *fsid; 8937488Smckusick { 9037488Smckusick register struct mount *mp; 9137488Smckusick 9238288Smckusick mp = rootfs; 9338288Smckusick do { 9437488Smckusick if (mp->m_fsid.val[0] == fsid->val[0] && 9537488Smckusick mp->m_fsid.val[1] == fsid->val[1]) { 9638288Smckusick return (mp); 9737488Smckusick } 9838288Smckusick mp = mp->m_next; 9938288Smckusick } while (mp != rootfs); 10038288Smckusick return ((struct mount *)0); 10137488Smckusick } 10237488Smckusick 10337488Smckusick /* 10437488Smckusick * Set vnode attributes to VNOVAL 10537488Smckusick */ 10637488Smckusick void vattr_null(vap) 10737488Smckusick register struct vattr *vap; 10837488Smckusick { 10937488Smckusick 11037488Smckusick vap->va_type = VNON; 11137488Smckusick vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid = 11237488Smckusick vap->va_fsid = vap->va_fileid = vap->va_size = 11337488Smckusick vap->va_size1 = vap->va_blocksize = vap->va_rdev = 11437488Smckusick vap->va_bytes = vap->va_bytes1 = 11537488Smckusick vap->va_atime.tv_sec = vap->va_atime.tv_usec = 11637488Smckusick vap->va_mtime.tv_sec = vap->va_mtime.tv_usec = 11738258Smckusick vap->va_ctime.tv_sec = vap->va_ctime.tv_usec = 11838258Smckusick vap->va_flags = vap->va_gen = VNOVAL; 11937488Smckusick } 12038265Smckusick 12138265Smckusick /* 12238265Smckusick * Initialize a nameidata structure 12338265Smckusick */ 12438265Smckusick ndinit(ndp) 12538265Smckusick register struct nameidata *ndp; 12638265Smckusick { 12738265Smckusick 12838265Smckusick bzero((caddr_t)ndp, sizeof(struct nameidata)); 12938265Smckusick ndp->ni_iov = &ndp->ni_nd.nd_iovec; 13038265Smckusick ndp->ni_iovcnt = 1; 13138265Smckusick ndp->ni_base = (caddr_t)&ndp->ni_dent; 13238265Smckusick ndp->ni_rw = UIO_WRITE; 13338265Smckusick ndp->ni_segflg = UIO_SYSSPACE; 13438265Smckusick } 13538265Smckusick 13638265Smckusick /* 13738265Smckusick * Duplicate a nameidata structure 13838265Smckusick */ 13938265Smckusick nddup(ndp, newndp) 14038265Smckusick register struct nameidata *ndp, *newndp; 14138265Smckusick { 14238265Smckusick 14338265Smckusick ndinit(newndp); 14438265Smckusick newndp->ni_cdir = ndp->ni_cdir; 14538348Smckusick VREF(newndp->ni_cdir); 14638265Smckusick newndp->ni_rdir = ndp->ni_rdir; 14738265Smckusick if (newndp->ni_rdir) 14838348Smckusick VREF(newndp->ni_rdir); 14938265Smckusick newndp->ni_cred = ndp->ni_cred; 15038265Smckusick crhold(newndp->ni_cred); 15138265Smckusick } 15238265Smckusick 15338265Smckusick /* 15438265Smckusick * Release a nameidata structure 15538265Smckusick */ 15638265Smckusick ndrele(ndp) 15738265Smckusick register struct nameidata *ndp; 15838265Smckusick { 15938265Smckusick 16038265Smckusick vrele(ndp->ni_cdir); 16138265Smckusick if (ndp->ni_rdir) 16238265Smckusick vrele(ndp->ni_rdir); 16338265Smckusick crfree(ndp->ni_cred); 16438265Smckusick } 165*39397Smckusick 166*39397Smckusick /* 167*39397Smckusick * Routines having to do with the management of the vnode table. 168*39397Smckusick */ 169*39397Smckusick struct vnode *vfreeh, **vfreet; 170*39397Smckusick extern struct vnodeops dead_vnodeops; 171*39397Smckusick 172*39397Smckusick /* 173*39397Smckusick * Build vnode free list. 174*39397Smckusick */ 175*39397Smckusick vhinit() 176*39397Smckusick { 177*39397Smckusick register struct vnode *vp = vnode; 178*39397Smckusick 179*39397Smckusick vfreeh = vp; 180*39397Smckusick vfreet = &vp->v_freef; 181*39397Smckusick vp->v_freeb = &vfreeh; 182*39397Smckusick vp->v_op = &dead_vnodeops; 183*39397Smckusick for (vp++; vp < vnodeNVNODE; vp++) { 184*39397Smckusick *vfreet = vp; 185*39397Smckusick vp->v_freeb = vfreet; 186*39397Smckusick vfreet = &vp->v_freef; 187*39397Smckusick vp->v_op = &dead_vnodeops; 188*39397Smckusick } 189*39397Smckusick vp--; 190*39397Smckusick vp->v_freef = NULL; 191*39397Smckusick } 192*39397Smckusick 193*39397Smckusick /* 194*39397Smckusick * Return the next vnode from the free list. 195*39397Smckusick */ 196*39397Smckusick getnewvnode(tag, mp, vops, vpp) 197*39397Smckusick enum vtagtype tag; 198*39397Smckusick struct mount *mp; 199*39397Smckusick struct vnodeops *vops; 200*39397Smckusick struct vnode **vpp; 201*39397Smckusick { 202*39397Smckusick register struct vnode *vp, *vq; 203*39397Smckusick 204*39397Smckusick if ((vp = vfreeh) == NULL) { 205*39397Smckusick tablefull("vnode"); 206*39397Smckusick *vpp = 0; 207*39397Smckusick return (ENFILE); 208*39397Smckusick } 209*39397Smckusick if (vp->v_count || VOP_RECLAIM(vp)) 210*39397Smckusick panic("free vnode isn't"); 211*39397Smckusick if (vq = vp->v_freef) 212*39397Smckusick vq->v_freeb = &vfreeh; 213*39397Smckusick vfreeh = vq; 214*39397Smckusick vp->v_freef = NULL; 215*39397Smckusick vp->v_freeb = NULL; 216*39397Smckusick vp->v_type = VNON; 217*39397Smckusick vp->v_flag = 0; 218*39397Smckusick vp->v_shlockc = 0; 219*39397Smckusick vp->v_exlockc = 0; 220*39397Smckusick vp->v_socket = 0; 221*39397Smckusick vp->v_op = vops; 222*39397Smckusick cache_purge(vp); 223*39397Smckusick vp->v_tag = tag; 224*39397Smckusick vp->v_mount = mp; 225*39397Smckusick insmntque(vp, mp); 226*39397Smckusick VREF(vp); 227*39397Smckusick *vpp = vp; 228*39397Smckusick return (0); 229*39397Smckusick } 230*39397Smckusick 231*39397Smckusick /* 232*39397Smckusick * Move a vnode from one mount queue to another. 233*39397Smckusick */ 234*39397Smckusick insmntque(vp, mp) 235*39397Smckusick register struct vnode *vp; 236*39397Smckusick register struct mount *mp; 237*39397Smckusick { 238*39397Smckusick struct vnode *vq; 239*39397Smckusick 240*39397Smckusick /* 241*39397Smckusick * Delete from old mount point vnode list, if on one. 242*39397Smckusick */ 243*39397Smckusick if (vp->v_mountb) { 244*39397Smckusick if (vq = vp->v_mountf) 245*39397Smckusick vq->v_mountb = vp->v_mountb; 246*39397Smckusick *vp->v_mountb = vq; 247*39397Smckusick } 248*39397Smckusick /* 249*39397Smckusick * Insert into list of vnodes for the new mount point, if available. 250*39397Smckusick */ 251*39397Smckusick if (mp == NULL) { 252*39397Smckusick vp->v_mountf = NULL; 253*39397Smckusick vp->v_mountb = NULL; 254*39397Smckusick return; 255*39397Smckusick } 256*39397Smckusick if (mp->m_mounth) { 257*39397Smckusick vp->v_mountf = mp->m_mounth; 258*39397Smckusick vp->v_mountb = &mp->m_mounth; 259*39397Smckusick mp->m_mounth->v_mountb = &vp->v_mountf; 260*39397Smckusick mp->m_mounth = vp; 261*39397Smckusick } else { 262*39397Smckusick mp->m_mounth = vp; 263*39397Smckusick vp->v_mountb = &mp->m_mounth; 264*39397Smckusick vp->v_mountf = NULL; 265*39397Smckusick } 266*39397Smckusick } 267*39397Smckusick 268*39397Smckusick /* 269*39397Smckusick * Grab a particular vnode from the free list. 270*39397Smckusick */ 271*39397Smckusick vget(vp) 272*39397Smckusick register struct vnode *vp; 273*39397Smckusick { 274*39397Smckusick register struct vnode *vq; 275*39397Smckusick 276*39397Smckusick if (vq = vp->v_freef) 277*39397Smckusick vq->v_freeb = vp->v_freeb; 278*39397Smckusick else 279*39397Smckusick vfreet = vp->v_freeb; 280*39397Smckusick *vp->v_freeb = vq; 281*39397Smckusick vp->v_freef = NULL; 282*39397Smckusick vp->v_freeb = NULL; 283*39397Smckusick VREF(vp); 284*39397Smckusick } 285*39397Smckusick 286*39397Smckusick /* 287*39397Smckusick * Vnode reference, just increment the count 288*39397Smckusick */ 289*39397Smckusick void vref(vp) 290*39397Smckusick struct vnode *vp; 291*39397Smckusick { 292*39397Smckusick 293*39397Smckusick vp->v_count++; 294*39397Smckusick } 295*39397Smckusick 296*39397Smckusick /* 297*39397Smckusick * vput(), just unlock and vrele() 298*39397Smckusick */ 299*39397Smckusick void vput(vp) 300*39397Smckusick register struct vnode *vp; 301*39397Smckusick { 302*39397Smckusick VOP_UNLOCK(vp); 303*39397Smckusick vrele(vp); 304*39397Smckusick } 305*39397Smckusick 306*39397Smckusick /* 307*39397Smckusick * Vnode release. 308*39397Smckusick * If count drops to zero, call inactive routine and return to freelist. 309*39397Smckusick */ 310*39397Smckusick void vrele(vp) 311*39397Smckusick register struct vnode *vp; 312*39397Smckusick { 313*39397Smckusick 314*39397Smckusick if (vp == NULL) 315*39397Smckusick return; 316*39397Smckusick vp->v_count--; 317*39397Smckusick if (vp->v_count < 0) 318*39397Smckusick printf("vnode bad ref count %d, type %d, tag %d\n", 319*39397Smckusick vp->v_count, vp->v_type, vp->v_tag); 320*39397Smckusick if (vp->v_count > 0) 321*39397Smckusick return; 322*39397Smckusick VOP_INACTIVE(vp); 323*39397Smckusick if (vfreeh == (struct vnode *)0) { 324*39397Smckusick /* 325*39397Smckusick * insert into empty list 326*39397Smckusick */ 327*39397Smckusick vfreeh = vp; 328*39397Smckusick vp->v_freeb = &vfreeh; 329*39397Smckusick vp->v_freef = NULL; 330*39397Smckusick vfreet = &vp->v_freef; 331*39397Smckusick } else if (vp->v_type == VNON) { 332*39397Smckusick /* 333*39397Smckusick * insert at head of list 334*39397Smckusick */ 335*39397Smckusick vp->v_freef = vfreeh; 336*39397Smckusick vp->v_freeb = &vfreeh; 337*39397Smckusick vfreeh->v_freeb = &vp->v_freef; 338*39397Smckusick vfreeh = vp; 339*39397Smckusick } else { 340*39397Smckusick /* 341*39397Smckusick * insert at tail of list 342*39397Smckusick */ 343*39397Smckusick *vfreet = vp; 344*39397Smckusick vp->v_freeb = vfreet; 345*39397Smckusick vp->v_freef = NULL; 346*39397Smckusick vfreet = &vp->v_freef; 347*39397Smckusick } 348*39397Smckusick } 349