xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 30749)
123399Smckusick /*
229117Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323399Smckusick  * All rights reserved.  The Berkeley software License Agreement
423399Smckusick  * specifies the terms and conditions for redistribution.
523399Smckusick  *
6*30749Skarels  *	@(#)lfs_inode.c	7.1.1.1 (Berkeley) 04/02/87
723399Smckusick  */
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"
1724525Sbloom #include "cmap.h"
187651Ssam #ifdef QUOTA
1917099Sbloom #include "quota.h"
207504Sroot #endif
2117099Sbloom #include "kernel.h"
2224Sbill 
2316840Smckusick #define	INOHSZ	512
247334Skre #if	((INOHSZ&(INOHSZ-1)) == 0)
257334Skre #define	INOHASH(dev,ino)	(((dev)+(ino))&(INOHSZ-1))
267334Skre #else
2710852Ssam #define	INOHASH(dev,ino)	(((unsigned)((dev)+(ino)))%INOHSZ)
287334Skre #endif
2924Sbill 
307334Skre union ihead {				/* inode LRU cache, Chris Maltby */
317334Skre 	union  ihead *ih_head[2];
327334Skre 	struct inode *ih_chain[2];
337334Skre } ihead[INOHSZ];
347334Skre 
357334Skre struct inode *ifreeh, **ifreet;
367334Skre 
3724Sbill /*
3824Sbill  * Initialize hash links for inodes
3924Sbill  * and build inode free list.
4024Sbill  */
4124Sbill ihinit()
4224Sbill {
4324Sbill 	register int i;
442737Swnj 	register struct inode *ip = inode;
457334Skre 	register union  ihead *ih = ihead;
4624Sbill 
477334Skre 	for (i = INOHSZ; --i >= 0; ih++) {
487334Skre 		ih->ih_head[0] = ih;
497334Skre 		ih->ih_head[1] = ih;
507334Skre 	}
517334Skre 	ifreeh = ip;
527334Skre 	ifreet = &ip->i_freef;
537334Skre 	ip->i_freeb = &ifreeh;
547334Skre 	ip->i_forw = ip;
557334Skre 	ip->i_back = ip;
567334Skre 	for (i = ninode; --i > 0; ) {
577334Skre 		++ip;
587334Skre 		ip->i_forw = ip;
597334Skre 		ip->i_back = ip;
607334Skre 		*ifreet = ip;
617334Skre 		ip->i_freeb = ifreet;
627334Skre 		ifreet = &ip->i_freef;
637334Skre 	}
647334Skre 	ip->i_freef = NULL;
6524Sbill }
6624Sbill 
677334Skre #ifdef notdef
6824Sbill /*
697334Skre  * Find an inode if it is incore.
707334Skre  * This is the equivalent, for inodes,
717334Skre  * of ``incore'' in bio.c or ``pfind'' in subr.c.
727334Skre  */
737334Skre struct inode *
747334Skre ifind(dev, ino)
757334Skre 	dev_t dev;
767334Skre 	ino_t ino;
777334Skre {
787334Skre 	register struct inode *ip;
797334Skre 	register union  ihead *ih;
807334Skre 
817334Skre 	ih = &ihead[INOHASH(dev, ino)];
827334Skre 	for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
837334Skre 		if (ino==ip->i_number && dev==ip->i_dev)
847334Skre 			return (ip);
857334Skre 	return ((struct inode *)0);
867334Skre }
877334Skre #endif notdef
887334Skre 
897334Skre /*
9024Sbill  * Look up an inode by device,inumber.
9124Sbill  * If it is in core (in the inode structure),
9224Sbill  * honor the locking protocol.
9324Sbill  * If it is not in core, read it in from the
9424Sbill  * specified device.
9524Sbill  * If the inode is mounted on, perform
9624Sbill  * the indicated indirection.
9724Sbill  * In all cases, a pointer to a locked
9824Sbill  * inode structure is returned.
9924Sbill  *
10024Sbill  * panic: no imt -- if the mounted file
10124Sbill  *	system is not in the mount table.
10224Sbill  *	"cannot happen"
10324Sbill  */
10424Sbill struct inode *
1056569Smckusic iget(dev, fs, ino)
1064818Swnj 	dev_t dev;
1076569Smckusic 	register struct fs *fs;
1084818Swnj 	ino_t ino;
10924Sbill {
1107335Skre 	register struct inode *ip;
1117335Skre 	register union  ihead *ih;
11224Sbill 	register struct mount *mp;
11324Sbill 	register struct buf *bp;
11424Sbill 	register struct dinode *dp;
1157334Skre 	register struct inode *iq;
11624Sbill 
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
188*30749Skarels #ifdef SECSIZE
189*30749Skarels 	bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize,
190*30749Skarels 	    fs->fs_dbsize);
191*30749Skarels #else SECSIZE
1928618Sroot 	bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize);
193*30749Skarels #endif SECSIZE
19424Sbill 	/*
19524Sbill 	 * Check I/O errors
19624Sbill 	 */
1974818Swnj 	if ((bp->b_flags&B_ERROR) != 0) {
19824Sbill 		brelse(bp);
1997334Skre 		/*
2007334Skre 		 * the inode doesn't contain anything useful, so it would
2017334Skre 		 * be misleading to leave it on its hash chain.
2027334Skre 		 * 'iput' will take care of putting it back on the free list.
2037334Skre 		 */
2047335Skre 		remque(ip);
2057334Skre 		ip->i_forw = ip;
2067334Skre 		ip->i_back = ip;
2077334Skre 		/*
2087334Skre 		 * we also loose its inumber, just in case (as iput
2097334Skre 		 * doesn't do that any more) - but as it isn't on its
2107334Skre 		 * hash chain, I doubt if this is really necessary .. kre
2117334Skre 		 * (probably the two methods are interchangable)
2127334Skre 		 */
2137334Skre 		ip->i_number = 0;
2147651Ssam #ifdef QUOTA
2157492Skre 		ip->i_dquot = NODQUOT;
2167492Skre #endif
21724Sbill 		iput(ip);
21824Sbill 		return(NULL);
21924Sbill 	}
22024Sbill 	dp = bp->b_un.b_dino;
2216569Smckusic 	dp += itoo(fs, ino);
2226569Smckusic 	ip->i_ic = dp->di_ic;
22324Sbill 	brelse(bp);
2247651Ssam #ifdef QUOTA
2257492Skre 	if (ip->i_mode == 0)
2267492Skre 		ip->i_dquot = NODQUOT;
2277492Skre 	else
2287492Skre 		ip->i_dquot = inoquota(ip);
2297492Skre #endif
2306569Smckusic 	return (ip);
23124Sbill }
23224Sbill 
23324Sbill /*
23416642Ssam  * Convert a pointer to an inode into a reference to an inode.
23516642Ssam  *
23616642Ssam  * This is basically the internal piece of iget (after the
23716642Ssam  * inode pointer is located) but without the test for mounted
23816642Ssam  * filesystems.  It is caller's responsibility to check that
23916642Ssam  * the inode pointer is valid.
24016642Ssam  */
24116642Ssam igrab(ip)
24216642Ssam 	register struct inode *ip;
24316642Ssam {
24416642Ssam 	while ((ip->i_flag&ILOCKED) != 0) {
24516642Ssam 		ip->i_flag |= IWANT;
24616642Ssam 		sleep((caddr_t)ip, PINOD);
24716642Ssam 	}
24816642Ssam 	if (ip->i_count == 0) {		/* ino on free list */
24916642Ssam 		register struct inode *iq;
25016642Ssam 
25116642Ssam 		if (iq = ip->i_freef)
25216642Ssam 			iq->i_freeb = ip->i_freeb;
25316642Ssam 		else
25416642Ssam 			ifreet = ip->i_freeb;
25516642Ssam 		*ip->i_freeb = iq;
25616642Ssam 		ip->i_freef = NULL;
25716642Ssam 		ip->i_freeb = NULL;
25816642Ssam 	}
25916642Ssam 	ip->i_count++;
26016642Ssam 	ip->i_flag |= ILOCKED;
26116642Ssam }
26216642Ssam 
26316642Ssam /*
26424Sbill  * Decrement reference count of
26524Sbill  * an inode structure.
26624Sbill  * On the last reference,
26724Sbill  * write the inode out and if necessary,
26824Sbill  * truncate and deallocate the file.
26924Sbill  */
27024Sbill iput(ip)
2714818Swnj 	register struct inode *ip;
27224Sbill {
2737118Smckusick 
2748452Sroot 	if ((ip->i_flag & ILOCKED) == 0)
2757118Smckusick 		panic("iput");
27616665Smckusick 	IUNLOCK(ip);
2777118Smckusick 	irele(ip);
2787118Smckusick }
2797118Smckusick 
2807118Smckusick irele(ip)
2817118Smckusick 	register struct inode *ip;
2827118Smckusick {
2836569Smckusic 	int mode;
28424Sbill 
28518445Smckusick 	if (ip->i_count == 1) {
2868452Sroot 		ip->i_flag |= ILOCKED;
28718445Smckusick 		if (ip->i_nlink <= 0 && ip->i_fs->fs_ronly == 0) {
2889165Ssam 			itrunc(ip, (u_long)0);
2896569Smckusic 			mode = ip->i_mode;
29024Sbill 			ip->i_mode = 0;
2917351Skre 			ip->i_rdev = 0;
29224Sbill 			ip->i_flag |= IUPD|ICHG;
2936569Smckusic 			ifree(ip, ip->i_number, mode);
2947651Ssam #ifdef QUOTA
29512645Ssam 			(void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
2967492Skre 			dqrele(ip->i_dquot);
2977492Skre 			ip->i_dquot = NODQUOT;
2987492Skre #endif
29924Sbill 		}
3008671Sroot 		IUPDAT(ip, &time, &time, 0);
30116665Smckusick 		IUNLOCK(ip);
3027334Skre 		ip->i_flag = 0;
3037334Skre 		/*
3047334Skre 		 * Put the inode on the end of the free list.
3057334Skre 		 * Possibly in some cases it would be better to
3067334Skre 		 * put the inode at the head of the free list,
3077334Skre 		 * (eg: where i_mode == 0 || i_number == 0)
3087334Skre 		 * but I will think about that later .. kre
3097334Skre 		 * (i_number is rarely 0 - only after an i/o error in iget,
3107334Skre 		 * where i_mode == 0, the inode will probably be wanted
3117334Skre 		 * again soon for an ialloc, so possibly we should keep it)
3127334Skre 		 */
3137334Skre 		if (ifreeh) {
3147334Skre 			*ifreet = ip;
3157334Skre 			ip->i_freeb = ifreet;
31624Sbill 		} else {
3177334Skre 			ifreeh = ip;
3187334Skre 			ip->i_freeb = &ifreeh;
31924Sbill 		}
3207334Skre 		ip->i_freef = NULL;
3217334Skre 		ifreet = &ip->i_freef;
32216058Skarels 	} else if (!(ip->i_flag & ILOCKED))
32316058Skarels 		ITIMES(ip, &time, &time);
32424Sbill 	ip->i_count--;
32524Sbill }
32624Sbill 
32724Sbill /*
32824Sbill  * Check accessed and update flags on
32924Sbill  * an inode structure.
33024Sbill  * If any is on, update the inode
33124Sbill  * with the current time.
3321203Sbill  * If waitfor is given, then must insure
3331203Sbill  * i/o order so wait for write to complete.
33424Sbill  */
3351203Sbill iupdat(ip, ta, tm, waitfor)
3364818Swnj 	register struct inode *ip;
3378630Sroot 	struct timeval *ta, *tm;
3384818Swnj 	int waitfor;
33924Sbill {
34024Sbill 	register struct buf *bp;
34124Sbill 	struct dinode *dp;
342*30749Skarels 	register struct fs *fs;
34324Sbill 
344*30749Skarels 	fs = ip->i_fs;
34516058Skarels 	if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) {
346*30749Skarels 		if (fs->fs_ronly)
34724Sbill 			return;
348*30749Skarels #ifdef SECSIZE
349*30749Skarels 		bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
350*30749Skarels 			(int)fs->fs_bsize, fs->fs_dbsize);
351*30749Skarels #else SECSIZE
352*30749Skarels 		bp = bread(ip->i_dev, fsbtodb(fs, itod(fs, ip->i_number)),
353*30749Skarels 			(int)fs->fs_bsize);
354*30749Skarels #endif SECSIZE
35524Sbill 		if (bp->b_flags & B_ERROR) {
35624Sbill 			brelse(bp);
35724Sbill 			return;
35824Sbill 		}
3594818Swnj 		if (ip->i_flag&IACC)
3608630Sroot 			ip->i_atime = ta->tv_sec;
3614818Swnj 		if (ip->i_flag&IUPD)
3628630Sroot 			ip->i_mtime = tm->tv_sec;
3634818Swnj 		if (ip->i_flag&ICHG)
3648106Sroot 			ip->i_ctime = time.tv_sec;
36516058Skarels 		ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
366*30749Skarels 		dp = bp->b_un.b_dino + itoo(fs, ip->i_number);
3677343Skre 		dp->di_ic = ip->i_ic;
3681203Sbill 		if (waitfor)
3691203Sbill 			bwrite(bp);
3701203Sbill 		else
3711203Sbill 			bdwrite(bp);
37224Sbill 	}
37324Sbill }
37424Sbill 
37510736Ssam #define	SINGLE	0	/* index of single indirect block */
37610736Ssam #define	DOUBLE	1	/* index of double indirect block */
37710736Ssam #define	TRIPLE	2	/* index of triple indirect block */
37824Sbill /*
3797702Ssam  * Truncate the inode ip to at most
3807702Ssam  * length size.  Free affected disk
3817702Ssam  * blocks -- the blocks of the file
3827702Ssam  * are removed in reverse order.
38310736Ssam  *
38410736Ssam  * NB: triple indirect blocks are untested.
38524Sbill  */
38610736Ssam itrunc(oip, length)
38717942Smckusick 	register struct inode *oip;
3889165Ssam 	u_long length;
38924Sbill {
3909165Ssam 	register daddr_t lastblock;
39126272Skarels 	daddr_t bn, lbn, lastiblock[NIADDR];
3926569Smckusic 	register struct fs *fs;
39310736Ssam 	register struct inode *ip;
39417942Smckusick 	struct buf *bp;
395*30749Skarels 	int offset, osize, size, count, level;
39617942Smckusick 	long nblocks, blocksreleased = 0;
39717942Smckusick 	register int i;
39817942Smckusick 	dev_t dev;
39910736Ssam 	struct inode tip;
40017942Smckusick 	extern long indirtrunc();
4019165Ssam 
40213000Ssam 	if (oip->i_size <= length) {
40313000Ssam 		oip->i_flag |= ICHG|IUPD;
40413000Ssam 		iupdat(oip, &time, &time, 1);
4059165Ssam 		return;
40613000Ssam 	}
4071203Sbill 	/*
40810736Ssam 	 * Calculate index into inode's block list of
40910736Ssam 	 * last direct and indirect blocks (if any)
41010736Ssam 	 * which we want to keep.  Lastblock is -1 when
41110736Ssam 	 * the file is truncated to 0.
4121203Sbill 	 */
41310736Ssam 	fs = oip->i_fs;
4149165Ssam 	lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
41510736Ssam 	lastiblock[SINGLE] = lastblock - NDADDR;
41610736Ssam 	lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
41710736Ssam 	lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
41812645Ssam 	nblocks = btodb(fs->fs_bsize);
4196569Smckusic 	/*
42017942Smckusick 	 * Update the size of the file. If the file is not being
42117942Smckusick 	 * truncated to a block boundry, the contents of the
42217942Smckusick 	 * partial block following the end of the file must be
42317942Smckusick 	 * zero'ed in case it ever become accessable again because
42417942Smckusick 	 * of subsequent file growth.
42517942Smckusick 	 */
42617942Smckusick 	osize = oip->i_size;
42717942Smckusick 	offset = blkoff(fs, length);
42817942Smckusick 	if (offset == 0) {
42917942Smckusick 		oip->i_size = length;
43017942Smckusick 	} else {
43117942Smckusick 		lbn = lblkno(fs, length);
43217942Smckusick 		bn = fsbtodb(fs, bmap(oip, lbn, B_WRITE, offset));
43317942Smckusick 		if (u.u_error || (long)bn < 0)
43417942Smckusick 			return;
43517942Smckusick 		oip->i_size = length;
43617942Smckusick 		size = blksize(fs, oip, lbn);
437*30749Skarels 		count = howmany(size, CLBYTES);
43817942Smckusick 		dev = oip->i_dev;
439*30749Skarels 		for (i = 0; i < count; i++)
440*30749Skarels #ifdef SECSIZE
441*30749Skarels 			munhash(dev, bn + i * CLBYTES / fs->fs_dbsize);
442*30749Skarels #else SECSIZE
443*30749Skarels 			munhash(dev, bn + i * CLBYTES / DEV_BSIZE);
444*30749Skarels #endif SECSIZE
44517942Smckusick 		bp = bread(dev, bn, size);
44617942Smckusick 		if (bp->b_flags & B_ERROR) {
44717942Smckusick 			u.u_error = EIO;
44817942Smckusick 			oip->i_size = osize;
44917942Smckusick 			brelse(bp);
45017942Smckusick 			return;
45117942Smckusick 		}
45226272Skarels 		bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
45317942Smckusick 		bdwrite(bp);
45417942Smckusick 	}
45517942Smckusick 	/*
45617942Smckusick 	 * Update file and block pointers
45710736Ssam 	 * on disk before we start freeing blocks.
45810736Ssam 	 * If we crash before free'ing blocks below,
45910736Ssam 	 * the blocks will be returned to the free list.
46010736Ssam 	 * lastiblock values are also normalized to -1
46110736Ssam 	 * for calls to indirtrunc below.
4626569Smckusic 	 */
46310736Ssam 	tip = *oip;
46417942Smckusick 	tip.i_size = osize;
46510736Ssam 	for (level = TRIPLE; level >= SINGLE; level--)
46610736Ssam 		if (lastiblock[level] < 0) {
46710736Ssam 			oip->i_ib[level] = 0;
46810736Ssam 			lastiblock[level] = -1;
4699165Ssam 		}
47010736Ssam 	for (i = NDADDR - 1; i > lastblock; i--)
47110736Ssam 		oip->i_db[i] = 0;
47210736Ssam 	oip->i_flag |= ICHG|IUPD;
47317942Smckusick 	syncip(oip);
47410736Ssam 
4756569Smckusic 	/*
47610736Ssam 	 * Indirect blocks first.
4776569Smckusic 	 */
47817942Smckusick 	ip = &tip;
47910736Ssam 	for (level = TRIPLE; level >= SINGLE; level--) {
48010736Ssam 		bn = ip->i_ib[level];
4819165Ssam 		if (bn != 0) {
48210736Ssam 			blocksreleased +=
48312645Ssam 			    indirtrunc(ip, bn, lastiblock[level], level);
48410736Ssam 			if (lastiblock[level] < 0) {
48510736Ssam 				ip->i_ib[level] = 0;
48610736Ssam 				free(ip, bn, (off_t)fs->fs_bsize);
48710736Ssam 				blocksreleased += nblocks;
48810736Ssam 			}
48910736Ssam 		}
49010736Ssam 		if (lastiblock[level] >= 0)
49110736Ssam 			goto done;
4929165Ssam 	}
49310736Ssam 
4946569Smckusic 	/*
49510736Ssam 	 * All whole direct blocks or frags.
4966569Smckusic 	 */
4979165Ssam 	for (i = NDADDR - 1; i > lastblock; i--) {
49826359Skarels 		register off_t bsize;
4999165Ssam 
5006569Smckusic 		bn = ip->i_db[i];
5019165Ssam 		if (bn == 0)
50224Sbill 			continue;
5039165Ssam 		ip->i_db[i] = 0;
50424525Sbloom 		bsize = (off_t)blksize(fs, ip, i);
50524525Sbloom 		free(ip, bn, bsize);
50624525Sbloom 		blocksreleased += btodb(bsize);
50724Sbill 	}
50810736Ssam 	if (lastblock < 0)
50910736Ssam 		goto done;
51010736Ssam 
5111203Sbill 	/*
5129165Ssam 	 * Finally, look for a change in size of the
5139165Ssam 	 * last direct block; release any frags.
5141203Sbill 	 */
51510736Ssam 	bn = ip->i_db[lastblock];
51610736Ssam 	if (bn != 0) {
51726359Skarels 		off_t oldspace, newspace;
51810736Ssam 
5199165Ssam 		/*
5209165Ssam 		 * Calculate amount of space we're giving
5219165Ssam 		 * back as old block size minus new block size.
5229165Ssam 		 */
52310736Ssam 		oldspace = blksize(fs, ip, lastblock);
5249165Ssam 		ip->i_size = length;
52510736Ssam 		newspace = blksize(fs, ip, lastblock);
52610736Ssam 		if (newspace == 0)
52710736Ssam 			panic("itrunc: newspace");
52810736Ssam 		if (oldspace - newspace > 0) {
5299165Ssam 			/*
5309165Ssam 			 * Block number of space to be free'd is
5319165Ssam 			 * the old block # plus the number of frags
5329165Ssam 			 * required for the storage we're keeping.
5339165Ssam 			 */
53410736Ssam 			bn += numfrags(fs, newspace);
53510736Ssam 			free(ip, bn, oldspace - newspace);
53612645Ssam 			blocksreleased += btodb(oldspace - newspace);
5379165Ssam 		}
5389165Ssam 	}
5399165Ssam done:
54010736Ssam /* BEGIN PARANOIA */
54110736Ssam 	for (level = SINGLE; level <= TRIPLE; level++)
54210736Ssam 		if (ip->i_ib[level] != oip->i_ib[level])
54310736Ssam 			panic("itrunc1");
54410736Ssam 	for (i = 0; i < NDADDR; i++)
54510736Ssam 		if (ip->i_db[i] != oip->i_db[i])
54610736Ssam 			panic("itrunc2");
54710736Ssam /* END PARANOIA */
54812645Ssam 	oip->i_blocks -= blocksreleased;
54912645Ssam 	if (oip->i_blocks < 0)			/* sanity */
55012645Ssam 		oip->i_blocks = 0;
55112645Ssam 	oip->i_flag |= ICHG;
5529165Ssam #ifdef QUOTA
55312645Ssam 	(void) chkdq(oip, -blocksreleased, 0);
5549165Ssam #endif
55524Sbill }
55624Sbill 
5579165Ssam /*
5589165Ssam  * Release blocks associated with the inode ip and
5599165Ssam  * stored in the indirect block bn.  Blocks are free'd
5609165Ssam  * in LIFO order up to (but not including) lastbn.  If
56110736Ssam  * level is greater than SINGLE, the block is an indirect
56210736Ssam  * block and recursive calls to indirtrunc must be used to
56310736Ssam  * cleanse other indirect blocks.
56410736Ssam  *
56510736Ssam  * NB: triple indirect blocks are untested.
5669165Ssam  */
5677492Skre long
56810736Ssam indirtrunc(ip, bn, lastbn, level)
5696569Smckusic 	register struct inode *ip;
5709165Ssam 	daddr_t bn, lastbn;
57110736Ssam 	int level;
57224Sbill {
5739165Ssam 	register int i;
57410736Ssam 	struct buf *bp, *copy;
57524Sbill 	register daddr_t *bap;
57610736Ssam 	register struct fs *fs = ip->i_fs;
5779165Ssam 	daddr_t nb, last;
57810736Ssam 	long factor;
5799165Ssam 	int blocksreleased = 0, nblocks;
58024Sbill 
58110736Ssam 	/*
58210736Ssam 	 * Calculate index in current block of last
58310736Ssam 	 * block to be kept.  -1 indicates the entire
58410736Ssam 	 * block so we need not calculate the index.
58510736Ssam 	 */
58610736Ssam 	factor = 1;
58710736Ssam 	for (i = SINGLE; i < level; i++)
58810736Ssam 		factor *= NINDIR(fs);
5899165Ssam 	last = lastbn;
59010736Ssam 	if (lastbn > 0)
59110736Ssam 		last /= factor;
59212645Ssam 	nblocks = btodb(fs->fs_bsize);
59310736Ssam 	/*
59410736Ssam 	 * Get buffer of block pointers, zero those
59510736Ssam 	 * entries corresponding to blocks to be free'd,
59610736Ssam 	 * and update on disk copy first.
59710736Ssam 	 */
59810736Ssam 	copy = geteblk((int)fs->fs_bsize);
599*30749Skarels #ifdef SECSIZE
600*30749Skarels 	bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize,
601*30749Skarels 	    fs->fs_dbsize);
602*30749Skarels #else SECSIZE
60310736Ssam 	bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize);
604*30749Skarels #endif SECSIZE
60510736Ssam 	if (bp->b_flags&B_ERROR) {
60610736Ssam 		brelse(copy);
60710736Ssam 		brelse(bp);
60810736Ssam 		return (0);
60910736Ssam 	}
61010736Ssam 	bap = bp->b_un.b_daddr;
61110736Ssam 	bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize);
61210736Ssam 	bzero((caddr_t)&bap[last + 1],
61310736Ssam 	  (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
61410736Ssam 	bwrite(bp);
61510736Ssam 	bp = copy, bap = bp->b_un.b_daddr;
61610736Ssam 
61710736Ssam 	/*
61810736Ssam 	 * Recursively free totally unused blocks.
61910736Ssam 	 */
6209165Ssam 	for (i = NINDIR(fs) - 1; i > last; i--) {
62124Sbill 		nb = bap[i];
6229165Ssam 		if (nb == 0)
62324Sbill 			continue;
62410736Ssam 		if (level > SINGLE)
6259165Ssam 			blocksreleased +=
62612645Ssam 			    indirtrunc(ip, nb, (daddr_t)-1, level - 1);
62726359Skarels 		free(ip, nb, (off_t)fs->fs_bsize);
6289165Ssam 		blocksreleased += nblocks;
62924Sbill 	}
63010736Ssam 
63110736Ssam 	/*
63210736Ssam 	 * Recursively free last partial block.
63310736Ssam 	 */
63410736Ssam 	if (level > SINGLE && lastbn >= 0) {
63510736Ssam 		last = lastbn % factor;
6369165Ssam 		nb = bap[i];
6379165Ssam 		if (nb != 0)
63812645Ssam 			blocksreleased += indirtrunc(ip, nb, last, level - 1);
6399165Ssam 	}
64010736Ssam 	brelse(bp);
6419165Ssam 	return (blocksreleased);
64224Sbill }
64324Sbill 
64424Sbill /*
645*30749Skarels  * Remove any inodes in the inode cache belonging to dev.
6467334Skre  *
6477334Skre  * There should not be any active ones, return error if any are found
648*30749Skarels  * (nb: this is a user error, not a system err).
6497334Skre  */
6507651Ssam #ifdef QUOTA
6517504Sroot iflush(dev, iq)
6527492Skre 	dev_t dev;
6537504Sroot 	struct inode *iq;
6547492Skre #else
6557334Skre iflush(dev)
6567334Skre 	dev_t dev;
6577492Skre #endif
6587334Skre {
6597335Skre 	register struct inode *ip;
6607334Skre 
6617334Skre 	for (ip = inode; ip < inodeNINODE; ip++) {
6627651Ssam #ifdef QUOTA
6637492Skre 		if (ip != iq && ip->i_dev == dev)
6647492Skre #else
6657334Skre 		if (ip->i_dev == dev)
6667492Skre #endif
6677334Skre 			if (ip->i_count)
668*30749Skarels 				return (EBUSY);
6697334Skre 			else {
6707335Skre 				remque(ip);
6717334Skre 				ip->i_forw = ip;
6727334Skre 				ip->i_back = ip;
6737334Skre 				/*
6747334Skre 				 * as i_count == 0, the inode was on the free
6757334Skre 				 * list already, just leave it there, it will
6767334Skre 				 * fall off the bottom eventually. We could
6777334Skre 				 * perhaps move it to the head of the free
6787334Skre 				 * list, but as umounts are done so
6797334Skre 				 * infrequently, we would gain very little,
6807334Skre 				 * while making the code bigger.
6817334Skre 				 */
6827651Ssam #ifdef QUOTA
6837492Skre 				dqrele(ip->i_dquot);
6847492Skre 				ip->i_dquot = NODQUOT;
6857492Skre #endif
6867334Skre 			}
6877334Skre 	}
688*30749Skarels 	return (0);
6897334Skre }
6907334Skre 
6913617Sroot /*
6924818Swnj  * Lock an inode. If its already locked, set the WANT bit and sleep.
6933617Sroot  */
6944818Swnj ilock(ip)
6954818Swnj 	register struct inode *ip;
6963617Sroot {
6973617Sroot 
6988452Sroot 	ILOCK(ip);
6993617Sroot }
7003617Sroot 
7013617Sroot /*
7024818Swnj  * Unlock an inode.  If WANT bit is on, wakeup.
7033617Sroot  */
7047118Smckusick iunlock(ip)
7054818Swnj 	register struct inode *ip;
7063617Sroot {
7073617Sroot 
7088452Sroot 	IUNLOCK(ip);
7093617Sroot }
710