1*16642Ssam /* lfs_inode.c 6.5 84/06/27 */ 224Sbill 324Sbill #include "../h/param.h" 424Sbill #include "../h/systm.h" 524Sbill #include "../h/mount.h" 624Sbill #include "../h/dir.h" 724Sbill #include "../h/user.h" 824Sbill #include "../h/inode.h" 96569Smckusic #include "../h/fs.h" 1024Sbill #include "../h/conf.h" 1124Sbill #include "../h/buf.h" 127651Ssam #ifdef QUOTA 137504Sroot #include "../h/quota.h" 147504Sroot #endif 158106Sroot #include "../h/kernel.h" 1624Sbill 1716524Skarels #define INOHSZ 64 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 11124Sbill loop: 1127334Skre ih = &ihead[INOHASH(dev, ino)]; 1137334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 1144818Swnj if (ino == ip->i_number && dev == ip->i_dev) { 115*16642Ssam /* 116*16642Ssam * Following is essentially an inline expanded 117*16642Ssam * copy of igrab(), expanded inline for speed, 118*16642Ssam * and so that the test for a mounted on inode 119*16642Ssam * can be deferred until after we are sure that 120*16642Ssam * the inode isn't busy. 121*16642Ssam */ 1228452Sroot if ((ip->i_flag&ILOCKED) != 0) { 12324Sbill ip->i_flag |= IWANT; 12424Sbill sleep((caddr_t)ip, PINOD); 12524Sbill goto loop; 12624Sbill } 1274818Swnj if ((ip->i_flag&IMOUNT) != 0) { 1286569Smckusic for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 1297334Skre if(mp->m_inodp == ip) { 1307334Skre dev = mp->m_dev; 1317334Skre fs = mp->m_bufp->b_un.b_fs; 1327334Skre ino = ROOTINO; 1337334Skre goto loop; 1347334Skre } 13524Sbill panic("no imt"); 13624Sbill } 1377334Skre if (ip->i_count == 0) { /* ino on free list */ 1387334Skre if (iq = ip->i_freef) 1397334Skre iq->i_freeb = ip->i_freeb; 1407334Skre else 1417334Skre ifreet = ip->i_freeb; 1427334Skre *ip->i_freeb = iq; 1437334Skre ip->i_freef = NULL; 1447334Skre ip->i_freeb = NULL; 1457334Skre } 14624Sbill ip->i_count++; 1478452Sroot ip->i_flag |= ILOCKED; 14824Sbill return(ip); 14924Sbill } 1507334Skre 1517334Skre if ((ip = ifreeh) == NULL) { 1522933Swnj tablefull("inode"); 15324Sbill u.u_error = ENFILE; 15424Sbill return(NULL); 15524Sbill } 1567334Skre if (iq = ip->i_freef) 1577334Skre iq->i_freeb = &ifreeh; 1587334Skre ifreeh = iq; 1597334Skre ip->i_freef = NULL; 1607334Skre ip->i_freeb = NULL; 1617334Skre /* 1627334Skre * Now to take inode off the hash chain it was on 1637334Skre * (initially, or after an iflush, it is on a "hash chain" 1647334Skre * consisting entirely of itself, and pointed to by no-one, 1657334Skre * but that doesn't matter), and put it on the chain for 1667334Skre * its new (ino, dev) pair 1677334Skre */ 1687335Skre remque(ip); 1697335Skre insque(ip, ih); 1707651Ssam #ifdef QUOTA 1717492Skre dqrele(ip->i_dquot); 1727492Skre #endif 17324Sbill ip->i_dev = dev; 1746569Smckusic ip->i_fs = fs; 17524Sbill ip->i_number = ino; 176*16642Ssam ip->i_id = ++nextinodeid; /* also used in rename */ 177*16642Ssam /* 178*16642Ssam * At an absurd rate of 100 calls/second, 179*16642Ssam * this should occur once every 16 months. 180*16642Ssam */ 181*16642Ssam if (nextinodeid == 0) 182*16642Ssam panic("iget: wrap"); 1838452Sroot ip->i_flag = ILOCKED; 18424Sbill ip->i_count++; 1856569Smckusic ip->i_lastr = 0; 1868618Sroot bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize); 18724Sbill /* 18824Sbill * Check I/O errors 18924Sbill */ 1904818Swnj if ((bp->b_flags&B_ERROR) != 0) { 19124Sbill brelse(bp); 1927334Skre /* 1937334Skre * the inode doesn't contain anything useful, so it would 1947334Skre * be misleading to leave it on its hash chain. 1957334Skre * 'iput' will take care of putting it back on the free list. 1967334Skre */ 1977335Skre remque(ip); 1987334Skre ip->i_forw = ip; 1997334Skre ip->i_back = ip; 2007334Skre /* 2017334Skre * we also loose its inumber, just in case (as iput 2027334Skre * doesn't do that any more) - but as it isn't on its 2037334Skre * hash chain, I doubt if this is really necessary .. kre 2047334Skre * (probably the two methods are interchangable) 2057334Skre */ 2067334Skre ip->i_number = 0; 2077651Ssam #ifdef QUOTA 2087492Skre ip->i_dquot = NODQUOT; 2097492Skre #endif 21024Sbill iput(ip); 21124Sbill return(NULL); 21224Sbill } 21324Sbill dp = bp->b_un.b_dino; 2146569Smckusic dp += itoo(fs, ino); 2156569Smckusic ip->i_ic = dp->di_ic; 21624Sbill brelse(bp); 2177651Ssam #ifdef QUOTA 2187492Skre if (ip->i_mode == 0) 2197492Skre ip->i_dquot = NODQUOT; 2207492Skre else 2217492Skre ip->i_dquot = inoquota(ip); 2227492Skre #endif 2236569Smckusic return (ip); 22424Sbill } 22524Sbill 22624Sbill /* 227*16642Ssam * Convert a pointer to an inode into a reference to an inode. 228*16642Ssam * 229*16642Ssam * This is basically the internal piece of iget (after the 230*16642Ssam * inode pointer is located) but without the test for mounted 231*16642Ssam * filesystems. It is caller's responsibility to check that 232*16642Ssam * the inode pointer is valid. 233*16642Ssam */ 234*16642Ssam igrab(ip) 235*16642Ssam register struct inode *ip; 236*16642Ssam { 237*16642Ssam while ((ip->i_flag&ILOCKED) != 0) { 238*16642Ssam ip->i_flag |= IWANT; 239*16642Ssam sleep((caddr_t)ip, PINOD); 240*16642Ssam } 241*16642Ssam if (ip->i_count == 0) { /* ino on free list */ 242*16642Ssam register struct inode *iq; 243*16642Ssam 244*16642Ssam if (iq = ip->i_freef) 245*16642Ssam iq->i_freeb = ip->i_freeb; 246*16642Ssam else 247*16642Ssam ifreet = ip->i_freeb; 248*16642Ssam *ip->i_freeb = iq; 249*16642Ssam ip->i_freef = NULL; 250*16642Ssam ip->i_freeb = NULL; 251*16642Ssam } 252*16642Ssam ip->i_count++; 253*16642Ssam ip->i_flag |= ILOCKED; 254*16642Ssam } 255*16642Ssam 256*16642Ssam /* 25724Sbill * Decrement reference count of 25824Sbill * an inode structure. 25924Sbill * On the last reference, 26024Sbill * write the inode out and if necessary, 26124Sbill * truncate and deallocate the file. 26224Sbill */ 26324Sbill iput(ip) 2644818Swnj register struct inode *ip; 26524Sbill { 2667118Smckusick 2678452Sroot if ((ip->i_flag & ILOCKED) == 0) 2687118Smckusick panic("iput"); 2697118Smckusick iunlock(ip); 2707118Smckusick irele(ip); 2717118Smckusick } 2727118Smckusick 2737118Smckusick irele(ip) 2747118Smckusick register struct inode *ip; 2757118Smckusick { 2766569Smckusic int mode; 27724Sbill 2784818Swnj if (ip->i_count == 1) { 2798452Sroot ip->i_flag |= ILOCKED; 2804818Swnj if (ip->i_nlink <= 0) { 2819165Ssam itrunc(ip, (u_long)0); 2826569Smckusic mode = ip->i_mode; 28324Sbill ip->i_mode = 0; 2847351Skre ip->i_rdev = 0; 28524Sbill ip->i_flag |= IUPD|ICHG; 2866569Smckusic ifree(ip, ip->i_number, mode); 2877651Ssam #ifdef QUOTA 28812645Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 2897492Skre dqrele(ip->i_dquot); 2907492Skre ip->i_dquot = NODQUOT; 2917492Skre #endif 29224Sbill } 2938671Sroot IUPDAT(ip, &time, &time, 0); 2947118Smckusick iunlock(ip); 2957334Skre ip->i_flag = 0; 2967334Skre /* 2977334Skre * Put the inode on the end of the free list. 2987334Skre * Possibly in some cases it would be better to 2997334Skre * put the inode at the head of the free list, 3007334Skre * (eg: where i_mode == 0 || i_number == 0) 3017334Skre * but I will think about that later .. kre 3027334Skre * (i_number is rarely 0 - only after an i/o error in iget, 3037334Skre * where i_mode == 0, the inode will probably be wanted 3047334Skre * again soon for an ialloc, so possibly we should keep it) 3057334Skre */ 3067334Skre if (ifreeh) { 3077334Skre *ifreet = ip; 3087334Skre ip->i_freeb = ifreet; 30924Sbill } else { 3107334Skre ifreeh = ip; 3117334Skre ip->i_freeb = &ifreeh; 31224Sbill } 3137334Skre ip->i_freef = NULL; 3147334Skre ifreet = &ip->i_freef; 31516058Skarels } else if (!(ip->i_flag & ILOCKED)) 31616058Skarels ITIMES(ip, &time, &time); 31724Sbill ip->i_count--; 31824Sbill } 31924Sbill 32024Sbill /* 32124Sbill * Check accessed and update flags on 32224Sbill * an inode structure. 32324Sbill * If any is on, update the inode 32424Sbill * with the current time. 3251203Sbill * If waitfor is given, then must insure 3261203Sbill * i/o order so wait for write to complete. 32724Sbill */ 3281203Sbill iupdat(ip, ta, tm, waitfor) 3294818Swnj register struct inode *ip; 3308630Sroot struct timeval *ta, *tm; 3314818Swnj int waitfor; 33224Sbill { 33324Sbill register struct buf *bp; 33424Sbill struct dinode *dp; 3356569Smckusic register struct fs *fp; 33624Sbill 3376569Smckusic fp = ip->i_fs; 33816058Skarels if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) { 3396569Smckusic if (fp->fs_ronly) 34024Sbill return; 3416569Smckusic bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), 3428618Sroot (int)fp->fs_bsize); 34324Sbill if (bp->b_flags & B_ERROR) { 34424Sbill brelse(bp); 34524Sbill return; 34624Sbill } 3474818Swnj if (ip->i_flag&IACC) 3488630Sroot ip->i_atime = ta->tv_sec; 3494818Swnj if (ip->i_flag&IUPD) 3508630Sroot ip->i_mtime = tm->tv_sec; 3514818Swnj if (ip->i_flag&ICHG) 3528106Sroot ip->i_ctime = time.tv_sec; 35316058Skarels ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 3547343Skre dp = bp->b_un.b_dino + itoo(fp, ip->i_number); 3557343Skre dp->di_ic = ip->i_ic; 3561203Sbill if (waitfor) 3571203Sbill bwrite(bp); 3581203Sbill else 3591203Sbill bdwrite(bp); 36024Sbill } 36124Sbill } 36224Sbill 36310736Ssam #define SINGLE 0 /* index of single indirect block */ 36410736Ssam #define DOUBLE 1 /* index of double indirect block */ 36510736Ssam #define TRIPLE 2 /* index of triple indirect block */ 36624Sbill /* 3677702Ssam * Truncate the inode ip to at most 3687702Ssam * length size. Free affected disk 3697702Ssam * blocks -- the blocks of the file 3707702Ssam * are removed in reverse order. 37110736Ssam * 37210736Ssam * NB: triple indirect blocks are untested. 37324Sbill */ 37410736Ssam itrunc(oip, length) 37510736Ssam struct inode *oip; 3769165Ssam u_long length; 37724Sbill { 37824Sbill register i; 3799165Ssam register daddr_t lastblock; 38010736Ssam daddr_t bn, lastiblock[NIADDR]; 3816569Smckusic register struct fs *fs; 38210736Ssam register struct inode *ip; 38310736Ssam struct inode tip; 3849165Ssam long blocksreleased = 0, nblocks; 3859165Ssam long indirtrunc(); 38612645Ssam int level; 3879165Ssam 38813000Ssam if (oip->i_size <= length) { 38913000Ssam oip->i_flag |= ICHG|IUPD; 39013000Ssam iupdat(oip, &time, &time, 1); 3919165Ssam return; 39213000Ssam } 3931203Sbill /* 39410736Ssam * Calculate index into inode's block list of 39510736Ssam * last direct and indirect blocks (if any) 39610736Ssam * which we want to keep. Lastblock is -1 when 39710736Ssam * the file is truncated to 0. 3981203Sbill */ 39910736Ssam fs = oip->i_fs; 4009165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 40110736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 40210736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 40310736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 40412645Ssam nblocks = btodb(fs->fs_bsize); 4056569Smckusic /* 40610736Ssam * Update size of file and block pointers 40710736Ssam * on disk before we start freeing blocks. 40810736Ssam * If we crash before free'ing blocks below, 40910736Ssam * the blocks will be returned to the free list. 41010736Ssam * lastiblock values are also normalized to -1 41110736Ssam * for calls to indirtrunc below. 41210736Ssam * (? fsck doesn't check validity of pointers in indirect blocks) 4136569Smckusic */ 41410736Ssam tip = *oip; 41510736Ssam for (level = TRIPLE; level >= SINGLE; level--) 41610736Ssam if (lastiblock[level] < 0) { 41710736Ssam oip->i_ib[level] = 0; 41810736Ssam lastiblock[level] = -1; 4199165Ssam } 42010736Ssam for (i = NDADDR - 1; i > lastblock; i--) 42110736Ssam oip->i_db[i] = 0; 42210736Ssam oip->i_size = length; 42310736Ssam oip->i_flag |= ICHG|IUPD; 42410736Ssam iupdat(oip, &time, &time, 1); 42510736Ssam ip = &tip; 42610736Ssam 4276569Smckusic /* 42810736Ssam * Indirect blocks first. 4296569Smckusic */ 43010736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 43110736Ssam bn = ip->i_ib[level]; 4329165Ssam if (bn != 0) { 43310736Ssam blocksreleased += 43412645Ssam indirtrunc(ip, bn, lastiblock[level], level); 43510736Ssam if (lastiblock[level] < 0) { 43610736Ssam ip->i_ib[level] = 0; 43710736Ssam free(ip, bn, (off_t)fs->fs_bsize); 43810736Ssam blocksreleased += nblocks; 43910736Ssam } 44010736Ssam } 44110736Ssam if (lastiblock[level] >= 0) 44210736Ssam goto done; 4439165Ssam } 44410736Ssam 4456569Smckusic /* 44610736Ssam * All whole direct blocks or frags. 4476569Smckusic */ 4489165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 4499165Ssam register int size; 4509165Ssam 4516569Smckusic bn = ip->i_db[i]; 4529165Ssam if (bn == 0) 45324Sbill continue; 4549165Ssam ip->i_db[i] = 0; 4559165Ssam size = (off_t)blksize(fs, ip, i); 4569165Ssam free(ip, bn, size); 45712645Ssam blocksreleased += btodb(size); 45824Sbill } 45910736Ssam if (lastblock < 0) 46010736Ssam goto done; 46110736Ssam 4621203Sbill /* 4639165Ssam * Finally, look for a change in size of the 4649165Ssam * last direct block; release any frags. 4651203Sbill */ 46610736Ssam bn = ip->i_db[lastblock]; 46710736Ssam if (bn != 0) { 46810736Ssam int oldspace, newspace; 46910736Ssam 4709165Ssam /* 4719165Ssam * Calculate amount of space we're giving 4729165Ssam * back as old block size minus new block size. 4739165Ssam */ 47410736Ssam oldspace = blksize(fs, ip, lastblock); 4759165Ssam ip->i_size = length; 47610736Ssam newspace = blksize(fs, ip, lastblock); 47710736Ssam if (newspace == 0) 47810736Ssam panic("itrunc: newspace"); 47910736Ssam if (oldspace - newspace > 0) { 4809165Ssam /* 4819165Ssam * Block number of space to be free'd is 4829165Ssam * the old block # plus the number of frags 4839165Ssam * required for the storage we're keeping. 4849165Ssam */ 48510736Ssam bn += numfrags(fs, newspace); 48610736Ssam free(ip, bn, oldspace - newspace); 48712645Ssam blocksreleased += btodb(oldspace - newspace); 4889165Ssam } 4899165Ssam } 4909165Ssam done: 49110736Ssam /* BEGIN PARANOIA */ 49210736Ssam for (level = SINGLE; level <= TRIPLE; level++) 49310736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 49410736Ssam panic("itrunc1"); 49510736Ssam for (i = 0; i < NDADDR; i++) 49610736Ssam if (ip->i_db[i] != oip->i_db[i]) 49710736Ssam panic("itrunc2"); 49810736Ssam /* END PARANOIA */ 49912645Ssam oip->i_blocks -= blocksreleased; 50012645Ssam if (oip->i_blocks < 0) /* sanity */ 50112645Ssam oip->i_blocks = 0; 50212645Ssam oip->i_flag |= ICHG; 5039165Ssam #ifdef QUOTA 50412645Ssam (void) chkdq(oip, -blocksreleased, 0); 5059165Ssam #endif 50624Sbill } 50724Sbill 5089165Ssam /* 5099165Ssam * Release blocks associated with the inode ip and 5109165Ssam * stored in the indirect block bn. Blocks are free'd 5119165Ssam * in LIFO order up to (but not including) lastbn. If 51210736Ssam * level is greater than SINGLE, the block is an indirect 51310736Ssam * block and recursive calls to indirtrunc must be used to 51410736Ssam * cleanse other indirect blocks. 51510736Ssam * 51610736Ssam * NB: triple indirect blocks are untested. 5179165Ssam */ 5187492Skre long 51910736Ssam indirtrunc(ip, bn, lastbn, level) 5206569Smckusic register struct inode *ip; 5219165Ssam daddr_t bn, lastbn; 52210736Ssam int level; 52324Sbill { 5249165Ssam register int i; 52510736Ssam struct buf *bp, *copy; 52624Sbill register daddr_t *bap; 52710736Ssam register struct fs *fs = ip->i_fs; 5289165Ssam daddr_t nb, last; 52910736Ssam long factor; 5309165Ssam int blocksreleased = 0, nblocks; 53124Sbill 53210736Ssam /* 53310736Ssam * Calculate index in current block of last 53410736Ssam * block to be kept. -1 indicates the entire 53510736Ssam * block so we need not calculate the index. 53610736Ssam */ 53710736Ssam factor = 1; 53810736Ssam for (i = SINGLE; i < level; i++) 53910736Ssam factor *= NINDIR(fs); 5409165Ssam last = lastbn; 54110736Ssam if (lastbn > 0) 54210736Ssam last /= factor; 54312645Ssam nblocks = btodb(fs->fs_bsize); 54410736Ssam /* 54510736Ssam * Get buffer of block pointers, zero those 54610736Ssam * entries corresponding to blocks to be free'd, 54710736Ssam * and update on disk copy first. 54810736Ssam */ 54910736Ssam copy = geteblk((int)fs->fs_bsize); 55010736Ssam bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize); 55110736Ssam if (bp->b_flags&B_ERROR) { 55210736Ssam brelse(copy); 55310736Ssam brelse(bp); 55410736Ssam return (0); 55510736Ssam } 55610736Ssam bap = bp->b_un.b_daddr; 55710736Ssam bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize); 55810736Ssam bzero((caddr_t)&bap[last + 1], 55910736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 56010736Ssam bwrite(bp); 56110736Ssam bp = copy, bap = bp->b_un.b_daddr; 56210736Ssam 56310736Ssam /* 56410736Ssam * Recursively free totally unused blocks. 56510736Ssam */ 5669165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 56724Sbill nb = bap[i]; 5689165Ssam if (nb == 0) 56924Sbill continue; 57010736Ssam if (level > SINGLE) 5719165Ssam blocksreleased += 57212645Ssam indirtrunc(ip, nb, (daddr_t)-1, level - 1); 5739165Ssam free(ip, nb, (int)fs->fs_bsize); 5749165Ssam blocksreleased += nblocks; 57524Sbill } 57610736Ssam 57710736Ssam /* 57810736Ssam * Recursively free last partial block. 57910736Ssam */ 58010736Ssam if (level > SINGLE && lastbn >= 0) { 58110736Ssam last = lastbn % factor; 5829165Ssam nb = bap[i]; 5839165Ssam if (nb != 0) 58412645Ssam blocksreleased += indirtrunc(ip, nb, last, level - 1); 5859165Ssam } 58610736Ssam brelse(bp); 5879165Ssam return (blocksreleased); 58824Sbill } 58924Sbill 59024Sbill /* 5917334Skre * remove any inodes in the inode cache belonging to dev 5927334Skre * 5937334Skre * There should not be any active ones, return error if any are found 5947334Skre * (nb: this is a user error, not a system err) 5957334Skre * 5967334Skre * Also, count the references to dev by block devices - this really 5977334Skre * has nothing to do with the object of the procedure, but as we have 5987334Skre * to scan the inode table here anyway, we might as well get the 5997334Skre * extra benefit. 6007334Skre * 6017334Skre * this is called from sumount()/sys3.c when dev is being unmounted 6027334Skre */ 6037651Ssam #ifdef QUOTA 6047504Sroot iflush(dev, iq) 6057492Skre dev_t dev; 6067504Sroot struct inode *iq; 6077492Skre #else 6087334Skre iflush(dev) 6097334Skre dev_t dev; 6107492Skre #endif 6117334Skre { 6127335Skre register struct inode *ip; 6137334Skre register open = 0; 6147334Skre 6157334Skre for (ip = inode; ip < inodeNINODE; ip++) { 6167651Ssam #ifdef QUOTA 6177492Skre if (ip != iq && ip->i_dev == dev) 6187492Skre #else 6197334Skre if (ip->i_dev == dev) 6207492Skre #endif 6217334Skre if (ip->i_count) 6227334Skre return(-1); 6237334Skre else { 6247335Skre remque(ip); 6257334Skre ip->i_forw = ip; 6267334Skre ip->i_back = ip; 6277334Skre /* 6287334Skre * as i_count == 0, the inode was on the free 6297334Skre * list already, just leave it there, it will 6307334Skre * fall off the bottom eventually. We could 6317334Skre * perhaps move it to the head of the free 6327334Skre * list, but as umounts are done so 6337334Skre * infrequently, we would gain very little, 6347334Skre * while making the code bigger. 6357334Skre */ 6367651Ssam #ifdef QUOTA 6377492Skre dqrele(ip->i_dquot); 6387492Skre ip->i_dquot = NODQUOT; 6397492Skre #endif 6407334Skre } 6417334Skre else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK && 6427334Skre ip->i_rdev == dev) 6437334Skre open++; 6447334Skre } 6457334Skre return (open); 6467334Skre } 6477334Skre 6483617Sroot /* 6494818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6503617Sroot */ 6514818Swnj ilock(ip) 6524818Swnj register struct inode *ip; 6533617Sroot { 6543617Sroot 6558452Sroot ILOCK(ip); 6563617Sroot } 6573617Sroot 6583617Sroot /* 6594818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6603617Sroot */ 6617118Smckusick iunlock(ip) 6624818Swnj register struct inode *ip; 6633617Sroot { 6643617Sroot 6658452Sroot IUNLOCK(ip); 6663617Sroot } 667