[BACK]Return to ffs_inode.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / ufs / ffs

Annotation of src/sys/ufs/ffs/ffs_inode.c, Revision 1.24.2.3

1.24.2.3! chs         1: /*     $NetBSD: ffs_inode.c,v 1.24.2.2 1999/02/25 04:03:31 chs Exp $   */
1.5       cgd         2:
1.1       mycroft     3: /*
                      4:  * Copyright (c) 1982, 1986, 1989, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by the University of
                     18:  *     California, Berkeley and its contributors.
                     19:  * 4. Neither the name of the University nor the names of its contributors
                     20:  *    may be used to endorse or promote products derived from this software
                     21:  *    without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  *
1.18      fvdl       35:  *     @(#)ffs_inode.c 8.13 (Berkeley) 4/21/95
1.1       mycroft    36:  */
1.17      mrg        37:
1.21      scottr     38: #if defined(_KERNEL) && !defined(_LKM)
1.20      scottr     39: #include "opt_quota.h"
1.17      mrg        40: #include "opt_uvm.h"
1.21      scottr     41: #endif
1.1       mycroft    42:
                     43: #include <sys/param.h>
                     44: #include <sys/systm.h>
                     45: #include <sys/mount.h>
                     46: #include <sys/proc.h>
                     47: #include <sys/file.h>
                     48: #include <sys/buf.h>
                     49: #include <sys/vnode.h>
                     50: #include <sys/kernel.h>
                     51: #include <sys/malloc.h>
                     52: #include <sys/trace.h>
                     53: #include <sys/resourcevar.h>
                     54:
                     55: #include <vm/vm.h>
                     56:
1.16      mrg        57: #if defined(UVM)
                     58: #include <uvm/uvm_extern.h>
                     59: #endif
                     60:
1.1       mycroft    61: #include <ufs/ufs/quota.h>
                     62: #include <ufs/ufs/inode.h>
                     63: #include <ufs/ufs/ufsmount.h>
                     64: #include <ufs/ufs/ufs_extern.h>
1.19      bouyer     65: #include <ufs/ufs/ufs_bswap.h>
1.1       mycroft    66:
                     67: #include <ufs/ffs/fs.h>
                     68: #include <ufs/ffs/ffs_extern.h>
                     69:
1.18      fvdl       70: static int ffs_indirtrunc __P((struct inode *, ufs_daddr_t, ufs_daddr_t,
                     71:                               ufs_daddr_t, int, long *));
1.1       mycroft    72:
                     73: /*
1.13      tls        74:  * Update the access, modified, and inode change times as specified
                     75:  * by the IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively.
                     76:  * The IN_MODIFIED flag is used to specify that the inode needs to be
                     77:  * updated but that the times have already been set. The access
                     78:  * and modified times are taken from the second and third parameters;
                     79:  * the inode change time is always taken from the current time. If
                     80:  * waitfor is set, then wait for the disk write of the inode to
1.1       mycroft    81:  * complete.
                     82:  */
1.13      tls        83:
1.1       mycroft    84: int
1.9       christos   85: ffs_update(v)
                     86:        void *v;
                     87: {
1.1       mycroft    88:        struct vop_update_args /* {
                     89:                struct vnode *a_vp;
1.10      mycroft    90:                struct timespec *a_access;
                     91:                struct timespec *a_modify;
1.1       mycroft    92:                int a_waitfor;
1.9       christos   93:        } */ *ap = v;
1.1       mycroft    94:        register struct fs *fs;
                     95:        struct buf *bp;
                     96:        struct inode *ip;
                     97:        int error;
1.11      mycroft    98:        struct timespec ts;
1.24      thorpej    99:        caddr_t cp;
1.1       mycroft   100:
1.11      mycroft   101:        if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
                    102:                return (0);
1.1       mycroft   103:        ip = VTOI(ap->a_vp);
1.11      mycroft   104:        TIMEVAL_TO_TIMESPEC(&time, &ts);
1.14      bouyer    105:        FFS_ITIMES(ip, ap->a_access, ap->a_modify, &ts);
1.11      mycroft   106:        if ((ip->i_flag & IN_MODIFIED) == 0)
1.1       mycroft   107:                return (0);
1.11      mycroft   108:        ip->i_flag &= ~IN_MODIFIED;
1.1       mycroft   109:        fs = ip->i_fs;
                    110:        /*
                    111:         * Ensure that uid and gid are correct. This is a temporary
                    112:         * fix until fsck has been changed to do the update.
                    113:         */
1.18      fvdl      114:        if (fs->fs_inodefmt < FS_44INODEFMT) {                  /* XXX */
                    115:                ip->i_din.ffs_din.di_ouid = ip->i_ffs_uid;      /* XXX */
                    116:                ip->i_din.ffs_din.di_ogid = ip->i_ffs_gid;      /* XXX */
                    117:        }                                                       /* XXX */
1.9       christos  118:        error = bread(ip->i_devvp,
                    119:                      fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
                    120:                      (int)fs->fs_bsize, NOCRED, &bp);
                    121:        if (error) {
1.1       mycroft   122:                brelse(bp);
                    123:                return (error);
                    124:        }
1.24      thorpej   125:        cp = (caddr_t)bp->b_data +
                    126:            (ino_to_fsbo(fs, ip->i_number) * DINODE_SIZE);
1.23      christos  127: #ifdef FFS_EI
1.19      bouyer    128:        if (UFS_MPNEEDSWAP(ap->a_vp->v_mount))
1.24      thorpej   129:                ffs_dinode_swap(&ip->i_din.ffs_din, (struct dinode *)cp);
1.19      bouyer    130:        else
1.23      christos  131: #endif
1.24      thorpej   132:                memcpy(cp, &ip->i_din.ffs_din, DINODE_SIZE);
1.18      fvdl      133:        if (ap->a_waitfor && (ap->a_vp->v_mount->mnt_flag & MNT_ASYNC) == 0)
1.1       mycroft   134:                return (bwrite(bp));
                    135:        else {
                    136:                bdwrite(bp);
                    137:                return (0);
                    138:        }
                    139: }
                    140:
                    141: #define        SINGLE  0       /* index of single indirect block */
                    142: #define        DOUBLE  1       /* index of double indirect block */
                    143: #define        TRIPLE  2       /* index of triple indirect block */
                    144: /*
                    145:  * Truncate the inode oip to at most length size, freeing the
                    146:  * disk blocks.
                    147:  */
1.9       christos  148: int
                    149: ffs_truncate(v)
                    150:        void *v;
                    151: {
1.1       mycroft   152:        struct vop_truncate_args /* {
                    153:                struct vnode *a_vp;
                    154:                off_t a_length;
                    155:                int a_flags;
                    156:                struct ucred *a_cred;
                    157:                struct proc *a_p;
1.9       christos  158:        } */ *ap = v;
1.1       mycroft   159:        register struct vnode *ovp = ap->a_vp;
1.18      fvdl      160:        register ufs_daddr_t lastblock;
1.1       mycroft   161:        register struct inode *oip;
1.18      fvdl      162:        ufs_daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
                    163:        ufs_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
1.1       mycroft   164:        off_t length = ap->a_length;
                    165:        register struct fs *fs;
                    166:        struct buf *bp;
                    167:        int offset, size, level;
                    168:        long count, nblocks, vflags, blocksreleased = 0;
1.10      mycroft   169:        struct timespec ts;
1.1       mycroft   170:        register int i;
                    171:        int aflags, error, allerror;
                    172:        off_t osize;
                    173:
1.2       pk        174:        if (length < 0)
1.3       mycroft   175:                return (EINVAL);
1.1       mycroft   176:        oip = VTOI(ovp);
1.10      mycroft   177:        TIMEVAL_TO_TIMESPEC(&time, &ts);
1.1       mycroft   178:        if (ovp->v_type == VLNK &&
1.14      bouyer    179:            (oip->i_ffs_size < ovp->v_mount->mnt_maxsymlinklen ||
1.4       mycroft   180:             (ovp->v_mount->mnt_maxsymlinklen == 0 &&
1.14      bouyer    181:              oip->i_din.ffs_din.di_blocks == 0))) {
1.1       mycroft   182: #ifdef DIAGNOSTIC
                    183:                if (length != 0)
                    184:                        panic("ffs_truncate: partial truncate of symlink");
                    185: #endif
1.22      perry     186:                memset((char *)&oip->i_ffs_shortlink, 0, (u_int)oip->i_ffs_size);
1.14      bouyer    187:                oip->i_ffs_size = 0;
1.1       mycroft   188:                oip->i_flag |= IN_CHANGE | IN_UPDATE;
1.10      mycroft   189:                return (VOP_UPDATE(ovp, &ts, &ts, 1));
1.1       mycroft   190:        }
1.14      bouyer    191:        if (oip->i_ffs_size == length) {
1.1       mycroft   192:                oip->i_flag |= IN_CHANGE | IN_UPDATE;
1.10      mycroft   193:                return (VOP_UPDATE(ovp, &ts, &ts, 0));
1.1       mycroft   194:        }
                    195: #ifdef QUOTA
1.9       christos  196:        if ((error = getinoquota(oip)) != 0)
1.1       mycroft   197:                return (error);
                    198: #endif
                    199:        fs = oip->i_fs;
1.14      bouyer    200:        osize = oip->i_ffs_size;
1.18      fvdl      201:        ovp->v_lasta = ovp->v_clen = ovp->v_cstart = ovp->v_lastw = 0;
1.1       mycroft   202:        /*
                    203:         * Lengthen the size of the file. We must ensure that the
                    204:         * last byte of the file is allocated. Since the smallest
1.6       mycroft   205:         * value of osize is 0, length will be at least 1.
1.1       mycroft   206:         */
1.24.2.2  chs       207:        /*
                    208:         * XXXCHS why must the last byte of the file be allocated?
                    209:         * this seems bogus.
                    210:         */
1.1       mycroft   211:        if (osize < length) {
1.6       mycroft   212:                if (length > fs->fs_maxfilesize)
                    213:                        return (EFBIG);
1.24.2.2  chs       214: #ifdef UBC
                    215:                aflags = 0;
                    216:                bp = 0;
                    217: #else
1.1       mycroft   218:                offset = blkoff(fs, length - 1);
                    219:                lbn = lblkno(fs, length - 1);
                    220:                aflags = B_CLRBUF;
                    221:                if (ap->a_flags & IO_SYNC)
                    222:                        aflags |= B_SYNC;
1.24.2.2  chs       223:                error = ffs_balloc(oip, lbn, offset + 1, ap->a_cred, &bp, NULL,
1.24.2.3! chs       224:                                   aflags);
1.9       christos  225:                if (error)
1.1       mycroft   226:                        return (error);
1.24.2.2  chs       227: #endif
1.14      bouyer    228:                oip->i_ffs_size = length;
1.16      mrg       229: #if defined(UVM)
1.18      fvdl      230:                uvm_vnp_setsize(ovp, length);
1.16      mrg       231:                (void) uvm_vnp_uncache(ovp);
                    232: #else
1.18      fvdl      233:                vnode_pager_setsize(ovp, length);
1.1       mycroft   234:                (void) vnode_pager_uncache(ovp);
1.16      mrg       235: #endif
1.24.2.1  chs       236: #ifdef UBC
                    237: #else
1.1       mycroft   238:                if (aflags & B_SYNC)
                    239:                        bwrite(bp);
                    240:                else
                    241:                        bawrite(bp);
1.24.2.1  chs       242: #endif
1.1       mycroft   243:                oip->i_flag |= IN_CHANGE | IN_UPDATE;
1.10      mycroft   244:                return (VOP_UPDATE(ovp, &ts, &ts, 1));
1.1       mycroft   245:        }
                    246:        /*
                    247:         * Shorten the size of the file. If the file is not being
                    248:         * truncated to a block boundry, the contents of the
                    249:         * partial block following the end of the file must be
                    250:         * zero'ed in case it ever become accessable again because
                    251:         * of subsequent file growth.
                    252:         */
                    253:        offset = blkoff(fs, length);
                    254:        if (offset == 0) {
1.14      bouyer    255:                oip->i_ffs_size = length;
1.1       mycroft   256:        } else {
1.24.2.3! chs       257:                lbn = lblkno(fs, length);
1.24.2.2  chs       258: #ifdef UBC
                    259: #else
1.1       mycroft   260:                aflags = B_CLRBUF;
                    261:                if (ap->a_flags & IO_SYNC)
                    262:                        aflags |= B_SYNC;
1.24.2.2  chs       263:                error = ffs_balloc(oip, lbn, offset, ap->a_cred, &bp, NULL,
1.24.2.3! chs       264:                                   aflags);
1.9       christos  265:                if (error)
1.1       mycroft   266:                        return (error);
1.24.2.2  chs       267: #endif
1.14      bouyer    268:                oip->i_ffs_size = length;
1.1       mycroft   269:                size = blksize(fs, oip, lbn);
1.16      mrg       270: #if defined(UVM)
                    271:                (void) uvm_vnp_uncache(ovp);
                    272: #else
1.1       mycroft   273:                (void) vnode_pager_uncache(ovp);
1.16      mrg       274: #endif
1.24.2.2  chs       275: #ifdef UBC
                    276:                uvm_vnp_zerorange(ovp, oip->i_ffs_size, size - offset);
                    277: #else
1.22      perry     278:                memset((char *)bp->b_data + offset, 0,  (u_int)(size - offset));
1.1       mycroft   279:                allocbuf(bp, size);
                    280:                if (aflags & B_SYNC)
                    281:                        bwrite(bp);
                    282:                else
                    283:                        bawrite(bp);
1.24.2.2  chs       284: #endif
1.1       mycroft   285:        }
1.18      fvdl      286: #if defined(UVM)
                    287:        uvm_vnp_setsize(ovp, length);
                    288: #else
                    289:        vnode_pager_setsize(ovp, length);
                    290: #endif
1.1       mycroft   291:        /*
                    292:         * Calculate index into inode's block list of
                    293:         * last direct and indirect blocks (if any)
                    294:         * which we want to keep.  Lastblock is -1 when
                    295:         * the file is truncated to 0.
                    296:         */
                    297:        lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
                    298:        lastiblock[SINGLE] = lastblock - NDADDR;
                    299:        lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
                    300:        lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
                    301:        nblocks = btodb(fs->fs_bsize);
                    302:        /*
                    303:         * Update file and block pointers on disk before we start freeing
                    304:         * blocks.  If we crash before free'ing blocks below, the blocks
                    305:         * will be returned to the free list.  lastiblock values are also
                    306:         * normalized to -1 for calls to ffs_indirtrunc below.
                    307:         */
1.22      perry     308:        memcpy((caddr_t)oldblks, (caddr_t)&oip->i_ffs_db[0], sizeof oldblks);
1.1       mycroft   309:        for (level = TRIPLE; level >= SINGLE; level--)
                    310:                if (lastiblock[level] < 0) {
1.14      bouyer    311:                        oip->i_ffs_ib[level] = 0;
1.1       mycroft   312:                        lastiblock[level] = -1;
                    313:                }
                    314:        for (i = NDADDR - 1; i > lastblock; i--)
1.14      bouyer    315:                oip->i_ffs_db[i] = 0;
1.1       mycroft   316:        oip->i_flag |= IN_CHANGE | IN_UPDATE;
1.10      mycroft   317:        if ((error = VOP_UPDATE(ovp, &ts, &ts, 1)) != 0)
1.1       mycroft   318:                allerror = error;
                    319:        /*
                    320:         * Having written the new inode to disk, save its new configuration
                    321:         * and put back the old block pointers long enough to process them.
                    322:         * Note that we save the new block configuration so we can check it
                    323:         * when we are done.
                    324:         */
1.22      perry     325:        memcpy((caddr_t)newblks, (caddr_t)&oip->i_ffs_db[0], sizeof newblks);
                    326:        memcpy((caddr_t)&oip->i_ffs_db[0], (caddr_t)oldblks, sizeof oldblks);
1.14      bouyer    327:        oip->i_ffs_size = osize;
1.1       mycroft   328:        vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
                    329:        allerror = vinvalbuf(ovp, vflags, ap->a_cred, ap->a_p, 0, 0);
                    330:
                    331:        /*
                    332:         * Indirect blocks first.
                    333:         */
                    334:        indir_lbn[SINGLE] = -NDADDR;
                    335:        indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
                    336:        indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
                    337:        for (level = TRIPLE; level >= SINGLE; level--) {
1.19      bouyer    338:                bn = ufs_rw32(oip->i_ffs_ib[level], UFS_MPNEEDSWAP(ovp->v_mount));
1.1       mycroft   339:                if (bn != 0) {
                    340:                        error = ffs_indirtrunc(oip, indir_lbn[level],
                    341:                            fsbtodb(fs, bn), lastiblock[level], level, &count);
                    342:                        if (error)
                    343:                                allerror = error;
                    344:                        blocksreleased += count;
                    345:                        if (lastiblock[level] < 0) {
1.14      bouyer    346:                                oip->i_ffs_ib[level] = 0;
1.1       mycroft   347:                                ffs_blkfree(oip, bn, fs->fs_bsize);
                    348:                                blocksreleased += nblocks;
                    349:                        }
                    350:                }
                    351:                if (lastiblock[level] >= 0)
                    352:                        goto done;
                    353:        }
                    354:
                    355:        /*
                    356:         * All whole direct blocks or frags.
                    357:         */
                    358:        for (i = NDADDR - 1; i > lastblock; i--) {
                    359:                register long bsize;
                    360:
1.19      bouyer    361:                bn = ufs_rw32(oip->i_ffs_db[i], UFS_MPNEEDSWAP(ovp->v_mount));
1.1       mycroft   362:                if (bn == 0)
                    363:                        continue;
1.14      bouyer    364:                oip->i_ffs_db[i] = 0;
1.1       mycroft   365:                bsize = blksize(fs, oip, i);
                    366:                ffs_blkfree(oip, bn, bsize);
                    367:                blocksreleased += btodb(bsize);
                    368:        }
                    369:        if (lastblock < 0)
                    370:                goto done;
                    371:
                    372:        /*
                    373:         * Finally, look for a change in size of the
                    374:         * last direct block; release any frags.
                    375:         */
1.19      bouyer    376:        bn = ufs_rw32(oip->i_ffs_db[lastblock], UFS_MPNEEDSWAP(ovp->v_mount));
1.1       mycroft   377:        if (bn != 0) {
                    378:                long oldspace, newspace;
                    379:
                    380:                /*
                    381:                 * Calculate amount of space we're giving
                    382:                 * back as old block size minus new block size.
                    383:                 */
                    384:                oldspace = blksize(fs, oip, lastblock);
1.14      bouyer    385:                oip->i_ffs_size = length;
1.1       mycroft   386:                newspace = blksize(fs, oip, lastblock);
                    387:                if (newspace == 0)
                    388:                        panic("itrunc: newspace");
                    389:                if (oldspace - newspace > 0) {
                    390:                        /*
                    391:                         * Block number of space to be free'd is
                    392:                         * the old block # plus the number of frags
                    393:                         * required for the storage we're keeping.
                    394:                         */
                    395:                        bn += numfrags(fs, newspace);
                    396:                        ffs_blkfree(oip, bn, oldspace - newspace);
                    397:                        blocksreleased += btodb(oldspace - newspace);
                    398:                }
                    399:        }
                    400: done:
                    401: #ifdef DIAGNOSTIC
                    402:        for (level = SINGLE; level <= TRIPLE; level++)
1.14      bouyer    403:                if (newblks[NDADDR + level] != oip->i_ffs_ib[level])
1.1       mycroft   404:                        panic("itrunc1");
                    405:        for (i = 0; i < NDADDR; i++)
1.14      bouyer    406:                if (newblks[i] != oip->i_ffs_db[i])
1.1       mycroft   407:                        panic("itrunc2");
                    408:        if (length == 0 &&
                    409:            (ovp->v_dirtyblkhd.lh_first || ovp->v_cleanblkhd.lh_first))
                    410:                panic("itrunc3");
                    411: #endif /* DIAGNOSTIC */
                    412:        /*
                    413:         * Put back the real size.
                    414:         */
1.14      bouyer    415:        oip->i_ffs_size = length;
                    416:        oip->i_ffs_blocks -= blocksreleased;
                    417:        if (oip->i_ffs_blocks < 0)                      /* sanity */
                    418:                oip->i_ffs_blocks = 0;
1.1       mycroft   419:        oip->i_flag |= IN_CHANGE;
                    420: #ifdef QUOTA
                    421:        (void) chkdq(oip, -blocksreleased, NOCRED, 0);
                    422: #endif
                    423:        return (allerror);
                    424: }
                    425:
                    426: /*
                    427:  * Release blocks associated with the inode ip and stored in the indirect
                    428:  * block bn.  Blocks are free'd in LIFO order up to (but not including)
                    429:  * lastbn.  If level is greater than SINGLE, the block is an indirect block
                    430:  * and recursive calls to indirtrunc must be used to cleanse other indirect
                    431:  * blocks.
                    432:  *
                    433:  * NB: triple indirect blocks are untested.
                    434:  */
                    435: static int
                    436: ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp)
                    437:        register struct inode *ip;
1.18      fvdl      438:        ufs_daddr_t lbn, lastbn;
                    439:        ufs_daddr_t dbn;
1.1       mycroft   440:        int level;
                    441:        long *countp;
                    442: {
                    443:        register int i;
                    444:        struct buf *bp;
                    445:        register struct fs *fs = ip->i_fs;
1.18      fvdl      446:        register ufs_daddr_t *bap;
1.1       mycroft   447:        struct vnode *vp;
1.18      fvdl      448:        ufs_daddr_t *copy = NULL, nb, nlbn, last;
1.1       mycroft   449:        long blkcount, factor;
                    450:        int nblocks, blocksreleased = 0;
                    451:        int error = 0, allerror = 0;
                    452:
                    453:        /*
                    454:         * Calculate index in current block of last
                    455:         * block to be kept.  -1 indicates the entire
                    456:         * block so we need not calculate the index.
                    457:         */
                    458:        factor = 1;
                    459:        for (i = SINGLE; i < level; i++)
                    460:                factor *= NINDIR(fs);
                    461:        last = lastbn;
                    462:        if (lastbn > 0)
                    463:                last /= factor;
                    464:        nblocks = btodb(fs->fs_bsize);
                    465:        /*
                    466:         * Get buffer of block pointers, zero those entries corresponding
                    467:         * to blocks to be free'd, and update on disk copy first.  Since
                    468:         * double(triple) indirect before single(double) indirect, calls
                    469:         * to bmap on these blocks will fail.  However, we already have
                    470:         * the on disk address, so we have to set the b_blkno field
                    471:         * explicitly instead of letting bread do everything for us.
                    472:         */
                    473:        vp = ITOV(ip);
                    474:        bp = getblk(vp, lbn, (int)fs->fs_bsize, 0, 0);
                    475:        if (bp->b_flags & (B_DONE | B_DELWRI)) {
                    476:                /* Braces must be here in case trace evaluates to nothing. */
                    477:                trace(TR_BREADHIT, pack(vp, fs->fs_bsize), lbn);
                    478:        } else {
                    479:                trace(TR_BREADMISS, pack(vp, fs->fs_bsize), lbn);
                    480:                curproc->p_stats->p_ru.ru_inblock++;    /* pay for read */
                    481:                bp->b_flags |= B_READ;
                    482:                if (bp->b_bcount > bp->b_bufsize)
                    483:                        panic("ffs_indirtrunc: bad buffer size");
                    484:                bp->b_blkno = dbn;
                    485:                VOP_STRATEGY(bp);
                    486:                error = biowait(bp);
                    487:        }
                    488:        if (error) {
                    489:                brelse(bp);
                    490:                *countp = 0;
                    491:                return (error);
                    492:        }
                    493:
1.18      fvdl      494:        bap = (ufs_daddr_t *)bp->b_data;
1.12      thorpej   495:        if (lastbn != -1) {
1.18      fvdl      496:                MALLOC(copy, ufs_daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK);
1.22      perry     497:                memcpy((caddr_t)copy, (caddr_t)bap, (u_int)fs->fs_bsize);
                    498:                memset((caddr_t)&bap[last + 1], 0,
1.18      fvdl      499:                  (u_int)(NINDIR(fs) - (last + 1)) * sizeof (ufs_daddr_t));
1.12      thorpej   500:                error = bwrite(bp);
                    501:                if (error)
                    502:                        allerror = error;
                    503:                bap = copy;
                    504:        }
1.1       mycroft   505:
                    506:        /*
                    507:         * Recursively free totally unused blocks.
                    508:         */
                    509:        for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
                    510:            i--, nlbn += factor) {
1.19      bouyer    511:                nb = ufs_rw32(bap[i], UFS_MPNEEDSWAP(vp->v_mount));
1.1       mycroft   512:                if (nb == 0)
                    513:                        continue;
                    514:                if (level > SINGLE) {
1.9       christos  515:                        error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
1.18      fvdl      516:                                               (ufs_daddr_t)-1, level - 1,
1.9       christos  517:                                               &blkcount);
                    518:                        if (error)
1.1       mycroft   519:                                allerror = error;
                    520:                        blocksreleased += blkcount;
                    521:                }
                    522:                ffs_blkfree(ip, nb, fs->fs_bsize);
                    523:                blocksreleased += nblocks;
                    524:        }
                    525:
                    526:        /*
                    527:         * Recursively free last partial block.
                    528:         */
                    529:        if (level > SINGLE && lastbn >= 0) {
                    530:                last = lastbn % factor;
1.19      bouyer    531:                nb = ufs_rw32(bap[i], UFS_MPNEEDSWAP(vp->v_mount));
1.1       mycroft   532:                if (nb != 0) {
1.9       christos  533:                        error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
                    534:                                               last, level - 1, &blkcount);
                    535:                        if (error)
1.1       mycroft   536:                                allerror = error;
                    537:                        blocksreleased += blkcount;
                    538:                }
                    539:        }
1.12      thorpej   540:
                    541:        if (copy != NULL) {
                    542:                FREE(copy, M_TEMP);
                    543:        } else {
                    544:                bp->b_flags |= B_INVAL;
                    545:                brelse(bp);
                    546:        }
                    547:
1.1       mycroft   548:        *countp = blocksreleased;
                    549:        return (allerror);
                    550: }

CVSweb <webmaster@jp.NetBSD.org>