|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms, with or without ! 6: * modification, are permitted provided that the following conditions ! 7: * are met: ! 8: * 1. Redistributions of source code must retain the above copyright ! 9: * notice, this list of conditions and the following disclaimer. ! 10: * 2. Redistributions in binary form must reproduce the above copyright ! 11: * notice, this list of conditions and the following disclaimer in the ! 12: * documentation and/or other materials provided with the distribution. ! 13: * 3. All advertising materials mentioning features or use of this software ! 14: * must display the following acknowledgement: ! 15: * This product includes software developed by the University of ! 16: * California, Berkeley and its contributors. ! 17: * 4. Neither the name of the University nor the names of its contributors ! 18: * may be used to endorse or promote products derived from this software ! 19: * without specific prior written permission. ! 20: * ! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 31: * SUCH DAMAGE. ! 32: * ! 33: * @(#)ufs_inode.c 7.40 (Berkeley) 5/8/91 ! 34: */ ! 35: ! 36: #include "param.h" ! 37: #include "systm.h" ! 38: #include "mount.h" ! 39: #include "proc.h" ! 40: #include "file.h" ! 41: #include "buf.h" ! 42: #include "vnode.h" ! 43: #include "kernel.h" ! 44: #include "malloc.h" ! 45: ! 46: #include "quota.h" ! 47: #include "inode.h" ! 48: #include "fs.h" ! 49: #include "ufsmount.h" ! 50: ! 51: #define INOHSZ 512 ! 52: #if ((INOHSZ&(INOHSZ-1)) == 0) ! 53: #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) ! 54: #else ! 55: #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) ! 56: #endif ! 57: ! 58: union ihead { ! 59: union ihead *ih_head[2]; ! 60: struct inode *ih_chain[2]; ! 61: } ihead[INOHSZ]; ! 62: ! 63: int prtactive; /* 1 => print out reclaim of active vnodes */ ! 64: ! 65: /* ! 66: * Initialize hash links for inodes. ! 67: */ ! 68: ufs_init() ! 69: { ! 70: register int i; ! 71: register union ihead *ih = ihead; ! 72: ! 73: #ifndef lint ! 74: if (VN_MAXPRIVATE < sizeof(struct inode)) ! 75: panic("ihinit: too small"); ! 76: #endif /* not lint */ ! 77: for (i = INOHSZ; --i >= 0; ih++) { ! 78: ih->ih_head[0] = ih; ! 79: ih->ih_head[1] = ih; ! 80: } ! 81: #ifdef QUOTA ! 82: dqinit(); ! 83: #endif /* QUOTA */ ! 84: } ! 85: ! 86: /* ! 87: * Look up a UFS dinode number to find its incore vnode. ! 88: * If it is not in core, read it in from the specified device. ! 89: * If it is in core, wait for the lock bit to clear, then ! 90: * return the inode locked. Detection and handling of mount ! 91: * points must be done by the calling routine. ! 92: */ ! 93: iget(xp, ino, ipp) ! 94: struct inode *xp; ! 95: ino_t ino; ! 96: struct inode **ipp; ! 97: { ! 98: dev_t dev = xp->i_dev; ! 99: struct mount *mntp = ITOV(xp)->v_mount; ! 100: register struct fs *fs = VFSTOUFS(mntp)->um_fs; ! 101: extern struct vnodeops ufs_vnodeops, spec_inodeops; ! 102: register struct inode *ip, *iq; ! 103: register struct vnode *vp; ! 104: struct vnode *nvp; ! 105: struct buf *bp; ! 106: struct dinode *dp; ! 107: union ihead *ih; ! 108: int i, error; ! 109: ! 110: ih = &ihead[INOHASH(dev, ino)]; ! 111: loop: ! 112: for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) { ! 113: if (ino != ip->i_number || dev != ip->i_dev) ! 114: continue; ! 115: if ((ip->i_flag&ILOCKED) != 0) { ! 116: ip->i_flag |= IWANT; ! 117: sleep((caddr_t)ip, PINOD); ! 118: goto loop; ! 119: } ! 120: if (vget(ITOV(ip))) ! 121: goto loop; ! 122: *ipp = ip; ! 123: return(0); ! 124: } ! 125: /* ! 126: * Allocate a new inode. ! 127: */ ! 128: if (error = getnewvnode(VT_UFS, mntp, &ufs_vnodeops, &nvp)) { ! 129: *ipp = 0; ! 130: return (error); ! 131: } ! 132: ip = VTOI(nvp); ! 133: ip->i_vnode = nvp; ! 134: ip->i_flag = 0; ! 135: ip->i_devvp = 0; ! 136: ip->i_mode = 0; ! 137: ip->i_diroff = 0; ! 138: ip->i_lockf = 0; ! 139: #ifdef QUOTA ! 140: for (i = 0; i < MAXQUOTAS; i++) ! 141: ip->i_dquot[i] = NODQUOT; ! 142: #endif ! 143: /* ! 144: * Put it onto its hash chain and lock it so that other requests for ! 145: * this inode will block if they arrive while we are sleeping waiting ! 146: * for old data structures to be purged or for the contents of the ! 147: * disk portion of this inode to be read. ! 148: */ ! 149: ip->i_dev = dev; ! 150: ip->i_number = ino; ! 151: insque(ip, ih); ! 152: ILOCK(ip); ! 153: /* ! 154: * Read in the disk contents for the inode. ! 155: */ ! 156: if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)), ! 157: (int)fs->fs_bsize, NOCRED, &bp)) { ! 158: /* ! 159: * The inode does not contain anything useful, so it would ! 160: * be misleading to leave it on its hash chain. ! 161: * Iput() will take care of putting it back on the free list. ! 162: */ ! 163: remque(ip); ! 164: ip->i_forw = ip; ! 165: ip->i_back = ip; ! 166: /* ! 167: * Unlock and discard unneeded inode. ! 168: */ ! 169: iput(ip); ! 170: brelse(bp); ! 171: *ipp = 0; ! 172: return (error); ! 173: } ! 174: dp = bp->b_un.b_dino; ! 175: dp += itoo(fs, ino); ! 176: ip->i_din = *dp; ! 177: brelse(bp); ! 178: /* ! 179: * Initialize the associated vnode ! 180: */ ! 181: vp = ITOV(ip); ! 182: vp->v_type = IFTOVT(ip->i_mode); ! 183: if (vp->v_type == VFIFO) { ! 184: #ifdef FIFO ! 185: extern struct vnodeops fifo_inodeops; ! 186: vp->v_op = &fifo_inodeops; ! 187: #else ! 188: iput(ip); ! 189: *ipp = 0; ! 190: return (EOPNOTSUPP); ! 191: #endif /* FIFO */ ! 192: } ! 193: if (vp->v_type == VCHR || vp->v_type == VBLK) { ! 194: vp->v_op = &spec_inodeops; ! 195: if (nvp = checkalias(vp, ip->i_rdev, mntp)) { ! 196: /* ! 197: * Reinitialize aliased inode. ! 198: */ ! 199: vp = nvp; ! 200: iq = VTOI(vp); ! 201: iq->i_vnode = vp; ! 202: iq->i_flag = 0; ! 203: ILOCK(iq); ! 204: iq->i_din = ip->i_din; ! 205: iq->i_dev = dev; ! 206: iq->i_number = ino; ! 207: insque(iq, ih); ! 208: /* ! 209: * Discard unneeded vnode ! 210: */ ! 211: ip->i_mode = 0; ! 212: iput(ip); ! 213: ip = iq; ! 214: } ! 215: } ! 216: if (ino == ROOTINO) ! 217: vp->v_flag |= VROOT; ! 218: /* ! 219: * Finish inode initialization. ! 220: */ ! 221: ip->i_fs = fs; ! 222: ip->i_devvp = VFSTOUFS(mntp)->um_devvp; ! 223: VREF(ip->i_devvp); ! 224: /* ! 225: * Set up a generation number for this inode if it does not ! 226: * already have one. This should only happen on old filesystems. ! 227: */ ! 228: if (ip->i_gen == 0) { ! 229: if (++nextgennumber < (u_long)time.tv_sec) ! 230: nextgennumber = time.tv_sec; ! 231: ip->i_gen = nextgennumber; ! 232: if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) ! 233: ip->i_flag |= IMOD; ! 234: } ! 235: *ipp = ip; ! 236: return (0); ! 237: } ! 238: ! 239: /* ! 240: * Unlock and decrement the reference count of an inode structure. ! 241: */ ! 242: iput(ip) ! 243: register struct inode *ip; ! 244: { ! 245: ! 246: if ((ip->i_flag & ILOCKED) == 0) ! 247: panic("iput"); ! 248: IUNLOCK(ip); ! 249: vrele(ITOV(ip)); ! 250: } ! 251: ! 252: /* ! 253: * Last reference to an inode, write the inode out and if necessary, ! 254: * truncate and deallocate the file. ! 255: */ ! 256: ufs_inactive(vp, p) ! 257: struct vnode *vp; ! 258: struct proc *p; ! 259: { ! 260: register struct inode *ip = VTOI(vp); ! 261: int mode, error = 0; ! 262: ! 263: if (prtactive && vp->v_usecount != 0) ! 264: vprint("ufs_inactive: pushing active", vp); ! 265: /* ! 266: * Get rid of inodes related to stale file handles. ! 267: */ ! 268: if (ip->i_mode == 0) { ! 269: if ((vp->v_flag & VXLOCK) == 0) ! 270: vgone(vp); ! 271: return (0); ! 272: } ! 273: ILOCK(ip); ! 274: if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { ! 275: #ifdef QUOTA ! 276: if (!getinoquota(ip)) ! 277: (void) chkiq(ip, -1, NOCRED, 0); ! 278: #endif ! 279: error = itrunc(ip, (u_long)0, 0); ! 280: mode = ip->i_mode; ! 281: ip->i_mode = 0; ! 282: ip->i_rdev = 0; ! 283: ip->i_flag |= IUPD|ICHG; ! 284: ifree(ip, ip->i_number, mode); ! 285: } ! 286: IUPDAT(ip, &time, &time, 0); ! 287: IUNLOCK(ip); ! 288: ip->i_flag = 0; ! 289: /* ! 290: * If we are done with the inode, reclaim it ! 291: * so that it can be reused immediately. ! 292: */ ! 293: if (vp->v_usecount == 0 && ip->i_mode == 0) ! 294: vgone(vp); ! 295: return (error); ! 296: } ! 297: ! 298: /* ! 299: * Reclaim an inode so that it can be used for other purposes. ! 300: */ ! 301: ufs_reclaim(vp) ! 302: register struct vnode *vp; ! 303: { ! 304: register struct inode *ip = VTOI(vp); ! 305: int i; ! 306: ! 307: if (prtactive && vp->v_usecount != 0) ! 308: vprint("ufs_reclaim: pushing active", vp); ! 309: /* ! 310: * Remove the inode from its hash chain. ! 311: */ ! 312: remque(ip); ! 313: ip->i_forw = ip; ! 314: ip->i_back = ip; ! 315: /* ! 316: * Purge old data structures associated with the inode. ! 317: */ ! 318: cache_purge(vp); ! 319: if (ip->i_devvp) { ! 320: vrele(ip->i_devvp); ! 321: ip->i_devvp = 0; ! 322: } ! 323: #ifdef QUOTA ! 324: for (i = 0; i < MAXQUOTAS; i++) { ! 325: if (ip->i_dquot[i] != NODQUOT) { ! 326: dqrele(vp, ip->i_dquot[i]); ! 327: ip->i_dquot[i] = NODQUOT; ! 328: } ! 329: } ! 330: #endif ! 331: ip->i_flag = 0; ! 332: return (0); ! 333: } ! 334: ! 335: /* ! 336: * Update the access, modified, and inode change times as specified ! 337: * by the IACC, IMOD, and ICHG flags respectively. The IUPD flag ! 338: * is used to specify that the inode needs to be updated but that ! 339: * the times have already been set. The access and modified times ! 340: * are taken from the second and third parameters; the inode change ! 341: * time is always taken from the current time. If waitfor is set, ! 342: * then wait for the disk write of the inode to complete. ! 343: */ ! 344: iupdat(ip, ta, tm, waitfor) ! 345: register struct inode *ip; ! 346: struct timeval *ta, *tm; ! 347: int waitfor; ! 348: { ! 349: struct buf *bp; ! 350: struct vnode *vp = ITOV(ip); ! 351: struct dinode *dp; ! 352: register struct fs *fs; ! 353: int error; ! 354: ! 355: fs = ip->i_fs; ! 356: if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) ! 357: return (0); ! 358: if (vp->v_mount->mnt_flag & MNT_RDONLY) ! 359: return (0); ! 360: error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)), ! 361: (int)fs->fs_bsize, NOCRED, &bp); ! 362: if (error) { ! 363: brelse(bp); ! 364: return (error); ! 365: } ! 366: if (ip->i_flag&IACC) ! 367: ip->i_atime = ta->tv_sec; ! 368: if (ip->i_flag&IUPD) ! 369: ip->i_mtime = tm->tv_sec; ! 370: if (ip->i_flag&ICHG) ! 371: ip->i_ctime = time.tv_sec; ! 372: ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); ! 373: dp = bp->b_un.b_dino + itoo(fs, ip->i_number); ! 374: *dp = ip->i_din; ! 375: if (waitfor) { ! 376: return (bwrite(bp)); ! 377: } else { ! 378: bdwrite(bp); ! 379: return (0); ! 380: } ! 381: } ! 382: ! 383: #define SINGLE 0 /* index of single indirect block */ ! 384: #define DOUBLE 1 /* index of double indirect block */ ! 385: #define TRIPLE 2 /* index of triple indirect block */ ! 386: /* ! 387: * Truncate the inode ip to at most length size. Free affected disk ! 388: * blocks -- the blocks of the file are removed in reverse order. ! 389: * ! 390: * NB: triple indirect blocks are untested. ! 391: */ ! 392: itrunc(oip, length, flags) ! 393: register struct inode *oip; ! 394: u_long length; ! 395: int flags; ! 396: { ! 397: register daddr_t lastblock; ! 398: daddr_t bn, lbn, lastiblock[NIADDR]; ! 399: register struct fs *fs; ! 400: register struct inode *ip; ! 401: struct buf *bp; ! 402: int offset, osize, size, level; ! 403: long count, nblocks, blocksreleased = 0; ! 404: register int i; ! 405: int aflags, error, allerror; ! 406: struct inode tip; ! 407: ! 408: vnode_pager_setsize(ITOV(oip), length); ! 409: if (oip->i_size <= length) { ! 410: oip->i_flag |= ICHG|IUPD; ! 411: error = iupdat(oip, &time, &time, 1); ! 412: return (error); ! 413: } ! 414: /* ! 415: * Calculate index into inode's block list of ! 416: * last direct and indirect blocks (if any) ! 417: * which we want to keep. Lastblock is -1 when ! 418: * the file is truncated to 0. ! 419: */ ! 420: fs = oip->i_fs; ! 421: lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; ! 422: lastiblock[SINGLE] = lastblock - NDADDR; ! 423: lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); ! 424: lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); ! 425: nblocks = btodb(fs->fs_bsize); ! 426: /* ! 427: * Update the size of the file. If the file is not being ! 428: * truncated to a block boundry, the contents of the ! 429: * partial block following the end of the file must be ! 430: * zero'ed in case it ever become accessable again because ! 431: * of subsequent file growth. ! 432: */ ! 433: osize = oip->i_size; ! 434: offset = blkoff(fs, length); ! 435: if (offset == 0) { ! 436: oip->i_size = length; ! 437: } else { ! 438: lbn = lblkno(fs, length); ! 439: aflags = B_CLRBUF; ! 440: if (flags & IO_SYNC) ! 441: aflags |= B_SYNC; ! 442: #ifdef QUOTA ! 443: if (error = getinoquota(oip)) ! 444: return (error); ! 445: #endif ! 446: if (error = balloc(oip, lbn, offset, &bp, aflags)) ! 447: return (error); ! 448: oip->i_size = length; ! 449: size = blksize(fs, oip, lbn); ! 450: (void) vnode_pager_uncache(ITOV(oip)); ! 451: bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); ! 452: allocbuf(bp, size); ! 453: if (flags & IO_SYNC) ! 454: bwrite(bp); ! 455: else ! 456: bdwrite(bp); ! 457: } ! 458: /* ! 459: * Update file and block pointers ! 460: * on disk before we start freeing blocks. ! 461: * If we crash before free'ing blocks below, ! 462: * the blocks will be returned to the free list. ! 463: * lastiblock values are also normalized to -1 ! 464: * for calls to indirtrunc below. ! 465: */ ! 466: tip = *oip; ! 467: tip.i_size = osize; ! 468: for (level = TRIPLE; level >= SINGLE; level--) ! 469: if (lastiblock[level] < 0) { ! 470: oip->i_ib[level] = 0; ! 471: lastiblock[level] = -1; ! 472: } ! 473: for (i = NDADDR - 1; i > lastblock; i--) ! 474: oip->i_db[i] = 0; ! 475: oip->i_flag |= ICHG|IUPD; ! 476: vinvalbuf(ITOV(oip), (length > 0)); ! 477: allerror = iupdat(oip, &time, &time, MNT_WAIT); ! 478: ! 479: /* ! 480: * Indirect blocks first. ! 481: */ ! 482: ip = &tip; ! 483: for (level = TRIPLE; level >= SINGLE; level--) { ! 484: bn = ip->i_ib[level]; ! 485: if (bn != 0) { ! 486: error = indirtrunc(ip, bn, lastiblock[level], level, ! 487: &count); ! 488: if (error) ! 489: allerror = error; ! 490: blocksreleased += count; ! 491: if (lastiblock[level] < 0) { ! 492: ip->i_ib[level] = 0; ! 493: blkfree(ip, bn, (off_t)fs->fs_bsize); ! 494: blocksreleased += nblocks; ! 495: } ! 496: } ! 497: if (lastiblock[level] >= 0) ! 498: goto done; ! 499: } ! 500: ! 501: /* ! 502: * All whole direct blocks or frags. ! 503: */ ! 504: for (i = NDADDR - 1; i > lastblock; i--) { ! 505: register off_t bsize; ! 506: ! 507: bn = ip->i_db[i]; ! 508: if (bn == 0) ! 509: continue; ! 510: ip->i_db[i] = 0; ! 511: bsize = (off_t)blksize(fs, ip, i); ! 512: blkfree(ip, bn, bsize); ! 513: blocksreleased += btodb(bsize); ! 514: } ! 515: if (lastblock < 0) ! 516: goto done; ! 517: ! 518: /* ! 519: * Finally, look for a change in size of the ! 520: * last direct block; release any frags. ! 521: */ ! 522: bn = ip->i_db[lastblock]; ! 523: if (bn != 0) { ! 524: off_t oldspace, newspace; ! 525: ! 526: /* ! 527: * Calculate amount of space we're giving ! 528: * back as old block size minus new block size. ! 529: */ ! 530: oldspace = blksize(fs, ip, lastblock); ! 531: ip->i_size = length; ! 532: newspace = blksize(fs, ip, lastblock); ! 533: if (newspace == 0) ! 534: panic("itrunc: newspace"); ! 535: if (oldspace - newspace > 0) { ! 536: /* ! 537: * Block number of space to be free'd is ! 538: * the old block # plus the number of frags ! 539: * required for the storage we're keeping. ! 540: */ ! 541: bn += numfrags(fs, newspace); ! 542: blkfree(ip, bn, oldspace - newspace); ! 543: blocksreleased += btodb(oldspace - newspace); ! 544: } ! 545: } ! 546: done: ! 547: /* BEGIN PARANOIA */ ! 548: for (level = SINGLE; level <= TRIPLE; level++) ! 549: if (ip->i_ib[level] != oip->i_ib[level]) ! 550: panic("itrunc1"); ! 551: for (i = 0; i < NDADDR; i++) ! 552: if (ip->i_db[i] != oip->i_db[i]) ! 553: panic("itrunc2"); ! 554: /* END PARANOIA */ ! 555: oip->i_blocks -= blocksreleased; ! 556: if (oip->i_blocks < 0) /* sanity */ ! 557: oip->i_blocks = 0; ! 558: oip->i_flag |= ICHG; ! 559: #ifdef QUOTA ! 560: if (!getinoquota(oip)) ! 561: (void) chkdq(oip, -blocksreleased, NOCRED, 0); ! 562: #endif ! 563: return (allerror); ! 564: } ! 565: ! 566: /* ! 567: * Release blocks associated with the inode ip and ! 568: * stored in the indirect block bn. Blocks are free'd ! 569: * in LIFO order up to (but not including) lastbn. If ! 570: * level is greater than SINGLE, the block is an indirect ! 571: * block and recursive calls to indirtrunc must be used to ! 572: * cleanse other indirect blocks. ! 573: * ! 574: * NB: triple indirect blocks are untested. ! 575: */ ! 576: indirtrunc(ip, bn, lastbn, level, countp) ! 577: register struct inode *ip; ! 578: daddr_t bn, lastbn; ! 579: int level; ! 580: long *countp; ! 581: { ! 582: register int i; ! 583: struct buf *bp; ! 584: register struct fs *fs = ip->i_fs; ! 585: register daddr_t *bap; ! 586: daddr_t *copy, nb, last; ! 587: long blkcount, factor; ! 588: int nblocks, blocksreleased = 0; ! 589: int error, allerror = 0; ! 590: ! 591: /* ! 592: * Calculate index in current block of last ! 593: * block to be kept. -1 indicates the entire ! 594: * block so we need not calculate the index. ! 595: */ ! 596: factor = 1; ! 597: for (i = SINGLE; i < level; i++) ! 598: factor *= NINDIR(fs); ! 599: last = lastbn; ! 600: if (lastbn > 0) ! 601: last /= factor; ! 602: nblocks = btodb(fs->fs_bsize); ! 603: /* ! 604: * Get buffer of block pointers, zero those ! 605: * entries corresponding to blocks to be free'd, ! 606: * and update on disk copy first. ! 607: */ ! 608: error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, ! 609: NOCRED, &bp); ! 610: if (error) { ! 611: brelse(bp); ! 612: *countp = 0; ! 613: return (error); ! 614: } ! 615: bap = bp->b_un.b_daddr; ! 616: MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); ! 617: bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); ! 618: bzero((caddr_t)&bap[last + 1], ! 619: (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); ! 620: if (last == -1) ! 621: bp->b_flags |= B_INVAL; ! 622: error = bwrite(bp); ! 623: if (error) ! 624: allerror = error; ! 625: bap = copy; ! 626: ! 627: /* ! 628: * Recursively free totally unused blocks. ! 629: */ ! 630: for (i = NINDIR(fs) - 1; i > last; i--) { ! 631: nb = bap[i]; ! 632: if (nb == 0) ! 633: continue; ! 634: if (level > SINGLE) { ! 635: error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, ! 636: &blkcount); ! 637: if (error) ! 638: allerror = error; ! 639: blocksreleased += blkcount; ! 640: } ! 641: blkfree(ip, nb, (off_t)fs->fs_bsize); ! 642: blocksreleased += nblocks; ! 643: } ! 644: ! 645: /* ! 646: * Recursively free last partial block. ! 647: */ ! 648: if (level > SINGLE && lastbn >= 0) { ! 649: last = lastbn % factor; ! 650: nb = bap[i]; ! 651: if (nb != 0) { ! 652: error = indirtrunc(ip, nb, last, level - 1, &blkcount); ! 653: if (error) ! 654: allerror = error; ! 655: blocksreleased += blkcount; ! 656: } ! 657: } ! 658: FREE(copy, M_TEMP); ! 659: *countp = blocksreleased; ! 660: return (allerror); ! 661: } ! 662: ! 663: /* ! 664: * Lock an inode. If its already locked, set the WANT bit and sleep. ! 665: */ ! 666: ilock(ip) ! 667: register struct inode *ip; ! 668: { ! 669: ! 670: while (ip->i_flag & ILOCKED) { ! 671: ip->i_flag |= IWANT; ! 672: if (ip->i_spare0 == curproc->p_pid) ! 673: panic("locking against myself"); ! 674: ip->i_spare1 = curproc->p_pid; ! 675: (void) sleep((caddr_t)ip, PINOD); ! 676: } ! 677: ip->i_spare1 = 0; ! 678: ip->i_spare0 = curproc->p_pid; ! 679: ip->i_flag |= ILOCKED; ! 680: } ! 681: ! 682: /* ! 683: * Unlock an inode. If WANT bit is on, wakeup. ! 684: */ ! 685: iunlock(ip) ! 686: register struct inode *ip; ! 687: { ! 688: ! 689: if ((ip->i_flag & ILOCKED) == 0) ! 690: vprint("iunlock: unlocked inode", ITOV(ip)); ! 691: ip->i_spare0 = 0; ! 692: ip->i_flag &= ~ILOCKED; ! 693: if (ip->i_flag&IWANT) { ! 694: ip->i_flag &= ~IWANT; ! 695: wakeup((caddr_t)ip); ! 696: } ! 697: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.