1*17099Sbloom /* lfs_inode.c 6.11 84/08/29 */ 224Sbill 3*17099Sbloom #include "param.h" 4*17099Sbloom #include "systm.h" 5*17099Sbloom #include "mount.h" 6*17099Sbloom #include "dir.h" 7*17099Sbloom #include "user.h" 8*17099Sbloom #include "inode.h" 9*17099Sbloom #include "fs.h" 10*17099Sbloom #include "conf.h" 11*17099Sbloom #include "buf.h" 127651Ssam #ifdef QUOTA 13*17099Sbloom #include "quota.h" 147504Sroot #endif 15*17099Sbloom #include "kernel.h" 1624Sbill 1716840Smckusick #define INOHSZ 512 187334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 197334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 207334Skre #else 2110852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 227334Skre #endif 2324Sbill 247334Skre union ihead { /* inode LRU cache, Chris Maltby */ 257334Skre union ihead *ih_head[2]; 267334Skre struct inode *ih_chain[2]; 277334Skre } ihead[INOHSZ]; 287334Skre 297334Skre struct inode *ifreeh, **ifreet; 307334Skre 3124Sbill /* 3224Sbill * Initialize hash links for inodes 3324Sbill * and build inode free list. 3424Sbill */ 3524Sbill ihinit() 3624Sbill { 3724Sbill register int i; 382737Swnj register struct inode *ip = inode; 397334Skre register union ihead *ih = ihead; 4024Sbill 417334Skre for (i = INOHSZ; --i >= 0; ih++) { 427334Skre ih->ih_head[0] = ih; 437334Skre ih->ih_head[1] = ih; 447334Skre } 457334Skre ifreeh = ip; 467334Skre ifreet = &ip->i_freef; 477334Skre ip->i_freeb = &ifreeh; 487334Skre ip->i_forw = ip; 497334Skre ip->i_back = ip; 507334Skre for (i = ninode; --i > 0; ) { 517334Skre ++ip; 527334Skre ip->i_forw = ip; 537334Skre ip->i_back = ip; 547334Skre *ifreet = ip; 557334Skre ip->i_freeb = ifreet; 567334Skre ifreet = &ip->i_freef; 577334Skre } 587334Skre ip->i_freef = NULL; 5924Sbill } 6024Sbill 617334Skre #ifdef notdef 6224Sbill /* 637334Skre * Find an inode if it is incore. 647334Skre * This is the equivalent, for inodes, 657334Skre * of ``incore'' in bio.c or ``pfind'' in subr.c. 667334Skre */ 677334Skre struct inode * 687334Skre ifind(dev, ino) 697334Skre dev_t dev; 707334Skre ino_t ino; 717334Skre { 727334Skre register struct inode *ip; 737334Skre register union ihead *ih; 747334Skre 757334Skre ih = &ihead[INOHASH(dev, ino)]; 767334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 777334Skre if (ino==ip->i_number && dev==ip->i_dev) 787334Skre return (ip); 797334Skre return ((struct inode *)0); 807334Skre } 817334Skre #endif notdef 827334Skre 837334Skre /* 8424Sbill * Look up an inode by device,inumber. 8524Sbill * If it is in core (in the inode structure), 8624Sbill * honor the locking protocol. 8724Sbill * If it is not in core, read it in from the 8824Sbill * specified device. 8924Sbill * If the inode is mounted on, perform 9024Sbill * the indicated indirection. 9124Sbill * In all cases, a pointer to a locked 9224Sbill * inode structure is returned. 9324Sbill * 9424Sbill * panic: no imt -- if the mounted file 9524Sbill * system is not in the mount table. 9624Sbill * "cannot happen" 9724Sbill */ 9824Sbill struct inode * 996569Smckusic iget(dev, fs, ino) 1004818Swnj dev_t dev; 1016569Smckusic register struct fs *fs; 1024818Swnj ino_t ino; 10324Sbill { 1047335Skre register struct inode *ip; 1057335Skre register union ihead *ih; 10624Sbill register struct mount *mp; 10724Sbill register struct buf *bp; 10824Sbill register struct dinode *dp; 1097334Skre register struct inode *iq; 11024Sbill 11116656Smckusick 11224Sbill loop: 1137334Skre ih = &ihead[INOHASH(dev, ino)]; 1147334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 1154818Swnj if (ino == ip->i_number && dev == ip->i_dev) { 11616642Ssam /* 11716642Ssam * Following is essentially an inline expanded 11816642Ssam * copy of igrab(), expanded inline for speed, 11916642Ssam * and so that the test for a mounted on inode 12016642Ssam * can be deferred until after we are sure that 12116642Ssam * the inode isn't busy. 12216642Ssam */ 1238452Sroot if ((ip->i_flag&ILOCKED) != 0) { 12424Sbill ip->i_flag |= IWANT; 12524Sbill sleep((caddr_t)ip, PINOD); 12624Sbill goto loop; 12724Sbill } 1284818Swnj if ((ip->i_flag&IMOUNT) != 0) { 1296569Smckusic for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 1307334Skre if(mp->m_inodp == ip) { 1317334Skre dev = mp->m_dev; 1327334Skre fs = mp->m_bufp->b_un.b_fs; 1337334Skre ino = ROOTINO; 1347334Skre goto loop; 1357334Skre } 13624Sbill panic("no imt"); 13724Sbill } 1387334Skre if (ip->i_count == 0) { /* ino on free list */ 1397334Skre if (iq = ip->i_freef) 1407334Skre iq->i_freeb = ip->i_freeb; 1417334Skre else 1427334Skre ifreet = ip->i_freeb; 1437334Skre *ip->i_freeb = iq; 1447334Skre ip->i_freef = NULL; 1457334Skre ip->i_freeb = NULL; 1467334Skre } 14724Sbill ip->i_count++; 1488452Sroot ip->i_flag |= ILOCKED; 14924Sbill return(ip); 15024Sbill } 1517334Skre 1527334Skre if ((ip = ifreeh) == NULL) { 1532933Swnj tablefull("inode"); 15424Sbill u.u_error = ENFILE; 15524Sbill return(NULL); 15624Sbill } 15716720Skarels if (ip->i_count) 15816720Skarels panic("free inode isn't"); 1597334Skre if (iq = ip->i_freef) 1607334Skre iq->i_freeb = &ifreeh; 1617334Skre ifreeh = iq; 1627334Skre ip->i_freef = NULL; 1637334Skre ip->i_freeb = NULL; 1647334Skre /* 1657334Skre * Now to take inode off the hash chain it was on 1667334Skre * (initially, or after an iflush, it is on a "hash chain" 1677334Skre * consisting entirely of itself, and pointed to by no-one, 1687334Skre * but that doesn't matter), and put it on the chain for 1697334Skre * its new (ino, dev) pair 1707334Skre */ 1717335Skre remque(ip); 1727335Skre insque(ip, ih); 17324Sbill ip->i_dev = dev; 1746569Smckusic ip->i_fs = fs; 17524Sbill ip->i_number = ino; 17616738Smckusick cacheinval(ip); 1778452Sroot ip->i_flag = ILOCKED; 17824Sbill ip->i_count++; 1796569Smckusic ip->i_lastr = 0; 18016720Skarels #ifdef QUOTA 18116720Skarels dqrele(ip->i_dquot); 18216720Skarels #endif 1838618Sroot bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize); 18424Sbill /* 18524Sbill * Check I/O errors 18624Sbill */ 1874818Swnj if ((bp->b_flags&B_ERROR) != 0) { 18824Sbill brelse(bp); 1897334Skre /* 1907334Skre * the inode doesn't contain anything useful, so it would 1917334Skre * be misleading to leave it on its hash chain. 1927334Skre * 'iput' will take care of putting it back on the free list. 1937334Skre */ 1947335Skre remque(ip); 1957334Skre ip->i_forw = ip; 1967334Skre ip->i_back = ip; 1977334Skre /* 1987334Skre * we also loose its inumber, just in case (as iput 1997334Skre * doesn't do that any more) - but as it isn't on its 2007334Skre * hash chain, I doubt if this is really necessary .. kre 2017334Skre * (probably the two methods are interchangable) 2027334Skre */ 2037334Skre ip->i_number = 0; 2047651Ssam #ifdef QUOTA 2057492Skre ip->i_dquot = NODQUOT; 2067492Skre #endif 20724Sbill iput(ip); 20824Sbill return(NULL); 20924Sbill } 21024Sbill dp = bp->b_un.b_dino; 2116569Smckusic dp += itoo(fs, ino); 2126569Smckusic ip->i_ic = dp->di_ic; 21324Sbill brelse(bp); 2147651Ssam #ifdef QUOTA 2157492Skre if (ip->i_mode == 0) 2167492Skre ip->i_dquot = NODQUOT; 2177492Skre else 2187492Skre ip->i_dquot = inoquota(ip); 2197492Skre #endif 2206569Smckusic return (ip); 22124Sbill } 22224Sbill 22324Sbill /* 22416642Ssam * Convert a pointer to an inode into a reference to an inode. 22516642Ssam * 22616642Ssam * This is basically the internal piece of iget (after the 22716642Ssam * inode pointer is located) but without the test for mounted 22816642Ssam * filesystems. It is caller's responsibility to check that 22916642Ssam * the inode pointer is valid. 23016642Ssam */ 23116642Ssam igrab(ip) 23216642Ssam register struct inode *ip; 23316642Ssam { 23416642Ssam while ((ip->i_flag&ILOCKED) != 0) { 23516642Ssam ip->i_flag |= IWANT; 23616642Ssam sleep((caddr_t)ip, PINOD); 23716642Ssam } 23816642Ssam if (ip->i_count == 0) { /* ino on free list */ 23916642Ssam register struct inode *iq; 24016642Ssam 24116642Ssam if (iq = ip->i_freef) 24216642Ssam iq->i_freeb = ip->i_freeb; 24316642Ssam else 24416642Ssam ifreet = ip->i_freeb; 24516642Ssam *ip->i_freeb = iq; 24616642Ssam ip->i_freef = NULL; 24716642Ssam ip->i_freeb = NULL; 24816642Ssam } 24916642Ssam ip->i_count++; 25016642Ssam ip->i_flag |= ILOCKED; 25116642Ssam } 25216642Ssam 25316642Ssam /* 25424Sbill * Decrement reference count of 25524Sbill * an inode structure. 25624Sbill * On the last reference, 25724Sbill * write the inode out and if necessary, 25824Sbill * truncate and deallocate the file. 25924Sbill */ 26024Sbill iput(ip) 2614818Swnj register struct inode *ip; 26224Sbill { 2637118Smckusick 2648452Sroot if ((ip->i_flag & ILOCKED) == 0) 2657118Smckusick panic("iput"); 26616665Smckusick IUNLOCK(ip); 2677118Smckusick irele(ip); 2687118Smckusick } 2697118Smckusick 2707118Smckusick irele(ip) 2717118Smckusick register struct inode *ip; 2727118Smckusick { 2736569Smckusic int mode; 27424Sbill 2754818Swnj if (ip->i_count == 1) { 2768452Sroot ip->i_flag |= ILOCKED; 2774818Swnj if (ip->i_nlink <= 0) { 2789165Ssam itrunc(ip, (u_long)0); 2796569Smckusic mode = ip->i_mode; 28024Sbill ip->i_mode = 0; 2817351Skre ip->i_rdev = 0; 28224Sbill ip->i_flag |= IUPD|ICHG; 2836569Smckusic ifree(ip, ip->i_number, mode); 2847651Ssam #ifdef QUOTA 28512645Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 2867492Skre dqrele(ip->i_dquot); 2877492Skre ip->i_dquot = NODQUOT; 2887492Skre #endif 28924Sbill } 2908671Sroot IUPDAT(ip, &time, &time, 0); 29116665Smckusick IUNLOCK(ip); 2927334Skre ip->i_flag = 0; 2937334Skre /* 2947334Skre * Put the inode on the end of the free list. 2957334Skre * Possibly in some cases it would be better to 2967334Skre * put the inode at the head of the free list, 2977334Skre * (eg: where i_mode == 0 || i_number == 0) 2987334Skre * but I will think about that later .. kre 2997334Skre * (i_number is rarely 0 - only after an i/o error in iget, 3007334Skre * where i_mode == 0, the inode will probably be wanted 3017334Skre * again soon for an ialloc, so possibly we should keep it) 3027334Skre */ 3037334Skre if (ifreeh) { 3047334Skre *ifreet = ip; 3057334Skre ip->i_freeb = ifreet; 30624Sbill } else { 3077334Skre ifreeh = ip; 3087334Skre ip->i_freeb = &ifreeh; 30924Sbill } 3107334Skre ip->i_freef = NULL; 3117334Skre ifreet = &ip->i_freef; 31216058Skarels } else if (!(ip->i_flag & ILOCKED)) 31316058Skarels ITIMES(ip, &time, &time); 31424Sbill ip->i_count--; 31524Sbill } 31624Sbill 31724Sbill /* 31824Sbill * Check accessed and update flags on 31924Sbill * an inode structure. 32024Sbill * If any is on, update the inode 32124Sbill * with the current time. 3221203Sbill * If waitfor is given, then must insure 3231203Sbill * i/o order so wait for write to complete. 32424Sbill */ 3251203Sbill iupdat(ip, ta, tm, waitfor) 3264818Swnj register struct inode *ip; 3278630Sroot struct timeval *ta, *tm; 3284818Swnj int waitfor; 32924Sbill { 33024Sbill register struct buf *bp; 33124Sbill struct dinode *dp; 3326569Smckusic register struct fs *fp; 33324Sbill 3346569Smckusic fp = ip->i_fs; 33516058Skarels if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) { 3366569Smckusic if (fp->fs_ronly) 33724Sbill return; 3386569Smckusic bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), 3398618Sroot (int)fp->fs_bsize); 34024Sbill if (bp->b_flags & B_ERROR) { 34124Sbill brelse(bp); 34224Sbill return; 34324Sbill } 3444818Swnj if (ip->i_flag&IACC) 3458630Sroot ip->i_atime = ta->tv_sec; 3464818Swnj if (ip->i_flag&IUPD) 3478630Sroot ip->i_mtime = tm->tv_sec; 3484818Swnj if (ip->i_flag&ICHG) 3498106Sroot ip->i_ctime = time.tv_sec; 35016058Skarels ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 3517343Skre dp = bp->b_un.b_dino + itoo(fp, ip->i_number); 3527343Skre dp->di_ic = ip->i_ic; 3531203Sbill if (waitfor) 3541203Sbill bwrite(bp); 3551203Sbill else 3561203Sbill bdwrite(bp); 35724Sbill } 35824Sbill } 35924Sbill 36010736Ssam #define SINGLE 0 /* index of single indirect block */ 36110736Ssam #define DOUBLE 1 /* index of double indirect block */ 36210736Ssam #define TRIPLE 2 /* index of triple indirect block */ 36324Sbill /* 3647702Ssam * Truncate the inode ip to at most 3657702Ssam * length size. Free affected disk 3667702Ssam * blocks -- the blocks of the file 3677702Ssam * are removed in reverse order. 36810736Ssam * 36910736Ssam * NB: triple indirect blocks are untested. 37024Sbill */ 37110736Ssam itrunc(oip, length) 37210736Ssam struct inode *oip; 3739165Ssam u_long length; 37424Sbill { 37524Sbill register i; 3769165Ssam register daddr_t lastblock; 37710736Ssam daddr_t bn, lastiblock[NIADDR]; 3786569Smckusic register struct fs *fs; 37910736Ssam register struct inode *ip; 38010736Ssam struct inode tip; 3819165Ssam long blocksreleased = 0, nblocks; 3829165Ssam long indirtrunc(); 38312645Ssam int level; 3849165Ssam 38513000Ssam if (oip->i_size <= length) { 38613000Ssam oip->i_flag |= ICHG|IUPD; 38713000Ssam iupdat(oip, &time, &time, 1); 3889165Ssam return; 38913000Ssam } 3901203Sbill /* 39110736Ssam * Calculate index into inode's block list of 39210736Ssam * last direct and indirect blocks (if any) 39310736Ssam * which we want to keep. Lastblock is -1 when 39410736Ssam * the file is truncated to 0. 3951203Sbill */ 39610736Ssam fs = oip->i_fs; 3979165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 39810736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 39910736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 40010736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 40112645Ssam nblocks = btodb(fs->fs_bsize); 4026569Smckusic /* 40310736Ssam * Update size of file and block pointers 40410736Ssam * on disk before we start freeing blocks. 40510736Ssam * If we crash before free'ing blocks below, 40610736Ssam * the blocks will be returned to the free list. 40710736Ssam * lastiblock values are also normalized to -1 40810736Ssam * for calls to indirtrunc below. 40910736Ssam * (? fsck doesn't check validity of pointers in indirect blocks) 4106569Smckusic */ 41110736Ssam tip = *oip; 41210736Ssam for (level = TRIPLE; level >= SINGLE; level--) 41310736Ssam if (lastiblock[level] < 0) { 41410736Ssam oip->i_ib[level] = 0; 41510736Ssam lastiblock[level] = -1; 4169165Ssam } 41710736Ssam for (i = NDADDR - 1; i > lastblock; i--) 41810736Ssam oip->i_db[i] = 0; 41910736Ssam oip->i_size = length; 42010736Ssam oip->i_flag |= ICHG|IUPD; 42110736Ssam iupdat(oip, &time, &time, 1); 42210736Ssam ip = &tip; 42310736Ssam 4246569Smckusic /* 42510736Ssam * Indirect blocks first. 4266569Smckusic */ 42710736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 42810736Ssam bn = ip->i_ib[level]; 4299165Ssam if (bn != 0) { 43010736Ssam blocksreleased += 43112645Ssam indirtrunc(ip, bn, lastiblock[level], level); 43210736Ssam if (lastiblock[level] < 0) { 43310736Ssam ip->i_ib[level] = 0; 43410736Ssam free(ip, bn, (off_t)fs->fs_bsize); 43510736Ssam blocksreleased += nblocks; 43610736Ssam } 43710736Ssam } 43810736Ssam if (lastiblock[level] >= 0) 43910736Ssam goto done; 4409165Ssam } 44110736Ssam 4426569Smckusic /* 44310736Ssam * All whole direct blocks or frags. 4446569Smckusic */ 4459165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 4469165Ssam register int size; 4479165Ssam 4486569Smckusic bn = ip->i_db[i]; 4499165Ssam if (bn == 0) 45024Sbill continue; 4519165Ssam ip->i_db[i] = 0; 4529165Ssam size = (off_t)blksize(fs, ip, i); 4539165Ssam free(ip, bn, size); 45412645Ssam blocksreleased += btodb(size); 45524Sbill } 45610736Ssam if (lastblock < 0) 45710736Ssam goto done; 45810736Ssam 4591203Sbill /* 4609165Ssam * Finally, look for a change in size of the 4619165Ssam * last direct block; release any frags. 4621203Sbill */ 46310736Ssam bn = ip->i_db[lastblock]; 46410736Ssam if (bn != 0) { 46510736Ssam int oldspace, newspace; 46610736Ssam 4679165Ssam /* 4689165Ssam * Calculate amount of space we're giving 4699165Ssam * back as old block size minus new block size. 4709165Ssam */ 47110736Ssam oldspace = blksize(fs, ip, lastblock); 4729165Ssam ip->i_size = length; 47310736Ssam newspace = blksize(fs, ip, lastblock); 47410736Ssam if (newspace == 0) 47510736Ssam panic("itrunc: newspace"); 47610736Ssam if (oldspace - newspace > 0) { 4779165Ssam /* 4789165Ssam * Block number of space to be free'd is 4799165Ssam * the old block # plus the number of frags 4809165Ssam * required for the storage we're keeping. 4819165Ssam */ 48210736Ssam bn += numfrags(fs, newspace); 48310736Ssam free(ip, bn, oldspace - newspace); 48412645Ssam blocksreleased += btodb(oldspace - newspace); 4859165Ssam } 4869165Ssam } 4879165Ssam done: 48810736Ssam /* BEGIN PARANOIA */ 48910736Ssam for (level = SINGLE; level <= TRIPLE; level++) 49010736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 49110736Ssam panic("itrunc1"); 49210736Ssam for (i = 0; i < NDADDR; i++) 49310736Ssam if (ip->i_db[i] != oip->i_db[i]) 49410736Ssam panic("itrunc2"); 49510736Ssam /* END PARANOIA */ 49612645Ssam oip->i_blocks -= blocksreleased; 49712645Ssam if (oip->i_blocks < 0) /* sanity */ 49812645Ssam oip->i_blocks = 0; 49912645Ssam oip->i_flag |= ICHG; 5009165Ssam #ifdef QUOTA 50112645Ssam (void) chkdq(oip, -blocksreleased, 0); 5029165Ssam #endif 50324Sbill } 50424Sbill 5059165Ssam /* 5069165Ssam * Release blocks associated with the inode ip and 5079165Ssam * stored in the indirect block bn. Blocks are free'd 5089165Ssam * in LIFO order up to (but not including) lastbn. If 50910736Ssam * level is greater than SINGLE, the block is an indirect 51010736Ssam * block and recursive calls to indirtrunc must be used to 51110736Ssam * cleanse other indirect blocks. 51210736Ssam * 51310736Ssam * NB: triple indirect blocks are untested. 5149165Ssam */ 5157492Skre long 51610736Ssam indirtrunc(ip, bn, lastbn, level) 5176569Smckusic register struct inode *ip; 5189165Ssam daddr_t bn, lastbn; 51910736Ssam int level; 52024Sbill { 5219165Ssam register int i; 52210736Ssam struct buf *bp, *copy; 52324Sbill register daddr_t *bap; 52410736Ssam register struct fs *fs = ip->i_fs; 5259165Ssam daddr_t nb, last; 52610736Ssam long factor; 5279165Ssam int blocksreleased = 0, nblocks; 52824Sbill 52910736Ssam /* 53010736Ssam * Calculate index in current block of last 53110736Ssam * block to be kept. -1 indicates the entire 53210736Ssam * block so we need not calculate the index. 53310736Ssam */ 53410736Ssam factor = 1; 53510736Ssam for (i = SINGLE; i < level; i++) 53610736Ssam factor *= NINDIR(fs); 5379165Ssam last = lastbn; 53810736Ssam if (lastbn > 0) 53910736Ssam last /= factor; 54012645Ssam nblocks = btodb(fs->fs_bsize); 54110736Ssam /* 54210736Ssam * Get buffer of block pointers, zero those 54310736Ssam * entries corresponding to blocks to be free'd, 54410736Ssam * and update on disk copy first. 54510736Ssam */ 54610736Ssam copy = geteblk((int)fs->fs_bsize); 54710736Ssam bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize); 54810736Ssam if (bp->b_flags&B_ERROR) { 54910736Ssam brelse(copy); 55010736Ssam brelse(bp); 55110736Ssam return (0); 55210736Ssam } 55310736Ssam bap = bp->b_un.b_daddr; 55410736Ssam bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize); 55510736Ssam bzero((caddr_t)&bap[last + 1], 55610736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 55710736Ssam bwrite(bp); 55810736Ssam bp = copy, bap = bp->b_un.b_daddr; 55910736Ssam 56010736Ssam /* 56110736Ssam * Recursively free totally unused blocks. 56210736Ssam */ 5639165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 56424Sbill nb = bap[i]; 5659165Ssam if (nb == 0) 56624Sbill continue; 56710736Ssam if (level > SINGLE) 5689165Ssam blocksreleased += 56912645Ssam indirtrunc(ip, nb, (daddr_t)-1, level - 1); 5709165Ssam free(ip, nb, (int)fs->fs_bsize); 5719165Ssam blocksreleased += nblocks; 57224Sbill } 57310736Ssam 57410736Ssam /* 57510736Ssam * Recursively free last partial block. 57610736Ssam */ 57710736Ssam if (level > SINGLE && lastbn >= 0) { 57810736Ssam last = lastbn % factor; 5799165Ssam nb = bap[i]; 5809165Ssam if (nb != 0) 58112645Ssam blocksreleased += indirtrunc(ip, nb, last, level - 1); 5829165Ssam } 58310736Ssam brelse(bp); 5849165Ssam return (blocksreleased); 58524Sbill } 58624Sbill 58724Sbill /* 5887334Skre * remove any inodes in the inode cache belonging to dev 5897334Skre * 5907334Skre * There should not be any active ones, return error if any are found 5917334Skre * (nb: this is a user error, not a system err) 5927334Skre * 5937334Skre * Also, count the references to dev by block devices - this really 5947334Skre * has nothing to do with the object of the procedure, but as we have 5957334Skre * to scan the inode table here anyway, we might as well get the 5967334Skre * extra benefit. 5977334Skre * 5987334Skre * this is called from sumount()/sys3.c when dev is being unmounted 5997334Skre */ 6007651Ssam #ifdef QUOTA 6017504Sroot iflush(dev, iq) 6027492Skre dev_t dev; 6037504Sroot struct inode *iq; 6047492Skre #else 6057334Skre iflush(dev) 6067334Skre dev_t dev; 6077492Skre #endif 6087334Skre { 6097335Skre register struct inode *ip; 6107334Skre register open = 0; 6117334Skre 6127334Skre for (ip = inode; ip < inodeNINODE; ip++) { 6137651Ssam #ifdef QUOTA 6147492Skre if (ip != iq && ip->i_dev == dev) 6157492Skre #else 6167334Skre if (ip->i_dev == dev) 6177492Skre #endif 6187334Skre if (ip->i_count) 6197334Skre return(-1); 6207334Skre else { 6217335Skre remque(ip); 6227334Skre ip->i_forw = ip; 6237334Skre ip->i_back = ip; 6247334Skre /* 6257334Skre * as i_count == 0, the inode was on the free 6267334Skre * list already, just leave it there, it will 6277334Skre * fall off the bottom eventually. We could 6287334Skre * perhaps move it to the head of the free 6297334Skre * list, but as umounts are done so 6307334Skre * infrequently, we would gain very little, 6317334Skre * while making the code bigger. 6327334Skre */ 6337651Ssam #ifdef QUOTA 6347492Skre dqrele(ip->i_dquot); 6357492Skre ip->i_dquot = NODQUOT; 6367492Skre #endif 6377334Skre } 6387334Skre else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK && 6397334Skre ip->i_rdev == dev) 6407334Skre open++; 6417334Skre } 6427334Skre return (open); 6437334Skre } 6447334Skre 6453617Sroot /* 6464818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6473617Sroot */ 6484818Swnj ilock(ip) 6494818Swnj register struct inode *ip; 6503617Sroot { 6513617Sroot 6528452Sroot ILOCK(ip); 6533617Sroot } 6543617Sroot 6553617Sroot /* 6564818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6573617Sroot */ 6587118Smckusick iunlock(ip) 6594818Swnj register struct inode *ip; 6603617Sroot { 6613617Sroot 6628452Sroot IUNLOCK(ip); 6633617Sroot } 664