Annotation of sys/ufs/ffs/ffs_inode.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ffs_inode.c,v 1.49 2007/06/01 18:54:27 pedro Exp $ */
! 2: /* $NetBSD: ffs_inode.c,v 1.10 1996/05/11 18:27:19 mycroft Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1989, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)ffs_inode.c 8.8 (Berkeley) 10/19/94
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/systm.h>
! 37: #include <sys/mount.h>
! 38: #include <sys/proc.h>
! 39: #include <sys/file.h>
! 40: #include <sys/buf.h>
! 41: #include <sys/vnode.h>
! 42: #include <sys/kernel.h>
! 43: #include <sys/malloc.h>
! 44: #include <sys/resourcevar.h>
! 45:
! 46: #include <uvm/uvm_extern.h>
! 47:
! 48: #include <ufs/ufs/quota.h>
! 49: #include <ufs/ufs/inode.h>
! 50: #include <ufs/ufs/ufsmount.h>
! 51: #include <ufs/ufs/ufs_extern.h>
! 52:
! 53: #include <ufs/ffs/fs.h>
! 54: #include <ufs/ffs/ffs_extern.h>
! 55:
! 56: int ffs_indirtrunc(struct inode *, daddr_t, daddr_t, daddr_t, int, long *);
! 57:
! 58: /*
! 59: * Update the access, modified, and inode change times as specified by the
! 60: * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. The IN_MODIFIED
! 61: * flag is used to specify that the inode needs to be updated but that the
! 62: * times have already been set. The access and modified times are taken from
! 63: * the second and third parameters; the inode change time is always taken
! 64: * from the current time. If waitfor is set, then wait for the disk write
! 65: * of the inode to complete.
! 66: */
! 67: int
! 68: ffs_update(struct inode *ip, struct timespec *atime,
! 69: struct timespec *mtime, int waitfor)
! 70: {
! 71: struct vnode *vp;
! 72: struct fs *fs;
! 73: struct buf *bp;
! 74: int error;
! 75: struct timespec ts;
! 76:
! 77: vp = ITOV(ip);
! 78: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
! 79: ip->i_flag &=
! 80: ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
! 81: return (0);
! 82: }
! 83:
! 84: if ((vp->v_mount->mnt_flag & MNT_NOATIME) &&
! 85: !(ip->i_flag & (IN_CHANGE | IN_UPDATE))) {
! 86: ip->i_flag &= ~IN_ACCESS;
! 87: }
! 88:
! 89: if ((ip->i_flag &
! 90: (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
! 91: waitfor != MNT_WAIT)
! 92: return (0);
! 93:
! 94: getnanotime(&ts);
! 95:
! 96: if (ip->i_flag & IN_ACCESS) {
! 97: DIP_ASSIGN(ip, atime, atime ? atime->tv_sec : ts.tv_sec);
! 98: DIP_ASSIGN(ip, atimensec, atime ? atime->tv_nsec : ts.tv_nsec);
! 99: }
! 100:
! 101: if (ip->i_flag & IN_UPDATE) {
! 102: DIP_ASSIGN(ip, mtime, mtime ? mtime->tv_sec : ts.tv_sec);
! 103: DIP_ASSIGN(ip, mtimensec, mtime ? mtime->tv_nsec : ts.tv_nsec);
! 104: ip->i_modrev++;
! 105: }
! 106:
! 107: if (ip->i_flag & IN_CHANGE) {
! 108: DIP_ASSIGN(ip, ctime, ts.tv_sec);
! 109: DIP_ASSIGN(ip, ctimensec, ts.tv_nsec);
! 110: }
! 111:
! 112: ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE);
! 113: fs = ip->i_fs;
! 114:
! 115: /*
! 116: * Ensure that uid and gid are correct. This is a temporary
! 117: * fix until fsck has been changed to do the update.
! 118: */
! 119: if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_inodefmt < FS_44INODEFMT) {
! 120: ip->i_din1->di_ouid = ip->i_ffs1_uid;
! 121: ip->i_din1->di_ogid = ip->i_ffs1_gid;
! 122: }
! 123:
! 124: error = bread(ip->i_devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
! 125: (int)fs->fs_bsize, NOCRED, &bp);
! 126: if (error) {
! 127: brelse(bp);
! 128: return (error);
! 129: }
! 130:
! 131: if (DOINGSOFTDEP(vp))
! 132: softdep_update_inodeblock(ip, bp, waitfor);
! 133: else if (ip->i_effnlink != DIP(ip, nlink))
! 134: panic("ffs_update: bad link cnt");
! 135:
! 136: #ifdef FFS2
! 137: if (ip->i_ump->um_fstype == UM_UFS2)
! 138: *((struct ufs2_dinode *)bp->b_data +
! 139: ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2;
! 140: else
! 141: #endif
! 142: *((struct ufs1_dinode *)bp->b_data +
! 143: ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1;
! 144:
! 145: if (waitfor && !DOINGASYNC(vp)) {
! 146: return (bwrite(bp));
! 147: } else {
! 148: bdwrite(bp);
! 149: return (0);
! 150: }
! 151: }
! 152:
! 153: #define SINGLE 0 /* index of single indirect block */
! 154: #define DOUBLE 1 /* index of double indirect block */
! 155: #define TRIPLE 2 /* index of triple indirect block */
! 156:
! 157: /*
! 158: * Truncate the inode oip to at most length size, freeing the
! 159: * disk blocks.
! 160: */
! 161: int
! 162: ffs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred)
! 163: {
! 164: struct vnode *ovp;
! 165: daddr64_t lastblock;
! 166: daddr64_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
! 167: daddr64_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
! 168: struct fs *fs;
! 169: struct buf *bp;
! 170: int offset, size, level;
! 171: long count, nblocks, vflags, blocksreleased = 0;
! 172: int i, aflags, error, allerror;
! 173: off_t osize;
! 174:
! 175: if (length < 0)
! 176: return (EINVAL);
! 177: ovp = ITOV(oip);
! 178:
! 179: if (ovp->v_type != VREG &&
! 180: ovp->v_type != VDIR &&
! 181: ovp->v_type != VLNK)
! 182: return (0);
! 183:
! 184: if (DIP(oip, size) == length)
! 185: return (0);
! 186:
! 187: if (ovp->v_type == VLNK &&
! 188: (DIP(oip, size) < ovp->v_mount->mnt_maxsymlinklen ||
! 189: (ovp->v_mount->mnt_maxsymlinklen == 0 &&
! 190: oip->i_din1->di_blocks == 0))) {
! 191: #ifdef DIAGNOSTIC
! 192: if (length != 0)
! 193: panic("ffs_truncate: partial truncate of symlink");
! 194: #endif
! 195: memset(SHORTLINK(oip), 0, (size_t) DIP(oip, size));
! 196: DIP_ASSIGN(oip, size, 0);
! 197: oip->i_flag |= IN_CHANGE | IN_UPDATE;
! 198: return (UFS_UPDATE(oip, MNT_WAIT));
! 199: }
! 200:
! 201: if ((error = getinoquota(oip)) != 0)
! 202: return (error);
! 203:
! 204: uvm_vnp_setsize(ovp, length);
! 205: oip->i_ci.ci_lasta = oip->i_ci.ci_clen
! 206: = oip->i_ci.ci_cstart = oip->i_ci.ci_lastw = 0;
! 207:
! 208: if (DOINGSOFTDEP(ovp)) {
! 209: if (length > 0 || softdep_slowdown(ovp)) {
! 210: /*
! 211: * If a file is only partially truncated, then
! 212: * we have to clean up the data structures
! 213: * describing the allocation past the truncation
! 214: * point. Finding and deallocating those structures
! 215: * is a lot of work. Since partial truncation occurs
! 216: * rarely, we solve the problem by syncing the file
! 217: * so that it will have no data structures left.
! 218: */
! 219: if ((error = VOP_FSYNC(ovp, cred, MNT_WAIT,
! 220: curproc)) != 0)
! 221: return (error);
! 222: } else {
! 223: (void)ufs_quota_free_blocks(oip, DIP(oip, blocks),
! 224: NOCRED);
! 225: softdep_setup_freeblocks(oip, length);
! 226: (void) vinvalbuf(ovp, 0, cred, curproc, 0, 0);
! 227: oip->i_flag |= IN_CHANGE | IN_UPDATE;
! 228: return (UFS_UPDATE(oip, 0));
! 229: }
! 230: }
! 231:
! 232: fs = oip->i_fs;
! 233: osize = DIP(oip, size);
! 234: /*
! 235: * Lengthen the size of the file. We must ensure that the
! 236: * last byte of the file is allocated. Since the smallest
! 237: * value of osize is 0, length will be at least 1.
! 238: */
! 239: if (osize < length) {
! 240: if (length > fs->fs_maxfilesize)
! 241: return (EFBIG);
! 242: aflags = B_CLRBUF;
! 243: if (flags & IO_SYNC)
! 244: aflags |= B_SYNC;
! 245: error = UFS_BUF_ALLOC(oip, length - 1, 1,
! 246: cred, aflags, &bp);
! 247: if (error)
! 248: return (error);
! 249: DIP_ASSIGN(oip, size, length);
! 250: uvm_vnp_setsize(ovp, length);
! 251: (void) uvm_vnp_uncache(ovp);
! 252: if (aflags & B_SYNC)
! 253: bwrite(bp);
! 254: else
! 255: bawrite(bp);
! 256: oip->i_flag |= IN_CHANGE | IN_UPDATE;
! 257: return (UFS_UPDATE(oip, MNT_WAIT));
! 258: }
! 259: uvm_vnp_setsize(ovp, length);
! 260:
! 261: /*
! 262: * Shorten the size of the file. If the file is not being
! 263: * truncated to a block boundary, the contents of the
! 264: * partial block following the end of the file must be
! 265: * zero'ed in case it ever becomes accessible again because
! 266: * of subsequent file growth. Directories however are not
! 267: * zero'ed as they should grow back initialized to empty.
! 268: */
! 269: offset = blkoff(fs, length);
! 270: if (offset == 0) {
! 271: DIP_ASSIGN(oip, size, length);
! 272: } else {
! 273: lbn = lblkno(fs, length);
! 274: aflags = B_CLRBUF;
! 275: if (flags & IO_SYNC)
! 276: aflags |= B_SYNC;
! 277: error = UFS_BUF_ALLOC(oip, length - 1, 1,
! 278: cred, aflags, &bp);
! 279: if (error)
! 280: return (error);
! 281: /*
! 282: * When we are doing soft updates and the UFS_BALLOC
! 283: * above fills in a direct block hole with a full sized
! 284: * block that will be truncated down to a fragment below,
! 285: * we must flush out the block dependency with an FSYNC
! 286: * so that we do not get a soft updates inconsistency
! 287: * when we create the fragment below.
! 288: */
! 289: if (DOINGSOFTDEP(ovp) && lbn < NDADDR &&
! 290: fragroundup(fs, blkoff(fs, length)) < fs->fs_bsize &&
! 291: (error = VOP_FSYNC(ovp, cred, MNT_WAIT, curproc)) != 0)
! 292: return (error);
! 293: DIP_ASSIGN(oip, size, length);
! 294: size = blksize(fs, oip, lbn);
! 295: (void) uvm_vnp_uncache(ovp);
! 296: if (ovp->v_type != VDIR)
! 297: bzero((char *)bp->b_data + offset,
! 298: (u_int)(size - offset));
! 299: bp->b_bcount = size;
! 300: if (aflags & B_SYNC)
! 301: bwrite(bp);
! 302: else
! 303: bawrite(bp);
! 304: }
! 305: /*
! 306: * Calculate index into inode's block list of
! 307: * last direct and indirect blocks (if any)
! 308: * which we want to keep. Lastblock is -1 when
! 309: * the file is truncated to 0.
! 310: */
! 311: lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
! 312: lastiblock[SINGLE] = lastblock - NDADDR;
! 313: lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
! 314: lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
! 315: nblocks = btodb(fs->fs_bsize);
! 316:
! 317: /*
! 318: * Update file and block pointers on disk before we start freeing
! 319: * blocks. If we crash before free'ing blocks below, the blocks
! 320: * will be returned to the free list. lastiblock values are also
! 321: * normalized to -1 for calls to ffs_indirtrunc below.
! 322: */
! 323: for (level = TRIPLE; level >= SINGLE; level--) {
! 324: oldblks[NDADDR + level] = DIP(oip, ib[level]);
! 325: if (lastiblock[level] < 0) {
! 326: DIP_ASSIGN(oip, ib[level], 0);
! 327: lastiblock[level] = -1;
! 328: }
! 329: }
! 330:
! 331: for (i = 0; i < NDADDR; i++) {
! 332: oldblks[i] = DIP(oip, db[i]);
! 333: if (i > lastblock)
! 334: DIP_ASSIGN(oip, db[i], 0);
! 335: }
! 336:
! 337: oip->i_flag |= IN_CHANGE | IN_UPDATE;
! 338: if ((error = UFS_UPDATE(oip, MNT_WAIT)) != 0)
! 339: allerror = error;
! 340:
! 341: /*
! 342: * Having written the new inode to disk, save its new configuration
! 343: * and put back the old block pointers long enough to process them.
! 344: * Note that we save the new block configuration so we can check it
! 345: * when we are done.
! 346: */
! 347: for (i = 0; i < NDADDR; i++) {
! 348: newblks[i] = DIP(oip, db[i]);
! 349: DIP_ASSIGN(oip, db[i], oldblks[i]);
! 350: }
! 351:
! 352: for (i = 0; i < NIADDR; i++) {
! 353: newblks[NDADDR + i] = DIP(oip, ib[i]);
! 354: DIP_ASSIGN(oip, ib[i], oldblks[NDADDR + i]);
! 355: }
! 356:
! 357: DIP_ASSIGN(oip, size, osize);
! 358: vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA;
! 359: allerror = vinvalbuf(ovp, vflags, cred, curproc, 0, 0);
! 360:
! 361: /*
! 362: * Indirect blocks first.
! 363: */
! 364: indir_lbn[SINGLE] = -NDADDR;
! 365: indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
! 366: indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
! 367: for (level = TRIPLE; level >= SINGLE; level--) {
! 368: bn = DIP(oip, ib[level]);
! 369: if (bn != 0) {
! 370: error = ffs_indirtrunc(oip, indir_lbn[level],
! 371: fsbtodb(fs, bn), lastiblock[level], level, &count);
! 372: if (error)
! 373: allerror = error;
! 374: blocksreleased += count;
! 375: if (lastiblock[level] < 0) {
! 376: DIP_ASSIGN(oip, ib[level], 0);
! 377: ffs_blkfree(oip, bn, fs->fs_bsize);
! 378: blocksreleased += nblocks;
! 379: }
! 380: }
! 381: if (lastiblock[level] >= 0)
! 382: goto done;
! 383: }
! 384:
! 385: /*
! 386: * All whole direct blocks or frags.
! 387: */
! 388: for (i = NDADDR - 1; i > lastblock; i--) {
! 389: long bsize;
! 390:
! 391: bn = DIP(oip, db[i]);
! 392: if (bn == 0)
! 393: continue;
! 394:
! 395: DIP_ASSIGN(oip, db[i], 0);
! 396: bsize = blksize(fs, oip, i);
! 397: ffs_blkfree(oip, bn, bsize);
! 398: blocksreleased += btodb(bsize);
! 399: }
! 400: if (lastblock < 0)
! 401: goto done;
! 402:
! 403: /*
! 404: * Finally, look for a change in size of the
! 405: * last direct block; release any frags.
! 406: */
! 407: bn = DIP(oip, db[lastblock]);
! 408: if (bn != 0) {
! 409: long oldspace, newspace;
! 410:
! 411: /*
! 412: * Calculate amount of space we're giving
! 413: * back as old block size minus new block size.
! 414: */
! 415: oldspace = blksize(fs, oip, lastblock);
! 416: DIP_ASSIGN(oip, size, length);
! 417: newspace = blksize(fs, oip, lastblock);
! 418: if (newspace == 0)
! 419: panic("ffs_truncate: newspace");
! 420: if (oldspace - newspace > 0) {
! 421: /*
! 422: * Block number of space to be free'd is
! 423: * the old block # plus the number of frags
! 424: * required for the storage we're keeping.
! 425: */
! 426: bn += numfrags(fs, newspace);
! 427: ffs_blkfree(oip, bn, oldspace - newspace);
! 428: blocksreleased += btodb(oldspace - newspace);
! 429: }
! 430: }
! 431: done:
! 432: #ifdef DIAGNOSTIC
! 433: for (level = SINGLE; level <= TRIPLE; level++)
! 434: if (newblks[NDADDR + level] != DIP(oip, ib[level]))
! 435: panic("ffs_truncate1");
! 436: for (i = 0; i < NDADDR; i++)
! 437: if (newblks[i] != DIP(oip, db[i]))
! 438: panic("ffs_truncate2");
! 439: #endif /* DIAGNOSTIC */
! 440: /*
! 441: * Put back the real size.
! 442: */
! 443: DIP_ASSIGN(oip, size, length);
! 444: DIP_ADD(oip, blocks, -blocksreleased);
! 445: if (DIP(oip, blocks) < 0) /* Sanity */
! 446: DIP_ASSIGN(oip, blocks, 0);
! 447: oip->i_flag |= IN_CHANGE;
! 448: (void)ufs_quota_free_blocks(oip, blocksreleased, NOCRED);
! 449: return (allerror);
! 450: }
! 451:
! 452: #ifdef FFS2
! 453: #define BAP(ip, i) (((ip)->i_ump->um_fstype == UM_UFS2) ? bap2[i] : bap1[i])
! 454: #else
! 455: #define BAP(ip, i) bap1[i]
! 456: #endif /* FFS2 */
! 457:
! 458: /*
! 459: * Release blocks associated with the inode ip and stored in the indirect
! 460: * block bn. Blocks are free'd in LIFO order up to (but not including)
! 461: * lastbn. If level is greater than SINGLE, the block is an indirect block
! 462: * and recursive calls to indirtrunc must be used to cleanse other indirect
! 463: * blocks.
! 464: *
! 465: * NB: triple indirect blocks are untested.
! 466: */
! 467: int
! 468: ffs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, daddr_t lastbn,
! 469: int level, long *countp)
! 470: {
! 471: int i;
! 472: struct buf *bp;
! 473: struct fs *fs = ip->i_fs;
! 474: struct vnode *vp;
! 475: void *copy = NULL;
! 476: daddr_t nb, nlbn, last;
! 477: long blkcount, factor;
! 478: int nblocks, blocksreleased = 0;
! 479: int error = 0, allerror = 0;
! 480: int32_t *bap1 = NULL;
! 481: #ifdef FFS2
! 482: int64_t *bap2 = NULL;
! 483: #endif
! 484:
! 485: /*
! 486: * Calculate index in current block of last
! 487: * block to be kept. -1 indicates the entire
! 488: * block so we need not calculate the index.
! 489: */
! 490: factor = 1;
! 491: for (i = SINGLE; i < level; i++)
! 492: factor *= NINDIR(fs);
! 493: last = lastbn;
! 494: if (lastbn > 0)
! 495: last /= factor;
! 496: nblocks = btodb(fs->fs_bsize);
! 497: /*
! 498: * Get buffer of block pointers, zero those entries corresponding
! 499: * to blocks to be free'd, and update on disk copy first. Since
! 500: * double(triple) indirect before single(double) indirect, calls
! 501: * to bmap on these blocks will fail. However, we already have
! 502: * the on disk address, so we have to set the b_blkno field
! 503: * explicitly instead of letting bread do everything for us.
! 504: */
! 505: vp = ITOV(ip);
! 506: bp = getblk(vp, lbn, (int)fs->fs_bsize, 0, 0);
! 507: if (!(bp->b_flags & (B_DONE | B_DELWRI))) {
! 508: curproc->p_stats->p_ru.ru_inblock++; /* pay for read */
! 509: bp->b_flags |= B_READ;
! 510: if (bp->b_bcount > bp->b_bufsize)
! 511: panic("ffs_indirtrunc: bad buffer size");
! 512: bp->b_blkno = dbn;
! 513: VOP_STRATEGY(bp);
! 514: error = biowait(bp);
! 515: }
! 516: if (error) {
! 517: brelse(bp);
! 518: *countp = 0;
! 519: return (error);
! 520: }
! 521:
! 522: #ifdef FFS2
! 523: if (ip->i_ump->um_fstype == UM_UFS2)
! 524: bap2 = (int64_t *)bp->b_data;
! 525: else
! 526: #endif
! 527: bap1 = (int32_t *)bp->b_data;
! 528:
! 529: if (lastbn != -1) {
! 530: MALLOC(copy, void *, fs->fs_bsize, M_TEMP, M_WAITOK);
! 531: bcopy(bp->b_data, copy, (u_int) fs->fs_bsize);
! 532:
! 533: for (i = last + 1; i < NINDIR(fs); i++)
! 534: BAP(ip, i) = 0;
! 535:
! 536: if (!DOINGASYNC(vp)) {
! 537: error = bwrite(bp);
! 538: if (error)
! 539: allerror = error;
! 540: } else {
! 541: bawrite(bp);
! 542: }
! 543:
! 544: #ifdef FFS2
! 545: if (ip->i_ump->um_fstype == UM_UFS2)
! 546: bap2 = (int64_t *)copy;
! 547: else
! 548: #endif
! 549: bap1 = (int32_t *)copy;
! 550: }
! 551:
! 552: /*
! 553: * Recursively free totally unused blocks.
! 554: */
! 555: for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
! 556: i--, nlbn += factor) {
! 557: nb = BAP(ip, i);
! 558: if (nb == 0)
! 559: continue;
! 560: if (level > SINGLE) {
! 561: error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
! 562: (daddr_t)-1, level - 1,
! 563: &blkcount);
! 564: if (error)
! 565: allerror = error;
! 566: blocksreleased += blkcount;
! 567: }
! 568: ffs_blkfree(ip, nb, fs->fs_bsize);
! 569: blocksreleased += nblocks;
! 570: }
! 571:
! 572: /*
! 573: * Recursively free last partial block.
! 574: */
! 575: if (level > SINGLE && lastbn >= 0) {
! 576: last = lastbn % factor;
! 577: nb = BAP(ip, i);
! 578: if (nb != 0) {
! 579: error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb),
! 580: last, level - 1, &blkcount);
! 581: if (error)
! 582: allerror = error;
! 583: blocksreleased += blkcount;
! 584: }
! 585: }
! 586: if (copy != NULL) {
! 587: FREE(copy, M_TEMP);
! 588: } else {
! 589: bp->b_flags |= B_INVAL;
! 590: brelse(bp);
! 591: }
! 592:
! 593: *countp = blocksreleased;
! 594: return (allerror);
! 595: }
CVSweb