1*17942Smckusick /* ufs_inode.c 6.12 85/02/11 */ 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 "conf.h" 1117099Sbloom #include "buf.h" 127651Ssam #ifdef QUOTA 1317099Sbloom #include "quota.h" 147504Sroot #endif 1517099Sbloom #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) 372*17942Smckusick register struct inode *oip; 3739165Ssam u_long length; 37424Sbill { 3759165Ssam register daddr_t lastblock; 37610736Ssam daddr_t bn, lastiblock[NIADDR]; 3776569Smckusic register struct fs *fs; 37810736Ssam register struct inode *ip; 379*17942Smckusick struct buf *bp; 380*17942Smckusick int offset, lbn, osize, size, error, count, level, s; 381*17942Smckusick long nblocks, blocksreleased = 0; 382*17942Smckusick register int i; 383*17942Smckusick dev_t dev; 38410736Ssam struct inode tip; 385*17942Smckusick extern long indirtrunc(); 386*17942Smckusick extern struct cmap *mfind(); 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 /* 406*17942Smckusick * Update the size of the file. If the file is not being 407*17942Smckusick * truncated to a block boundry, the contents of the 408*17942Smckusick * partial block following the end of the file must be 409*17942Smckusick * zero'ed in case it ever become accessable again because 410*17942Smckusick * of subsequent file growth. 411*17942Smckusick */ 412*17942Smckusick osize = oip->i_size; 413*17942Smckusick offset = blkoff(fs, length); 414*17942Smckusick if (offset == 0) { 415*17942Smckusick oip->i_size = length; 416*17942Smckusick } else { 417*17942Smckusick lbn = lblkno(fs, length); 418*17942Smckusick bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset)); 419*17942Smckusick if (u.u_error || (long)bn < 0) 420*17942Smckusick return; 421*17942Smckusick oip->i_size = length; 422*17942Smckusick size = blksize(fs, oip, lbn); 423*17942Smckusick count = howmany(size, DEV_BSIZE); 424*17942Smckusick dev = oip->i_dev; 425*17942Smckusick s = splimp(); 426*17942Smckusick for (i = 0; i < count; i += CLSIZE) 427*17942Smckusick if (mfind(dev, bn + i)) 428*17942Smckusick munhash(dev, bn + i); 429*17942Smckusick splx(s); 430*17942Smckusick bp = bread(dev, bn, size); 431*17942Smckusick if (bp->b_flags & B_ERROR) { 432*17942Smckusick u.u_error = EIO; 433*17942Smckusick oip->i_size = osize; 434*17942Smckusick brelse(bp); 435*17942Smckusick return; 436*17942Smckusick } 437*17942Smckusick bzero(bp->b_un.b_addr + offset, size - offset); 438*17942Smckusick bdwrite(bp); 439*17942Smckusick } 440*17942Smckusick /* 441*17942Smckusick * Update file and block pointers 44210736Ssam * on disk before we start freeing blocks. 44310736Ssam * If we crash before free'ing blocks below, 44410736Ssam * the blocks will be returned to the free list. 44510736Ssam * lastiblock values are also normalized to -1 44610736Ssam * for calls to indirtrunc below. 4476569Smckusic */ 44810736Ssam tip = *oip; 449*17942Smckusick tip.i_size = osize; 45010736Ssam for (level = TRIPLE; level >= SINGLE; level--) 45110736Ssam if (lastiblock[level] < 0) { 45210736Ssam oip->i_ib[level] = 0; 45310736Ssam lastiblock[level] = -1; 4549165Ssam } 45510736Ssam for (i = NDADDR - 1; i > lastblock; i--) 45610736Ssam oip->i_db[i] = 0; 45710736Ssam oip->i_flag |= ICHG|IUPD; 458*17942Smckusick syncip(oip); 45910736Ssam 4606569Smckusic /* 46110736Ssam * Indirect blocks first. 4626569Smckusic */ 463*17942Smckusick ip = &tip; 46410736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 46510736Ssam bn = ip->i_ib[level]; 4669165Ssam if (bn != 0) { 46710736Ssam blocksreleased += 46812645Ssam indirtrunc(ip, bn, lastiblock[level], level); 46910736Ssam if (lastiblock[level] < 0) { 47010736Ssam ip->i_ib[level] = 0; 47110736Ssam free(ip, bn, (off_t)fs->fs_bsize); 47210736Ssam blocksreleased += nblocks; 47310736Ssam } 47410736Ssam } 47510736Ssam if (lastiblock[level] >= 0) 47610736Ssam goto done; 4779165Ssam } 47810736Ssam 4796569Smckusic /* 48010736Ssam * All whole direct blocks or frags. 4816569Smckusic */ 4829165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 4839165Ssam register int size; 4849165Ssam 4856569Smckusic bn = ip->i_db[i]; 4869165Ssam if (bn == 0) 48724Sbill continue; 4889165Ssam ip->i_db[i] = 0; 4899165Ssam size = (off_t)blksize(fs, ip, i); 4909165Ssam free(ip, bn, size); 49112645Ssam blocksreleased += btodb(size); 49224Sbill } 49310736Ssam if (lastblock < 0) 49410736Ssam goto done; 49510736Ssam 4961203Sbill /* 4979165Ssam * Finally, look for a change in size of the 4989165Ssam * last direct block; release any frags. 4991203Sbill */ 50010736Ssam bn = ip->i_db[lastblock]; 50110736Ssam if (bn != 0) { 50210736Ssam int oldspace, newspace; 50310736Ssam 5049165Ssam /* 5059165Ssam * Calculate amount of space we're giving 5069165Ssam * back as old block size minus new block size. 5079165Ssam */ 50810736Ssam oldspace = blksize(fs, ip, lastblock); 5099165Ssam ip->i_size = length; 51010736Ssam newspace = blksize(fs, ip, lastblock); 51110736Ssam if (newspace == 0) 51210736Ssam panic("itrunc: newspace"); 51310736Ssam if (oldspace - newspace > 0) { 5149165Ssam /* 5159165Ssam * Block number of space to be free'd is 5169165Ssam * the old block # plus the number of frags 5179165Ssam * required for the storage we're keeping. 5189165Ssam */ 51910736Ssam bn += numfrags(fs, newspace); 52010736Ssam free(ip, bn, oldspace - newspace); 52112645Ssam blocksreleased += btodb(oldspace - newspace); 5229165Ssam } 5239165Ssam } 5249165Ssam done: 52510736Ssam /* BEGIN PARANOIA */ 52610736Ssam for (level = SINGLE; level <= TRIPLE; level++) 52710736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 52810736Ssam panic("itrunc1"); 52910736Ssam for (i = 0; i < NDADDR; i++) 53010736Ssam if (ip->i_db[i] != oip->i_db[i]) 53110736Ssam panic("itrunc2"); 53210736Ssam /* END PARANOIA */ 53312645Ssam oip->i_blocks -= blocksreleased; 53412645Ssam if (oip->i_blocks < 0) /* sanity */ 53512645Ssam oip->i_blocks = 0; 53612645Ssam oip->i_flag |= ICHG; 5379165Ssam #ifdef QUOTA 53812645Ssam (void) chkdq(oip, -blocksreleased, 0); 5399165Ssam #endif 54024Sbill } 54124Sbill 5429165Ssam /* 5439165Ssam * Release blocks associated with the inode ip and 5449165Ssam * stored in the indirect block bn. Blocks are free'd 5459165Ssam * in LIFO order up to (but not including) lastbn. If 54610736Ssam * level is greater than SINGLE, the block is an indirect 54710736Ssam * block and recursive calls to indirtrunc must be used to 54810736Ssam * cleanse other indirect blocks. 54910736Ssam * 55010736Ssam * NB: triple indirect blocks are untested. 5519165Ssam */ 5527492Skre long 55310736Ssam indirtrunc(ip, bn, lastbn, level) 5546569Smckusic register struct inode *ip; 5559165Ssam daddr_t bn, lastbn; 55610736Ssam int level; 55724Sbill { 5589165Ssam register int i; 55910736Ssam struct buf *bp, *copy; 56024Sbill register daddr_t *bap; 56110736Ssam register struct fs *fs = ip->i_fs; 5629165Ssam daddr_t nb, last; 56310736Ssam long factor; 5649165Ssam int blocksreleased = 0, nblocks; 56524Sbill 56610736Ssam /* 56710736Ssam * Calculate index in current block of last 56810736Ssam * block to be kept. -1 indicates the entire 56910736Ssam * block so we need not calculate the index. 57010736Ssam */ 57110736Ssam factor = 1; 57210736Ssam for (i = SINGLE; i < level; i++) 57310736Ssam factor *= NINDIR(fs); 5749165Ssam last = lastbn; 57510736Ssam if (lastbn > 0) 57610736Ssam last /= factor; 57712645Ssam nblocks = btodb(fs->fs_bsize); 57810736Ssam /* 57910736Ssam * Get buffer of block pointers, zero those 58010736Ssam * entries corresponding to blocks to be free'd, 58110736Ssam * and update on disk copy first. 58210736Ssam */ 58310736Ssam copy = geteblk((int)fs->fs_bsize); 58410736Ssam bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize); 58510736Ssam if (bp->b_flags&B_ERROR) { 58610736Ssam brelse(copy); 58710736Ssam brelse(bp); 58810736Ssam return (0); 58910736Ssam } 59010736Ssam bap = bp->b_un.b_daddr; 59110736Ssam bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize); 59210736Ssam bzero((caddr_t)&bap[last + 1], 59310736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 59410736Ssam bwrite(bp); 59510736Ssam bp = copy, bap = bp->b_un.b_daddr; 59610736Ssam 59710736Ssam /* 59810736Ssam * Recursively free totally unused blocks. 59910736Ssam */ 6009165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 60124Sbill nb = bap[i]; 6029165Ssam if (nb == 0) 60324Sbill continue; 60410736Ssam if (level > SINGLE) 6059165Ssam blocksreleased += 60612645Ssam indirtrunc(ip, nb, (daddr_t)-1, level - 1); 6079165Ssam free(ip, nb, (int)fs->fs_bsize); 6089165Ssam blocksreleased += nblocks; 60924Sbill } 61010736Ssam 61110736Ssam /* 61210736Ssam * Recursively free last partial block. 61310736Ssam */ 61410736Ssam if (level > SINGLE && lastbn >= 0) { 61510736Ssam last = lastbn % factor; 6169165Ssam nb = bap[i]; 6179165Ssam if (nb != 0) 61812645Ssam blocksreleased += indirtrunc(ip, nb, last, level - 1); 6199165Ssam } 62010736Ssam brelse(bp); 6219165Ssam return (blocksreleased); 62224Sbill } 62324Sbill 62424Sbill /* 6257334Skre * remove any inodes in the inode cache belonging to dev 6267334Skre * 6277334Skre * There should not be any active ones, return error if any are found 6287334Skre * (nb: this is a user error, not a system err) 6297334Skre * 6307334Skre * Also, count the references to dev by block devices - this really 6317334Skre * has nothing to do with the object of the procedure, but as we have 6327334Skre * to scan the inode table here anyway, we might as well get the 6337334Skre * extra benefit. 6347334Skre * 6357334Skre * this is called from sumount()/sys3.c when dev is being unmounted 6367334Skre */ 6377651Ssam #ifdef QUOTA 6387504Sroot iflush(dev, iq) 6397492Skre dev_t dev; 6407504Sroot struct inode *iq; 6417492Skre #else 6427334Skre iflush(dev) 6437334Skre dev_t dev; 6447492Skre #endif 6457334Skre { 6467335Skre register struct inode *ip; 6477334Skre register open = 0; 6487334Skre 6497334Skre for (ip = inode; ip < inodeNINODE; ip++) { 6507651Ssam #ifdef QUOTA 6517492Skre if (ip != iq && ip->i_dev == dev) 6527492Skre #else 6537334Skre if (ip->i_dev == dev) 6547492Skre #endif 6557334Skre if (ip->i_count) 6567334Skre return(-1); 6577334Skre else { 6587335Skre remque(ip); 6597334Skre ip->i_forw = ip; 6607334Skre ip->i_back = ip; 6617334Skre /* 6627334Skre * as i_count == 0, the inode was on the free 6637334Skre * list already, just leave it there, it will 6647334Skre * fall off the bottom eventually. We could 6657334Skre * perhaps move it to the head of the free 6667334Skre * list, but as umounts are done so 6677334Skre * infrequently, we would gain very little, 6687334Skre * while making the code bigger. 6697334Skre */ 6707651Ssam #ifdef QUOTA 6717492Skre dqrele(ip->i_dquot); 6727492Skre ip->i_dquot = NODQUOT; 6737492Skre #endif 6747334Skre } 6757334Skre else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK && 6767334Skre ip->i_rdev == dev) 6777334Skre open++; 6787334Skre } 6797334Skre return (open); 6807334Skre } 6817334Skre 6823617Sroot /* 6834818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6843617Sroot */ 6854818Swnj ilock(ip) 6864818Swnj register struct inode *ip; 6873617Sroot { 6883617Sroot 6898452Sroot ILOCK(ip); 6903617Sroot } 6913617Sroot 6923617Sroot /* 6934818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6943617Sroot */ 6957118Smckusick iunlock(ip) 6964818Swnj register struct inode *ip; 6973617Sroot { 6983617Sroot 6998452Sroot IUNLOCK(ip); 7003617Sroot } 701