Annotation of Net2/ufs/ufs_inode.c, revision 1.1.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.