Annotation of 43BSDReno/sys/kern/vfs_subr.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1989 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution is only permitted until one year after the first shipment
                      6:  * of 4.4BSD by the Regents.  Otherwise, redistribution and use in source and
                      7:  * binary forms are permitted provided that: (1) source distributions retain
                      8:  * this entire copyright notice and comment, and (2) distributions including
                      9:  * binaries display the following acknowledgement:  This product includes
                     10:  * software developed by the University of California, Berkeley and its
                     11:  * contributors'' in the documentation or other materials provided with the
                     12:  * distribution and in all advertising materials mentioning features or use
                     13:  * of this software.  Neither the name of the University nor the names of
                     14:  * its contributors may be used to endorse or promote products derived from
                     15:  * this software without specific prior written permission.
                     16:  * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     17:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     18:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     19:  *
                     20:  *     @(#)vfs_subr.c  7.47 (Berkeley) 6/28/90
                     21:  */
                     22: 
                     23: /*
                     24:  * External virtual filesystem routines
                     25:  */
                     26: 
                     27: #include "param.h"
                     28: #include "mount.h"
                     29: #include "time.h"
                     30: #include "vnode.h"
                     31: #include "specdev.h"
                     32: #include "namei.h"
                     33: #include "ucred.h"
                     34: #include "errno.h"
                     35: #include "malloc.h"
                     36: 
                     37: /*
                     38:  * Remove a mount point from the list of mounted filesystems.
                     39:  * Unmount of the root is illegal.
                     40:  */
                     41: void
                     42: vfs_remove(mp)
                     43:        register struct mount *mp;
                     44: {
                     45: 
                     46:        if (mp == rootfs)
                     47:                panic("vfs_remove: unmounting root");
                     48:        mp->mnt_prev->mnt_next = mp->mnt_next;
                     49:        mp->mnt_next->mnt_prev = mp->mnt_prev;
                     50:        mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
                     51:        vfs_unlock(mp);
                     52: }
                     53: 
                     54: /*
                     55:  * Lock a filesystem.
                     56:  * Used to prevent access to it while mounting and unmounting.
                     57:  */
                     58: vfs_lock(mp)
                     59:        register struct mount *mp;
                     60: {
                     61: 
                     62:        while(mp->mnt_flag & MNT_MLOCK) {
                     63:                mp->mnt_flag |= MNT_MWAIT;
                     64:                sleep((caddr_t)mp, PVFS);
                     65:        }
                     66:        mp->mnt_flag |= MNT_MLOCK;
                     67:        return (0);
                     68: }
                     69: 
                     70: /*
                     71:  * Unlock a locked filesystem.
                     72:  * Panic if filesystem is not locked.
                     73:  */
                     74: void
                     75: vfs_unlock(mp)
                     76:        register struct mount *mp;
                     77: {
                     78: 
                     79:        if ((mp->mnt_flag & MNT_MLOCK) == 0)
                     80:                panic("vfs_unlock: not locked");
                     81:        mp->mnt_flag &= ~MNT_MLOCK;
                     82:        if (mp->mnt_flag & MNT_MWAIT) {
                     83:                mp->mnt_flag &= ~MNT_MWAIT;
                     84:                wakeup((caddr_t)mp);
                     85:        }
                     86: }
                     87: 
                     88: /*
                     89:  * Mark a mount point as busy.
                     90:  * Used to synchronize access and to delay unmounting.
                     91:  */
                     92: vfs_busy(mp)
                     93:        register struct mount *mp;
                     94: {
                     95: 
                     96:        while(mp->mnt_flag & MNT_MPBUSY) {
                     97:                mp->mnt_flag |= MNT_MPWANT;
                     98:                sleep((caddr_t)&mp->mnt_flag, PVFS);
                     99:        }
                    100:        if (mp->mnt_flag & MNT_UNMOUNT)
                    101:                return (1);
                    102:        mp->mnt_flag |= MNT_MPBUSY;
                    103:        return (0);
                    104: }
                    105: 
                    106: /*
                    107:  * Free a busy filesystem.
                    108:  * Panic if filesystem is not busy.
                    109:  */
                    110: void
                    111: vfs_unbusy(mp)
                    112:        register struct mount *mp;
                    113: {
                    114: 
                    115:        if ((mp->mnt_flag & MNT_MPBUSY) == 0)
                    116:                panic("vfs_unbusy: not busy");
                    117:        mp->mnt_flag &= ~MNT_MPBUSY;
                    118:        if (mp->mnt_flag & MNT_MPWANT) {
                    119:                mp->mnt_flag &= ~MNT_MPWANT;
                    120:                wakeup((caddr_t)&mp->mnt_flag);
                    121:        }
                    122: }
                    123: 
                    124: /*
                    125:  * Lookup a mount point by filesystem identifier.
                    126:  */
                    127: struct mount *
                    128: getvfs(fsid)
                    129:        fsid_t *fsid;
                    130: {
                    131:        register struct mount *mp;
                    132: 
                    133:        mp = rootfs;
                    134:        do {
                    135:                if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] &&
                    136:                    mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) {
                    137:                        return (mp);
                    138:                }
                    139:                mp = mp->mnt_next;
                    140:        } while (mp != rootfs);
                    141:        return ((struct mount *)0);
                    142: }
                    143: 
                    144: /*
                    145:  * Set vnode attributes to VNOVAL
                    146:  */
                    147: void vattr_null(vap)
                    148:        register struct vattr *vap;
                    149: {
                    150: 
                    151:        vap->va_type = VNON;
                    152:        vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
                    153:                vap->va_fsid = vap->va_fileid = vap->va_size =
                    154:                vap->va_size_rsv = vap->va_blocksize = vap->va_rdev =
                    155:                vap->va_bytes = vap->va_bytes_rsv =
                    156:                vap->va_atime.tv_sec = vap->va_atime.tv_usec =
                    157:                vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
                    158:                vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
                    159:                vap->va_flags = vap->va_gen = VNOVAL;
                    160: }
                    161: 
                    162: /*
                    163:  * Initialize a nameidata structure
                    164:  */
                    165: ndinit(ndp)
                    166:        register struct nameidata *ndp;
                    167: {
                    168: 
                    169:        bzero((caddr_t)ndp, sizeof(struct nameidata));
                    170:        ndp->ni_iov = &ndp->ni_nd.nd_iovec;
                    171:        ndp->ni_iovcnt = 1;
                    172:        ndp->ni_base = (caddr_t)&ndp->ni_dent;
                    173:        ndp->ni_rw = UIO_WRITE;
                    174:        ndp->ni_uioseg = UIO_SYSSPACE;
                    175: }
                    176: 
                    177: /*
                    178:  * Duplicate a nameidata structure
                    179:  */
                    180: nddup(ndp, newndp)
                    181:        register struct nameidata *ndp, *newndp;
                    182: {
                    183: 
                    184:        ndinit(newndp);
                    185:        newndp->ni_cdir = ndp->ni_cdir;
                    186:        VREF(newndp->ni_cdir);
                    187:        newndp->ni_rdir = ndp->ni_rdir;
                    188:        if (newndp->ni_rdir)
                    189:                VREF(newndp->ni_rdir);
                    190:        newndp->ni_cred = ndp->ni_cred;
                    191:        crhold(newndp->ni_cred);
                    192: }
                    193: 
                    194: /*
                    195:  * Release a nameidata structure
                    196:  */
                    197: ndrele(ndp)
                    198:        register struct nameidata *ndp;
                    199: {
                    200: 
                    201:        vrele(ndp->ni_cdir);
                    202:        if (ndp->ni_rdir)
                    203:                vrele(ndp->ni_rdir);
                    204:        crfree(ndp->ni_cred);
                    205: }
                    206: 
                    207: /*
                    208:  * Routines having to do with the management of the vnode table.
                    209:  */
                    210: struct vnode *vfreeh, **vfreet;
                    211: extern struct vnodeops dead_vnodeops, spec_vnodeops;
                    212: extern void vclean();
                    213: long numvnodes;
                    214: struct vattr va_null;
                    215: 
                    216: /*
                    217:  * Initialize the vnode structures and initialize each file system type.
                    218:  */
                    219: vfsinit()
                    220: {
                    221:        struct vfsops **vfsp;
                    222: 
                    223:        /*
                    224:         * Initialize the vnode name cache
                    225:         */
                    226:        nchinit();
                    227:        /*
                    228:         * Initialize each file system type.
                    229:         */
                    230:        vattr_null(&va_null);
                    231:        for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
                    232:                if (*vfsp == NULL)
                    233:                        continue;
                    234:                (*(*vfsp)->vfs_init)();
                    235:        }
                    236: }
                    237: 
                    238: /*
                    239:  * Return the next vnode from the free list.
                    240:  */
                    241: getnewvnode(tag, mp, vops, vpp)
                    242:        enum vtagtype tag;
                    243:        struct mount *mp;
                    244:        struct vnodeops *vops;
                    245:        struct vnode **vpp;
                    246: {
                    247:        register struct vnode *vp, *vq;
                    248: 
                    249:        if (numvnodes < desiredvnodes) {
                    250:                vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK);
                    251:                bzero((char *)vp, sizeof *vp);
                    252:                numvnodes++;
                    253:        } else {
                    254:                if ((vp = vfreeh) == NULL) {
                    255:                        tablefull("vnode");
                    256:                        *vpp = 0;
                    257:                        return (ENFILE);
                    258:                }
                    259:                if (vp->v_usecount)
                    260:                        panic("free vnode isn't");
                    261:                if (vq = vp->v_freef)
                    262:                        vq->v_freeb = &vfreeh;
                    263:                else
                    264:                        vfreet = &vfreeh;
                    265:                vfreeh = vq;
                    266:                vp->v_freef = NULL;
                    267:                vp->v_freeb = NULL;
                    268:                if (vp->v_type != VBAD)
                    269:                        vgone(vp);
                    270:                vp->v_flag = 0;
                    271:                vp->v_shlockc = 0;
                    272:                vp->v_exlockc = 0;
                    273:                vp->v_lastr = 0;
                    274:                vp->v_socket = 0;
                    275:        }
                    276:        vp->v_type = VNON;
                    277:        cache_purge(vp);
                    278:        vp->v_tag = tag;
                    279:        vp->v_op = vops;
                    280:        insmntque(vp, mp);
                    281:        VREF(vp);
                    282:        *vpp = vp;
                    283:        return (0);
                    284: }
                    285: 
                    286: /*
                    287:  * Move a vnode from one mount queue to another.
                    288:  */
                    289: insmntque(vp, mp)
                    290:        register struct vnode *vp;
                    291:        register struct mount *mp;
                    292: {
                    293:        struct vnode *vq;
                    294: 
                    295:        /*
                    296:         * Delete from old mount point vnode list, if on one.
                    297:         */
                    298:        if (vp->v_mountb) {
                    299:                if (vq = vp->v_mountf)
                    300:                        vq->v_mountb = vp->v_mountb;
                    301:                *vp->v_mountb = vq;
                    302:        }
                    303:        /*
                    304:         * Insert into list of vnodes for the new mount point, if available.
                    305:         */
                    306:        vp->v_mount = mp;
                    307:        if (mp == NULL) {
                    308:                vp->v_mountf = NULL;
                    309:                vp->v_mountb = NULL;
                    310:                return;
                    311:        }
                    312:        if (mp->mnt_mounth) {
                    313:                vp->v_mountf = mp->mnt_mounth;
                    314:                vp->v_mountb = &mp->mnt_mounth;
                    315:                mp->mnt_mounth->v_mountb = &vp->v_mountf;
                    316:                mp->mnt_mounth = vp;
                    317:        } else {
                    318:                mp->mnt_mounth = vp;
                    319:                vp->v_mountb = &mp->mnt_mounth;
                    320:                vp->v_mountf = NULL;
                    321:        }
                    322: }
                    323: 
                    324: /*
                    325:  * Create a vnode for a block device.
                    326:  * Used for root filesystem, argdev, and swap areas.
                    327:  * Also used for memory file system special devices.
                    328:  */
                    329: bdevvp(dev, vpp)
                    330:        dev_t dev;
                    331:        struct vnode **vpp;
                    332: {
                    333:        register struct vnode *vp;
                    334:        struct vnode *nvp;
                    335:        int error;
                    336: 
                    337:        error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
                    338:        if (error) {
                    339:                *vpp = 0;
                    340:                return (error);
                    341:        }
                    342:        vp = nvp;
                    343:        vp->v_type = VBLK;
                    344:        if (nvp = checkalias(vp, dev, (struct mount *)0)) {
                    345:                vput(vp);
                    346:                vp = nvp;
                    347:        }
                    348:        *vpp = vp;
                    349:        return (0);
                    350: }
                    351: 
                    352: /*
                    353:  * Check to see if the new vnode represents a special device
                    354:  * for which we already have a vnode (either because of
                    355:  * bdevvp() or because of a different vnode representing
                    356:  * the same block device). If such an alias exists, deallocate
                    357:  * the existing contents and return the aliased vnode. The
                    358:  * caller is responsible for filling it with its new contents.
                    359:  */
                    360: struct vnode *
                    361: checkalias(nvp, nvp_rdev, mp)
                    362:        register struct vnode *nvp;
                    363:        dev_t nvp_rdev;
                    364:        struct mount *mp;
                    365: {
                    366:        register struct vnode *vp;
                    367:        struct vnode **vpp;
                    368: 
                    369:        if (nvp->v_type != VBLK && nvp->v_type != VCHR)
                    370:                return (NULLVP);
                    371: 
                    372:        vpp = &speclisth[SPECHASH(nvp_rdev)];
                    373: loop:
                    374:        for (vp = *vpp; vp; vp = vp->v_specnext) {
                    375:                if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
                    376:                        continue;
                    377:                /*
                    378:                 * Alias, but not in use, so flush it out.
                    379:                 */
                    380:                if (vp->v_usecount == 0) {
                    381:                        vgone(vp);
                    382:                        goto loop;
                    383:                }
                    384:                if (vget(vp))
                    385:                        goto loop;
                    386:                break;
                    387:        }
                    388:        if (vp == NULL || vp->v_tag != VT_NON) {
                    389:                MALLOC(nvp->v_specinfo, struct specinfo *,
                    390:                        sizeof(struct specinfo), M_VNODE, M_WAITOK);
                    391:                nvp->v_rdev = nvp_rdev;
                    392:                nvp->v_hashchain = vpp;
                    393:                nvp->v_specnext = *vpp;
                    394:                nvp->v_specflags = 0;
                    395:                *vpp = nvp;
                    396:                if (vp != NULL) {
                    397:                        nvp->v_flag |= VALIASED;
                    398:                        vp->v_flag |= VALIASED;
                    399:                        vput(vp);
                    400:                }
                    401:                return (NULLVP);
                    402:        }
                    403:        VOP_UNLOCK(vp);
                    404:        vclean(vp, 0);
                    405:        vp->v_op = nvp->v_op;
                    406:        vp->v_tag = nvp->v_tag;
                    407:        nvp->v_type = VNON;
                    408:        insmntque(vp, mp);
                    409:        return (vp);
                    410: }
                    411: 
                    412: /*
                    413:  * Grab a particular vnode from the free list, increment its
                    414:  * reference count and lock it. The vnode lock bit is set the
                    415:  * vnode is being eliminated in vgone. The process is awakened
                    416:  * when the transition is completed, and an error returned to
                    417:  * indicate that the vnode is no longer usable (possibly having
                    418:  * been changed to a new file system type).
                    419:  */
                    420: vget(vp)
                    421:        register struct vnode *vp;
                    422: {
                    423:        register struct vnode *vq;
                    424: 
                    425:        if (vp->v_flag & VXLOCK) {
                    426:                vp->v_flag |= VXWANT;
                    427:                sleep((caddr_t)vp, PINOD);
                    428:                return (1);
                    429:        }
                    430:        if (vp->v_usecount == 0) {
                    431:                if (vq = vp->v_freef)
                    432:                        vq->v_freeb = vp->v_freeb;
                    433:                else
                    434:                        vfreet = vp->v_freeb;
                    435:                *vp->v_freeb = vq;
                    436:                vp->v_freef = NULL;
                    437:                vp->v_freeb = NULL;
                    438:        }
                    439:        VREF(vp);
                    440:        VOP_LOCK(vp);
                    441:        return (0);
                    442: }
                    443: 
                    444: /*
                    445:  * Vnode reference, just increment the count
                    446:  */
                    447: void vref(vp)
                    448:        struct vnode *vp;
                    449: {
                    450: 
                    451:        vp->v_usecount++;
                    452: }
                    453: 
                    454: /*
                    455:  * vput(), just unlock and vrele()
                    456:  */
                    457: void vput(vp)
                    458:        register struct vnode *vp;
                    459: {
                    460:        VOP_UNLOCK(vp);
                    461:        vrele(vp);
                    462: }
                    463: 
                    464: /*
                    465:  * Vnode release.
                    466:  * If count drops to zero, call inactive routine and return to freelist.
                    467:  */
                    468: void vrele(vp)
                    469:        register struct vnode *vp;
                    470: {
                    471: 
                    472:        if (vp == NULL)
                    473:                panic("vrele: null vp");
                    474:        vp->v_usecount--;
                    475:        if (vp->v_usecount < 0)
                    476:                vprint("vrele: bad ref count", vp);
                    477:        if (vp->v_usecount > 0)
                    478:                return;
                    479:        if (vfreeh == NULLVP) {
                    480:                /*
                    481:                 * insert into empty list
                    482:                 */
                    483:                vfreeh = vp;
                    484:                vp->v_freeb = &vfreeh;
                    485:        } else {
                    486:                /*
                    487:                 * insert at tail of list
                    488:                 */
                    489:                *vfreet = vp;
                    490:                vp->v_freeb = vfreet;
                    491:        }
                    492:        vp->v_freef = NULL;
                    493:        vfreet = &vp->v_freef;
                    494:        VOP_INACTIVE(vp);
                    495: }
                    496: 
                    497: /*
                    498:  * Page or buffer structure gets a reference.
                    499:  */
                    500: vhold(vp)
                    501:        register struct vnode *vp;
                    502: {
                    503: 
                    504:        vp->v_holdcnt++;
                    505: }
                    506: 
                    507: /*
                    508:  * Page or buffer structure frees a reference.
                    509:  */
                    510: holdrele(vp)
                    511:        register struct vnode *vp;
                    512: {
                    513: 
                    514:        if (vp->v_holdcnt <= 0)
                    515:                panic("holdrele: holdcnt");
                    516:        vp->v_holdcnt--;
                    517: }
                    518: 
                    519: /*
                    520:  * Remove any vnodes in the vnode table belonging to mount point mp.
                    521:  *
                    522:  * If MNT_NOFORCE is specified, there should not be any active ones,
                    523:  * return error if any are found (nb: this is a user error, not a
                    524:  * system error). If MNT_FORCE is specified, detach any active vnodes
                    525:  * that are found.
                    526:  */
                    527: int busyprt = 0;       /* patch to print out busy vnodes */
                    528: 
                    529: vflush(mp, skipvp, flags)
                    530:        struct mount *mp;
                    531:        struct vnode *skipvp;
                    532:        int flags;
                    533: {
                    534:        register struct vnode *vp, *nvp;
                    535:        int busy = 0;
                    536: 
                    537:        if ((mp->mnt_flag & MNT_MPBUSY) == 0)
                    538:                panic("vflush: not busy");
                    539: loop:
                    540:        for (vp = mp->mnt_mounth; vp; vp = nvp) {
                    541:                if (vp->v_mount != mp)
                    542:                        goto loop;
                    543:                nvp = vp->v_mountf;
                    544:                /*
                    545:                 * Skip over a selected vnode.
                    546:                 */
                    547:                if (vp == skipvp)
                    548:                        continue;
                    549:                /*
                    550:                 * Skip over a vnodes marked VSYSTEM.
                    551:                 */
                    552:                if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM))
                    553:                        continue;
                    554:                /*
                    555:                 * With v_usecount == 0, all we need to do is clear
                    556:                 * out the vnode data structures and we are done.
                    557:                 */
                    558:                if (vp->v_usecount == 0) {
                    559:                        vgone(vp);
                    560:                        continue;
                    561:                }
                    562:                /*
                    563:                 * For block or character devices, revert to an
                    564:                 * anonymous device. For all other files, just kill them.
                    565:                 */
                    566:                if (flags & FORCECLOSE) {
                    567:                        if (vp->v_type != VBLK && vp->v_type != VCHR) {
                    568:                                vgone(vp);
                    569:                        } else {
                    570:                                vclean(vp, 0);
                    571:                                vp->v_op = &spec_vnodeops;
                    572:                                insmntque(vp, (struct mount *)0);
                    573:                        }
                    574:                        continue;
                    575:                }
                    576:                if (busyprt)
                    577:                        vprint("vflush: busy vnode", vp);
                    578:                busy++;
                    579:        }
                    580:        if (busy)
                    581:                return (EBUSY);
                    582:        return (0);
                    583: }
                    584: 
                    585: /*
                    586:  * Disassociate the underlying file system from a vnode.
                    587:  */
                    588: void vclean(vp, flags)
                    589:        register struct vnode *vp;
                    590:        long flags;
                    591: {
                    592:        struct vnodeops *origops;
                    593:        int active;
                    594: 
                    595:        /*
                    596:         * Check to see if the vnode is in use.
                    597:         * If so we have to reference it before we clean it out
                    598:         * so that its count cannot fall to zero and generate a
                    599:         * race against ourselves to recycle it.
                    600:         */
                    601:        if (active = vp->v_usecount)
                    602:                VREF(vp);
                    603:        /*
                    604:         * Prevent the vnode from being recycled or
                    605:         * brought into use while we clean it out.
                    606:         */
                    607:        if (vp->v_flag & VXLOCK)
                    608:                panic("vclean: deadlock");
                    609:        vp->v_flag |= VXLOCK;
                    610:        /*
                    611:         * Even if the count is zero, the VOP_INACTIVE routine may still
                    612:         * have the object locked while it cleans it out. The VOP_LOCK
                    613:         * ensures that the VOP_INACTIVE routine is done with its work.
                    614:         * For active vnodes, it ensures that no other activity can
                    615:         * occur while the buffer list is being cleaned out.
                    616:         */
                    617:        VOP_LOCK(vp);
                    618:        if (flags & DOCLOSE)
                    619:                vinvalbuf(vp, 1);
                    620:        /*
                    621:         * Prevent any further operations on the vnode from
                    622:         * being passed through to the old file system.
                    623:         */
                    624:        origops = vp->v_op;
                    625:        vp->v_op = &dead_vnodeops;
                    626:        vp->v_tag = VT_NON;
                    627:        /*
                    628:         * If purging an active vnode, it must be unlocked, closed,
                    629:         * and deactivated before being reclaimed.
                    630:         */
                    631:        (*(origops->vn_unlock))(vp);
                    632:        if (active) {
                    633:                if (flags & DOCLOSE)
                    634:                        (*(origops->vn_close))(vp, 0, NOCRED);
                    635:                (*(origops->vn_inactive))(vp);
                    636:        }
                    637:        /*
                    638:         * Reclaim the vnode.
                    639:         */
                    640:        if ((*(origops->vn_reclaim))(vp))
                    641:                panic("vclean: cannot reclaim");
                    642:        if (active)
                    643:                vrele(vp);
                    644:        /*
                    645:         * Done with purge, notify sleepers in vget of the grim news.
                    646:         */
                    647:        vp->v_flag &= ~VXLOCK;
                    648:        if (vp->v_flag & VXWANT) {
                    649:                vp->v_flag &= ~VXWANT;
                    650:                wakeup((caddr_t)vp);
                    651:        }
                    652: }
                    653: 
                    654: /*
                    655:  * Eliminate all activity associated with  the requested vnode
                    656:  * and with all vnodes aliased to the requested vnode.
                    657:  */
                    658: void vgoneall(vp)
                    659:        register struct vnode *vp;
                    660: {
                    661:        register struct vnode *vq;
                    662: 
                    663:        if (vp->v_flag & VALIASED) {
                    664:                /*
                    665:                 * If a vgone (or vclean) is already in progress,
                    666:                 * wait until it is done and return.
                    667:                 */
                    668:                if (vp->v_flag & VXLOCK) {
                    669:                        vp->v_flag |= VXWANT;
                    670:                        sleep((caddr_t)vp, PINOD);
                    671:                        return;
                    672:                }
                    673:                /*
                    674:                 * Ensure that vp will not be vgone'd while we
                    675:                 * are eliminating its aliases.
                    676:                 */
                    677:                vp->v_flag |= VXLOCK;
                    678:                while (vp->v_flag & VALIASED) {
                    679:                        for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
                    680:                                if (vq->v_rdev != vp->v_rdev ||
                    681:                                    vq->v_type != vp->v_type || vp == vq)
                    682:                                        continue;
                    683:                                vgone(vq);
                    684:                                break;
                    685:                        }
                    686:                }
                    687:                /*
                    688:                 * Remove the lock so that vgone below will
                    689:                 * really eliminate the vnode after which time
                    690:                 * vgone will awaken any sleepers.
                    691:                 */
                    692:                vp->v_flag &= ~VXLOCK;
                    693:        }
                    694:        vgone(vp);
                    695: }
                    696: 
                    697: /*
                    698:  * Eliminate all activity associated with a vnode
                    699:  * in preparation for reuse.
                    700:  */
                    701: void vgone(vp)
                    702:        register struct vnode *vp;
                    703: {
                    704:        register struct vnode *vq;
                    705:        struct vnode *vx;
                    706:        long count;
                    707: 
                    708:        /*
                    709:         * If a vgone (or vclean) is already in progress,
                    710:         * wait until it is done and return.
                    711:         */
                    712:        if (vp->v_flag & VXLOCK) {
                    713:                vp->v_flag |= VXWANT;
                    714:                sleep((caddr_t)vp, PINOD);
                    715:                return;
                    716:        }
                    717:        /*
                    718:         * Clean out the filesystem specific data.
                    719:         */
                    720:        vclean(vp, DOCLOSE);
                    721:        /*
                    722:         * Delete from old mount point vnode list, if on one.
                    723:         */
                    724:        if (vp->v_mountb) {
                    725:                if (vq = vp->v_mountf)
                    726:                        vq->v_mountb = vp->v_mountb;
                    727:                *vp->v_mountb = vq;
                    728:                vp->v_mountf = NULL;
                    729:                vp->v_mountb = NULL;
                    730:        }
                    731:        /*
                    732:         * If special device, remove it from special device alias list.
                    733:         */
                    734:        if (vp->v_type == VBLK || vp->v_type == VCHR) {
                    735:                if (*vp->v_hashchain == vp) {
                    736:                        *vp->v_hashchain = vp->v_specnext;
                    737:                } else {
                    738:                        for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
                    739:                                if (vq->v_specnext != vp)
                    740:                                        continue;
                    741:                                vq->v_specnext = vp->v_specnext;
                    742:                                break;
                    743:                        }
                    744:                        if (vq == NULL)
                    745:                                panic("missing bdev");
                    746:                }
                    747:                if (vp->v_flag & VALIASED) {
                    748:                        count = 0;
                    749:                        for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
                    750:                                if (vq->v_rdev != vp->v_rdev ||
                    751:                                    vq->v_type != vp->v_type)
                    752:                                        continue;
                    753:                                count++;
                    754:                                vx = vq;
                    755:                        }
                    756:                        if (count == 0)
                    757:                                panic("missing alias");
                    758:                        if (count == 1)
                    759:                                vx->v_flag &= ~VALIASED;
                    760:                        vp->v_flag &= ~VALIASED;
                    761:                }
                    762:                FREE(vp->v_specinfo, M_VNODE);
                    763:                vp->v_specinfo = NULL;
                    764:        }
                    765:        /*
                    766:         * If it is on the freelist, move it to the head of the list.
                    767:         */
                    768:        if (vp->v_freeb) {
                    769:                if (vq = vp->v_freef)
                    770:                        vq->v_freeb = vp->v_freeb;
                    771:                else
                    772:                        vfreet = vp->v_freeb;
                    773:                *vp->v_freeb = vq;
                    774:                vp->v_freef = vfreeh;
                    775:                vp->v_freeb = &vfreeh;
                    776:                vfreeh->v_freeb = &vp->v_freef;
                    777:                vfreeh = vp;
                    778:        }
                    779:        vp->v_type = VBAD;
                    780: }
                    781: 
                    782: /*
                    783:  * Lookup a vnode by device number.
                    784:  */
                    785: vfinddev(dev, type, vpp)
                    786:        dev_t dev;
                    787:        enum vtype type;
                    788:        struct vnode **vpp;
                    789: {
                    790:        register struct vnode *vp;
                    791: 
                    792:        for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
                    793:                if (dev != vp->v_rdev || type != vp->v_type)
                    794:                        continue;
                    795:                *vpp = vp;
                    796:                return (0);
                    797:        }
                    798:        return (1);
                    799: }
                    800: 
                    801: /*
                    802:  * Calculate the total number of references to a special device.
                    803:  */
                    804: vcount(vp)
                    805:        register struct vnode *vp;
                    806: {
                    807:        register struct vnode *vq;
                    808:        int count;
                    809: 
                    810:        if ((vp->v_flag & VALIASED) == 0)
                    811:                return (vp->v_usecount);
                    812: loop:
                    813:        for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
                    814:                if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
                    815:                        continue;
                    816:                /*
                    817:                 * Alias, but not in use, so flush it out.
                    818:                 */
                    819:                if (vq->v_usecount == 0) {
                    820:                        vgone(vq);
                    821:                        goto loop;
                    822:                }
                    823:                count += vq->v_usecount;
                    824:        }
                    825:        return (count);
                    826: }
                    827: 
                    828: /*
                    829:  * Print out a description of a vnode.
                    830:  */
                    831: static char *typename[] =
                    832:    { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
                    833: 
                    834: vprint(label, vp)
                    835:        char *label;
                    836:        register struct vnode *vp;
                    837: {
                    838:        char buf[64];
                    839: 
                    840:        if (label != NULL)
                    841:                printf("%s: ", label);
                    842:        printf("type %s, usecount %d, refcount %d,", typename[vp->v_type],
                    843:                vp->v_usecount, vp->v_holdcnt);
                    844:        buf[0] = '\0';
                    845:        if (vp->v_flag & VROOT)
                    846:                strcat(buf, "|VROOT");
                    847:        if (vp->v_flag & VTEXT)
                    848:                strcat(buf, "|VTEXT");
                    849:        if (vp->v_flag & VSYSTEM)
                    850:                strcat(buf, "|VSYSTEM");
                    851:        if (vp->v_flag & VEXLOCK)
                    852:                strcat(buf, "|VEXLOCK");
                    853:        if (vp->v_flag & VSHLOCK)
                    854:                strcat(buf, "|VSHLOCK");
                    855:        if (vp->v_flag & VLWAIT)
                    856:                strcat(buf, "|VLWAIT");
                    857:        if (vp->v_flag & VXLOCK)
                    858:                strcat(buf, "|VXLOCK");
                    859:        if (vp->v_flag & VXWANT)
                    860:                strcat(buf, "|VXWANT");
                    861:        if (vp->v_flag & VBWAIT)
                    862:                strcat(buf, "|VBWAIT");
                    863:        if (vp->v_flag & VALIASED)
                    864:                strcat(buf, "|VALIASED");
                    865:        if (buf[0] != '\0')
                    866:                printf(" flags (%s)", &buf[1]);
                    867:        printf("\n\t");
                    868:        VOP_PRINT(vp);
                    869: }
                    870: 
                    871: int kinfo_vdebug = 1;
                    872: int kinfo_vgetfailed;
                    873: #define KINFO_VNODESLOP        10
                    874: /*
                    875:  * Dump vnode list (via kinfo).
                    876:  * Copyout address of vnode followed by vnode.
                    877:  */
                    878: kinfo_vnode(op, where, acopysize, arg, aneeded)
                    879:        char *where;
                    880:        int *acopysize, *aneeded;
                    881: {
                    882:        register struct mount *mp = rootfs;
                    883:        struct mount *omp;
                    884:        struct vnode *vp;
                    885:        register needed = 0;
                    886:        register char *bp = where, *savebp;
                    887:        char *ewhere = where + *acopysize;
                    888:        int error;
                    889: 
                    890: #define VPTRSZ sizeof (struct vnode *)
                    891: #define VNODESZ        sizeof (struct vnode)
                    892:        if (where == NULL) {
                    893:                *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ);
                    894:                return (0);
                    895:        }
                    896:                
                    897:        do {
                    898:                if (vfs_busy(mp)) {
                    899:                        mp = mp->mnt_next;
                    900:                        continue;
                    901:                }
                    902:                savebp = bp;
                    903: again:
                    904:                for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
                    905:                        /*
                    906:                         * Check that the vp is still associated with
                    907:                         * this filesystem.  RACE: could have been
                    908:                         * recycled onto the same filesystem.
                    909:                         */
                    910:                        if (vp->v_mount != mp) {
                    911:                                if (kinfo_vdebug)
                    912:                                        printf("kinfo: vp changed\n");
                    913:                                bp = savebp;
                    914:                                goto again;
                    915:                        }
                    916:                        if ((bp + VPTRSZ + VNODESZ <= ewhere) && 
                    917:                            ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
                    918:                             (error = copyout((caddr_t)vp, bp + VPTRSZ, 
                    919:                              VNODESZ))))
                    920:                                return (error);
                    921:                        bp += VPTRSZ + VNODESZ;
                    922:                }
                    923:                omp = mp;
                    924:                mp = mp->mnt_next;
                    925:                vfs_unbusy(omp);
                    926:        } while (mp != rootfs);
                    927: 
                    928:        *aneeded = bp - where;
                    929:        if (bp > ewhere)
                    930:                *acopysize = ewhere - where;
                    931:        else
                    932:                *acopysize = bp - where;
                    933:        return (0);
                    934: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.