xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 18445)
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