1*18445Smckusick /* lfs_inode.c 6.15 85/03/20 */ 224Sbill 317099Sbloom #include "param.h" 417099Sbloom #include "systm.h" 517099Sbloom #include "mount.h" 617099Sbloom #include "dir.h" 717099Sbloom #include "user.h" 817099Sbloom #include "inode.h" 917099Sbloom #include "fs.h" 1017099Sbloom #include "buf.h" 117651Ssam #ifdef QUOTA 1217099Sbloom #include "quota.h" 137504Sroot #endif 1417099Sbloom #include "kernel.h" 1524Sbill 1616840Smckusick #define INOHSZ 512 177334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 187334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 197334Skre #else 2010852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 217334Skre #endif 2224Sbill 237334Skre union ihead { /* inode LRU cache, Chris Maltby */ 247334Skre union ihead *ih_head[2]; 257334Skre struct inode *ih_chain[2]; 267334Skre } ihead[INOHSZ]; 277334Skre 287334Skre struct inode *ifreeh, **ifreet; 297334Skre 3024Sbill /* 3124Sbill * Initialize hash links for inodes 3224Sbill * and build inode free list. 3324Sbill */ 3424Sbill ihinit() 3524Sbill { 3624Sbill register int i; 372737Swnj register struct inode *ip = inode; 387334Skre register union ihead *ih = ihead; 3924Sbill 407334Skre for (i = INOHSZ; --i >= 0; ih++) { 417334Skre ih->ih_head[0] = ih; 427334Skre ih->ih_head[1] = ih; 437334Skre } 447334Skre ifreeh = ip; 457334Skre ifreet = &ip->i_freef; 467334Skre ip->i_freeb = &ifreeh; 477334Skre ip->i_forw = ip; 487334Skre ip->i_back = ip; 497334Skre for (i = ninode; --i > 0; ) { 507334Skre ++ip; 517334Skre ip->i_forw = ip; 527334Skre ip->i_back = ip; 537334Skre *ifreet = ip; 547334Skre ip->i_freeb = ifreet; 557334Skre ifreet = &ip->i_freef; 567334Skre } 577334Skre ip->i_freef = NULL; 5824Sbill } 5924Sbill 607334Skre #ifdef notdef 6124Sbill /* 627334Skre * Find an inode if it is incore. 637334Skre * This is the equivalent, for inodes, 647334Skre * of ``incore'' in bio.c or ``pfind'' in subr.c. 657334Skre */ 667334Skre struct inode * 677334Skre ifind(dev, ino) 687334Skre dev_t dev; 697334Skre ino_t ino; 707334Skre { 717334Skre register struct inode *ip; 727334Skre register union ihead *ih; 737334Skre 747334Skre ih = &ihead[INOHASH(dev, ino)]; 757334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 767334Skre if (ino==ip->i_number && dev==ip->i_dev) 777334Skre return (ip); 787334Skre return ((struct inode *)0); 797334Skre } 807334Skre #endif notdef 817334Skre 827334Skre /* 8324Sbill * Look up an inode by device,inumber. 8424Sbill * If it is in core (in the inode structure), 8524Sbill * honor the locking protocol. 8624Sbill * If it is not in core, read it in from the 8724Sbill * specified device. 8824Sbill * If the inode is mounted on, perform 8924Sbill * the indicated indirection. 9024Sbill * In all cases, a pointer to a locked 9124Sbill * inode structure is returned. 9224Sbill * 9324Sbill * panic: no imt -- if the mounted file 9424Sbill * system is not in the mount table. 9524Sbill * "cannot happen" 9624Sbill */ 9724Sbill struct inode * 986569Smckusic iget(dev, fs, ino) 994818Swnj dev_t dev; 1006569Smckusic register struct fs *fs; 1014818Swnj ino_t ino; 10224Sbill { 1037335Skre register struct inode *ip; 1047335Skre register union ihead *ih; 10524Sbill register struct mount *mp; 10624Sbill register struct buf *bp; 10724Sbill register struct dinode *dp; 1087334Skre register struct inode *iq; 10924Sbill 11016656Smckusick 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) { 11516642Ssam /* 11616642Ssam * Following is essentially an inline expanded 11716642Ssam * copy of igrab(), expanded inline for speed, 11816642Ssam * and so that the test for a mounted on inode 11916642Ssam * can be deferred until after we are sure that 12016642Ssam * the inode isn't busy. 12116642Ssam */ 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 } 15616720Skarels if (ip->i_count) 15716720Skarels panic("free inode isn't"); 1587334Skre if (iq = ip->i_freef) 1597334Skre iq->i_freeb = &ifreeh; 1607334Skre ifreeh = iq; 1617334Skre ip->i_freef = NULL; 1627334Skre ip->i_freeb = NULL; 1637334Skre /* 1647334Skre * Now to take inode off the hash chain it was on 1657334Skre * (initially, or after an iflush, it is on a "hash chain" 1667334Skre * consisting entirely of itself, and pointed to by no-one, 1677334Skre * but that doesn't matter), and put it on the chain for 1687334Skre * its new (ino, dev) pair 1697334Skre */ 1707335Skre remque(ip); 1717335Skre insque(ip, ih); 17224Sbill ip->i_dev = dev; 1736569Smckusic ip->i_fs = fs; 17424Sbill ip->i_number = ino; 17516738Smckusick cacheinval(ip); 1768452Sroot ip->i_flag = ILOCKED; 17724Sbill ip->i_count++; 1786569Smckusic ip->i_lastr = 0; 17916720Skarels #ifdef QUOTA 18016720Skarels dqrele(ip->i_dquot); 18116720Skarels #endif 1828618Sroot bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize); 18324Sbill /* 18424Sbill * Check I/O errors 18524Sbill */ 1864818Swnj if ((bp->b_flags&B_ERROR) != 0) { 18724Sbill brelse(bp); 1887334Skre /* 1897334Skre * the inode doesn't contain anything useful, so it would 1907334Skre * be misleading to leave it on its hash chain. 1917334Skre * 'iput' will take care of putting it back on the free list. 1927334Skre */ 1937335Skre remque(ip); 1947334Skre ip->i_forw = ip; 1957334Skre ip->i_back = ip; 1967334Skre /* 1977334Skre * we also loose its inumber, just in case (as iput 1987334Skre * doesn't do that any more) - but as it isn't on its 1997334Skre * hash chain, I doubt if this is really necessary .. kre 2007334Skre * (probably the two methods are interchangable) 2017334Skre */ 2027334Skre ip->i_number = 0; 2037651Ssam #ifdef QUOTA 2047492Skre ip->i_dquot = NODQUOT; 2057492Skre #endif 20624Sbill iput(ip); 20724Sbill return(NULL); 20824Sbill } 20924Sbill dp = bp->b_un.b_dino; 2106569Smckusic dp += itoo(fs, ino); 2116569Smckusic ip->i_ic = dp->di_ic; 21224Sbill brelse(bp); 2137651Ssam #ifdef QUOTA 2147492Skre if (ip->i_mode == 0) 2157492Skre ip->i_dquot = NODQUOT; 2167492Skre else 2177492Skre ip->i_dquot = inoquota(ip); 2187492Skre #endif 2196569Smckusic return (ip); 22024Sbill } 22124Sbill 22224Sbill /* 22316642Ssam * Convert a pointer to an inode into a reference to an inode. 22416642Ssam * 22516642Ssam * This is basically the internal piece of iget (after the 22616642Ssam * inode pointer is located) but without the test for mounted 22716642Ssam * filesystems. It is caller's responsibility to check that 22816642Ssam * the inode pointer is valid. 22916642Ssam */ 23016642Ssam igrab(ip) 23116642Ssam register struct inode *ip; 23216642Ssam { 23316642Ssam while ((ip->i_flag&ILOCKED) != 0) { 23416642Ssam ip->i_flag |= IWANT; 23516642Ssam sleep((caddr_t)ip, PINOD); 23616642Ssam } 23716642Ssam if (ip->i_count == 0) { /* ino on free list */ 23816642Ssam register struct inode *iq; 23916642Ssam 24016642Ssam if (iq = ip->i_freef) 24116642Ssam iq->i_freeb = ip->i_freeb; 24216642Ssam else 24316642Ssam ifreet = ip->i_freeb; 24416642Ssam *ip->i_freeb = iq; 24516642Ssam ip->i_freef = NULL; 24616642Ssam ip->i_freeb = NULL; 24716642Ssam } 24816642Ssam ip->i_count++; 24916642Ssam ip->i_flag |= ILOCKED; 25016642Ssam } 25116642Ssam 25216642Ssam /* 25324Sbill * Decrement reference count of 25424Sbill * an inode structure. 25524Sbill * On the last reference, 25624Sbill * write the inode out and if necessary, 25724Sbill * truncate and deallocate the file. 25824Sbill */ 25924Sbill iput(ip) 2604818Swnj register struct inode *ip; 26124Sbill { 2627118Smckusick 2638452Sroot if ((ip->i_flag & ILOCKED) == 0) 2647118Smckusick panic("iput"); 26516665Smckusick IUNLOCK(ip); 2667118Smckusick irele(ip); 2677118Smckusick } 2687118Smckusick 2697118Smckusick irele(ip) 2707118Smckusick register struct inode *ip; 2717118Smckusick { 2726569Smckusic int mode; 27324Sbill 274*18445Smckusick if (ip->i_count == 1) { 2758452Sroot ip->i_flag |= ILOCKED; 276*18445Smckusick if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) { 2779165Ssam itrunc(ip, (u_long)0); 2786569Smckusic mode = ip->i_mode; 27924Sbill ip->i_mode = 0; 2807351Skre ip->i_rdev = 0; 28124Sbill ip->i_flag |= IUPD|ICHG; 2826569Smckusic ifree(ip, ip->i_number, mode); 2837651Ssam #ifdef QUOTA 28412645Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 2857492Skre dqrele(ip->i_dquot); 2867492Skre ip->i_dquot = NODQUOT; 2877492Skre #endif 28824Sbill } 2898671Sroot IUPDAT(ip, &time, &time, 0); 29016665Smckusick IUNLOCK(ip); 2917334Skre ip->i_flag = 0; 2927334Skre /* 2937334Skre * Put the inode on the end of the free list. 2947334Skre * Possibly in some cases it would be better to 2957334Skre * put the inode at the head of the free list, 2967334Skre * (eg: where i_mode == 0 || i_number == 0) 2977334Skre * but I will think about that later .. kre 2987334Skre * (i_number is rarely 0 - only after an i/o error in iget, 2997334Skre * where i_mode == 0, the inode will probably be wanted 3007334Skre * again soon for an ialloc, so possibly we should keep it) 3017334Skre */ 3027334Skre if (ifreeh) { 3037334Skre *ifreet = ip; 3047334Skre ip->i_freeb = ifreet; 30524Sbill } else { 3067334Skre ifreeh = ip; 3077334Skre ip->i_freeb = &ifreeh; 30824Sbill } 3097334Skre ip->i_freef = NULL; 3107334Skre ifreet = &ip->i_freef; 31116058Skarels } else if (!(ip->i_flag & ILOCKED)) 31216058Skarels ITIMES(ip, &time, &time); 31324Sbill ip->i_count--; 31424Sbill } 31524Sbill 31624Sbill /* 31724Sbill * Check accessed and update flags on 31824Sbill * an inode structure. 31924Sbill * If any is on, update the inode 32024Sbill * with the current time. 3211203Sbill * If waitfor is given, then must insure 3221203Sbill * i/o order so wait for write to complete. 32324Sbill */ 3241203Sbill iupdat(ip, ta, tm, waitfor) 3254818Swnj register struct inode *ip; 3268630Sroot struct timeval *ta, *tm; 3274818Swnj int waitfor; 32824Sbill { 32924Sbill register struct buf *bp; 33024Sbill struct dinode *dp; 3316569Smckusic register struct fs *fp; 33224Sbill 3336569Smckusic fp = ip->i_fs; 33416058Skarels if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) { 3356569Smckusic if (fp->fs_ronly) 33624Sbill return; 3376569Smckusic bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), 3388618Sroot (int)fp->fs_bsize); 33924Sbill if (bp->b_flags & B_ERROR) { 34024Sbill brelse(bp); 34124Sbill return; 34224Sbill } 3434818Swnj if (ip->i_flag&IACC) 3448630Sroot ip->i_atime = ta->tv_sec; 3454818Swnj if (ip->i_flag&IUPD) 3468630Sroot ip->i_mtime = tm->tv_sec; 3474818Swnj if (ip->i_flag&ICHG) 3488106Sroot ip->i_ctime = time.tv_sec; 34916058Skarels ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 3507343Skre dp = bp->b_un.b_dino + itoo(fp, ip->i_number); 3517343Skre dp->di_ic = ip->i_ic; 3521203Sbill if (waitfor) 3531203Sbill bwrite(bp); 3541203Sbill else 3551203Sbill bdwrite(bp); 35624Sbill } 35724Sbill } 35824Sbill 35910736Ssam #define SINGLE 0 /* index of single indirect block */ 36010736Ssam #define DOUBLE 1 /* index of double indirect block */ 36110736Ssam #define TRIPLE 2 /* index of triple indirect block */ 36224Sbill /* 3637702Ssam * Truncate the inode ip to at most 3647702Ssam * length size. Free affected disk 3657702Ssam * blocks -- the blocks of the file 3667702Ssam * are removed in reverse order. 36710736Ssam * 36810736Ssam * NB: triple indirect blocks are untested. 36924Sbill */ 37010736Ssam itrunc(oip, length) 37117942Smckusick register struct inode *oip; 3729165Ssam u_long length; 37324Sbill { 3749165Ssam register daddr_t lastblock; 37510736Ssam daddr_t bn, lastiblock[NIADDR]; 3766569Smckusic register struct fs *fs; 37710736Ssam register struct inode *ip; 37817942Smckusick struct buf *bp; 37917942Smckusick int offset, lbn, osize, size, error, count, level, s; 38017942Smckusick long nblocks, blocksreleased = 0; 38117942Smckusick register int i; 38217942Smckusick dev_t dev; 38310736Ssam struct inode tip; 38417942Smckusick extern long indirtrunc(); 38517942Smckusick extern struct cmap *mfind(); 3869165Ssam 38713000Ssam if (oip->i_size <= length) { 38813000Ssam oip->i_flag |= ICHG|IUPD; 38913000Ssam iupdat(oip, &time, &time, 1); 3909165Ssam return; 39113000Ssam } 3921203Sbill /* 39310736Ssam * Calculate index into inode's block list of 39410736Ssam * last direct and indirect blocks (if any) 39510736Ssam * which we want to keep. Lastblock is -1 when 39610736Ssam * the file is truncated to 0. 3971203Sbill */ 39810736Ssam fs = oip->i_fs; 3999165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 40010736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 40110736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 40210736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 40312645Ssam nblocks = btodb(fs->fs_bsize); 4046569Smckusic /* 40517942Smckusick * Update the size of the file. If the file is not being 40617942Smckusick * truncated to a block boundry, the contents of the 40717942Smckusick * partial block following the end of the file must be 40817942Smckusick * zero'ed in case it ever become accessable again because 40917942Smckusick * of subsequent file growth. 41017942Smckusick */ 41117942Smckusick osize = oip->i_size; 41217942Smckusick offset = blkoff(fs, length); 41317942Smckusick if (offset == 0) { 41417942Smckusick oip->i_size = length; 41517942Smckusick } else { 41617942Smckusick lbn = lblkno(fs, length); 41717942Smckusick bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset)); 41817942Smckusick if (u.u_error || (long)bn < 0) 41917942Smckusick return; 42017942Smckusick oip->i_size = length; 42117942Smckusick size = blksize(fs, oip, lbn); 42217942Smckusick count = howmany(size, DEV_BSIZE); 42317942Smckusick dev = oip->i_dev; 42417942Smckusick s = splimp(); 42517942Smckusick for (i = 0; i < count; i += CLSIZE) 42617942Smckusick if (mfind(dev, bn + i)) 42717942Smckusick munhash(dev, bn + i); 42817942Smckusick splx(s); 42917942Smckusick bp = bread(dev, bn, size); 43017942Smckusick if (bp->b_flags & B_ERROR) { 43117942Smckusick u.u_error = EIO; 43217942Smckusick oip->i_size = osize; 43317942Smckusick brelse(bp); 43417942Smckusick return; 43517942Smckusick } 43617942Smckusick bzero(bp->b_un.b_addr + offset, size - offset); 43717942Smckusick bdwrite(bp); 43817942Smckusick } 43917942Smckusick /* 44017942Smckusick * Update file and block pointers 44110736Ssam * on disk before we start freeing blocks. 44210736Ssam * If we crash before free'ing blocks below, 44310736Ssam * the blocks will be returned to the free list. 44410736Ssam * lastiblock values are also normalized to -1 44510736Ssam * for calls to indirtrunc below. 4466569Smckusic */ 44710736Ssam tip = *oip; 44817942Smckusick tip.i_size = osize; 44910736Ssam for (level = TRIPLE; level >= SINGLE; level--) 45010736Ssam if (lastiblock[level] < 0) { 45110736Ssam oip->i_ib[level] = 0; 45210736Ssam lastiblock[level] = -1; 4539165Ssam } 45410736Ssam for (i = NDADDR - 1; i > lastblock; i--) 45510736Ssam oip->i_db[i] = 0; 45610736Ssam oip->i_flag |= ICHG|IUPD; 45717942Smckusick syncip(oip); 45810736Ssam 4596569Smckusic /* 46010736Ssam * Indirect blocks first. 4616569Smckusic */ 46217942Smckusick ip = &tip; 46310736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 46410736Ssam bn = ip->i_ib[level]; 4659165Ssam if (bn != 0) { 46610736Ssam blocksreleased += 46712645Ssam indirtrunc(ip, bn, lastiblock[level], level); 46810736Ssam if (lastiblock[level] < 0) { 46910736Ssam ip->i_ib[level] = 0; 47010736Ssam free(ip, bn, (off_t)fs->fs_bsize); 47110736Ssam blocksreleased += nblocks; 47210736Ssam } 47310736Ssam } 47410736Ssam if (lastiblock[level] >= 0) 47510736Ssam goto done; 4769165Ssam } 47710736Ssam 4786569Smckusic /* 47910736Ssam * All whole direct blocks or frags. 4806569Smckusic */ 4819165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 4829165Ssam register int size; 4839165Ssam 4846569Smckusic bn = ip->i_db[i]; 4859165Ssam if (bn == 0) 48624Sbill continue; 4879165Ssam ip->i_db[i] = 0; 4889165Ssam size = (off_t)blksize(fs, ip, i); 4899165Ssam free(ip, bn, size); 49012645Ssam blocksreleased += btodb(size); 49124Sbill } 49210736Ssam if (lastblock < 0) 49310736Ssam goto done; 49410736Ssam 4951203Sbill /* 4969165Ssam * Finally, look for a change in size of the 4979165Ssam * last direct block; release any frags. 4981203Sbill */ 49910736Ssam bn = ip->i_db[lastblock]; 50010736Ssam if (bn != 0) { 50110736Ssam int oldspace, newspace; 50210736Ssam 5039165Ssam /* 5049165Ssam * Calculate amount of space we're giving 5059165Ssam * back as old block size minus new block size. 5069165Ssam */ 50710736Ssam oldspace = blksize(fs, ip, lastblock); 5089165Ssam ip->i_size = length; 50910736Ssam newspace = blksize(fs, ip, lastblock); 51010736Ssam if (newspace == 0) 51110736Ssam panic("itrunc: newspace"); 51210736Ssam if (oldspace - newspace > 0) { 5139165Ssam /* 5149165Ssam * Block number of space to be free'd is 5159165Ssam * the old block # plus the number of frags 5169165Ssam * required for the storage we're keeping. 5179165Ssam */ 51810736Ssam bn += numfrags(fs, newspace); 51910736Ssam free(ip, bn, oldspace - newspace); 52012645Ssam blocksreleased += btodb(oldspace - newspace); 5219165Ssam } 5229165Ssam } 5239165Ssam done: 52410736Ssam /* BEGIN PARANOIA */ 52510736Ssam for (level = SINGLE; level <= TRIPLE; level++) 52610736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 52710736Ssam panic("itrunc1"); 52810736Ssam for (i = 0; i < NDADDR; i++) 52910736Ssam if (ip->i_db[i] != oip->i_db[i]) 53010736Ssam panic("itrunc2"); 53110736Ssam /* END PARANOIA */ 53212645Ssam oip->i_blocks -= blocksreleased; 53312645Ssam if (oip->i_blocks < 0) /* sanity */ 53412645Ssam oip->i_blocks = 0; 53512645Ssam oip->i_flag |= ICHG; 5369165Ssam #ifdef QUOTA 53712645Ssam (void) chkdq(oip, -blocksreleased, 0); 5389165Ssam #endif 53924Sbill } 54024Sbill 5419165Ssam /* 5429165Ssam * Release blocks associated with the inode ip and 5439165Ssam * stored in the indirect block bn. Blocks are free'd 5449165Ssam * in LIFO order up to (but not including) lastbn. If 54510736Ssam * level is greater than SINGLE, the block is an indirect 54610736Ssam * block and recursive calls to indirtrunc must be used to 54710736Ssam * cleanse other indirect blocks. 54810736Ssam * 54910736Ssam * NB: triple indirect blocks are untested. 5509165Ssam */ 5517492Skre long 55210736Ssam indirtrunc(ip, bn, lastbn, level) 5536569Smckusic register struct inode *ip; 5549165Ssam daddr_t bn, lastbn; 55510736Ssam int level; 55624Sbill { 5579165Ssam register int i; 55810736Ssam struct buf *bp, *copy; 55924Sbill register daddr_t *bap; 56010736Ssam register struct fs *fs = ip->i_fs; 5619165Ssam daddr_t nb, last; 56210736Ssam long factor; 5639165Ssam int blocksreleased = 0, nblocks; 56424Sbill 56510736Ssam /* 56610736Ssam * Calculate index in current block of last 56710736Ssam * block to be kept. -1 indicates the entire 56810736Ssam * block so we need not calculate the index. 56910736Ssam */ 57010736Ssam factor = 1; 57110736Ssam for (i = SINGLE; i < level; i++) 57210736Ssam factor *= NINDIR(fs); 5739165Ssam last = lastbn; 57410736Ssam if (lastbn > 0) 57510736Ssam last /= factor; 57612645Ssam nblocks = btodb(fs->fs_bsize); 57710736Ssam /* 57810736Ssam * Get buffer of block pointers, zero those 57910736Ssam * entries corresponding to blocks to be free'd, 58010736Ssam * and update on disk copy first. 58110736Ssam */ 58210736Ssam copy = geteblk((int)fs->fs_bsize); 58310736Ssam bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize); 58410736Ssam if (bp->b_flags&B_ERROR) { 58510736Ssam brelse(copy); 58610736Ssam brelse(bp); 58710736Ssam return (0); 58810736Ssam } 58910736Ssam bap = bp->b_un.b_daddr; 59010736Ssam bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize); 59110736Ssam bzero((caddr_t)&bap[last + 1], 59210736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 59310736Ssam bwrite(bp); 59410736Ssam bp = copy, bap = bp->b_un.b_daddr; 59510736Ssam 59610736Ssam /* 59710736Ssam * Recursively free totally unused blocks. 59810736Ssam */ 5999165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 60024Sbill nb = bap[i]; 6019165Ssam if (nb == 0) 60224Sbill continue; 60310736Ssam if (level > SINGLE) 6049165Ssam blocksreleased += 60512645Ssam indirtrunc(ip, nb, (daddr_t)-1, level - 1); 6069165Ssam free(ip, nb, (int)fs->fs_bsize); 6079165Ssam blocksreleased += nblocks; 60824Sbill } 60910736Ssam 61010736Ssam /* 61110736Ssam * Recursively free last partial block. 61210736Ssam */ 61310736Ssam if (level > SINGLE && lastbn >= 0) { 61410736Ssam last = lastbn % factor; 6159165Ssam nb = bap[i]; 6169165Ssam if (nb != 0) 61712645Ssam blocksreleased += indirtrunc(ip, nb, last, level - 1); 6189165Ssam } 61910736Ssam brelse(bp); 6209165Ssam return (blocksreleased); 62124Sbill } 62224Sbill 62324Sbill /* 6247334Skre * remove any inodes in the inode cache belonging to dev 6257334Skre * 6267334Skre * There should not be any active ones, return error if any are found 6277334Skre * (nb: this is a user error, not a system err) 6287334Skre * 6297334Skre * Also, count the references to dev by block devices - this really 6307334Skre * has nothing to do with the object of the procedure, but as we have 6317334Skre * to scan the inode table here anyway, we might as well get the 6327334Skre * extra benefit. 6337334Skre * 6347334Skre * this is called from sumount()/sys3.c when dev is being unmounted 6357334Skre */ 6367651Ssam #ifdef QUOTA 6377504Sroot iflush(dev, iq) 6387492Skre dev_t dev; 6397504Sroot struct inode *iq; 6407492Skre #else 6417334Skre iflush(dev) 6427334Skre dev_t dev; 6437492Skre #endif 6447334Skre { 6457335Skre register struct inode *ip; 6467334Skre register open = 0; 6477334Skre 6487334Skre for (ip = inode; ip < inodeNINODE; ip++) { 6497651Ssam #ifdef QUOTA 6507492Skre if (ip != iq && ip->i_dev == dev) 6517492Skre #else 6527334Skre if (ip->i_dev == dev) 6537492Skre #endif 6547334Skre if (ip->i_count) 6557334Skre return(-1); 6567334Skre else { 6577335Skre remque(ip); 6587334Skre ip->i_forw = ip; 6597334Skre ip->i_back = ip; 6607334Skre /* 6617334Skre * as i_count == 0, the inode was on the free 6627334Skre * list already, just leave it there, it will 6637334Skre * fall off the bottom eventually. We could 6647334Skre * perhaps move it to the head of the free 6657334Skre * list, but as umounts are done so 6667334Skre * infrequently, we would gain very little, 6677334Skre * while making the code bigger. 6687334Skre */ 6697651Ssam #ifdef QUOTA 6707492Skre dqrele(ip->i_dquot); 6717492Skre ip->i_dquot = NODQUOT; 6727492Skre #endif 6737334Skre } 6747334Skre else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK && 6757334Skre ip->i_rdev == dev) 6767334Skre open++; 6777334Skre } 6787334Skre return (open); 6797334Skre } 6807334Skre 6813617Sroot /* 6824818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6833617Sroot */ 6844818Swnj ilock(ip) 6854818Swnj register struct inode *ip; 6863617Sroot { 6873617Sroot 6888452Sroot ILOCK(ip); 6893617Sroot } 6903617Sroot 6913617Sroot /* 6924818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6933617Sroot */ 6947118Smckusick iunlock(ip) 6954818Swnj register struct inode *ip; 6963617Sroot { 6973617Sroot 6988452Sroot IUNLOCK(ip); 6993617Sroot } 700