xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 16720)
1*16720Skarels /*	lfs_inode.c	6.8	84/07/15	*/
224Sbill 
324Sbill #include "../h/param.h"
424Sbill #include "../h/systm.h"
524Sbill #include "../h/mount.h"
624Sbill #include "../h/dir.h"
724Sbill #include "../h/user.h"
824Sbill #include "../h/inode.h"
96569Smckusic #include "../h/fs.h"
1024Sbill #include "../h/conf.h"
1124Sbill #include "../h/buf.h"
127651Ssam #ifdef QUOTA
137504Sroot #include "../h/quota.h"
147504Sroot #endif
158106Sroot #include "../h/kernel.h"
1624Sbill 
1716524Skarels #define	INOHSZ	64
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;
11016656Smckusick 	struct inode *xp;
11124Sbill 
11216656Smckusick 
11324Sbill loop:
1147334Skre 	ih = &ihead[INOHASH(dev, ino)];
1157334Skre 	for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
1164818Swnj 		if (ino == ip->i_number && dev == ip->i_dev) {
11716642Ssam 			/*
11816642Ssam 			 * Following is essentially an inline expanded
11916642Ssam 			 * copy of igrab(), expanded inline for speed,
12016642Ssam 			 * and so that the test for a mounted on inode
12116642Ssam 			 * can be deferred until after we are sure that
12216642Ssam 			 * the inode isn't busy.
12316642Ssam 			 */
1248452Sroot 			if ((ip->i_flag&ILOCKED) != 0) {
12524Sbill 				ip->i_flag |= IWANT;
12624Sbill 				sleep((caddr_t)ip, PINOD);
12724Sbill 				goto loop;
12824Sbill 			}
1294818Swnj 			if ((ip->i_flag&IMOUNT) != 0) {
1306569Smckusic 				for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
1317334Skre 					if(mp->m_inodp == ip) {
1327334Skre 						dev = mp->m_dev;
1337334Skre 						fs = mp->m_bufp->b_un.b_fs;
1347334Skre 						ino = ROOTINO;
1357334Skre 						goto loop;
1367334Skre 					}
13724Sbill 				panic("no imt");
13824Sbill 			}
1397334Skre 			if (ip->i_count == 0) {		/* ino on free list */
1407334Skre 				if (iq = ip->i_freef)
1417334Skre 					iq->i_freeb = ip->i_freeb;
1427334Skre 				else
1437334Skre 					ifreet = ip->i_freeb;
1447334Skre 				*ip->i_freeb = iq;
1457334Skre 				ip->i_freef = NULL;
1467334Skre 				ip->i_freeb = NULL;
1477334Skre 			}
14824Sbill 			ip->i_count++;
1498452Sroot 			ip->i_flag |= ILOCKED;
15024Sbill 			return(ip);
15124Sbill 		}
1527334Skre 
1537334Skre 	if ((ip = ifreeh) == NULL) {
1542933Swnj 		tablefull("inode");
15524Sbill 		u.u_error = ENFILE;
15624Sbill 		return(NULL);
15724Sbill 	}
158*16720Skarels 	if (ip->i_count)
159*16720Skarels 		panic("free inode isn't");
1607334Skre 	if (iq = ip->i_freef)
1617334Skre 		iq->i_freeb = &ifreeh;
1627334Skre 	ifreeh = iq;
1637334Skre 	ip->i_freef = NULL;
1647334Skre 	ip->i_freeb = NULL;
1657334Skre 	/*
1667334Skre 	 * Now to take inode off the hash chain it was on
1677334Skre 	 * (initially, or after an iflush, it is on a "hash chain"
1687334Skre 	 * consisting entirely of itself, and pointed to by no-one,
1697334Skre 	 * but that doesn't matter), and put it on the chain for
1707334Skre 	 * its new (ino, dev) pair
1717334Skre 	 */
1727335Skre 	remque(ip);
1737335Skre 	insque(ip, ih);
17424Sbill 	ip->i_dev = dev;
1756569Smckusic 	ip->i_fs = fs;
17624Sbill 	ip->i_number = ino;
17716642Ssam 	ip->i_id = ++nextinodeid;	/* also used in rename */
17816642Ssam 	/*
17916642Ssam 	 * At an absurd rate of 100 calls/second,
18016656Smckusick 	 * this should occur once every 8 months.
18116642Ssam 	 */
18216656Smckusick 	if (nextinodeid < 0)
18316656Smckusick 		for (nextinodeid = 0, xp = inode; xp < inodeNINODE; xp++)
18416656Smckusick 			xp->i_id = 0;
1858452Sroot 	ip->i_flag = ILOCKED;
18624Sbill 	ip->i_count++;
1876569Smckusic 	ip->i_lastr = 0;
188*16720Skarels #ifdef QUOTA
189*16720Skarels 	dqrele(ip->i_dquot);
190*16720Skarels #endif
1918618Sroot 	bp = bread(dev, fsbtodb(fs, itod(fs, ino)), (int)fs->fs_bsize);
19224Sbill 	/*
19324Sbill 	 * Check I/O errors
19424Sbill 	 */
1954818Swnj 	if ((bp->b_flags&B_ERROR) != 0) {
19624Sbill 		brelse(bp);
1977334Skre 		/*
1987334Skre 		 * the inode doesn't contain anything useful, so it would
1997334Skre 		 * be misleading to leave it on its hash chain.
2007334Skre 		 * 'iput' will take care of putting it back on the free list.
2017334Skre 		 */
2027335Skre 		remque(ip);
2037334Skre 		ip->i_forw = ip;
2047334Skre 		ip->i_back = ip;
2057334Skre 		/*
2067334Skre 		 * we also loose its inumber, just in case (as iput
2077334Skre 		 * doesn't do that any more) - but as it isn't on its
2087334Skre 		 * hash chain, I doubt if this is really necessary .. kre
2097334Skre 		 * (probably the two methods are interchangable)
2107334Skre 		 */
2117334Skre 		ip->i_number = 0;
2127651Ssam #ifdef QUOTA
2137492Skre 		ip->i_dquot = NODQUOT;
2147492Skre #endif
21524Sbill 		iput(ip);
21624Sbill 		return(NULL);
21724Sbill 	}
21824Sbill 	dp = bp->b_un.b_dino;
2196569Smckusic 	dp += itoo(fs, ino);
2206569Smckusic 	ip->i_ic = dp->di_ic;
22124Sbill 	brelse(bp);
2227651Ssam #ifdef QUOTA
2237492Skre 	if (ip->i_mode == 0)
2247492Skre 		ip->i_dquot = NODQUOT;
2257492Skre 	else
2267492Skre 		ip->i_dquot = inoquota(ip);
2277492Skre #endif
2286569Smckusic 	return (ip);
22924Sbill }
23024Sbill 
23124Sbill /*
23216642Ssam  * Convert a pointer to an inode into a reference to an inode.
23316642Ssam  *
23416642Ssam  * This is basically the internal piece of iget (after the
23516642Ssam  * inode pointer is located) but without the test for mounted
23616642Ssam  * filesystems.  It is caller's responsibility to check that
23716642Ssam  * the inode pointer is valid.
23816642Ssam  */
23916642Ssam igrab(ip)
24016642Ssam 	register struct inode *ip;
24116642Ssam {
24216642Ssam 	while ((ip->i_flag&ILOCKED) != 0) {
24316642Ssam 		ip->i_flag |= IWANT;
24416642Ssam 		sleep((caddr_t)ip, PINOD);
24516642Ssam 	}
24616642Ssam 	if (ip->i_count == 0) {		/* ino on free list */
24716642Ssam 		register struct inode *iq;
24816642Ssam 
24916642Ssam 		if (iq = ip->i_freef)
25016642Ssam 			iq->i_freeb = ip->i_freeb;
25116642Ssam 		else
25216642Ssam 			ifreet = ip->i_freeb;
25316642Ssam 		*ip->i_freeb = iq;
25416642Ssam 		ip->i_freef = NULL;
25516642Ssam 		ip->i_freeb = NULL;
25616642Ssam 	}
25716642Ssam 	ip->i_count++;
25816642Ssam 	ip->i_flag |= ILOCKED;
25916642Ssam }
26016642Ssam 
26116642Ssam /*
26224Sbill  * Decrement reference count of
26324Sbill  * an inode structure.
26424Sbill  * On the last reference,
26524Sbill  * write the inode out and if necessary,
26624Sbill  * truncate and deallocate the file.
26724Sbill  */
26824Sbill iput(ip)
2694818Swnj 	register struct inode *ip;
27024Sbill {
2717118Smckusick 
2728452Sroot 	if ((ip->i_flag & ILOCKED) == 0)
2737118Smckusick 		panic("iput");
27416665Smckusick 	IUNLOCK(ip);
2757118Smckusick 	irele(ip);
2767118Smckusick }
2777118Smckusick 
2787118Smckusick irele(ip)
2797118Smckusick 	register struct inode *ip;
2807118Smckusick {
2816569Smckusic 	int mode;
28224Sbill 
2834818Swnj 	if (ip->i_count == 1) {
2848452Sroot 		ip->i_flag |= ILOCKED;
2854818Swnj 		if (ip->i_nlink <= 0) {
2869165Ssam 			itrunc(ip, (u_long)0);
2876569Smckusic 			mode = ip->i_mode;
28824Sbill 			ip->i_mode = 0;
2897351Skre 			ip->i_rdev = 0;
29024Sbill 			ip->i_flag |= IUPD|ICHG;
2916569Smckusic 			ifree(ip, ip->i_number, mode);
2927651Ssam #ifdef QUOTA
29312645Ssam 			(void) chkiq(ip->i_dev, ip, ip->i_uid, 0);
2947492Skre 			dqrele(ip->i_dquot);
2957492Skre 			ip->i_dquot = NODQUOT;
2967492Skre #endif
29724Sbill 		}
2988671Sroot 		IUPDAT(ip, &time, &time, 0);
29916665Smckusick 		IUNLOCK(ip);
3007334Skre 		ip->i_flag = 0;
3017334Skre 		/*
3027334Skre 		 * Put the inode on the end of the free list.
3037334Skre 		 * Possibly in some cases it would be better to
3047334Skre 		 * put the inode at the head of the free list,
3057334Skre 		 * (eg: where i_mode == 0 || i_number == 0)
3067334Skre 		 * but I will think about that later .. kre
3077334Skre 		 * (i_number is rarely 0 - only after an i/o error in iget,
3087334Skre 		 * where i_mode == 0, the inode will probably be wanted
3097334Skre 		 * again soon for an ialloc, so possibly we should keep it)
3107334Skre 		 */
3117334Skre 		if (ifreeh) {
3127334Skre 			*ifreet = ip;
3137334Skre 			ip->i_freeb = ifreet;
31424Sbill 		} else {
3157334Skre 			ifreeh = ip;
3167334Skre 			ip->i_freeb = &ifreeh;
31724Sbill 		}
3187334Skre 		ip->i_freef = NULL;
3197334Skre 		ifreet = &ip->i_freef;
32016058Skarels 	} else if (!(ip->i_flag & ILOCKED))
32116058Skarels 		ITIMES(ip, &time, &time);
32224Sbill 	ip->i_count--;
32324Sbill }
32424Sbill 
32524Sbill /*
32624Sbill  * Check accessed and update flags on
32724Sbill  * an inode structure.
32824Sbill  * If any is on, update the inode
32924Sbill  * with the current time.
3301203Sbill  * If waitfor is given, then must insure
3311203Sbill  * i/o order so wait for write to complete.
33224Sbill  */
3331203Sbill iupdat(ip, ta, tm, waitfor)
3344818Swnj 	register struct inode *ip;
3358630Sroot 	struct timeval *ta, *tm;
3364818Swnj 	int waitfor;
33724Sbill {
33824Sbill 	register struct buf *bp;
33924Sbill 	struct dinode *dp;
3406569Smckusic 	register struct fs *fp;
34124Sbill 
3426569Smckusic 	fp = ip->i_fs;
34316058Skarels 	if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) != 0) {
3446569Smckusic 		if (fp->fs_ronly)
34524Sbill 			return;
3466569Smckusic 		bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)),
3478618Sroot 			(int)fp->fs_bsize);
34824Sbill 		if (bp->b_flags & B_ERROR) {
34924Sbill 			brelse(bp);
35024Sbill 			return;
35124Sbill 		}
3524818Swnj 		if (ip->i_flag&IACC)
3538630Sroot 			ip->i_atime = ta->tv_sec;
3544818Swnj 		if (ip->i_flag&IUPD)
3558630Sroot 			ip->i_mtime = tm->tv_sec;
3564818Swnj 		if (ip->i_flag&ICHG)
3578106Sroot 			ip->i_ctime = time.tv_sec;
35816058Skarels 		ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
3597343Skre 		dp = bp->b_un.b_dino + itoo(fp, ip->i_number);
3607343Skre 		dp->di_ic = ip->i_ic;
3611203Sbill 		if (waitfor)
3621203Sbill 			bwrite(bp);
3631203Sbill 		else
3641203Sbill 			bdwrite(bp);
36524Sbill 	}
36624Sbill }
36724Sbill 
36810736Ssam #define	SINGLE	0	/* index of single indirect block */
36910736Ssam #define	DOUBLE	1	/* index of double indirect block */
37010736Ssam #define	TRIPLE	2	/* index of triple indirect block */
37124Sbill /*
3727702Ssam  * Truncate the inode ip to at most
3737702Ssam  * length size.  Free affected disk
3747702Ssam  * blocks -- the blocks of the file
3757702Ssam  * are removed in reverse order.
37610736Ssam  *
37710736Ssam  * NB: triple indirect blocks are untested.
37824Sbill  */
37910736Ssam itrunc(oip, length)
38010736Ssam 	struct inode *oip;
3819165Ssam 	u_long length;
38224Sbill {
38324Sbill 	register i;
3849165Ssam 	register daddr_t lastblock;
38510736Ssam 	daddr_t bn, lastiblock[NIADDR];
3866569Smckusic 	register struct fs *fs;
38710736Ssam 	register struct inode *ip;
38810736Ssam 	struct inode tip;
3899165Ssam 	long blocksreleased = 0, nblocks;
3909165Ssam 	long indirtrunc();
39112645Ssam 	int level;
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 	/*
41110736Ssam 	 * Update size of file and block pointers
41210736Ssam 	 * on disk before we start freeing blocks.
41310736Ssam 	 * If we crash before free'ing blocks below,
41410736Ssam 	 * the blocks will be returned to the free list.
41510736Ssam 	 * lastiblock values are also normalized to -1
41610736Ssam 	 * for calls to indirtrunc below.
41710736Ssam 	 * (? fsck doesn't check validity of pointers in indirect blocks)
4186569Smckusic 	 */
41910736Ssam 	tip = *oip;
42010736Ssam 	for (level = TRIPLE; level >= SINGLE; level--)
42110736Ssam 		if (lastiblock[level] < 0) {
42210736Ssam 			oip->i_ib[level] = 0;
42310736Ssam 			lastiblock[level] = -1;
4249165Ssam 		}
42510736Ssam 	for (i = NDADDR - 1; i > lastblock; i--)
42610736Ssam 		oip->i_db[i] = 0;
42710736Ssam 	oip->i_size = length;
42810736Ssam 	oip->i_flag |= ICHG|IUPD;
42910736Ssam 	iupdat(oip, &time, &time, 1);
43010736Ssam 	ip = &tip;
43110736Ssam 
4326569Smckusic 	/*
43310736Ssam 	 * Indirect blocks first.
4346569Smckusic 	 */
43510736Ssam 	for (level = TRIPLE; level >= SINGLE; level--) {
43610736Ssam 		bn = ip->i_ib[level];
4379165Ssam 		if (bn != 0) {
43810736Ssam 			blocksreleased +=
43912645Ssam 			    indirtrunc(ip, bn, lastiblock[level], level);
44010736Ssam 			if (lastiblock[level] < 0) {
44110736Ssam 				ip->i_ib[level] = 0;
44210736Ssam 				free(ip, bn, (off_t)fs->fs_bsize);
44310736Ssam 				blocksreleased += nblocks;
44410736Ssam 			}
44510736Ssam 		}
44610736Ssam 		if (lastiblock[level] >= 0)
44710736Ssam 			goto done;
4489165Ssam 	}
44910736Ssam 
4506569Smckusic 	/*
45110736Ssam 	 * All whole direct blocks or frags.
4526569Smckusic 	 */
4539165Ssam 	for (i = NDADDR - 1; i > lastblock; i--) {
4549165Ssam 		register int size;
4559165Ssam 
4566569Smckusic 		bn = ip->i_db[i];
4579165Ssam 		if (bn == 0)
45824Sbill 			continue;
4599165Ssam 		ip->i_db[i] = 0;
4609165Ssam 		size = (off_t)blksize(fs, ip, i);
4619165Ssam 		free(ip, bn, size);
46212645Ssam 		blocksreleased += btodb(size);
46324Sbill 	}
46410736Ssam 	if (lastblock < 0)
46510736Ssam 		goto done;
46610736Ssam 
4671203Sbill 	/*
4689165Ssam 	 * Finally, look for a change in size of the
4699165Ssam 	 * last direct block; release any frags.
4701203Sbill 	 */
47110736Ssam 	bn = ip->i_db[lastblock];
47210736Ssam 	if (bn != 0) {
47310736Ssam 		int oldspace, newspace;
47410736Ssam 
4759165Ssam 		/*
4769165Ssam 		 * Calculate amount of space we're giving
4779165Ssam 		 * back as old block size minus new block size.
4789165Ssam 		 */
47910736Ssam 		oldspace = blksize(fs, ip, lastblock);
4809165Ssam 		ip->i_size = length;
48110736Ssam 		newspace = blksize(fs, ip, lastblock);
48210736Ssam 		if (newspace == 0)
48310736Ssam 			panic("itrunc: newspace");
48410736Ssam 		if (oldspace - newspace > 0) {
4859165Ssam 			/*
4869165Ssam 			 * Block number of space to be free'd is
4879165Ssam 			 * the old block # plus the number of frags
4889165Ssam 			 * required for the storage we're keeping.
4899165Ssam 			 */
49010736Ssam 			bn += numfrags(fs, newspace);
49110736Ssam 			free(ip, bn, oldspace - newspace);
49212645Ssam 			blocksreleased += btodb(oldspace - newspace);
4939165Ssam 		}
4949165Ssam 	}
4959165Ssam done:
49610736Ssam /* BEGIN PARANOIA */
49710736Ssam 	for (level = SINGLE; level <= TRIPLE; level++)
49810736Ssam 		if (ip->i_ib[level] != oip->i_ib[level])
49910736Ssam 			panic("itrunc1");
50010736Ssam 	for (i = 0; i < NDADDR; i++)
50110736Ssam 		if (ip->i_db[i] != oip->i_db[i])
50210736Ssam 			panic("itrunc2");
50310736Ssam /* END PARANOIA */
50412645Ssam 	oip->i_blocks -= blocksreleased;
50512645Ssam 	if (oip->i_blocks < 0)			/* sanity */
50612645Ssam 		oip->i_blocks = 0;
50712645Ssam 	oip->i_flag |= ICHG;
5089165Ssam #ifdef QUOTA
50912645Ssam 	(void) chkdq(oip, -blocksreleased, 0);
5109165Ssam #endif
51124Sbill }
51224Sbill 
5139165Ssam /*
5149165Ssam  * Release blocks associated with the inode ip and
5159165Ssam  * stored in the indirect block bn.  Blocks are free'd
5169165Ssam  * in LIFO order up to (but not including) lastbn.  If
51710736Ssam  * level is greater than SINGLE, the block is an indirect
51810736Ssam  * block and recursive calls to indirtrunc must be used to
51910736Ssam  * cleanse other indirect blocks.
52010736Ssam  *
52110736Ssam  * NB: triple indirect blocks are untested.
5229165Ssam  */
5237492Skre long
52410736Ssam indirtrunc(ip, bn, lastbn, level)
5256569Smckusic 	register struct inode *ip;
5269165Ssam 	daddr_t bn, lastbn;
52710736Ssam 	int level;
52824Sbill {
5299165Ssam 	register int i;
53010736Ssam 	struct buf *bp, *copy;
53124Sbill 	register daddr_t *bap;
53210736Ssam 	register struct fs *fs = ip->i_fs;
5339165Ssam 	daddr_t nb, last;
53410736Ssam 	long factor;
5359165Ssam 	int blocksreleased = 0, nblocks;
53624Sbill 
53710736Ssam 	/*
53810736Ssam 	 * Calculate index in current block of last
53910736Ssam 	 * block to be kept.  -1 indicates the entire
54010736Ssam 	 * block so we need not calculate the index.
54110736Ssam 	 */
54210736Ssam 	factor = 1;
54310736Ssam 	for (i = SINGLE; i < level; i++)
54410736Ssam 		factor *= NINDIR(fs);
5459165Ssam 	last = lastbn;
54610736Ssam 	if (lastbn > 0)
54710736Ssam 		last /= factor;
54812645Ssam 	nblocks = btodb(fs->fs_bsize);
54910736Ssam 	/*
55010736Ssam 	 * Get buffer of block pointers, zero those
55110736Ssam 	 * entries corresponding to blocks to be free'd,
55210736Ssam 	 * and update on disk copy first.
55310736Ssam 	 */
55410736Ssam 	copy = geteblk((int)fs->fs_bsize);
55510736Ssam 	bp = bread(ip->i_dev, fsbtodb(fs, bn), (int)fs->fs_bsize);
55610736Ssam 	if (bp->b_flags&B_ERROR) {
55710736Ssam 		brelse(copy);
55810736Ssam 		brelse(bp);
55910736Ssam 		return (0);
56010736Ssam 	}
56110736Ssam 	bap = bp->b_un.b_daddr;
56210736Ssam 	bcopy((caddr_t)bap, (caddr_t)copy->b_un.b_daddr, (u_int)fs->fs_bsize);
56310736Ssam 	bzero((caddr_t)&bap[last + 1],
56410736Ssam 	  (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t));
56510736Ssam 	bwrite(bp);
56610736Ssam 	bp = copy, bap = bp->b_un.b_daddr;
56710736Ssam 
56810736Ssam 	/*
56910736Ssam 	 * Recursively free totally unused blocks.
57010736Ssam 	 */
5719165Ssam 	for (i = NINDIR(fs) - 1; i > last; i--) {
57224Sbill 		nb = bap[i];
5739165Ssam 		if (nb == 0)
57424Sbill 			continue;
57510736Ssam 		if (level > SINGLE)
5769165Ssam 			blocksreleased +=
57712645Ssam 			    indirtrunc(ip, nb, (daddr_t)-1, level - 1);
5789165Ssam 		free(ip, nb, (int)fs->fs_bsize);
5799165Ssam 		blocksreleased += nblocks;
58024Sbill 	}
58110736Ssam 
58210736Ssam 	/*
58310736Ssam 	 * Recursively free last partial block.
58410736Ssam 	 */
58510736Ssam 	if (level > SINGLE && lastbn >= 0) {
58610736Ssam 		last = lastbn % factor;
5879165Ssam 		nb = bap[i];
5889165Ssam 		if (nb != 0)
58912645Ssam 			blocksreleased += indirtrunc(ip, nb, last, level - 1);
5909165Ssam 	}
59110736Ssam 	brelse(bp);
5929165Ssam 	return (blocksreleased);
59324Sbill }
59424Sbill 
59524Sbill /*
5967334Skre  * remove any inodes in the inode cache belonging to dev
5977334Skre  *
5987334Skre  * There should not be any active ones, return error if any are found
5997334Skre  * (nb: this is a user error, not a system err)
6007334Skre  *
6017334Skre  * Also, count the references to dev by block devices - this really
6027334Skre  * has nothing to do with the object of the procedure, but as we have
6037334Skre  * to scan the inode table here anyway, we might as well get the
6047334Skre  * extra benefit.
6057334Skre  *
6067334Skre  * this is called from sumount()/sys3.c when dev is being unmounted
6077334Skre  */
6087651Ssam #ifdef QUOTA
6097504Sroot iflush(dev, iq)
6107492Skre 	dev_t dev;
6117504Sroot 	struct inode *iq;
6127492Skre #else
6137334Skre iflush(dev)
6147334Skre 	dev_t dev;
6157492Skre #endif
6167334Skre {
6177335Skre 	register struct inode *ip;
6187334Skre 	register open = 0;
6197334Skre 
6207334Skre 	for (ip = inode; ip < inodeNINODE; ip++) {
6217651Ssam #ifdef QUOTA
6227492Skre 		if (ip != iq && ip->i_dev == dev)
6237492Skre #else
6247334Skre 		if (ip->i_dev == dev)
6257492Skre #endif
6267334Skre 			if (ip->i_count)
6277334Skre 				return(-1);
6287334Skre 			else {
6297335Skre 				remque(ip);
6307334Skre 				ip->i_forw = ip;
6317334Skre 				ip->i_back = ip;
6327334Skre 				/*
6337334Skre 				 * as i_count == 0, the inode was on the free
6347334Skre 				 * list already, just leave it there, it will
6357334Skre 				 * fall off the bottom eventually. We could
6367334Skre 				 * perhaps move it to the head of the free
6377334Skre 				 * list, but as umounts are done so
6387334Skre 				 * infrequently, we would gain very little,
6397334Skre 				 * while making the code bigger.
6407334Skre 				 */
6417651Ssam #ifdef QUOTA
6427492Skre 				dqrele(ip->i_dquot);
6437492Skre 				ip->i_dquot = NODQUOT;
6447492Skre #endif
6457334Skre 			}
6467334Skre 		else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK &&
6477334Skre 		    ip->i_rdev == dev)
6487334Skre 			open++;
6497334Skre 	}
6507334Skre 	return (open);
6517334Skre }
6527334Skre 
6533617Sroot /*
6544818Swnj  * Lock an inode. If its already locked, set the WANT bit and sleep.
6553617Sroot  */
6564818Swnj ilock(ip)
6574818Swnj 	register struct inode *ip;
6583617Sroot {
6593617Sroot 
6608452Sroot 	ILOCK(ip);
6613617Sroot }
6623617Sroot 
6633617Sroot /*
6644818Swnj  * Unlock an inode.  If WANT bit is on, wakeup.
6653617Sroot  */
6667118Smckusick iunlock(ip)
6674818Swnj 	register struct inode *ip;
6683617Sroot {
6693617Sroot 
6708452Sroot 	IUNLOCK(ip);
6713617Sroot }
672