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

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

unix.superglobalmegacorp.com

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