Annotation of Net2/ufs/ufs_inode.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  * 3. All advertising materials mentioning features or use of this software
        !            14:  *    must display the following acknowledgement:
        !            15:  *     This product includes software developed by the University of
        !            16:  *     California, Berkeley and its contributors.
        !            17:  * 4. Neither the name of the University nor the names of its contributors
        !            18:  *    may be used to endorse or promote products derived from this software
        !            19:  *    without specific prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            31:  * SUCH DAMAGE.
        !            32:  *
        !            33:  *     @(#)ufs_inode.c 7.40 (Berkeley) 5/8/91
        !            34:  */
        !            35: 
        !            36: #include "param.h"
        !            37: #include "systm.h"
        !            38: #include "mount.h"
        !            39: #include "proc.h"
        !            40: #include "file.h"
        !            41: #include "buf.h"
        !            42: #include "vnode.h"
        !            43: #include "kernel.h"
        !            44: #include "malloc.h"
        !            45: 
        !            46: #include "quota.h"
        !            47: #include "inode.h"
        !            48: #include "fs.h"
        !            49: #include "ufsmount.h"
        !            50: 
        !            51: #define        INOHSZ  512
        !            52: #if    ((INOHSZ&(INOHSZ-1)) == 0)
        !            53: #define        INOHASH(dev,ino)        (((dev)+(ino))&(INOHSZ-1))
        !            54: #else
        !            55: #define        INOHASH(dev,ino)        (((unsigned)((dev)+(ino)))%INOHSZ)
        !            56: #endif
        !            57: 
        !            58: union ihead {
        !            59:        union  ihead *ih_head[2];
        !            60:        struct inode *ih_chain[2];
        !            61: } ihead[INOHSZ];
        !            62: 
        !            63: int prtactive; /* 1 => print out reclaim of active vnodes */
        !            64: 
        !            65: /*
        !            66:  * Initialize hash links for inodes.
        !            67:  */
        !            68: ufs_init()
        !            69: {
        !            70:        register int i;
        !            71:        register union ihead *ih = ihead;
        !            72: 
        !            73: #ifndef lint
        !            74:        if (VN_MAXPRIVATE < sizeof(struct inode))
        !            75:                panic("ihinit: too small");
        !            76: #endif /* not lint */
        !            77:        for (i = INOHSZ; --i >= 0; ih++) {
        !            78:                ih->ih_head[0] = ih;
        !            79:                ih->ih_head[1] = ih;
        !            80:        }
        !            81: #ifdef QUOTA
        !            82:        dqinit();
        !            83: #endif /* QUOTA */
        !            84: }
        !            85: 
        !            86: /*
        !            87:  * Look up a UFS dinode number to find its incore vnode.
        !            88:  * If it is not in core, read it in from the specified device.
        !            89:  * If it is in core, wait for the lock bit to clear, then
        !            90:  * return the inode locked. Detection and handling of mount
        !            91:  * points must be done by the calling routine.
        !            92:  */
        !            93: iget(xp, ino, ipp)
        !            94:        struct inode *xp;
        !            95:        ino_t ino;
        !            96:        struct inode **ipp;
        !            97: {
        !            98:        dev_t dev = xp->i_dev;
        !            99:        struct mount *mntp = ITOV(xp)->v_mount;
        !           100:        register struct fs *fs = VFSTOUFS(mntp)->um_fs;
        !           101:        extern struct vnodeops ufs_vnodeops, spec_inodeops;
        !           102:        register struct inode *ip, *iq;
        !           103:        register struct vnode *vp;
        !           104:        struct vnode *nvp;
        !           105:        struct buf *bp;
        !           106:        struct dinode *dp;
        !           107:        union ihead *ih;
        !           108:        int i, error;
        !           109: 
        !           110:        ih = &ihead[INOHASH(dev, ino)];
        !           111: loop:
        !           112:        for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) {
        !           113:                if (ino != ip->i_number || dev != ip->i_dev)
        !           114:                        continue;
        !           115:                if ((ip->i_flag&ILOCKED) != 0) {
        !           116:                        ip->i_flag |= IWANT;
        !           117:                        sleep((caddr_t)ip, PINOD);
        !           118:                        goto loop;
        !           119:                }
        !           120:                if (vget(ITOV(ip)))
        !           121:                        goto loop;
        !           122:                *ipp = ip;
        !           123:                return(0);
        !           124:        }
        !           125:        /*
        !           126:         * Allocate a new inode.
        !           127:         */
        !           128:        if (error = getnewvnode(VT_UFS, mntp, &ufs_vnodeops, &nvp)) {
        !           129:                *ipp = 0;
        !           130:                return (error);
        !           131:        }
        !           132:        ip = VTOI(nvp);
        !           133:        ip->i_vnode = nvp;
        !           134:        ip->i_flag = 0;
        !           135:        ip->i_devvp = 0;
        !           136:        ip->i_mode = 0;
        !           137:        ip->i_diroff = 0;
        !           138:        ip->i_lockf = 0;
        !           139: #ifdef QUOTA
        !           140:        for (i = 0; i < MAXQUOTAS; i++)
        !           141:                ip->i_dquot[i] = NODQUOT;
        !           142: #endif
        !           143:        /*
        !           144:         * Put it onto its hash chain and lock it so that other requests for
        !           145:         * this inode will block if they arrive while we are sleeping waiting
        !           146:         * for old data structures to be purged or for the contents of the
        !           147:         * disk portion of this inode to be read.
        !           148:         */
        !           149:        ip->i_dev = dev;
        !           150:        ip->i_number = ino;
        !           151:        insque(ip, ih);
        !           152:        ILOCK(ip);
        !           153:        /*
        !           154:         * Read in the disk contents for the inode.
        !           155:         */
        !           156:        if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)),
        !           157:            (int)fs->fs_bsize, NOCRED, &bp)) {
        !           158:                /*
        !           159:                 * The inode does not contain anything useful, so it would
        !           160:                 * be misleading to leave it on its hash chain.
        !           161:                 * Iput() will take care of putting it back on the free list.
        !           162:                 */
        !           163:                remque(ip);
        !           164:                ip->i_forw = ip;
        !           165:                ip->i_back = ip;
        !           166:                /*
        !           167:                 * Unlock and discard unneeded inode.
        !           168:                 */
        !           169:                iput(ip);
        !           170:                brelse(bp);
        !           171:                *ipp = 0;
        !           172:                return (error);
        !           173:        }
        !           174:        dp = bp->b_un.b_dino;
        !           175:        dp += itoo(fs, ino);
        !           176:        ip->i_din = *dp;
        !           177:        brelse(bp);
        !           178:        /*
        !           179:         * Initialize the associated vnode
        !           180:         */
        !           181:        vp = ITOV(ip);
        !           182:        vp->v_type = IFTOVT(ip->i_mode);
        !           183:        if (vp->v_type == VFIFO) {
        !           184: #ifdef FIFO
        !           185:                extern struct vnodeops fifo_inodeops;
        !           186:                vp->v_op = &fifo_inodeops;
        !           187: #else
        !           188:                iput(ip);
        !           189:                *ipp = 0;
        !           190:                return (EOPNOTSUPP);
        !           191: #endif /* FIFO */
        !           192:        }
        !           193:        if (vp->v_type == VCHR || vp->v_type == VBLK) {
        !           194:                vp->v_op = &spec_inodeops;
        !           195:                if (nvp = checkalias(vp, ip->i_rdev, mntp)) {
        !           196:                        /*
        !           197:                         * Reinitialize aliased inode.
        !           198:                         */
        !           199:                        vp = nvp;
        !           200:                        iq = VTOI(vp);
        !           201:                        iq->i_vnode = vp;
        !           202:                        iq->i_flag = 0;
        !           203:                        ILOCK(iq);
        !           204:                        iq->i_din = ip->i_din;
        !           205:                        iq->i_dev = dev;
        !           206:                        iq->i_number = ino;
        !           207:                        insque(iq, ih);
        !           208:                        /*
        !           209:                         * Discard unneeded vnode
        !           210:                         */
        !           211:                        ip->i_mode = 0;
        !           212:                        iput(ip);
        !           213:                        ip = iq;
        !           214:                }
        !           215:        }
        !           216:        if (ino == ROOTINO)
        !           217:                vp->v_flag |= VROOT;
        !           218:        /*
        !           219:         * Finish inode initialization.
        !           220:         */
        !           221:        ip->i_fs = fs;
        !           222:        ip->i_devvp = VFSTOUFS(mntp)->um_devvp;
        !           223:        VREF(ip->i_devvp);
        !           224:        /*
        !           225:         * Set up a generation number for this inode if it does not
        !           226:         * already have one. This should only happen on old filesystems.
        !           227:         */
        !           228:        if (ip->i_gen == 0) {
        !           229:                if (++nextgennumber < (u_long)time.tv_sec)
        !           230:                        nextgennumber = time.tv_sec;
        !           231:                ip->i_gen = nextgennumber;
        !           232:                if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
        !           233:                        ip->i_flag |= IMOD;
        !           234:        }
        !           235:        *ipp = ip;
        !           236:        return (0);
        !           237: }
        !           238: 
        !           239: /*
        !           240:  * Unlock and decrement the reference count of an inode structure.
        !           241:  */
        !           242: iput(ip)
        !           243:        register struct inode *ip;
        !           244: {
        !           245: 
        !           246:        if ((ip->i_flag & ILOCKED) == 0)
        !           247:                panic("iput");
        !           248:        IUNLOCK(ip);
        !           249:        vrele(ITOV(ip));
        !           250: }
        !           251: 
        !           252: /*
        !           253:  * Last reference to an inode, write the inode out and if necessary,
        !           254:  * truncate and deallocate the file.
        !           255:  */
        !           256: ufs_inactive(vp, p)
        !           257:        struct vnode *vp;
        !           258:        struct proc *p;
        !           259: {
        !           260:        register struct inode *ip = VTOI(vp);
        !           261:        int mode, error = 0;
        !           262: 
        !           263:        if (prtactive && vp->v_usecount != 0)
        !           264:                vprint("ufs_inactive: pushing active", vp);
        !           265:        /*
        !           266:         * Get rid of inodes related to stale file handles.
        !           267:         */
        !           268:        if (ip->i_mode == 0) {
        !           269:                if ((vp->v_flag & VXLOCK) == 0)
        !           270:                        vgone(vp);
        !           271:                return (0);
        !           272:        }
        !           273:        ILOCK(ip);
        !           274:        if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
        !           275: #ifdef QUOTA
        !           276:                if (!getinoquota(ip))
        !           277:                        (void) chkiq(ip, -1, NOCRED, 0);
        !           278: #endif
        !           279:                error = itrunc(ip, (u_long)0, 0);
        !           280:                mode = ip->i_mode;
        !           281:                ip->i_mode = 0;
        !           282:                ip->i_rdev = 0;
        !           283:                ip->i_flag |= IUPD|ICHG;
        !           284:                ifree(ip, ip->i_number, mode);
        !           285:        }
        !           286:        IUPDAT(ip, &time, &time, 0);
        !           287:        IUNLOCK(ip);
        !           288:        ip->i_flag = 0;
        !           289:        /*
        !           290:         * If we are done with the inode, reclaim it
        !           291:         * so that it can be reused immediately.
        !           292:         */
        !           293:        if (vp->v_usecount == 0 && ip->i_mode == 0)
        !           294:                vgone(vp);
        !           295:        return (error);
        !           296: }
        !           297: 
        !           298: /*
        !           299:  * Reclaim an inode so that it can be used for other purposes.
        !           300:  */
        !           301: ufs_reclaim(vp)
        !           302:        register struct vnode *vp;
        !           303: {
        !           304:        register struct inode *ip = VTOI(vp);
        !           305:        int i;
        !           306: 
        !           307:        if (prtactive && vp->v_usecount != 0)
        !           308:                vprint("ufs_reclaim: pushing active", vp);
        !           309:        /*
        !           310:         * Remove the inode from its hash chain.
        !           311:         */
        !           312:        remque(ip);
        !           313:        ip->i_forw = ip;
        !           314:        ip->i_back = ip;
        !           315:        /*
        !           316:         * Purge old data structures associated with the inode.
        !           317:         */
        !           318:        cache_purge(vp);
        !           319:        if (ip->i_devvp) {
        !           320:                vrele(ip->i_devvp);
        !           321:                ip->i_devvp = 0;
        !           322:        }
        !           323: #ifdef QUOTA
        !           324:        for (i = 0; i < MAXQUOTAS; i++) {
        !           325:                if (ip->i_dquot[i] != NODQUOT) {
        !           326:                        dqrele(vp, ip->i_dquot[i]);
        !           327:                        ip->i_dquot[i] = NODQUOT;
        !           328:                }
        !           329:        }
        !           330: #endif
        !           331:        ip->i_flag = 0;
        !           332:        return (0);
        !           333: }
        !           334: 
        !           335: /*
        !           336:  * Update the access, modified, and inode change times as specified
        !           337:  * by the IACC, IMOD, and ICHG flags respectively. The IUPD flag
        !           338:  * is used to specify that the inode needs to be updated but that
        !           339:  * the times have already been set. The access and modified times
        !           340:  * are taken from the second and third parameters; the inode change
        !           341:  * time is always taken from the current time. If waitfor is set,
        !           342:  * then wait for the disk write of the inode to complete.
        !           343:  */
        !           344: iupdat(ip, ta, tm, waitfor)
        !           345:        register struct inode *ip;
        !           346:        struct timeval *ta, *tm;
        !           347:        int waitfor;
        !           348: {
        !           349:        struct buf *bp;
        !           350:        struct vnode *vp = ITOV(ip);
        !           351:        struct dinode *dp;
        !           352:        register struct fs *fs;
        !           353:        int error;
        !           354: 
        !           355:        fs = ip->i_fs;
        !           356:        if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
        !           357:                return (0);
        !           358:        if (vp->v_mount->mnt_flag & MNT_RDONLY)
        !           359:                return (0);
        !           360:        error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)),
        !           361:                (int)fs->fs_bsize, NOCRED, &bp);
        !           362:        if (error) {
        !           363:                brelse(bp);
        !           364:                return (error);
        !           365:        }
        !           366:        if (ip->i_flag&IACC)
        !           367:                ip->i_atime = ta->tv_sec;
        !           368:        if (ip->i_flag&IUPD)
        !           369:                ip->i_mtime = tm->tv_sec;
        !           370:        if (ip->i_flag&ICHG)
        !           371:                ip->i_ctime = time.tv_sec;
        !           372:        ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
        !           373:        dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
        !           374:        *dp = ip->i_din;
        !           375:        if (waitfor) {
        !           376:                return (bwrite(bp));
        !           377:        } else {
        !           378:                bdwrite(bp);
        !           379:                return (0);
        !           380:        }
        !           381: }
        !           382: 
        !           383: #define        SINGLE  0       /* index of single indirect block */
        !           384: #define        DOUBLE  1       /* index of double indirect block */
        !           385: #define        TRIPLE  2       /* index of triple indirect block */
        !           386: /*
        !           387:  * Truncate the inode ip to at most length size.  Free affected disk
        !           388:  * blocks -- the blocks of the file are removed in reverse order.
        !           389:  *
        !           390:  * NB: triple indirect blocks are untested.
        !           391:  */
        !           392: itrunc(oip, length, flags)
        !           393:        register struct inode *oip;
        !           394:        u_long length;
        !           395:        int flags;
        !           396: {
        !           397:        register daddr_t lastblock;
        !           398:        daddr_t bn, lbn, lastiblock[NIADDR];
        !           399:        register struct fs *fs;
        !           400:        register struct inode *ip;
        !           401:        struct buf *bp;
        !           402:        int offset, osize, size, level;
        !           403:        long count, nblocks, blocksreleased = 0;
        !           404:        register int i;
        !           405:        int aflags, error, allerror;
        !           406:        struct inode tip;
        !           407: 
        !           408:        vnode_pager_setsize(ITOV(oip), length);
        !           409:        if (oip->i_size <= length) {
        !           410:                oip->i_flag |= ICHG|IUPD;
        !           411:                error = iupdat(oip, &time, &time, 1);
        !           412:                return (error);
        !           413:        }
        !           414:        /*
        !           415:         * Calculate index into inode's block list of
        !           416:         * last direct and indirect blocks (if any)
        !           417:         * which we want to keep.  Lastblock is -1 when
        !           418:         * the file is truncated to 0.
        !           419:         */
        !           420:        fs = oip->i_fs;
        !           421:        lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
        !           422:        lastiblock[SINGLE] = lastblock - NDADDR;
        !           423:        lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
        !           424:        lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
        !           425:        nblocks = btodb(fs->fs_bsize);
        !           426:        /*
        !           427:         * Update the size of the file. If the file is not being
        !           428:         * truncated to a block boundry, the contents of the
        !           429:         * partial block following the end of the file must be
        !           430:         * zero'ed in case it ever become accessable again because
        !           431:         * of subsequent file growth.
        !           432:         */
        !           433:        osize = oip->i_size;
        !           434:        offset = blkoff(fs, length);
        !           435:        if (offset == 0) {
        !           436:                oip->i_size = length;
        !           437:        } else {
        !           438:                lbn = lblkno(fs, length);
        !           439:                aflags = B_CLRBUF;
        !           440:                if (flags & IO_SYNC)
        !           441:                        aflags |= B_SYNC;
        !           442: #ifdef QUOTA
        !           443:                if (error = getinoquota(oip))
        !           444:                        return (error);
        !           445: #endif
        !           446:                if (error = balloc(oip, lbn, offset, &bp, aflags))
        !           447:                        return (error);
        !           448:                oip->i_size = length;
        !           449:                size = blksize(fs, oip, lbn);
        !           450:                (void) vnode_pager_uncache(ITOV(oip));
        !           451:                bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
        !           452:                allocbuf(bp, size);
        !           453:                if (flags & IO_SYNC)
        !           454:                        bwrite(bp);
        !           455:                else
        !           456:                        bdwrite(bp);
        !           457:        }
        !           458:        /*
        !           459:         * Update file and block pointers
        !           460:         * on disk before we start freeing blocks.
        !           461:         * If we crash before free'ing blocks below,
        !           462:         * the blocks will be returned to the free list.
        !           463:         * lastiblock values are also normalized to -1
        !           464:         * for calls to indirtrunc below.
        !           465:         */
        !           466:        tip = *oip;
        !           467:        tip.i_size = osize;
        !           468:        for (level = TRIPLE; level >= SINGLE; level--)
        !           469:                if (lastiblock[level] < 0) {
        !           470:                        oip->i_ib[level] = 0;
        !           471:                        lastiblock[level] = -1;
        !           472:                }
        !           473:        for (i = NDADDR - 1; i > lastblock; i--)
        !           474:                oip->i_db[i] = 0;
        !           475:        oip->i_flag |= ICHG|IUPD;
        !           476:        vinvalbuf(ITOV(oip), (length > 0));
        !           477:        allerror = iupdat(oip, &time, &time, MNT_WAIT);
        !           478: 
        !           479:        /*
        !           480:         * Indirect blocks first.
        !           481:         */
        !           482:        ip = &tip;
        !           483:        for (level = TRIPLE; level >= SINGLE; level--) {
        !           484:                bn = ip->i_ib[level];
        !           485:                if (bn != 0) {
        !           486:                        error = indirtrunc(ip, bn, lastiblock[level], level,
        !           487:                                &count);
        !           488:                        if (error)
        !           489:                                allerror = error;
        !           490:                        blocksreleased += count;
        !           491:                        if (lastiblock[level] < 0) {
        !           492:                                ip->i_ib[level] = 0;
        !           493:                                blkfree(ip, bn, (off_t)fs->fs_bsize);
        !           494:                                blocksreleased += nblocks;
        !           495:                        }
        !           496:                }
        !           497:                if (lastiblock[level] >= 0)
        !           498:                        goto done;
        !           499:        }
        !           500: 
        !           501:        /*
        !           502:         * All whole direct blocks or frags.
        !           503:         */
        !           504:        for (i = NDADDR - 1; i > lastblock; i--) {
        !           505:                register off_t bsize;
        !           506: 
        !           507:                bn = ip->i_db[i];
        !           508:                if (bn == 0)
        !           509:                        continue;
        !           510:                ip->i_db[i] = 0;
        !           511:                bsize = (off_t)blksize(fs, ip, i);
        !           512:                blkfree(ip, bn, bsize);
        !           513:                blocksreleased += btodb(bsize);
        !           514:        }
        !           515:        if (lastblock < 0)
        !           516:                goto done;
        !           517: 
        !           518:        /*
        !           519:         * Finally, look for a change in size of the
        !           520:         * last direct block; release any frags.
        !           521:         */
        !           522:        bn = ip->i_db[lastblock];
        !           523:        if (bn != 0) {
        !           524:                off_t oldspace, newspace;
        !           525: 
        !           526:                /*
        !           527:                 * Calculate amount of space we're giving
        !           528:                 * back as old block size minus new block size.
        !           529:                 */
        !           530:                oldspace = blksize(fs, ip, lastblock);
        !           531:                ip->i_size = length;
        !           532:                newspace = blksize(fs, ip, lastblock);
        !           533:                if (newspace == 0)
        !           534:                        panic("itrunc: newspace");
        !           535:                if (oldspace - newspace > 0) {
        !           536:                        /*
        !           537:                         * Block number of space to be free'd is
        !           538:                         * the old block # plus the number of frags
        !           539:                         * required for the storage we're keeping.
        !           540:                         */
        !           541:                        bn += numfrags(fs, newspace);
        !           542:                        blkfree(ip, bn, oldspace - newspace);
        !           543:                        blocksreleased += btodb(oldspace - newspace);
        !           544:                }
        !           545:        }
        !           546: done:
        !           547: /* BEGIN PARANOIA */
        !           548:        for (level = SINGLE; level <= TRIPLE; level++)
        !           549:                if (ip->i_ib[level] != oip->i_ib[level])
        !           550:                        panic("itrunc1");
        !           551:        for (i = 0; i < NDADDR; i++)
        !           552:                if (ip->i_db[i] != oip->i_db[i])
        !           553:                        panic("itrunc2");
        !           554: /* END PARANOIA */
        !           555:        oip->i_blocks -= blocksreleased;
        !           556:        if (oip->i_blocks < 0)                  /* sanity */
        !           557:                oip->i_blocks = 0;
        !           558:        oip->i_flag |= ICHG;
        !           559: #ifdef QUOTA
        !           560:        if (!getinoquota(oip))
        !           561:                (void) chkdq(oip, -blocksreleased, NOCRED, 0);
        !           562: #endif
        !           563:        return (allerror);
        !           564: }
        !           565: 
        !           566: /*
        !           567:  * Release blocks associated with the inode ip and
        !           568:  * stored in the indirect block bn.  Blocks are free'd
        !           569:  * in LIFO order up to (but not including) lastbn.  If
        !           570:  * level is greater than SINGLE, the block is an indirect
        !           571:  * block and recursive calls to indirtrunc must be used to
        !           572:  * cleanse other indirect blocks.
        !           573:  *
        !           574:  * NB: triple indirect blocks are untested.
        !           575:  */
        !           576: indirtrunc(ip, bn, lastbn, level, countp)
        !           577:        register struct inode *ip;
        !           578:        daddr_t bn, lastbn;
        !           579:        int level;
        !           580:        long *countp;
        !           581: {
        !           582:        register int i;
        !           583:        struct buf *bp;
        !           584:        register struct fs *fs = ip->i_fs;
        !           585:        register daddr_t *bap;
        !           586:        daddr_t *copy, nb, last;
        !           587:        long blkcount, factor;
        !           588:        int nblocks, blocksreleased = 0;
        !           589:        int error, allerror = 0;
        !           590: 
        !           591:        /*
        !           592:         * Calculate index in current block of last
        !           593:         * block to be kept.  -1 indicates the entire
        !           594:         * block so we need not calculate the index.
        !           595:         */
        !           596:        factor = 1;
        !           597:        for (i = SINGLE; i < level; i++)
        !           598:                factor *= NINDIR(fs);
        !           599:        last = lastbn;
        !           600:        if (lastbn > 0)
        !           601:                last /= factor;
        !           602:        nblocks = btodb(fs->fs_bsize);
        !           603:        /*
        !           604:         * Get buffer of block pointers, zero those 
        !           605:         * entries corresponding to blocks to be free'd,
        !           606:         * and update on disk copy first.
        !           607:         */
        !           608:        error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize,
        !           609:                NOCRED, &bp);
        !           610:        if (error) {
        !           611:                brelse(bp);
        !           612:                *countp = 0;
        !           613:                return (error);
        !           614:        }
        !           615:        bap = bp->b_un.b_daddr;
        !           616:        MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
        !           617:        bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
        !           618:        bzero((caddr_t)&bap[last + 1],
        !           619:          (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
        !           620:        if (last == -1)
        !           621:                bp->b_flags |= B_INVAL;
        !           622:        error = bwrite(bp);
        !           623:        if (error)
        !           624:                allerror = error;
        !           625:        bap = copy;
        !           626: 
        !           627:        /*
        !           628:         * Recursively free totally unused blocks.
        !           629:         */
        !           630:        for (i = NINDIR(fs) - 1; i > last; i--) {
        !           631:                nb = bap[i];
        !           632:                if (nb == 0)
        !           633:                        continue;
        !           634:                if (level > SINGLE) {
        !           635:                        error = indirtrunc(ip, nb, (daddr_t)-1, level - 1,
        !           636:                                &blkcount);
        !           637:                        if (error)
        !           638:                                allerror = error;
        !           639:                        blocksreleased += blkcount;
        !           640:                }
        !           641:                blkfree(ip, nb, (off_t)fs->fs_bsize);
        !           642:                blocksreleased += nblocks;
        !           643:        }
        !           644: 
        !           645:        /*
        !           646:         * Recursively free last partial block.
        !           647:         */
        !           648:        if (level > SINGLE && lastbn >= 0) {
        !           649:                last = lastbn % factor;
        !           650:                nb = bap[i];
        !           651:                if (nb != 0) {
        !           652:                        error = indirtrunc(ip, nb, last, level - 1, &blkcount);
        !           653:                        if (error)
        !           654:                                allerror = error;
        !           655:                        blocksreleased += blkcount;
        !           656:                }
        !           657:        }
        !           658:        FREE(copy, M_TEMP);
        !           659:        *countp = blocksreleased;
        !           660:        return (allerror);
        !           661: }
        !           662: 
        !           663: /*
        !           664:  * Lock an inode. If its already locked, set the WANT bit and sleep.
        !           665:  */
        !           666: ilock(ip)
        !           667:        register struct inode *ip;
        !           668: {
        !           669: 
        !           670:        while (ip->i_flag & ILOCKED) {
        !           671:                ip->i_flag |= IWANT;
        !           672:                if (ip->i_spare0 == curproc->p_pid)
        !           673:                        panic("locking against myself");
        !           674:                ip->i_spare1 = curproc->p_pid;
        !           675:                (void) sleep((caddr_t)ip, PINOD);
        !           676:        }
        !           677:        ip->i_spare1 = 0;
        !           678:        ip->i_spare0 = curproc->p_pid;
        !           679:        ip->i_flag |= ILOCKED;
        !           680: }
        !           681: 
        !           682: /*
        !           683:  * Unlock an inode.  If WANT bit is on, wakeup.
        !           684:  */
        !           685: iunlock(ip)
        !           686:        register struct inode *ip;
        !           687: {
        !           688: 
        !           689:        if ((ip->i_flag & ILOCKED) == 0)
        !           690:                vprint("iunlock: unlocked inode", ITOV(ip));
        !           691:        ip->i_spare0 = 0;
        !           692:        ip->i_flag &= ~ILOCKED;
        !           693:        if (ip->i_flag&IWANT) {
        !           694:                ip->i_flag &= ~IWANT;
        !           695:                wakeup((caddr_t)ip);
        !           696:        }
        !           697: }

unix.superglobalmegacorp.com

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