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