1*16720Skarels /* lfs_inode.c 6.8 84/07/15 */ 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; 11016656Smckusick struct inode *xp; 11124Sbill 11216656Smckusick 11324Sbill loop: 1147334Skre ih = &ihead[INOHASH(dev, ino)]; 1157334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 1164818Swnj if (ino == ip->i_number && dev == ip->i_dev) { 11716642Ssam /* 11816642Ssam * Following is essentially an inline expanded 11916642Ssam * copy of igrab(), expanded inline for speed, 12016642Ssam * and so that the test for a mounted on inode 12116642Ssam * can be deferred until after we are sure that 12216642Ssam * the inode isn't busy. 12316642Ssam */ 1248452Sroot if ((ip->i_flag&ILOCKED) != 0) { 12524Sbill ip->i_flag |= IWANT; 12624Sbill sleep((caddr_t)ip, PINOD); 12724Sbill goto loop; 12824Sbill } 1294818Swnj if ((ip->i_flag&IMOUNT) != 0) { 1306569Smckusic for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 1317334Skre if(mp->m_inodp == ip) { 1327334Skre dev = mp->m_dev; 1337334Skre fs = mp->m_bufp->b_un.b_fs; 1347334Skre ino = ROOTINO; 1357334Skre goto loop; 1367334Skre } 13724Sbill panic("no imt"); 13824Sbill } 1397334Skre if (ip->i_count == 0) { /* ino on free list */ 1407334Skre if (iq = ip->i_freef) 1417334Skre iq->i_freeb = ip->i_freeb; 1427334Skre else 1437334Skre ifreet = ip->i_freeb; 1447334Skre *ip->i_freeb = iq; 1457334Skre ip->i_freef = NULL; 1467334Skre ip->i_freeb = NULL; 1477334Skre } 14824Sbill ip->i_count++; 1498452Sroot ip->i_flag |= ILOCKED; 15024Sbill return(ip); 15124Sbill } 1527334Skre 1537334Skre if ((ip = ifreeh) == NULL) { 1542933Swnj tablefull("inode"); 15524Sbill u.u_error = ENFILE; 15624Sbill return(NULL); 15724Sbill } 158*16720Skarels if (ip->i_count) 159*16720Skarels panic("free inode isn't"); 1607334Skre if (iq = ip->i_freef) 1617334Skre iq->i_freeb = &ifreeh; 1627334Skre ifreeh = iq; 1637334Skre ip->i_freef = NULL; 1647334Skre ip->i_freeb = NULL; 1657334Skre /* 1667334Skre * Now to take inode off the hash chain it was on 1677334Skre * (initially, or after an iflush, it is on a "hash chain" 1687334Skre * consisting entirely of itself, and pointed to by no-one, 1697334Skre * but that doesn't matter), and put it on the chain for 1707334Skre * its new (ino, dev) pair 1717334Skre */ 1727335Skre remque(ip); 1737335Skre insque(ip, ih); 17424Sbill ip->i_dev = dev; 1756569Smckusic ip->i_fs = fs; 17624Sbill ip->i_number = ino; 17716642Ssam ip->i_id = ++nextinodeid; /* also used in rename */ 17816642Ssam /* 17916642Ssam * At an absurd rate of 100 calls/second, 18016656Smckusick * this should occur once every 8 months. 18116642Ssam */ 18216656Smckusick if (nextinodeid < 0) 18316656Smckusick for (nextinodeid = 0, xp = inode; xp < inodeNINODE; xp++) 18416656Smckusick xp->i_id = 0; 1858452Sroot ip->i_flag = ILOCKED; 18624Sbill ip->i_count++; 1876569Smckusic ip->i_lastr = 0; 188*16720Skarels #ifdef QUOTA 189*16720Skarels dqrele(ip->i_dquot); 190*16720Skarels #endif 1918618Sroot bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize); 19224Sbill /* 19324Sbill * Check I/O errors 19424Sbill */ 1954818Swnj if ((bp->b_flags&B_ERROR) != 0) { 19624Sbill brelse(bp); 1977334Skre /* 1987334Skre * the inode doesn't contain anything useful, so it would 1997334Skre * be misleading to leave it on its hash chain. 2007334Skre * 'iput' will take care of putting it back on the free list. 2017334Skre */ 2027335Skre remque(ip); 2037334Skre ip->i_forw = ip; 2047334Skre ip->i_back = ip; 2057334Skre /* 2067334Skre * we also loose its inumber, just in case (as iput 2077334Skre * doesn't do that any more) - but as it isn't on its 2087334Skre * hash chain, I doubt if this is really necessary .. kre 2097334Skre * (probably the two methods are interchangable) 2107334Skre */ 2117334Skre ip->i_number = 0; 2127651Ssam #ifdef QUOTA 2137492Skre ip->i_dquot = NODQUOT; 2147492Skre #endif 21524Sbill iput(ip); 21624Sbill return(NULL); 21724Sbill } 21824Sbill dp = bp->b_un.b_dino; 2196569Smckusic dp += itoo(fs, ino); 2206569Smckusic ip->i_ic = dp->di_ic; 22124Sbill brelse(bp); 2227651Ssam #ifdef QUOTA 2237492Skre if (ip->i_mode == 0) 2247492Skre ip->i_dquot = NODQUOT; 2257492Skre else 2267492Skre ip->i_dquot = inoquota(ip); 2277492Skre #endif 2286569Smckusic return (ip); 22924Sbill } 23024Sbill 23124Sbill /* 23216642Ssam * Convert a pointer to an inode into a reference to an inode. 23316642Ssam * 23416642Ssam * This is basically the internal piece of iget (after the 23516642Ssam * inode pointer is located) but without the test for mounted 23616642Ssam * filesystems. It is caller's responsibility to check that 23716642Ssam * the inode pointer is valid. 23816642Ssam */ 23916642Ssam igrab(ip) 24016642Ssam register struct inode *ip; 24116642Ssam { 24216642Ssam while ((ip->i_flag&ILOCKED) != 0) { 24316642Ssam ip->i_flag |= IWANT; 24416642Ssam sleep((caddr_t)ip, PINOD); 24516642Ssam } 24616642Ssam if (ip->i_count == 0) { /* ino on free list */ 24716642Ssam register struct inode *iq; 24816642Ssam 24916642Ssam if (iq = ip->i_freef) 25016642Ssam iq->i_freeb = ip->i_freeb; 25116642Ssam else 25216642Ssam ifreet = ip->i_freeb; 25316642Ssam *ip->i_freeb = iq; 25416642Ssam ip->i_freef = NULL; 25516642Ssam ip->i_freeb = NULL; 25616642Ssam } 25716642Ssam ip->i_count++; 25816642Ssam ip->i_flag |= ILOCKED; 25916642Ssam } 26016642Ssam 26116642Ssam /* 26224Sbill * Decrement reference count of 26324Sbill * an inode structure. 26424Sbill * On the last reference, 26524Sbill * write the inode out and if necessary, 26624Sbill * truncate and deallocate the file. 26724Sbill */ 26824Sbill iput(ip) 2694818Swnj register struct inode *ip; 27024Sbill { 2717118Smckusick 2728452Sroot if ((ip->i_flag & ILOCKED) == 0) 2737118Smckusick panic("iput"); 27416665Smckusick IUNLOCK(ip); 2757118Smckusick irele(ip); 2767118Smckusick } 2777118Smckusick 2787118Smckusick irele(ip) 2797118Smckusick register struct inode *ip; 2807118Smckusick { 2816569Smckusic int mode; 28224Sbill 2834818Swnj if (ip->i_count == 1) { 2848452Sroot ip->i_flag |= ILOCKED; 2854818Swnj if (ip->i_nlink <= 0) { 2869165Ssam itrunc(ip, (u_long)0); 2876569Smckusic mode = ip->i_mode; 28824Sbill ip->i_mode = 0; 2897351Skre ip->i_rdev = 0; 29024Sbill ip->i_flag |= IUPD|ICHG; 2916569Smckusic ifree(ip, ip->i_number, mode); 2927651Ssam #ifdef QUOTA 29312645Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 2947492Skre dqrele(ip->i_dquot); 2957492Skre ip->i_dquot = NODQUOT; 2967492Skre #endif 29724Sbill } 2988671Sroot IUPDAT(ip, &time, &time, 0); 29916665Smckusick IUNLOCK(ip); 3007334Skre ip->i_flag = 0; 3017334Skre /* 3027334Skre * Put the inode on the end of the free list. 3037334Skre * Possibly in some cases it would be better to 3047334Skre * put the inode at the head of the free list, 3057334Skre * (eg: where i_mode == 0 || i_number == 0) 3067334Skre * but I will think about that later .. kre 3077334Skre * (i_number is rarely 0 - only after an i/o error in iget, 3087334Skre * where i_mode == 0, the inode will probably be wanted 3097334Skre * again soon for an ialloc, so possibly we should keep it) 3107334Skre */ 3117334Skre if (ifreeh) { 3127334Skre *ifreet = ip; 3137334Skre ip->i_freeb = ifreet; 31424Sbill } else { 3157334Skre ifreeh = ip; 3167334Skre ip->i_freeb = &ifreeh; 31724Sbill } 3187334Skre ip->i_freef = NULL; 3197334Skre ifreet = &ip->i_freef; 32016058Skarels } else if (!(ip->i_flag & ILOCKED)) 32116058Skarels ITIMES(ip, &time, &time); 32224Sbill ip->i_count--; 32324Sbill } 32424Sbill 32524Sbill /* 32624Sbill * Check accessed and update flags on 32724Sbill * an inode structure. 32824Sbill * If any is on, update the inode 32924Sbill * with the current time. 3301203Sbill * If waitfor is given, then must insure 3311203Sbill * i/o order so wait for write to complete. 33224Sbill */ 3331203Sbill iupdat(ip, ta, tm, waitfor) 3344818Swnj register struct inode *ip; 3358630Sroot struct timeval *ta, *tm; 3364818Swnj int waitfor; 33724Sbill { 33824Sbill register struct buf *bp; 33924Sbill struct dinode *dp; 3406569Smckusic register struct fs *fp; 34124Sbill 3426569Smckusic fp = ip->i_fs; 34316058Skarels if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) { 3446569Smckusic if (fp->fs_ronly) 34524Sbill return; 3466569Smckusic bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), 3478618Sroot (int)fp->fs_bsize); 34824Sbill if (bp->b_flags & B_ERROR) { 34924Sbill brelse(bp); 35024Sbill return; 35124Sbill } 3524818Swnj if (ip->i_flag&IACC) 3538630Sroot ip->i_atime = ta->tv_sec; 3544818Swnj if (ip->i_flag&IUPD) 3558630Sroot ip->i_mtime = tm->tv_sec; 3564818Swnj if (ip->i_flag&ICHG) 3578106Sroot ip->i_ctime = time.tv_sec; 35816058Skarels ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 3597343Skre dp = bp->b_un.b_dino + itoo(fp, ip->i_number); 3607343Skre dp->di_ic = ip->i_ic; 3611203Sbill if (waitfor) 3621203Sbill bwrite(bp); 3631203Sbill else 3641203Sbill bdwrite(bp); 36524Sbill } 36624Sbill } 36724Sbill 36810736Ssam #define SINGLE 0 /* index of single indirect block */ 36910736Ssam #define DOUBLE 1 /* index of double indirect block */ 37010736Ssam #define TRIPLE 2 /* index of triple indirect block */ 37124Sbill /* 3727702Ssam * Truncate the inode ip to at most 3737702Ssam * length size. Free affected disk 3747702Ssam * blocks -- the blocks of the file 3757702Ssam * are removed in reverse order. 37610736Ssam * 37710736Ssam * NB: triple indirect blocks are untested. 37824Sbill */ 37910736Ssam itrunc(oip, length) 38010736Ssam struct inode *oip; 3819165Ssam u_long length; 38224Sbill { 38324Sbill register i; 3849165Ssam register daddr_t lastblock; 38510736Ssam daddr_t bn, lastiblock[NIADDR]; 3866569Smckusic register struct fs *fs; 38710736Ssam register struct inode *ip; 38810736Ssam struct inode tip; 3899165Ssam long blocksreleased = 0, nblocks; 3909165Ssam long indirtrunc(); 39112645Ssam int level; 3929165Ssam 39313000Ssam if (oip->i_size <= length) { 39413000Ssam oip->i_flag |= ICHG|IUPD; 39513000Ssam iupdat(oip, &time, &time, 1); 3969165Ssam return; 39713000Ssam } 3981203Sbill /* 39910736Ssam * Calculate index into inode's block list of 40010736Ssam * last direct and indirect blocks (if any) 40110736Ssam * which we want to keep. Lastblock is -1 when 40210736Ssam * the file is truncated to 0. 4031203Sbill */ 40410736Ssam fs = oip->i_fs; 4059165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 40610736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 40710736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 40810736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 40912645Ssam nblocks = btodb(fs->fs_bsize); 4106569Smckusic /* 41110736Ssam * Update size of file and block pointers 41210736Ssam * on disk before we start freeing blocks. 41310736Ssam * If we crash before free'ing blocks below, 41410736Ssam * the blocks will be returned to the free list. 41510736Ssam * lastiblock values are also normalized to -1 41610736Ssam * for calls to indirtrunc below. 41710736Ssam * (? fsck doesn't check validity of pointers in indirect blocks) 4186569Smckusic */ 41910736Ssam tip = *oip; 42010736Ssam for (level = TRIPLE; level >= SINGLE; level--) 42110736Ssam if (lastiblock[level] < 0) { 42210736Ssam oip->i_ib[level] = 0; 42310736Ssam lastiblock[level] = -1; 4249165Ssam } 42510736Ssam for (i = NDADDR - 1; i > lastblock; i--) 42610736Ssam oip->i_db[i] = 0; 42710736Ssam oip->i_size = length; 42810736Ssam oip->i_flag |= ICHG|IUPD; 42910736Ssam iupdat(oip, &time, &time, 1); 43010736Ssam ip = &tip; 43110736Ssam 4326569Smckusic /* 43310736Ssam * Indirect blocks first. 4346569Smckusic */ 43510736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 43610736Ssam bn = ip->i_ib[level]; 4379165Ssam if (bn != 0) { 43810736Ssam blocksreleased += 43912645Ssam indirtrunc(ip, bn, lastiblock[level], level); 44010736Ssam if (lastiblock[level] < 0) { 44110736Ssam ip->i_ib[level] = 0; 44210736Ssam free(ip, bn, (off_t)fs->fs_bsize); 44310736Ssam blocksreleased += nblocks; 44410736Ssam } 44510736Ssam } 44610736Ssam if (lastiblock[level] >= 0) 44710736Ssam goto done; 4489165Ssam } 44910736Ssam 4506569Smckusic /* 45110736Ssam * All whole direct blocks or frags. 4526569Smckusic */ 4539165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 4549165Ssam register int size; 4559165Ssam 4566569Smckusic bn = ip->i_db[i]; 4579165Ssam if (bn == 0) 45824Sbill continue; 4599165Ssam ip->i_db[i] = 0; 4609165Ssam size = (off_t)blksize(fs, ip, i); 4619165Ssam free(ip, bn, size); 46212645Ssam blocksreleased += btodb(size); 46324Sbill } 46410736Ssam if (lastblock < 0) 46510736Ssam goto done; 46610736Ssam 4671203Sbill /* 4689165Ssam * Finally, look for a change in size of the 4699165Ssam * last direct block; release any frags. 4701203Sbill */ 47110736Ssam bn = ip->i_db[lastblock]; 47210736Ssam if (bn != 0) { 47310736Ssam int oldspace, newspace; 47410736Ssam 4759165Ssam /* 4769165Ssam * Calculate amount of space we're giving 4779165Ssam * back as old block size minus new block size. 4789165Ssam */ 47910736Ssam oldspace = blksize(fs, ip, lastblock); 4809165Ssam ip->i_size = length; 48110736Ssam newspace = blksize(fs, ip, lastblock); 48210736Ssam if (newspace == 0) 48310736Ssam panic("itrunc: newspace"); 48410736Ssam if (oldspace - newspace > 0) { 4859165Ssam /* 4869165Ssam * Block number of space to be free'd is 4879165Ssam * the old block # plus the number of frags 4889165Ssam * required for the storage we're keeping. 4899165Ssam */ 49010736Ssam bn += numfrags(fs, newspace); 49110736Ssam free(ip, bn, oldspace - newspace); 49212645Ssam blocksreleased += btodb(oldspace - newspace); 4939165Ssam } 4949165Ssam } 4959165Ssam done: 49610736Ssam /* BEGIN PARANOIA */ 49710736Ssam for (level = SINGLE; level <= TRIPLE; level++) 49810736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 49910736Ssam panic("itrunc1"); 50010736Ssam for (i = 0; i < NDADDR; i++) 50110736Ssam if (ip->i_db[i] != oip->i_db[i]) 50210736Ssam panic("itrunc2"); 50310736Ssam /* END PARANOIA */ 50412645Ssam oip->i_blocks -= blocksreleased; 50512645Ssam if (oip->i_blocks < 0) /* sanity */ 50612645Ssam oip->i_blocks = 0; 50712645Ssam oip->i_flag |= ICHG; 5089165Ssam #ifdef QUOTA 50912645Ssam (void) chkdq(oip, -blocksreleased, 0); 5109165Ssam #endif 51124Sbill } 51224Sbill 5139165Ssam /* 5149165Ssam * Release blocks associated with the inode ip and 5159165Ssam * stored in the indirect block bn. Blocks are free'd 5169165Ssam * in LIFO order up to (but not including) lastbn. If 51710736Ssam * level is greater than SINGLE, the block is an indirect 51810736Ssam * block and recursive calls to indirtrunc must be used to 51910736Ssam * cleanse other indirect blocks. 52010736Ssam * 52110736Ssam * NB: triple indirect blocks are untested. 5229165Ssam */ 5237492Skre long 52410736Ssam indirtrunc(ip, bn, lastbn, level) 5256569Smckusic register struct inode *ip; 5269165Ssam daddr_t bn, lastbn; 52710736Ssam int level; 52824Sbill { 5299165Ssam register int i; 53010736Ssam struct buf *bp, *copy; 53124Sbill register daddr_t *bap; 53210736Ssam register struct fs *fs = ip->i_fs; 5339165Ssam daddr_t nb, last; 53410736Ssam long factor; 5359165Ssam int blocksreleased = 0, nblocks; 53624Sbill 53710736Ssam /* 53810736Ssam * Calculate index in current block of last 53910736Ssam * block to be kept. -1 indicates the entire 54010736Ssam * block so we need not calculate the index. 54110736Ssam */ 54210736Ssam factor = 1; 54310736Ssam for (i = SINGLE; i < level; i++) 54410736Ssam factor *= NINDIR(fs); 5459165Ssam last = lastbn; 54610736Ssam if (lastbn > 0) 54710736Ssam last /= factor; 54812645Ssam nblocks = btodb(fs->fs_bsize); 54910736Ssam /* 55010736Ssam * Get buffer of block pointers, zero those 55110736Ssam * entries corresponding to blocks to be free'd, 55210736Ssam * and update on disk copy first. 55310736Ssam */ 55410736Ssam copy = geteblk((int)fs->fs_bsize); 55510736Ssam bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize); 55610736Ssam if (bp->b_flags&B_ERROR) { 55710736Ssam brelse(copy); 55810736Ssam brelse(bp); 55910736Ssam return (0); 56010736Ssam } 56110736Ssam bap = bp->b_un.b_daddr; 56210736Ssam bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize); 56310736Ssam bzero((caddr_t)&bap[last + 1], 56410736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 56510736Ssam bwrite(bp); 56610736Ssam bp = copy, bap = bp->b_un.b_daddr; 56710736Ssam 56810736Ssam /* 56910736Ssam * Recursively free totally unused blocks. 57010736Ssam */ 5719165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 57224Sbill nb = bap[i]; 5739165Ssam if (nb == 0) 57424Sbill continue; 57510736Ssam if (level > SINGLE) 5769165Ssam blocksreleased += 57712645Ssam indirtrunc(ip, nb, (daddr_t)-1, level - 1); 5789165Ssam free(ip, nb, (int)fs->fs_bsize); 5799165Ssam blocksreleased += nblocks; 58024Sbill } 58110736Ssam 58210736Ssam /* 58310736Ssam * Recursively free last partial block. 58410736Ssam */ 58510736Ssam if (level > SINGLE && lastbn >= 0) { 58610736Ssam last = lastbn % factor; 5879165Ssam nb = bap[i]; 5889165Ssam if (nb != 0) 58912645Ssam blocksreleased += indirtrunc(ip, nb, last, level - 1); 5909165Ssam } 59110736Ssam brelse(bp); 5929165Ssam return (blocksreleased); 59324Sbill } 59424Sbill 59524Sbill /* 5967334Skre * remove any inodes in the inode cache belonging to dev 5977334Skre * 5987334Skre * There should not be any active ones, return error if any are found 5997334Skre * (nb: this is a user error, not a system err) 6007334Skre * 6017334Skre * Also, count the references to dev by block devices - this really 6027334Skre * has nothing to do with the object of the procedure, but as we have 6037334Skre * to scan the inode table here anyway, we might as well get the 6047334Skre * extra benefit. 6057334Skre * 6067334Skre * this is called from sumount()/sys3.c when dev is being unmounted 6077334Skre */ 6087651Ssam #ifdef QUOTA 6097504Sroot iflush(dev, iq) 6107492Skre dev_t dev; 6117504Sroot struct inode *iq; 6127492Skre #else 6137334Skre iflush(dev) 6147334Skre dev_t dev; 6157492Skre #endif 6167334Skre { 6177335Skre register struct inode *ip; 6187334Skre register open = 0; 6197334Skre 6207334Skre for (ip = inode; ip < inodeNINODE; ip++) { 6217651Ssam #ifdef QUOTA 6227492Skre if (ip != iq && ip->i_dev == dev) 6237492Skre #else 6247334Skre if (ip->i_dev == dev) 6257492Skre #endif 6267334Skre if (ip->i_count) 6277334Skre return(-1); 6287334Skre else { 6297335Skre remque(ip); 6307334Skre ip->i_forw = ip; 6317334Skre ip->i_back = ip; 6327334Skre /* 6337334Skre * as i_count == 0, the inode was on the free 6347334Skre * list already, just leave it there, it will 6357334Skre * fall off the bottom eventually. We could 6367334Skre * perhaps move it to the head of the free 6377334Skre * list, but as umounts are done so 6387334Skre * infrequently, we would gain very little, 6397334Skre * while making the code bigger. 6407334Skre */ 6417651Ssam #ifdef QUOTA 6427492Skre dqrele(ip->i_dquot); 6437492Skre ip->i_dquot = NODQUOT; 6447492Skre #endif 6457334Skre } 6467334Skre else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK && 6477334Skre ip->i_rdev == dev) 6487334Skre open++; 6497334Skre } 6507334Skre return (open); 6517334Skre } 6527334Skre 6533617Sroot /* 6544818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6553617Sroot */ 6564818Swnj ilock(ip) 6574818Swnj register struct inode *ip; 6583617Sroot { 6593617Sroot 6608452Sroot ILOCK(ip); 6613617Sroot } 6623617Sroot 6633617Sroot /* 6644818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6653617Sroot */ 6667118Smckusick iunlock(ip) 6674818Swnj register struct inode *ip; 6683617Sroot { 6693617Sroot 6708452Sroot IUNLOCK(ip); 6713617Sroot } 672