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

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

unix.superglobalmegacorp.com

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