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

unix.superglobalmegacorp.com

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