1*23399Smckusick /* 2*23399Smckusick * Copyright (c) 1982 Regents of the University of California. 3*23399Smckusick * All rights reserved. The Berkeley software License Agreement 4*23399Smckusick * specifies the terms and conditions for redistribution. 5*23399Smckusick * 6*23399Smckusick * @(#)lfs_inode.c 6.16 (Berkeley) 06/08/85 7*23399Smckusick */ 824Sbill 917099Sbloom #include "param.h" 1017099Sbloom #include "systm.h" 1117099Sbloom #include "mount.h" 1217099Sbloom #include "dir.h" 1317099Sbloom #include "user.h" 1417099Sbloom #include "inode.h" 1517099Sbloom #include "fs.h" 1617099Sbloom #include "buf.h" 177651Ssam #ifdef QUOTA 1817099Sbloom #include "quota.h" 197504Sroot #endif 2017099Sbloom #include "kernel.h" 2124Sbill 2216840Smckusick #define INOHSZ 512 237334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 247334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 257334Skre #else 2610852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 277334Skre #endif 2824Sbill 297334Skre union ihead { /* inode LRU cache, Chris Maltby */ 307334Skre union ihead *ih_head[2]; 317334Skre struct inode *ih_chain[2]; 327334Skre } ihead[INOHSZ]; 337334Skre 347334Skre struct inode *ifreeh, **ifreet; 357334Skre 3624Sbill /* 3724Sbill * Initialize hash links for inodes 3824Sbill * and build inode free list. 3924Sbill */ 4024Sbill ihinit() 4124Sbill { 4224Sbill register int i; 432737Swnj register struct inode *ip = inode; 447334Skre register union ihead *ih = ihead; 4524Sbill 467334Skre for (i = INOHSZ; --i >= 0; ih++) { 477334Skre ih->ih_head[0] = ih; 487334Skre ih->ih_head[1] = ih; 497334Skre } 507334Skre ifreeh = ip; 517334Skre ifreet = &ip->i_freef; 527334Skre ip->i_freeb = &ifreeh; 537334Skre ip->i_forw = ip; 547334Skre ip->i_back = ip; 557334Skre for (i = ninode; --i > 0; ) { 567334Skre ++ip; 577334Skre ip->i_forw = ip; 587334Skre ip->i_back = ip; 597334Skre *ifreet = ip; 607334Skre ip->i_freeb = ifreet; 617334Skre ifreet = &ip->i_freef; 627334Skre } 637334Skre ip->i_freef = NULL; 6424Sbill } 6524Sbill 667334Skre #ifdef notdef 6724Sbill /* 687334Skre * Find an inode if it is incore. 697334Skre * This is the equivalent, for inodes, 707334Skre * of ``incore'' in bio.c or ``pfind'' in subr.c. 717334Skre */ 727334Skre struct inode * 737334Skre ifind(dev, ino) 747334Skre dev_t dev; 757334Skre ino_t ino; 767334Skre { 777334Skre register struct inode *ip; 787334Skre register union ihead *ih; 797334Skre 807334Skre ih = &ihead[INOHASH(dev, ino)]; 817334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 827334Skre if (ino==ip->i_number && dev==ip->i_dev) 837334Skre return (ip); 847334Skre return ((struct inode *)0); 857334Skre } 867334Skre #endif notdef 877334Skre 887334Skre /* 8924Sbill * Look up an inode by device,inumber. 9024Sbill * If it is in core (in the inode structure), 9124Sbill * honor the locking protocol. 9224Sbill * If it is not in core, read it in from the 9324Sbill * specified device. 9424Sbill * If the inode is mounted on, perform 9524Sbill * the indicated indirection. 9624Sbill * In all cases, a pointer to a locked 9724Sbill * inode structure is returned. 9824Sbill * 9924Sbill * panic: no imt -- if the mounted file 10024Sbill * system is not in the mount table. 10124Sbill * "cannot happen" 10224Sbill */ 10324Sbill struct inode * 1046569Smckusic iget(dev, fs, ino) 1054818Swnj dev_t dev; 1066569Smckusic register struct fs *fs; 1074818Swnj ino_t ino; 10824Sbill { 1097335Skre register struct inode *ip; 1107335Skre register union ihead *ih; 11124Sbill register struct mount *mp; 11224Sbill register struct buf *bp; 11324Sbill register struct dinode *dp; 1147334Skre register struct inode *iq; 11524Sbill 11616656Smckusick 11724Sbill loop: 1187334Skre ih = &ihead[INOHASH(dev, ino)]; 1197334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 1204818Swnj if (ino == ip->i_number && dev == ip->i_dev) { 12116642Ssam /* 12216642Ssam * Following is essentially an inline expanded 12316642Ssam * copy of igrab(), expanded inline for speed, 12416642Ssam * and so that the test for a mounted on inode 12516642Ssam * can be deferred until after we are sure that 12616642Ssam * the inode isn't busy. 12716642Ssam */ 1288452Sroot if ((ip->i_flag&ILOCKED) != 0) { 12924Sbill ip->i_flag |= IWANT; 13024Sbill sleep((caddr_t)ip, PINOD); 13124Sbill goto loop; 13224Sbill } 1334818Swnj if ((ip->i_flag&IMOUNT) != 0) { 1346569Smckusic for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) 1357334Skre if(mp->m_inodp == ip) { 1367334Skre dev = mp->m_dev; 1377334Skre fs = mp->m_bufp->b_un.b_fs; 1387334Skre ino = ROOTINO; 1397334Skre goto loop; 1407334Skre } 14124Sbill panic("no imt"); 14224Sbill } 1437334Skre if (ip->i_count == 0) { /* ino on free list */ 1447334Skre if (iq = ip->i_freef) 1457334Skre iq->i_freeb = ip->i_freeb; 1467334Skre else 1477334Skre ifreet = ip->i_freeb; 1487334Skre *ip->i_freeb = iq; 1497334Skre ip->i_freef = NULL; 1507334Skre ip->i_freeb = NULL; 1517334Skre } 15224Sbill ip->i_count++; 1538452Sroot ip->i_flag |= ILOCKED; 15424Sbill return(ip); 15524Sbill } 1567334Skre 1577334Skre if ((ip = ifreeh) == NULL) { 1582933Swnj tablefull("inode"); 15924Sbill u.u_error = ENFILE; 16024Sbill return(NULL); 16124Sbill } 16216720Skarels if (ip->i_count) 16316720Skarels panic("free inode isn't"); 1647334Skre if (iq = ip->i_freef) 1657334Skre iq->i_freeb = &ifreeh; 1667334Skre ifreeh = iq; 1677334Skre ip->i_freef = NULL; 1687334Skre ip->i_freeb = NULL; 1697334Skre /* 1707334Skre * Now to take inode off the hash chain it was on 1717334Skre * (initially, or after an iflush, it is on a "hash chain" 1727334Skre * consisting entirely of itself, and pointed to by no-one, 1737334Skre * but that doesn't matter), and put it on the chain for 1747334Skre * its new (ino, dev) pair 1757334Skre */ 1767335Skre remque(ip); 1777335Skre insque(ip, ih); 17824Sbill ip->i_dev = dev; 1796569Smckusic ip->i_fs = fs; 18024Sbill ip->i_number = ino; 18116738Smckusick cacheinval(ip); 1828452Sroot ip->i_flag = ILOCKED; 18324Sbill ip->i_count++; 1846569Smckusic ip->i_lastr = 0; 18516720Skarels #ifdef QUOTA 18616720Skarels dqrele(ip->i_dquot); 18716720Skarels #endif 1888618Sroot bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize); 18924Sbill /* 19024Sbill * Check I/O errors 19124Sbill */ 1924818Swnj if ((bp->b_flags&B_ERROR) != 0) { 19324Sbill brelse(bp); 1947334Skre /* 1957334Skre * the inode doesn't contain anything useful, so it would 1967334Skre * be misleading to leave it on its hash chain. 1977334Skre * 'iput' will take care of putting it back on the free list. 1987334Skre */ 1997335Skre remque(ip); 2007334Skre ip->i_forw = ip; 2017334Skre ip->i_back = ip; 2027334Skre /* 2037334Skre * we also loose its inumber, just in case (as iput 2047334Skre * doesn't do that any more) - but as it isn't on its 2057334Skre * hash chain, I doubt if this is really necessary .. kre 2067334Skre * (probably the two methods are interchangable) 2077334Skre */ 2087334Skre ip->i_number = 0; 2097651Ssam #ifdef QUOTA 2107492Skre ip->i_dquot = NODQUOT; 2117492Skre #endif 21224Sbill iput(ip); 21324Sbill return(NULL); 21424Sbill } 21524Sbill dp = bp->b_un.b_dino; 2166569Smckusic dp += itoo(fs, ino); 2176569Smckusic ip->i_ic = dp->di_ic; 21824Sbill brelse(bp); 2197651Ssam #ifdef QUOTA 2207492Skre if (ip->i_mode == 0) 2217492Skre ip->i_dquot = NODQUOT; 2227492Skre else 2237492Skre ip->i_dquot = inoquota(ip); 2247492Skre #endif 2256569Smckusic return (ip); 22624Sbill } 22724Sbill 22824Sbill /* 22916642Ssam * Convert a pointer to an inode into a reference to an inode. 23016642Ssam * 23116642Ssam * This is basically the internal piece of iget (after the 23216642Ssam * inode pointer is located) but without the test for mounted 23316642Ssam * filesystems. It is caller's responsibility to check that 23416642Ssam * the inode pointer is valid. 23516642Ssam */ 23616642Ssam igrab(ip) 23716642Ssam register struct inode *ip; 23816642Ssam { 23916642Ssam while ((ip->i_flag&ILOCKED) != 0) { 24016642Ssam ip->i_flag |= IWANT; 24116642Ssam sleep((caddr_t)ip, PINOD); 24216642Ssam } 24316642Ssam if (ip->i_count == 0) { /* ino on free list */ 24416642Ssam register struct inode *iq; 24516642Ssam 24616642Ssam if (iq = ip->i_freef) 24716642Ssam iq->i_freeb = ip->i_freeb; 24816642Ssam else 24916642Ssam ifreet = ip->i_freeb; 25016642Ssam *ip->i_freeb = iq; 25116642Ssam ip->i_freef = NULL; 25216642Ssam ip->i_freeb = NULL; 25316642Ssam } 25416642Ssam ip->i_count++; 25516642Ssam ip->i_flag |= ILOCKED; 25616642Ssam } 25716642Ssam 25816642Ssam /* 25924Sbill * Decrement reference count of 26024Sbill * an inode structure. 26124Sbill * On the last reference, 26224Sbill * write the inode out and if necessary, 26324Sbill * truncate and deallocate the file. 26424Sbill */ 26524Sbill iput(ip) 2664818Swnj register struct inode *ip; 26724Sbill { 2687118Smckusick 2698452Sroot if ((ip->i_flag & ILOCKED) == 0) 2707118Smckusick panic("iput"); 27116665Smckusick IUNLOCK(ip); 2727118Smckusick irele(ip); 2737118Smckusick } 2747118Smckusick 2757118Smckusick irele(ip) 2767118Smckusick register struct inode *ip; 2777118Smckusick { 2786569Smckusic int mode; 27924Sbill 28018445Smckusick if (ip->i_count == 1) { 2818452Sroot ip->i_flag |= ILOCKED; 28218445Smckusick if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) { 2839165Ssam itrunc(ip, (u_long)0); 2846569Smckusic mode = ip->i_mode; 28524Sbill ip->i_mode = 0; 2867351Skre ip->i_rdev = 0; 28724Sbill ip->i_flag |= IUPD|ICHG; 2886569Smckusic ifree(ip, ip->i_number, mode); 2897651Ssam #ifdef QUOTA 29012645Ssam (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 2917492Skre dqrele(ip->i_dquot); 2927492Skre ip->i_dquot = NODQUOT; 2937492Skre #endif 29424Sbill } 2958671Sroot IUPDAT(ip, &time, &time, 0); 29616665Smckusick IUNLOCK(ip); 2977334Skre ip->i_flag = 0; 2987334Skre /* 2997334Skre * Put the inode on the end of the free list. 3007334Skre * Possibly in some cases it would be better to 3017334Skre * put the inode at the head of the free list, 3027334Skre * (eg: where i_mode == 0 || i_number == 0) 3037334Skre * but I will think about that later .. kre 3047334Skre * (i_number is rarely 0 - only after an i/o error in iget, 3057334Skre * where i_mode == 0, the inode will probably be wanted 3067334Skre * again soon for an ialloc, so possibly we should keep it) 3077334Skre */ 3087334Skre if (ifreeh) { 3097334Skre *ifreet = ip; 3107334Skre ip->i_freeb = ifreet; 31124Sbill } else { 3127334Skre ifreeh = ip; 3137334Skre ip->i_freeb = &ifreeh; 31424Sbill } 3157334Skre ip->i_freef = NULL; 3167334Skre ifreet = &ip->i_freef; 31716058Skarels } else if (!(ip->i_flag & ILOCKED)) 31816058Skarels ITIMES(ip, &time, &time); 31924Sbill ip->i_count--; 32024Sbill } 32124Sbill 32224Sbill /* 32324Sbill * Check accessed and update flags on 32424Sbill * an inode structure. 32524Sbill * If any is on, update the inode 32624Sbill * with the current time. 3271203Sbill * If waitfor is given, then must insure 3281203Sbill * i/o order so wait for write to complete. 32924Sbill */ 3301203Sbill iupdat(ip, ta, tm, waitfor) 3314818Swnj register struct inode *ip; 3328630Sroot struct timeval *ta, *tm; 3334818Swnj int waitfor; 33424Sbill { 33524Sbill register struct buf *bp; 33624Sbill struct dinode *dp; 3376569Smckusic register struct fs *fp; 33824Sbill 3396569Smckusic fp = ip->i_fs; 34016058Skarels if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) { 3416569Smckusic if (fp->fs_ronly) 34224Sbill return; 3436569Smckusic bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)), 3448618Sroot (int)fp->fs_bsize); 34524Sbill if (bp->b_flags & B_ERROR) { 34624Sbill brelse(bp); 34724Sbill return; 34824Sbill } 3494818Swnj if (ip->i_flag&IACC) 3508630Sroot ip->i_atime = ta->tv_sec; 3514818Swnj if (ip->i_flag&IUPD) 3528630Sroot ip->i_mtime = tm->tv_sec; 3534818Swnj if (ip->i_flag&ICHG) 3548106Sroot ip->i_ctime = time.tv_sec; 35516058Skarels ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 3567343Skre dp = bp->b_un.b_dino + itoo(fp, ip->i_number); 3577343Skre dp->di_ic = ip->i_ic; 3581203Sbill if (waitfor) 3591203Sbill bwrite(bp); 3601203Sbill else 3611203Sbill bdwrite(bp); 36224Sbill } 36324Sbill } 36424Sbill 36510736Ssam #define SINGLE 0 /* index of single indirect block */ 36610736Ssam #define DOUBLE 1 /* index of double indirect block */ 36710736Ssam #define TRIPLE 2 /* index of triple indirect block */ 36824Sbill /* 3697702Ssam * Truncate the inode ip to at most 3707702Ssam * length size. Free affected disk 3717702Ssam * blocks -- the blocks of the file 3727702Ssam * are removed in reverse order. 37310736Ssam * 37410736Ssam * NB: triple indirect blocks are untested. 37524Sbill */ 37610736Ssam itrunc(oip, length) 37717942Smckusick register struct inode *oip; 3789165Ssam u_long length; 37924Sbill { 3809165Ssam register daddr_t lastblock; 38110736Ssam daddr_t bn, lastiblock[NIADDR]; 3826569Smckusic register struct fs *fs; 38310736Ssam register struct inode *ip; 38417942Smckusick struct buf *bp; 38517942Smckusick int offset, lbn, osize, size, error, count, level, s; 38617942Smckusick long nblocks, blocksreleased = 0; 38717942Smckusick register int i; 38817942Smckusick dev_t dev; 38910736Ssam struct inode tip; 39017942Smckusick extern long indirtrunc(); 39117942Smckusick extern struct cmap *mfind(); 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 /* 41117942Smckusick * Update the size of the file. If the file is not being 41217942Smckusick * truncated to a block boundry, the contents of the 41317942Smckusick * partial block following the end of the file must be 41417942Smckusick * zero'ed in case it ever become accessable again because 41517942Smckusick * of subsequent file growth. 41617942Smckusick */ 41717942Smckusick osize = oip->i_size; 41817942Smckusick offset = blkoff(fs, length); 41917942Smckusick if (offset == 0) { 42017942Smckusick oip->i_size = length; 42117942Smckusick } else { 42217942Smckusick lbn = lblkno(fs, length); 42317942Smckusick bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset)); 42417942Smckusick if (u.u_error || (long)bn < 0) 42517942Smckusick return; 42617942Smckusick oip->i_size = length; 42717942Smckusick size = blksize(fs, oip, lbn); 42817942Smckusick count = howmany(size, DEV_BSIZE); 42917942Smckusick dev = oip->i_dev; 43017942Smckusick s = splimp(); 43117942Smckusick for (i = 0; i < count; i += CLSIZE) 43217942Smckusick if (mfind(dev, bn + i)) 43317942Smckusick munhash(dev, bn + i); 43417942Smckusick splx(s); 43517942Smckusick bp = bread(dev, bn, size); 43617942Smckusick if (bp->b_flags & B_ERROR) { 43717942Smckusick u.u_error = EIO; 43817942Smckusick oip->i_size = osize; 43917942Smckusick brelse(bp); 44017942Smckusick return; 44117942Smckusick } 44217942Smckusick bzero(bp->b_un.b_addr + offset, size - offset); 44317942Smckusick bdwrite(bp); 44417942Smckusick } 44517942Smckusick /* 44617942Smckusick * Update file and block pointers 44710736Ssam * on disk before we start freeing blocks. 44810736Ssam * If we crash before free'ing blocks below, 44910736Ssam * the blocks will be returned to the free list. 45010736Ssam * lastiblock values are also normalized to -1 45110736Ssam * for calls to indirtrunc below. 4526569Smckusic */ 45310736Ssam tip = *oip; 45417942Smckusick tip.i_size = osize; 45510736Ssam for (level = TRIPLE; level >= SINGLE; level--) 45610736Ssam if (lastiblock[level] < 0) { 45710736Ssam oip->i_ib[level] = 0; 45810736Ssam lastiblock[level] = -1; 4599165Ssam } 46010736Ssam for (i = NDADDR - 1; i > lastblock; i--) 46110736Ssam oip->i_db[i] = 0; 46210736Ssam oip->i_flag |= ICHG|IUPD; 46317942Smckusick syncip(oip); 46410736Ssam 4656569Smckusic /* 46610736Ssam * Indirect blocks first. 4676569Smckusic */ 46817942Smckusick ip = &tip; 46910736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 47010736Ssam bn = ip->i_ib[level]; 4719165Ssam if (bn != 0) { 47210736Ssam blocksreleased += 47312645Ssam indirtrunc(ip, bn, lastiblock[level], level); 47410736Ssam if (lastiblock[level] < 0) { 47510736Ssam ip->i_ib[level] = 0; 47610736Ssam free(ip, bn, (off_t)fs->fs_bsize); 47710736Ssam blocksreleased += nblocks; 47810736Ssam } 47910736Ssam } 48010736Ssam if (lastiblock[level] >= 0) 48110736Ssam goto done; 4829165Ssam } 48310736Ssam 4846569Smckusic /* 48510736Ssam * All whole direct blocks or frags. 4866569Smckusic */ 4879165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 4889165Ssam register int size; 4899165Ssam 4906569Smckusic bn = ip->i_db[i]; 4919165Ssam if (bn == 0) 49224Sbill continue; 4939165Ssam ip->i_db[i] = 0; 4949165Ssam size = (off_t)blksize(fs, ip, i); 4959165Ssam free(ip, bn, size); 49612645Ssam blocksreleased += btodb(size); 49724Sbill } 49810736Ssam if (lastblock < 0) 49910736Ssam goto done; 50010736Ssam 5011203Sbill /* 5029165Ssam * Finally, look for a change in size of the 5039165Ssam * last direct block; release any frags. 5041203Sbill */ 50510736Ssam bn = ip->i_db[lastblock]; 50610736Ssam if (bn != 0) { 50710736Ssam int oldspace, newspace; 50810736Ssam 5099165Ssam /* 5109165Ssam * Calculate amount of space we're giving 5119165Ssam * back as old block size minus new block size. 5129165Ssam */ 51310736Ssam oldspace = blksize(fs, ip, lastblock); 5149165Ssam ip->i_size = length; 51510736Ssam newspace = blksize(fs, ip, lastblock); 51610736Ssam if (newspace == 0) 51710736Ssam panic("itrunc: newspace"); 51810736Ssam if (oldspace - newspace > 0) { 5199165Ssam /* 5209165Ssam * Block number of space to be free'd is 5219165Ssam * the old block # plus the number of frags 5229165Ssam * required for the storage we're keeping. 5239165Ssam */ 52410736Ssam bn += numfrags(fs, newspace); 52510736Ssam free(ip, bn, oldspace - newspace); 52612645Ssam blocksreleased += btodb(oldspace - newspace); 5279165Ssam } 5289165Ssam } 5299165Ssam done: 53010736Ssam /* BEGIN PARANOIA */ 53110736Ssam for (level = SINGLE; level <= TRIPLE; level++) 53210736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 53310736Ssam panic("itrunc1"); 53410736Ssam for (i = 0; i < NDADDR; i++) 53510736Ssam if (ip->i_db[i] != oip->i_db[i]) 53610736Ssam panic("itrunc2"); 53710736Ssam /* END PARANOIA */ 53812645Ssam oip->i_blocks -= blocksreleased; 53912645Ssam if (oip->i_blocks < 0) /* sanity */ 54012645Ssam oip->i_blocks = 0; 54112645Ssam oip->i_flag |= ICHG; 5429165Ssam #ifdef QUOTA 54312645Ssam (void) chkdq(oip, -blocksreleased, 0); 5449165Ssam #endif 54524Sbill } 54624Sbill 5479165Ssam /* 5489165Ssam * Release blocks associated with the inode ip and 5499165Ssam * stored in the indirect block bn. Blocks are free'd 5509165Ssam * in LIFO order up to (but not including) lastbn. If 55110736Ssam * level is greater than SINGLE, the block is an indirect 55210736Ssam * block and recursive calls to indirtrunc must be used to 55310736Ssam * cleanse other indirect blocks. 55410736Ssam * 55510736Ssam * NB: triple indirect blocks are untested. 5569165Ssam */ 5577492Skre long 55810736Ssam indirtrunc(ip, bn, lastbn, level) 5596569Smckusic register struct inode *ip; 5609165Ssam daddr_t bn, lastbn; 56110736Ssam int level; 56224Sbill { 5639165Ssam register int i; 56410736Ssam struct buf *bp, *copy; 56524Sbill register daddr_t *bap; 56610736Ssam register struct fs *fs = ip->i_fs; 5679165Ssam daddr_t nb, last; 56810736Ssam long factor; 5699165Ssam int blocksreleased = 0, nblocks; 57024Sbill 57110736Ssam /* 57210736Ssam * Calculate index in current block of last 57310736Ssam * block to be kept. -1 indicates the entire 57410736Ssam * block so we need not calculate the index. 57510736Ssam */ 57610736Ssam factor = 1; 57710736Ssam for (i = SINGLE; i < level; i++) 57810736Ssam factor *= NINDIR(fs); 5799165Ssam last = lastbn; 58010736Ssam if (lastbn > 0) 58110736Ssam last /= factor; 58212645Ssam nblocks = btodb(fs->fs_bsize); 58310736Ssam /* 58410736Ssam * Get buffer of block pointers, zero those 58510736Ssam * entries corresponding to blocks to be free'd, 58610736Ssam * and update on disk copy first. 58710736Ssam */ 58810736Ssam copy = geteblk((int)fs->fs_bsize); 58910736Ssam bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize); 59010736Ssam if (bp->b_flags&B_ERROR) { 59110736Ssam brelse(copy); 59210736Ssam brelse(bp); 59310736Ssam return (0); 59410736Ssam } 59510736Ssam bap = bp->b_un.b_daddr; 59610736Ssam bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize); 59710736Ssam bzero((caddr_t)&bap[last + 1], 59810736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 59910736Ssam bwrite(bp); 60010736Ssam bp = copy, bap = bp->b_un.b_daddr; 60110736Ssam 60210736Ssam /* 60310736Ssam * Recursively free totally unused blocks. 60410736Ssam */ 6059165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 60624Sbill nb = bap[i]; 6079165Ssam if (nb == 0) 60824Sbill continue; 60910736Ssam if (level > SINGLE) 6109165Ssam blocksreleased += 61112645Ssam indirtrunc(ip, nb, (daddr_t)-1, level - 1); 6129165Ssam free(ip, nb, (int)fs->fs_bsize); 6139165Ssam blocksreleased += nblocks; 61424Sbill } 61510736Ssam 61610736Ssam /* 61710736Ssam * Recursively free last partial block. 61810736Ssam */ 61910736Ssam if (level > SINGLE && lastbn >= 0) { 62010736Ssam last = lastbn % factor; 6219165Ssam nb = bap[i]; 6229165Ssam if (nb != 0) 62312645Ssam blocksreleased += indirtrunc(ip, nb, last, level - 1); 6249165Ssam } 62510736Ssam brelse(bp); 6269165Ssam return (blocksreleased); 62724Sbill } 62824Sbill 62924Sbill /* 6307334Skre * remove any inodes in the inode cache belonging to dev 6317334Skre * 6327334Skre * There should not be any active ones, return error if any are found 6337334Skre * (nb: this is a user error, not a system err) 6347334Skre * 6357334Skre * Also, count the references to dev by block devices - this really 6367334Skre * has nothing to do with the object of the procedure, but as we have 6377334Skre * to scan the inode table here anyway, we might as well get the 6387334Skre * extra benefit. 6397334Skre * 6407334Skre * this is called from sumount()/sys3.c when dev is being unmounted 6417334Skre */ 6427651Ssam #ifdef QUOTA 6437504Sroot iflush(dev, iq) 6447492Skre dev_t dev; 6457504Sroot struct inode *iq; 6467492Skre #else 6477334Skre iflush(dev) 6487334Skre dev_t dev; 6497492Skre #endif 6507334Skre { 6517335Skre register struct inode *ip; 6527334Skre register open = 0; 6537334Skre 6547334Skre for (ip = inode; ip < inodeNINODE; ip++) { 6557651Ssam #ifdef QUOTA 6567492Skre if (ip != iq && ip->i_dev == dev) 6577492Skre #else 6587334Skre if (ip->i_dev == dev) 6597492Skre #endif 6607334Skre if (ip->i_count) 6617334Skre return(-1); 6627334Skre else { 6637335Skre remque(ip); 6647334Skre ip->i_forw = ip; 6657334Skre ip->i_back = ip; 6667334Skre /* 6677334Skre * as i_count == 0, the inode was on the free 6687334Skre * list already, just leave it there, it will 6697334Skre * fall off the bottom eventually. We could 6707334Skre * perhaps move it to the head of the free 6717334Skre * list, but as umounts are done so 6727334Skre * infrequently, we would gain very little, 6737334Skre * while making the code bigger. 6747334Skre */ 6757651Ssam #ifdef QUOTA 6767492Skre dqrele(ip->i_dquot); 6777492Skre ip->i_dquot = NODQUOT; 6787492Skre #endif 6797334Skre } 6807334Skre else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK && 6817334Skre ip->i_rdev == dev) 6827334Skre open++; 6837334Skre } 6847334Skre return (open); 6857334Skre } 6867334Skre 6873617Sroot /* 6884818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 6893617Sroot */ 6904818Swnj ilock(ip) 6914818Swnj register struct inode *ip; 6923617Sroot { 6933617Sroot 6948452Sroot ILOCK(ip); 6953617Sroot } 6963617Sroot 6973617Sroot /* 6984818Swnj * Unlock an inode. If WANT bit is on, wakeup. 6993617Sroot */ 7007118Smckusick iunlock(ip) 7014818Swnj register struct inode *ip; 7023617Sroot { 7033617Sroot 7048452Sroot IUNLOCK(ip); 7053617Sroot } 706