|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.