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