123399Smckusick /* 229117Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323399Smckusick * All rights reserved. The Berkeley software License Agreement 423399Smckusick * specifies the terms and conditions for redistribution. 523399Smckusick * 6*30749Skarels * @(#)lfs_inode.c 7.1.1.1 (Berkeley) 04/02/87 723399Smckusick */ 824Sbill 917099Sbloom #include "param.h" 1017099Sbloom #include "systm.h" 1117099Sbloom #include "mount.h" 1217099Sbloom #include "dir.h" 1317099Sbloom #include "user.h" 1417099Sbloom #include "inode.h" 1517099Sbloom #include "fs.h" 1617099Sbloom #include "buf.h" 1724525Sbloom #include "cmap.h" 187651Ssam #ifdef QUOTA 1917099Sbloom #include "quota.h" 207504Sroot #endif 2117099Sbloom #include "kernel.h" 2224Sbill 2316840Smckusick #define INOHSZ 512 247334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 257334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 267334Skre #else 2710852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 287334Skre #endif 2924Sbill 307334Skre union ihead { /* inode LRU cache, Chris Maltby */ 317334Skre union ihead *ih_head[2]; 327334Skre struct inode *ih_chain[2]; 337334Skre } ihead[INOHSZ]; 347334Skre 357334Skre struct inode *ifreeh, **ifreet; 367334Skre 3724Sbill /* 3824Sbill * Initialize hash links for inodes 3924Sbill * and build inode free list. 4024Sbill */ 4124Sbill ihinit() 4224Sbill { 4324Sbill register int i; 442737Swnj register struct inode *ip = inode; 457334Skre register union ihead *ih = ihead; 4624Sbill 477334Skre for (i = INOHSZ; --i >= 0; ih++) { 487334Skre ih->ih_head[0] = ih; 497334Skre ih->ih_head[1] = ih; 507334Skre } 517334Skre ifreeh = ip; 527334Skre ifreet = &ip->i_freef; 537334Skre ip->i_freeb = &ifreeh; 547334Skre ip->i_forw = ip; 557334Skre ip->i_back = ip; 567334Skre for (i = ninode; --i > 0; ) { 577334Skre ++ip; 587334Skre ip->i_forw = ip; 597334Skre ip->i_back = ip; 607334Skre *ifreet = ip; 617334Skre ip->i_freeb = ifreet; 627334Skre ifreet = &ip->i_freef; 637334Skre } 647334Skre ip->i_freef = NULL; 6524Sbill } 6624Sbill 677334Skre #ifdef notdef 6824Sbill /* 697334Skre * Find an inode if it is incore. 707334Skre * This is the equivalent, for inodes, 717334Skre * of ``incore'' in bio.c or ``pfind'' in subr.c. 727334Skre */ 737334Skre struct inode * 747334Skre ifind(dev, ino) 757334Skre dev_t dev; 767334Skre ino_t ino; 777334Skre { 787334Skre register struct inode *ip; 797334Skre register union ihead *ih; 807334Skre 817334Skre ih = &ihead[INOHASH(dev, ino)]; 827334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 837334Skre if (ino==ip->i_number && dev==ip->i_dev) 847334Skre return (ip); 857334Skre return ((struct inode *)0); 867334Skre } 877334Skre #endif notdef 887334Skre 897334Skre /* 9024Sbill * Look up an inode by device,inumber. 9124Sbill * If it is in core (in the inode structure), 9224Sbill * honor the locking protocol. 9324Sbill * If it is not in core, read it in from the 9424Sbill * specified device. 9524Sbill * If the inode is mounted on, perform 9624Sbill * the indicated indirection. 9724Sbill * In all cases, a pointer to a locked 9824Sbill * inode structure is returned. 9924Sbill * 10024Sbill * panic: no imt -- if the mounted file 10124Sbill * system is not in the mount table. 10224Sbill * "cannot happen" 10324Sbill */ 10424Sbill struct inode * 1056569Smckusic iget(dev, fs, ino) 1064818Swnj dev_t dev; 1076569Smckusic register struct fs *fs; 1084818Swnj ino_t ino; 10924Sbill { 1107335Skre register struct inode *ip; 1117335Skre register union ihead *ih; 11224Sbill register struct mount *mp; 11324Sbill register struct buf *bp; 11424Sbill register struct dinode *dp; 1157334Skre register struct inode *iq; 11624Sbill 11724Sbill loop: 1187334Skre ih = &ihead[INOHASH(dev, ino)]; 1197334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 1204818Swnj if (ino == ip->i_number && dev == ip->i_dev) { 12116642Ssam /* 12216642Ssam * Following is essentially an inline expanded 12316642Ssam * copy of igrab(), expanded inline for speed, 12416642Ssam * and so that the test for a mounted on inode 12516642Ssam * can be deferred until after we are sure that 12616642Ssam * the inode isn't busy. 12716642Ssam */ 1288452Sroot if ((ip->i_flag&ILOCKED) != 0) { 12924Sbill ip->i_flag |= IWANT; 13024Sbill sleep((caddr_t)ip, PINOD); 13124Sbill goto loop; 13224Sbill } 1334818Swnj if ((ip->i_flag&IMOUNT) != 0) { 1346569Smckusic for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 1357334Skre if(mp->m_inodp == ip) { 1367334Skre dev = mp->m_dev; 1377334Skre fs = mp->m_bufp->b_un.b_fs; 1387334Skre ino = ROOTINO; 1397334Skre goto loop; 1407334Skre } 14124Sbill panic("no imt"); 14224Sbill } 1437334Skre if (ip->i_count == 0) { /* ino on free list */ 1447334Skre if (iq = ip->i_freef) 1457334Skre iq->i_freeb = ip->i_freeb; 1467334Skre else 1477334Skre ifreet = ip->i_freeb; 1487334Skre *ip->i_freeb = iq; 1497334Skre ip->i_freef = NULL; 1507334Skre ip->i_freeb = NULL; 1517334Skre } 15224Sbill ip->i_count++; 1538452Sroot ip->i_flag |= ILOCKED; 15424Sbill return(ip); 15524Sbill } 1567334Skre 1577334Skre if ((ip = ifreeh) == NULL) { 1582933Swnj tablefull("inode"); 15924Sbill u.u_error = ENFILE; 16024Sbill return(NULL); 16124Sbill } 16216720Skarels if (ip->i_count) 16316720Skarels panic("free inode isn't"); 1647334Skre if (iq = ip->i_freef) 1657334Skre iq->i_freeb = &ifreeh; 1667334Skre ifreeh = iq; 1677334Skre ip->i_freef = NULL; 1687334Skre ip->i_freeb = NULL; 1697334Skre /* 1707334Skre * Now to take inode off the hash chain it was on 1717334Skre * (initially, or after an iflush, it is on a "hash chain" 1727334Skre * consisting entirely of itself, and pointed to by no-one, 1737334Skre * but that doesn't matter), and put it on the chain for 1747334Skre * its new (ino, dev) pair 1757334Skre */ 1767335Skre remque(ip); 1777335Skre insque(ip, ih); 17824Sbill ip->i_dev = dev; 1796569Smckusic ip->i_fs = fs; 18024Sbill ip->i_number = ino; 18116738Smckusick cacheinval(ip); 1828452Sroot ip->i_flag = ILOCKED; 18324Sbill ip->i_count++; 1846569Smckusic ip->i_lastr = 0; 18516720Skarels #ifdef QUOTA 18616720Skarels dqrele(ip->i_dquot); 18716720Skarels #endif 188*30749Skarels #ifdef SECSIZE 189*30749Skarels bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize, 190*30749Skarels fs->fs_dbsize); 191*30749Skarels #else SECSIZE 1928618Sroot bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize); 193*30749Skarels #endif SECSIZE 19424Sbill /* 19524Sbill * Check I/O errors 19624Sbill */ 1974818Swnj if ((bp->b_flags&B_ERROR) != 0) { 19824Sbill brelse(bp); 1997334Skre /* 2007334Skre * the inode doesn't contain anything useful, so it would 2017334Skre * be misleading to leave it on its hash chain. 2027334Skre * 'iput' will take care of putting it back on the free list. 2037334Skre */ 2047335Skre remque(ip); 2057334Skre ip->i_forw = ip; 2067334Skre ip->i_back = ip; 2077334Skre /* 2087334Skre * we also loose its inumber, just in case (as iput 2097334Skre * doesn't do that any more) - but as it isn't on its 2107334Skre * hash chain, I doubt if this is really necessary .. kre 2117334Skre * (probably the two methods are interchangable) 2127334Skre */ 2137334Skre ip->i_number = 0; 2147651Ssam #ifdef QUOTA 2157492Skre ip->i_dquot = NODQUOT; 2167492Skre #endif 21724Sbill iput(ip); 21824Sbill return(NULL); 21924Sbill } 22024Sbill dp = bp->b_un.b_dino; 2216569Smckusic dp += itoo(fs, ino); 2226569Smckusic ip->i_ic = dp->di_ic; 22324Sbill brelse(bp); 2247651Ssam #ifdef QUOTA 2257492Skre if (ip->i_mode == 0) 2267492Skre ip->i_dquot = NODQUOT; 2277492Skre else 2287492Skre ip->i_dquot = inoquota(ip); 2297492Skre #endif 2306569Smckusic return (ip); 23124Sbill } 23224Sbill 23324Sbill /* 23416642Ssam * Convert a pointer to an inode into a reference to an inode. 23516642Ssam * 23616642Ssam * This is basically the internal piece of iget (after the 23716642Ssam * inode pointer is located) but without the test for mounted 23816642Ssam * filesystems. It is caller's responsibility to check that 23916642Ssam * the inode pointer is valid. 24016642Ssam */ 24116642Ssam igrab(ip) 24216642Ssam register struct inode *ip; 24316642Ssam { 24416642Ssam while ((ip->i_flag&ILOCKED) != 0) { 24516642Ssam ip->i_flag |= IWANT; 24616642Ssam sleep((caddr_t)ip, PINOD); 24716642Ssam } 24816642Ssam if (ip->i_count == 0) { /* ino on free list */ 24916642Ssam register struct inode *iq; 25016642Ssam 25116642Ssam if (iq = ip->i_freef) 25216642Ssam iq->i_freeb = ip->i_freeb; 25316642Ssam else 25416642Ssam ifreet = ip->i_freeb; 25516642Ssam *ip->i_freeb = iq; 25616642Ssam ip->i_freef = NULL; 25716642Ssam ip->i_freeb = NULL; 25816642Ssam } 25916642Ssam ip->i_count++; 26016642Ssam ip->i_flag |= ILOCKED; 26116642Ssam } 26216642Ssam 26316642Ssam /* 26424Sbill * Decrement reference count of 26524Sbill * an inode structure. 26624Sbill * On the last reference, 26724Sbill * write the inode out and if necessary, 26824Sbill * truncate and deallocate the file. 26924Sbill */ 27024Sbill iput(ip) 2714818Swnj register struct inode *ip; 27224Sbill { 2737118Smckusick 2748452Sroot if ((ip->i_flag & ILOCKED) == 0) 2757118Smckusick panic("iput"); 27616665Smckusick IUNLOCK(ip); 2777118Smckusick irele(ip); 2787118Smckusick } 2797118Smckusick 2807118Smckusick irele(ip) 2817118Smckusick register struct inode *ip; 2827118Smckusick { 2836569Smckusic int mode; 28424Sbill 28518445Smckusick if (ip->i_count == 1) { 2868452Sroot ip->i_flag |= ILOCKED; 28718445Smckusick if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) { 2889165Ssam itrunc(ip, (u_long)0); 2896569Smckusic mode = ip->i_mode; 29024Sbill ip->i_mode = 0; 2917351Skre ip->i_rdev = 0; 29224Sbill ip->i_flag |= IUPD|ICHG; 2936569Smckusic ifree(ip, ip->i_number, mode); 2947651Ssam #ifdef QUOTA 29512645Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 2967492Skre dqrele(ip->i_dquot); 2977492Skre ip->i_dquot = NODQUOT; 2987492Skre #endif 29924Sbill } 3008671Sroot IUPDAT(ip, &time, &time, 0); 30116665Smckusick IUNLOCK(ip); 3027334Skre ip->i_flag = 0; 3037334Skre /* 3047334Skre * Put the inode on the end of the free list. 3057334Skre * Possibly in some cases it would be better to 3067334Skre * put the inode at the head of the free list, 3077334Skre * (eg: where i_mode == 0 || i_number == 0) 3087334Skre * but I will think about that later .. kre 3097334Skre * (i_number is rarely 0 - only after an i/o error in iget, 3107334Skre * where i_mode == 0, the inode will probably be wanted 3117334Skre * again soon for an ialloc, so possibly we should keep it) 3127334Skre */ 3137334Skre if (ifreeh) { 3147334Skre *ifreet = ip; 3157334Skre ip->i_freeb = ifreet; 31624Sbill } else { 3177334Skre ifreeh = ip; 3187334Skre ip->i_freeb = &ifreeh; 31924Sbill } 3207334Skre ip->i_freef = NULL; 3217334Skre ifreet = &ip->i_freef; 32216058Skarels } else if (!(ip->i_flag & ILOCKED)) 32316058Skarels ITIMES(ip, &time, &time); 32424Sbill ip->i_count--; 32524Sbill } 32624Sbill 32724Sbill /* 32824Sbill * Check accessed and update flags on 32924Sbill * an inode structure. 33024Sbill * If any is on, update the inode 33124Sbill * with the current time. 3321203Sbill * If waitfor is given, then must insure 3331203Sbill * i/o order so wait for write to complete. 33424Sbill */ 3351203Sbill iupdat(ip, ta, tm, waitfor) 3364818Swnj register struct inode *ip; 3378630Sroot struct timeval *ta, *tm; 3384818Swnj int waitfor; 33924Sbill { 34024Sbill register struct buf *bp; 34124Sbill struct dinode *dp; 342*30749Skarels register struct fs *fs; 34324Sbill 344*30749Skarels fs = ip->i_fs; 34516058Skarels if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) { 346*30749Skarels if (fs->fs_ronly) 34724Sbill return; 348*30749Skarels #ifdef SECSIZE 349*30749Skarels bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)), 350*30749Skarels (int)fs->fs_bsize, fs->fs_dbsize); 351*30749Skarels #else SECSIZE 352*30749Skarels bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)), 353*30749Skarels (int)fs->fs_bsize); 354*30749Skarels #endif SECSIZE 35524Sbill if (bp->b_flags & B_ERROR) { 35624Sbill brelse(bp); 35724Sbill return; 35824Sbill } 3594818Swnj if (ip->i_flag&IACC) 3608630Sroot ip->i_atime = ta->tv_sec; 3614818Swnj if (ip->i_flag&IUPD) 3628630Sroot ip->i_mtime = tm->tv_sec; 3634818Swnj if (ip->i_flag&ICHG) 3648106Sroot ip->i_ctime = time.tv_sec; 36516058Skarels ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 366*30749Skarels dp = bp->b_un.b_dino + itoo(fs, ip->i_number); 3677343Skre dp->di_ic = ip->i_ic; 3681203Sbill if (waitfor) 3691203Sbill bwrite(bp); 3701203Sbill else 3711203Sbill bdwrite(bp); 37224Sbill } 37324Sbill } 37424Sbill 37510736Ssam #define SINGLE 0 /* index of single indirect block */ 37610736Ssam #define DOUBLE 1 /* index of double indirect block */ 37710736Ssam #define TRIPLE 2 /* index of triple indirect block */ 37824Sbill /* 3797702Ssam * Truncate the inode ip to at most 3807702Ssam * length size. Free affected disk 3817702Ssam * blocks -- the blocks of the file 3827702Ssam * are removed in reverse order. 38310736Ssam * 38410736Ssam * NB: triple indirect blocks are untested. 38524Sbill */ 38610736Ssam itrunc(oip, length) 38717942Smckusick register struct inode *oip; 3889165Ssam u_long length; 38924Sbill { 3909165Ssam register daddr_t lastblock; 39126272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 3926569Smckusic register struct fs *fs; 39310736Ssam register struct inode *ip; 39417942Smckusick struct buf *bp; 395*30749Skarels int offset, osize, size, count, level; 39617942Smckusick long nblocks, blocksreleased = 0; 39717942Smckusick register int i; 39817942Smckusick dev_t dev; 39910736Ssam struct inode tip; 40017942Smckusick extern long indirtrunc(); 4019165Ssam 40213000Ssam if (oip->i_size <= length) { 40313000Ssam oip->i_flag |= ICHG|IUPD; 40413000Ssam iupdat(oip, &time, &time, 1); 4059165Ssam return; 40613000Ssam } 4071203Sbill /* 40810736Ssam * Calculate index into inode's block list of 40910736Ssam * last direct and indirect blocks (if any) 41010736Ssam * which we want to keep. Lastblock is -1 when 41110736Ssam * the file is truncated to 0. 4121203Sbill */ 41310736Ssam fs = oip->i_fs; 4149165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 41510736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 41610736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 41710736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 41812645Ssam nblocks = btodb(fs->fs_bsize); 4196569Smckusic /* 42017942Smckusick * Update the size of the file. If the file is not being 42117942Smckusick * truncated to a block boundry, the contents of the 42217942Smckusick * partial block following the end of the file must be 42317942Smckusick * zero'ed in case it ever become accessable again because 42417942Smckusick * of subsequent file growth. 42517942Smckusick */ 42617942Smckusick osize = oip->i_size; 42717942Smckusick offset = blkoff(fs, length); 42817942Smckusick if (offset == 0) { 42917942Smckusick oip->i_size = length; 43017942Smckusick } else { 43117942Smckusick lbn = lblkno(fs, length); 43217942Smckusick bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset)); 43317942Smckusick if (u.u_error || (long)bn < 0) 43417942Smckusick return; 43517942Smckusick oip->i_size = length; 43617942Smckusick size = blksize(fs, oip, lbn); 437*30749Skarels count = howmany(size, CLBYTES); 43817942Smckusick dev = oip->i_dev; 439*30749Skarels for (i = 0; i < count; i++) 440*30749Skarels #ifdef SECSIZE 441*30749Skarels munhash(dev, bn + i * CLBYTES / fs->fs_dbsize); 442*30749Skarels #else SECSIZE 443*30749Skarels munhash(dev, bn + i * CLBYTES / DEV_BSIZE); 444*30749Skarels #endif SECSIZE 44517942Smckusick bp = bread(dev, bn, size); 44617942Smckusick if (bp->b_flags & B_ERROR) { 44717942Smckusick u.u_error = EIO; 44817942Smckusick oip->i_size = osize; 44917942Smckusick brelse(bp); 45017942Smckusick return; 45117942Smckusick } 45226272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 45317942Smckusick bdwrite(bp); 45417942Smckusick } 45517942Smckusick /* 45617942Smckusick * Update file and block pointers 45710736Ssam * on disk before we start freeing blocks. 45810736Ssam * If we crash before free'ing blocks below, 45910736Ssam * the blocks will be returned to the free list. 46010736Ssam * lastiblock values are also normalized to -1 46110736Ssam * for calls to indirtrunc below. 4626569Smckusic */ 46310736Ssam tip = *oip; 46417942Smckusick tip.i_size = osize; 46510736Ssam for (level = TRIPLE; level >= SINGLE; level--) 46610736Ssam if (lastiblock[level] < 0) { 46710736Ssam oip->i_ib[level] = 0; 46810736Ssam lastiblock[level] = -1; 4699165Ssam } 47010736Ssam for (i = NDADDR - 1; i > lastblock; i--) 47110736Ssam oip->i_db[i] = 0; 47210736Ssam oip->i_flag |= ICHG|IUPD; 47317942Smckusick syncip(oip); 47410736Ssam 4756569Smckusic /* 47610736Ssam * Indirect blocks first. 4776569Smckusic */ 47817942Smckusick ip = &tip; 47910736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 48010736Ssam bn = ip->i_ib[level]; 4819165Ssam if (bn != 0) { 48210736Ssam blocksreleased += 48312645Ssam indirtrunc(ip, bn, lastiblock[level], level); 48410736Ssam if (lastiblock[level] < 0) { 48510736Ssam ip->i_ib[level] = 0; 48610736Ssam free(ip, bn, (off_t)fs->fs_bsize); 48710736Ssam blocksreleased += nblocks; 48810736Ssam } 48910736Ssam } 49010736Ssam if (lastiblock[level] >= 0) 49110736Ssam goto done; 4929165Ssam } 49310736Ssam 4946569Smckusic /* 49510736Ssam * All whole direct blocks or frags. 4966569Smckusic */ 4979165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 49826359Skarels register off_t bsize; 4999165Ssam 5006569Smckusic bn = ip->i_db[i]; 5019165Ssam if (bn == 0) 50224Sbill continue; 5039165Ssam ip->i_db[i] = 0; 50424525Sbloom bsize = (off_t)blksize(fs, ip, i); 50524525Sbloom free(ip, bn, bsize); 50624525Sbloom blocksreleased += btodb(bsize); 50724Sbill } 50810736Ssam if (lastblock < 0) 50910736Ssam goto done; 51010736Ssam 5111203Sbill /* 5129165Ssam * Finally, look for a change in size of the 5139165Ssam * last direct block; release any frags. 5141203Sbill */ 51510736Ssam bn = ip->i_db[lastblock]; 51610736Ssam if (bn != 0) { 51726359Skarels off_t oldspace, newspace; 51810736Ssam 5199165Ssam /* 5209165Ssam * Calculate amount of space we're giving 5219165Ssam * back as old block size minus new block size. 5229165Ssam */ 52310736Ssam oldspace = blksize(fs, ip, lastblock); 5249165Ssam ip->i_size = length; 52510736Ssam newspace = blksize(fs, ip, lastblock); 52610736Ssam if (newspace == 0) 52710736Ssam panic("itrunc: newspace"); 52810736Ssam if (oldspace - newspace > 0) { 5299165Ssam /* 5309165Ssam * Block number of space to be free'd is 5319165Ssam * the old block # plus the number of frags 5329165Ssam * required for the storage we're keeping. 5339165Ssam */ 53410736Ssam bn += numfrags(fs, newspace); 53510736Ssam free(ip, bn, oldspace - newspace); 53612645Ssam blocksreleased += btodb(oldspace - newspace); 5379165Ssam } 5389165Ssam } 5399165Ssam done: 54010736Ssam /* BEGIN PARANOIA */ 54110736Ssam for (level = SINGLE; level <= TRIPLE; level++) 54210736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 54310736Ssam panic("itrunc1"); 54410736Ssam for (i = 0; i < NDADDR; i++) 54510736Ssam if (ip->i_db[i] != oip->i_db[i]) 54610736Ssam panic("itrunc2"); 54710736Ssam /* END PARANOIA */ 54812645Ssam oip->i_blocks -= blocksreleased; 54912645Ssam if (oip->i_blocks < 0) /* sanity */ 55012645Ssam oip->i_blocks = 0; 55112645Ssam oip->i_flag |= ICHG; 5529165Ssam #ifdef QUOTA 55312645Ssam (void) chkdq(oip, -blocksreleased, 0); 5549165Ssam #endif 55524Sbill } 55624Sbill 5579165Ssam /* 5589165Ssam * Release blocks associated with the inode ip and 5599165Ssam * stored in the indirect block bn. Blocks are free'd 5609165Ssam * in LIFO order up to (but not including) lastbn. If 56110736Ssam * level is greater than SINGLE, the block is an indirect 56210736Ssam * block and recursive calls to indirtrunc must be used to 56310736Ssam * cleanse other indirect blocks. 56410736Ssam * 56510736Ssam * NB: triple indirect blocks are untested. 5669165Ssam */ 5677492Skre long 56810736Ssam indirtrunc(ip, bn, lastbn, level) 5696569Smckusic register struct inode *ip; 5709165Ssam daddr_t bn, lastbn; 57110736Ssam int level; 57224Sbill { 5739165Ssam register int i; 57410736Ssam struct buf *bp, *copy; 57524Sbill register daddr_t *bap; 57610736Ssam register struct fs *fs = ip->i_fs; 5779165Ssam daddr_t nb, last; 57810736Ssam long factor; 5799165Ssam int blocksreleased = 0, nblocks; 58024Sbill 58110736Ssam /* 58210736Ssam * Calculate index in current block of last 58310736Ssam * block to be kept. -1 indicates the entire 58410736Ssam * block so we need not calculate the index. 58510736Ssam */ 58610736Ssam factor = 1; 58710736Ssam for (i = SINGLE; i < level; i++) 58810736Ssam factor *= NINDIR(fs); 5899165Ssam last = lastbn; 59010736Ssam if (lastbn > 0) 59110736Ssam last /= factor; 59212645Ssam nblocks = btodb(fs->fs_bsize); 59310736Ssam /* 59410736Ssam * Get buffer of block pointers, zero those 59510736Ssam * entries corresponding to blocks to be free'd, 59610736Ssam * and update on disk copy first. 59710736Ssam */ 59810736Ssam copy = geteblk((int)fs->fs_bsize); 599*30749Skarels #ifdef SECSIZE 600*30749Skarels bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize, 601*30749Skarels fs->fs_dbsize); 602*30749Skarels #else SECSIZE 60310736Ssam bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize); 604*30749Skarels #endif SECSIZE 60510736Ssam if (bp->b_flags&B_ERROR) { 60610736Ssam brelse(copy); 60710736Ssam brelse(bp); 60810736Ssam return (0); 60910736Ssam } 61010736Ssam bap = bp->b_un.b_daddr; 61110736Ssam bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize); 61210736Ssam bzero((caddr_t)&bap[last + 1], 61310736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 61410736Ssam bwrite(bp); 61510736Ssam bp = copy, bap = bp->b_un.b_daddr; 61610736Ssam 61710736Ssam /* 61810736Ssam * Recursively free totally unused blocks. 61910736Ssam */ 6209165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 62124Sbill nb = bap[i]; 6229165Ssam if (nb == 0) 62324Sbill continue; 62410736Ssam if (level > SINGLE) 6259165Ssam blocksreleased += 62612645Ssam indirtrunc(ip, nb, (daddr_t)-1, level - 1); 62726359Skarels free(ip, nb, (off_t)fs->fs_bsize); 6289165Ssam blocksreleased += nblocks; 62924Sbill } 63010736Ssam 63110736Ssam /* 63210736Ssam * Recursively free last partial block. 63310736Ssam */ 63410736Ssam if (level > SINGLE && lastbn >= 0) { 63510736Ssam last = lastbn % factor; 6369165Ssam nb = bap[i]; 6379165Ssam if (nb != 0) 63812645Ssam blocksreleased += indirtrunc(ip, nb, last, level - 1); 6399165Ssam } 64010736Ssam brelse(bp); 6419165Ssam return (blocksreleased); 64224Sbill } 64324Sbill 64424Sbill /* 645*30749Skarels * Remove any inodes in the inode cache belonging to dev. 6467334Skre * 6477334Skre * There should not be any active ones, return error if any are found 648*30749Skarels * (nb: this is a user error, not a system err). 6497334Skre */ 6507651Ssam #ifdef QUOTA 6517504Sroot iflush(dev, iq) 6527492Skre dev_t dev; 6537504Sroot struct inode *iq; 6547492Skre #else 6557334Skre iflush(dev) 6567334Skre dev_t dev; 6577492Skre #endif 6587334Skre { 6597335Skre register struct inode *ip; 6607334Skre 6617334Skre for (ip = inode; ip < inodeNINODE; ip++) { 6627651Ssam #ifdef QUOTA 6637492Skre if (ip != iq && ip->i_dev == dev) 6647492Skre #else 6657334Skre if (ip->i_dev == dev) 6667492Skre #endif 6677334Skre if (ip->i_count) 668*30749Skarels return (EBUSY); 6697334Skre else { 6707335Skre remque(ip); 6717334Skre ip->i_forw = ip; 6727334Skre ip->i_back = ip; 6737334Skre /* 6747334Skre * as i_count == 0, the inode was on the free 6757334Skre * list already, just leave it there, it will 6767334Skre * fall off the bottom eventually. We could 6777334Skre * perhaps move it to the head of the free 6787334Skre * list, but as umounts are done so 6797334Skre * infrequently, we would gain very little, 6807334Skre * while making the code bigger. 6817334Skre */ 6827651Ssam #ifdef QUOTA 6837492Skre dqrele(ip->i_dquot); 6847492Skre ip->i_dquot = NODQUOT; 6857492Skre #endif 6867334Skre } 6877334Skre } 688*30749Skarels return (0); 6897334Skre } 6907334Skre 6913617Sroot /* 6924818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6933617Sroot */ 6944818Swnj ilock(ip) 6954818Swnj register struct inode *ip; 6963617Sroot { 6973617Sroot 6988452Sroot ILOCK(ip); 6993617Sroot } 7003617Sroot 7013617Sroot /* 7024818Swnj * Unlock an inode. If WANT bit is on, wakeup. 7033617Sroot */ 7047118Smckusick iunlock(ip) 7054818Swnj register struct inode *ip; 7063617Sroot { 7073617Sroot 7088452Sroot IUNLOCK(ip); 7093617Sroot } 710