Annotation of XNU/bsd/ufs/ffs/ffs_inode.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
                     23: /*
                     24:  * Copyright (c) 1982, 1986, 1989, 1993
                     25:  *     The Regents of the University of California.  All rights reserved.
                     26:  *
                     27:  * Redistribution and use in source and binary forms, with or without
                     28:  * modification, are permitted provided that the following conditions
                     29:  * are met:
                     30:  * 1. Redistributions of source code must retain the above copyright
                     31:  *    notice, this list of conditions and the following disclaimer.
                     32:  * 2. Redistributions in binary form must reproduce the above copyright
                     33:  *    notice, this list of conditions and the following disclaimer in the
                     34:  *    documentation and/or other materials provided with the distribution.
                     35:  * 3. All advertising materials mentioning features or use of this software
                     36:  *    must display the following acknowledgement:
                     37:  *     This product includes software developed by the University of
                     38:  *     California, Berkeley and its contributors.
                     39:  * 4. Neither the name of the University nor the names of its contributors
                     40:  *    may be used to endorse or promote products derived from this software
                     41:  *    without specific prior written permission.
                     42:  *
                     43:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     44:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     45:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     46:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     47:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     48:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     49:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     50:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     51:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     52:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     53:  * SUCH DAMAGE.
                     54:  *
                     55:  *     @(#)ffs_inode.c 8.13 (Berkeley) 4/21/95
                     56:  */
                     57: 
                     58: #include <rev_endian_fs.h>
                     59: #include <mach_nbc.h>
                     60: #include <vm/vm_pager.h>
                     61: #include <vm/vnode_pager.h>
                     62: 
                     63: #include <sys/param.h>
                     64: #include <sys/systm.h>
                     65: #include <sys/mount.h>
                     66: #include <sys/proc.h>
                     67: #include <sys/file.h>
                     68: #include <sys/buf.h>
                     69: #include <sys/vnode.h>
                     70: #include <sys/kernel.h>
                     71: #include <sys/malloc.h>
                     72: #include <sys/trace.h>
                     73: #include <sys/resourcevar.h>
                     74: 
                     75: #include <sys/vm.h>
                     76: 
                     77: #include <ufs/ufs/quota.h>
                     78: #include <ufs/ufs/inode.h>
                     79: #include <ufs/ufs/ufsmount.h>
                     80: #include <ufs/ufs/ufs_extern.h>
                     81: 
                     82: #include <ufs/ffs/fs.h>
                     83: #include <ufs/ffs/ffs_extern.h>
                     84: 
                     85: #if REV_ENDIAN_FS
                     86: #include <ufs/ufs/ufs_byte_order.h>
                     87: #include <architecture/byte_order.h>
                     88: #endif /* REV_ENDIAN_FS */
                     89: 
                     90: #if MACH_NBC 
                     91: #include <kern/mapfs.h>
                     92: #endif /* MACH_NBC */
                     93: 
                     94: 
                     95: 
                     96: static int ffs_indirtrunc __P((struct inode *, ufs_daddr_t, ufs_daddr_t,
                     97:            ufs_daddr_t, int, long *));
                     98: 
                     99: /*
                    100:  * Update the access, modified, and inode change times as specified by the
                    101:  * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is
                    102:  * used to specify that the inode needs to be updated but that the times have
                    103:  * already been set. The access and modified times are taken from the second
                    104:  * and third parameters; the inode change time is always taken from the current
                    105:  * time. If waitfor is set, then wait for the disk write of the inode to
                    106:  * complete.
                    107:  */
                    108: int
                    109: ffs_update(ap)
                    110:        struct vop_update_args /* {
                    111:                struct vnode *a_vp;
                    112:                struct timeval *a_access;
                    113:                struct timeval *a_modify;
                    114:                int a_waitfor;
                    115:        } */ *ap;
                    116: {
                    117:        register struct fs *fs;
                    118:        struct buf *bp;
                    119:        struct inode *ip;
                    120:        int error;
                    121: #if REV_ENDIAN_FS
                    122:        struct mount *mp=(ap->a_vp)->v_mount;
                    123:        int rev_endian=(mp->mnt_flag & MNT_REVEND);
                    124: #endif /* REV_ENDIAN_FS */
                    125: 
                    126:        ip = VTOI(ap->a_vp);
                    127:        if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) {
                    128:                ip->i_flag &=
                    129:                    ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
                    130:                return (0);
                    131:        }
                    132:        if ((ip->i_flag &
                    133:            (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0)
                    134:                return (0);
                    135:        if (ip->i_flag & IN_ACCESS)
                    136:                ip->i_atime = ap->a_access->tv_sec;
                    137:        if (ip->i_flag & IN_UPDATE) {
                    138:                ip->i_mtime = ap->a_modify->tv_sec;
                    139:                ip->i_modrev++;
                    140:        }
                    141:        if (ip->i_flag & IN_CHANGE)
                    142:                ip->i_ctime = time.tv_sec;
                    143:        ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
                    144:        fs = ip->i_fs;
                    145:        /*
                    146:         * Ensure that uid and gid are correct. This is a temporary
                    147:         * fix until fsck has been changed to do the update.
                    148:         */
                    149:        if (fs->fs_inodefmt < FS_44INODEFMT) {          /* XXX */
                    150:                ip->i_din.di_ouid = ip->i_uid;          /* XXX */
                    151:                ip->i_din.di_ogid = ip->i_gid;          /* XXX */
                    152:        }                                               /* XXX */
                    153:        if (error = bread(ip->i_devvp,
                    154:            fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
                    155:                (int)fs->fs_bsize, NOCRED, &bp)) {
                    156:                brelse(bp);
                    157:                return (error);
                    158:        }
                    159: #if REV_ENDIAN_FS
                    160:        if (rev_endian)
                    161:                byte_swap_inode_out(ip, ((struct dinode *)bp->b_data + ino_to_fsbo(fs, ip->i_number)));
                    162:        else {
                    163: #endif /* REV_ENDIAN_FS */
                    164:        *((struct dinode *)bp->b_data +
                    165:            ino_to_fsbo(fs, ip->i_number)) = ip->i_din;
                    166: #if REV_ENDIAN_FS
                    167:        }
                    168: #endif /* REV_ENDIAN_FS */
                    169: 
                    170:        if (ap->a_waitfor && (ap->a_vp->v_mount->mnt_flag & MNT_ASYNC) == 0)
                    171:                return (bwrite(bp));
                    172:        else {
                    173:                bdwrite(bp);
                    174:                return (0);
                    175:        }
                    176: }
                    177: 
                    178: #define        SINGLE  0       /* index of single indirect block */
                    179: #define        DOUBLE  1       /* index of double indirect block */
                    180: #define        TRIPLE  2       /* index of triple indirect block */
                    181: /*
                    182:  * Truncate the inode oip to at most length size, freeing the
                    183:  * disk blocks.
                    184:  */
                    185: ffs_truncate(ap)
                    186:        struct vop_truncate_args /* {
                    187:                struct vnode *a_vp;
                    188:                off_t a_length;
                    189:                int a_flags;
                    190:                struct ucred *a_cred;
                    191:                struct proc *a_p;
                    192:        } */ *ap;
                    193: {
                    194:        register struct vnode *ovp = ap->a_vp;
                    195:        ufs_daddr_t lastblock;
                    196:        register struct inode *oip;
                    197:        ufs_daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
                    198:        ufs_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
                    199:        off_t length = ap->a_length;
                    200:        register struct fs *fs;
                    201:        struct buf *bp;
                    202:        int offset, size, level;
                    203:        long count, nblocks, vflags, blocksreleased = 0;
                    204:        struct timeval tv;
                    205:        register int i;
                    206:        int aflags, error, allerror;
                    207:        off_t osize;
                    208: #if NeXT
                    209:        int devBlockSize=0;
                    210: #endif
                    211: 
                    212:        if (length < 0)
                    213:                return (EINVAL);
                    214: 
                    215:        oip = VTOI(ovp);
                    216:        fs = oip->i_fs;
                    217: 
                    218:        if (length > fs->fs_maxfilesize)
                    219:                return (EFBIG);
                    220: 
                    221:        tv = time;
                    222:        if (ovp->v_type == VLNK &&
                    223:            oip->i_size < ovp->v_mount->mnt_maxsymlinklen) {
                    224: #if DIAGNOSTIC
                    225:                if (length != 0)
                    226:                        panic("ffs_truncate: partial truncate of symlink");
                    227: #endif
                    228:                bzero((char *)&oip->i_shortlink, (u_int)oip->i_size);
                    229:                oip->i_size = 0;
                    230:                oip->i_flag |= IN_CHANGE | IN_UPDATE;
                    231: #if MACH_NBC
                    232:                error = mapfs_trunc(ovp, (vm_offset_t)0);
                    233:                if (error)
                    234:                        return (error);
                    235: #endif /* MACH_NBC */
                    236: /* needs to be present till Unified buffer cache implementaiton */
                    237:                ubc_truncate(ovp, (vm_offset_t)0);
                    238: 
                    239:                return (VOP_UPDATE(ovp, &tv, &tv, 1));
                    240:        }
                    241: 
                    242: #if MACH_NBC
                    243:        error = mapfs_trunc(ovp, (vm_offset_t)length);
                    244:        if (error)
                    245:                return (error);
                    246: #endif /* MACH_NBC */
                    247: /* this needs to be present till Unified buffer cache implementaiton */
                    248:        ubc_truncate(ovp, (vm_offset_t)length);
                    249: 
                    250: 
                    251:        if (oip->i_size == length) {
                    252:                oip->i_flag |= IN_CHANGE | IN_UPDATE;
                    253:                return (VOP_UPDATE(ovp, &tv, &tv, 0));
                    254:        }
                    255: #if QUOTA
                    256:        if (error = getinoquota(oip))
                    257:                return (error);
                    258: #endif
                    259:        osize = oip->i_size;
                    260: 
                    261:        /*
                    262:         * Lengthen the size of the file. We must ensure that the
                    263:         * last byte of the file is allocated. Since the smallest
                    264:         * value of osize is 0, length will be at least 1.
                    265:         */
                    266:        if (osize < length) {
                    267:                offset = blkoff(fs, length - 1);
                    268:                lbn = lblkno(fs, length - 1);
                    269:                aflags = B_CLRBUF;
                    270:                if (ap->a_flags & IO_SYNC)
                    271:                        aflags |= B_SYNC;
                    272:                if (error = ffs_balloc(oip, lbn, offset + 1, ap->a_cred, &bp,
                    273:                    aflags))
                    274:                        return (error);
                    275:                oip->i_size = length;
                    276: #if MACH_NBC
                    277:                if ((ovp->v_type == VREG) && (ovp->v_vm_info && !(ovp->v_vm_info->mapped))) {
                    278: #endif /* MACH_NBC */
                    279:                vnode_pager_setsize(ovp, (u_long)length);
                    280:                vnode_uncache(ovp);
                    281: #if MACH_NBC
                    282:                }
                    283: #endif /* !MACH_NBC */
                    284:                if (aflags & B_SYNC)
                    285:                        bwrite(bp);
                    286:                else
                    287:                        bawrite(bp);
                    288:                oip->i_flag |= IN_CHANGE | IN_UPDATE;
                    289:                return (VOP_UPDATE(ovp, &tv, &tv, 1));
                    290:        }
                    291:        /*
                    292:         * Shorten the size of the file. If the file is not being
                    293:         * truncated to a block boundry, the contents of the
                    294:         * partial block following the end of the file must be
                    295:         * zero'ed in case it ever become accessable again because
                    296:         * of subsequent file growth.
                    297:         */
                    298:        offset = blkoff(fs, length);
                    299:        if (offset == 0) {
                    300:                oip->i_size = length;
                    301:        } else {
                    302:                lbn = lblkno(fs, length);
                    303:                aflags = B_CLRBUF;
                    304:                if (ap->a_flags & IO_SYNC)
                    305:                        aflags |= B_SYNC;
                    306:                if (error = ffs_balloc(oip, lbn, offset, ap->a_cred, &bp,
                    307:                    aflags))
                    308:                        return (error);
                    309:                oip->i_size = length;
                    310:                size = blksize(fs, oip, lbn);
                    311:                (void) vnode_uncache(ovp); /* Ignore errors! */
                    312:                bzero((char *)bp->b_data + offset, (u_int)(size - offset));
                    313:                allocbuf(bp, size);
                    314:                if (aflags & B_SYNC)
                    315:                        bwrite(bp);
                    316:                else
                    317:                        bawrite(bp);
                    318:        }
                    319: #if MACH_NBC
                    320:        if ((ovp->v_type == VREG) && (ovp->v_vm_info && !(ovp->v_vm_info->mapped))) {
                    321: #endif /* MACH_NBC */
                    322:                vnode_pager_setsize(ovp, (u_long)length);
                    323: #if MACH_NBC
                    324:        }
                    325: #endif /* MACH_NBC */
                    326: 
                    327:        /*
                    328:         * Calculate index into inode's block list of
                    329:         * last direct and indirect blocks (if any)
                    330:         * which we want to keep.  Lastblock is -1 when
                    331:         * the file is truncated to 0.
                    332:         */
                    333:        lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
                    334:        lastiblock[SINGLE] = lastblock - NDADDR;
                    335:        lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
                    336:        lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
                    337: #ifdef NeXT
                    338:        VOP_DEVBLOCKSIZE(oip->i_devvp,&devBlockSize);
                    339:        nblocks = btodb(fs->fs_bsize, devBlockSize);
                    340: #else
                    341:        nblocks = btodb(fs->fs_bsize);
                    342: #endif /* NeXT */
                    343:        /*
                    344:         * Update file and block pointers on disk before we start freeing
                    345:         * blocks.  If we crash before free'ing blocks below, the blocks
                    346:         * will be returned to the free list.  lastiblock values are also
                    347:         * normalized to -1 for calls to ffs_indirtrunc below.
                    348:         */
                    349:        bcopy((caddr_t)&oip->i_db[0], (caddr_t)oldblks, sizeof oldblks);
                    350:        for (level = TRIPLE; level >= SINGLE; level--)
                    351:                if (lastiblock[level] < 0) {
                    352:                        oip->i_ib[level] = 0;
                    353:                        lastiblock[level] = -1;
                    354:                }
                    355:        for (i = NDADDR - 1; i > lastblock; i--)
                    356:                oip->i_db[i] = 0;
                    357:        oip->i_flag |= IN_CHANGE | IN_UPDATE;
                    358:        if (error = VOP_UPDATE(ovp, &tv, &tv, MNT_WAIT))
                    359:                allerror = error;
                    360:        /*
                    361:         * Having written the new inode to disk, save its new configuration
                    362:         * and put back the old block pointers long enough to process them.
                    363:         * Note that we save the new block configuration so we can check it
                    364:         * when we are done.
                    365:         */
                    366:        bcopy((caddr_t)&oip->i_db[0], (caddr_t)newblks, sizeof newblks);
                    367:        bcopy((caddr_t)oldblks, (caddr_t)&oip->i_db[0], sizeof oldblks);
                    368:        oip->i_size = osize;
                    369:        vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
                    370:        allerror = vinvalbuf(ovp, vflags, ap->a_cred, ap->a_p, 0, 0);
                    371: 
                    372:        /*
                    373:         * Indirect blocks first.
                    374:         */
                    375:        indir_lbn[SINGLE] = -NDADDR;
                    376:        indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
                    377:        indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
                    378:        for (level = TRIPLE; level >= SINGLE; level--) {
                    379:                bn = oip->i_ib[level];
                    380:                if (bn != 0) {
                    381:                        error = ffs_indirtrunc(oip, indir_lbn[level],
                    382:                            fsbtodb(fs, bn), lastiblock[level], level, &count);
                    383:                        if (error)
                    384:                                allerror = error;
                    385:                        blocksreleased += count;
                    386:                        if (lastiblock[level] < 0) {
                    387:                                oip->i_ib[level] = 0;
                    388:                                ffs_blkfree(oip, bn, fs->fs_bsize);
                    389:                                blocksreleased += nblocks;
                    390:                        }
                    391:                }
                    392:                if (lastiblock[level] >= 0)
                    393:                        goto done;
                    394:        }
                    395: 
                    396:        /*
                    397:         * All whole direct blocks or frags.
                    398:         */
                    399:        for (i = NDADDR - 1; i > lastblock; i--) {
                    400:                register long bsize;
                    401: 
                    402:                bn = oip->i_db[i];
                    403:                if (bn == 0)
                    404:                        continue;
                    405:                oip->i_db[i] = 0;
                    406:                bsize = blksize(fs, oip, i);
                    407:                ffs_blkfree(oip, bn, bsize);
                    408: #ifdef NeXT
                    409:                blocksreleased += btodb(bsize, devBlockSize);
                    410: #else
                    411:                blocksreleased += btodb(bsize);
                    412: #endif /* NeXT */
                    413:        }
                    414:        if (lastblock < 0)
                    415:                goto done;
                    416: 
                    417:        /*
                    418:         * Finally, look for a change in size of the
                    419:         * last direct block; release any frags.
                    420:         */
                    421:        bn = oip->i_db[lastblock];
                    422:        if (bn != 0) {
                    423:                long oldspace, newspace;
                    424: 
                    425:                /*
                    426:                 * Calculate amount of space we're giving
                    427:                 * back as old block size minus new block size.
                    428:                 */
                    429:                oldspace = blksize(fs, oip, lastblock);
                    430:                oip->i_size = length;
                    431:                newspace = blksize(fs, oip, lastblock);
                    432:                if (newspace == 0)
                    433:                        panic("itrunc: newspace");
                    434:                if (oldspace - newspace > 0) {
                    435:                        /*
                    436:                         * Block number of space to be free'd is
                    437:                         * the old block # plus the number of frags
                    438:                         * required for the storage we're keeping.
                    439:                         */
                    440:                        bn += numfrags(fs, newspace);
                    441:                        ffs_blkfree(oip, bn, oldspace - newspace);
                    442: #ifdef NeXT
                    443:                        blocksreleased += btodb(oldspace - newspace, devBlockSize);
                    444: #else
                    445:                        blocksreleased += btodb(oldspace - newspace);
                    446: #endif /* NeXT */
                    447:                }
                    448:        }
                    449: done:
                    450: #if DIAGNOSTIC
                    451:        for (level = SINGLE; level <= TRIPLE; level++)
                    452:                if (newblks[NDADDR + level] != oip->i_ib[level])
                    453:                        panic("itrunc1");
                    454:        for (i = 0; i < NDADDR; i++)
                    455:                if (newblks[i] != oip->i_db[i])
                    456:                        panic("itrunc2");
                    457:        if (length == 0 &&
                    458:            (ovp->v_dirtyblkhd.lh_first || ovp->v_cleanblkhd.lh_first))
                    459:                panic("itrunc3");
                    460: #endif /* DIAGNOSTIC */
                    461:        /*
                    462:         * Put back the real size.
                    463:         */
                    464:        oip->i_size = length;
                    465:        oip->i_blocks -= blocksreleased;
                    466:        if (oip->i_blocks < 0)                  /* sanity */
                    467:                oip->i_blocks = 0;
                    468:        oip->i_flag |= IN_CHANGE;
                    469: #if QUOTA
                    470:        (void) chkdq(oip, -blocksreleased, NOCRED, 0);
                    471: #endif
                    472:        return (allerror);
                    473: }
                    474: 
                    475: /*
                    476:  * Release blocks associated with the inode ip and stored in the indirect
                    477:  * block bn.  Blocks are free'd in LIFO order up to (but not including)
                    478:  * lastbn.  If level is greater than SINGLE, the block is an indirect block
                    479:  * and recursive calls to indirtrunc must be used to cleanse other indirect
                    480:  * blocks.
                    481:  *
                    482:  * NB: triple indirect blocks are untested.
                    483:  */
                    484: static int
                    485: ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
                    486:        register struct inode *ip;
                    487:        ufs_daddr_t lbn, lastbn;
                    488:        ufs_daddr_t dbn;
                    489:        int level;
                    490:        long *countp;
                    491: {
                    492:        register int i;
                    493:        struct buf *bp;
                    494:        struct buf *tbp;
                    495:        register struct fs *fs = ip->i_fs;
                    496:        register ufs_daddr_t *bap;
                    497:        struct vnode *vp=ITOV(ip);
                    498:        ufs_daddr_t *copy, nb, nlbn, last;
                    499:        long blkcount, factor;
                    500:        int nblocks, blocksreleased = 0;
                    501:        int error = 0, allerror = 0;
                    502: #if NeXT
                    503:        int devBlockSize=0;
                    504: #endif /* NeXT */
                    505: #if REV_ENDIAN_FS
                    506:        struct mount *mp=vp->v_mount;
                    507:        int rev_endian=(mp->mnt_flag & MNT_REVEND);
                    508: #endif /* REV_ENDIAN_FS */
                    509: 
                    510:        /*
                    511:         * Calculate index in current block of last
                    512:         * block to be kept.  -1 indicates the entire
                    513:         * block so we need not calculate the index.
                    514:         */
                    515:        factor = 1;
                    516:        for (i = SINGLE; i < level; i++)
                    517:                factor *= NINDIR(fs);
                    518:        last = lastbn;
                    519:        if (lastbn > 0)
                    520:                last /= factor;
                    521: #if NeXT
                    522:        VOP_DEVBLOCKSIZE(ip->i_devvp,&devBlockSize);
                    523:        nblocks = btodb(fs->fs_bsize, devBlockSize);
                    524: #else
                    525:        nblocks = btodb(fs->fs_bsize);
                    526: #endif /* NeXT */
                    527: 
                    528:        /* Doing a MALLOC here is asking for trouble. We can still
                    529:         * deadlock on pagerfile lock, in case we are running
                    530:         * low on memory and block in MALLOC
                    531:         */
                    532: 
                    533:        tbp = geteblk(fs->fs_bsize);
                    534:        copy = (ufs_daddr_t *)tbp->b_data;
                    535: 
                    536:        /*
                    537:         * Get buffer of block pointers, zero those entries corresponding
                    538:         * to blocks to be free'd, and update on disk copy first.  Since
                    539:         * double(triple) indirect before single(double) indirect, calls
                    540:         * to bmap on these blocks will fail.  However, we already have
                    541:         * the on disk address, so we have to set the b_blkno field
                    542:         * explicitly instead of letting bread do everything for us.
                    543:         */
                    544: 
                    545:        vp = ITOV(ip);
                    546:        bp = getblk(vp, lbn, (int)fs->fs_bsize, 0, 0);
                    547:        if (bp->b_flags & (B_DONE | B_DELWRI)) {
                    548:                /* Braces must be here in case trace evaluates to nothing. */
                    549:                trace(TR_BREADHIT, pack(vp, fs->fs_bsize), lbn);
                    550:        } else {
                    551:                trace(TR_BREADMISS, pack(vp, fs->fs_bsize), lbn);
                    552:                current_proc()->p_stats->p_ru.ru_inblock++;     /* pay for read */
                    553:                bp->b_flags |= B_READ;
                    554:                if (bp->b_bcount > bp->b_bufsize)
                    555:                        panic("ffs_indirtrunc: bad buffer size");
                    556:                bp->b_blkno = dbn;
                    557:                VOP_STRATEGY(bp);
                    558:                error = biowait(bp);
                    559:        }
                    560:        if (error) {
                    561:                brelse(bp);
                    562:                *countp = 0;
                    563:                brelse(tbp);
                    564:                return (error);
                    565:        }
                    566: 
                    567:        bap = (ufs_daddr_t *)bp->b_data;
                    568:        bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize);
                    569:        bzero((caddr_t)&bap[last + 1],
                    570:          (u_int)(NINDIR(fs) - (last + 1)) * sizeof (ufs_daddr_t));
                    571:        if (last == -1)
                    572:                bp->b_flags |= B_INVAL;
                    573:        error = bwrite(bp);
                    574:        if (error)
                    575:                allerror = error;
                    576:        bap = copy;
                    577: 
                    578:        /*
                    579:         * Recursively free totally unused blocks.
                    580:         */
                    581:        for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
                    582:            i--, nlbn += factor) {
                    583: #if    REV_ENDIAN_FS
                    584:                if (rev_endian)
                    585:                        nb = NXSwapLong(bap[i]);
                    586:                else {
                    587: #endif /* REV_ENDIAN_FS */
                    588:                        nb = bap[i];
                    589: #if    REV_ENDIAN_FS
                    590:                }
                    591: #endif /* REV_ENDIAN_FS */
                    592:                if (nb == 0)
                    593:                        continue;
                    594:                if (level > SINGLE) {
                    595:                        if (error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
                    596:                            (ufs_daddr_t)-1, level - 1, &blkcount))
                    597:                                allerror = error;
                    598:                        blocksreleased += blkcount;
                    599:                }
                    600:                ffs_blkfree(ip, nb, fs->fs_bsize);
                    601:                blocksreleased += nblocks;
                    602:        }
                    603: 
                    604:        /*
                    605:         * Recursively free last partial block.
                    606:         */
                    607:        if (level > SINGLE && lastbn >= 0) {
                    608:                last = lastbn % factor;
                    609: #if    REV_ENDIAN_FS
                    610:                if (rev_endian)
                    611:                        nb = NXSwapLong(bap[i]);
                    612:                else {
                    613: #endif /* REV_ENDIAN_FS */
                    614:                        nb = bap[i];
                    615: #if    REV_ENDIAN_FS
                    616:                }
                    617: #endif /* REV_ENDIAN_FS */
                    618:                if (nb != 0) {
                    619:                        if (error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
                    620:                            last, level - 1, &blkcount))
                    621:                                allerror = error;
                    622:                        blocksreleased += blkcount;
                    623:                }
                    624:        }
                    625:        brelse(tbp);
                    626:        *countp = blocksreleased;
                    627:        return (allerror);
                    628: }
                    629: 

unix.superglobalmegacorp.com

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