xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 7533)
1*7533Sroot /*	lfs_inode.c	4.20	82/07/25	*/
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"
1224Sbill #include "../h/inline.h"
137504Sroot #ifdef	QUOTA
147504Sroot #include "../h/quota.h"
157504Sroot #endif
1624Sbill 
1724Sbill #define	INOHSZ	63
187334Skre #if	((INOHSZ&(INOHSZ-1)) == 0)
197334Skre #define	INOHASH(dev,ino)	(((dev)+(ino))&(INOHSZ-1))
207334Skre #else
2124Sbill #define	INOHASH(dev,ino)	(((dev)+(ino))%INOHSZ)
227334Skre #endif
2324Sbill 
247334Skre union ihead {				/* inode LRU cache, Chris Maltby */
257334Skre 	union  ihead *ih_head[2];
267334Skre 	struct inode *ih_chain[2];
277334Skre } ihead[INOHSZ];
287334Skre 
297334Skre struct inode *ifreeh, **ifreet;
307334Skre 
3124Sbill /*
3224Sbill  * Initialize hash links for inodes
3324Sbill  * and build inode free list.
3424Sbill  */
3524Sbill ihinit()
3624Sbill {
3724Sbill 	register int i;
382737Swnj 	register struct inode *ip = inode;
397334Skre 	register union  ihead *ih = ihead;
4024Sbill 
417334Skre 	for (i = INOHSZ; --i >= 0; ih++) {
427334Skre 		ih->ih_head[0] = ih;
437334Skre 		ih->ih_head[1] = ih;
447334Skre 	}
457334Skre 	ifreeh = ip;
467334Skre 	ifreet = &ip->i_freef;
477334Skre 	ip->i_freeb = &ifreeh;
487334Skre 	ip->i_forw = ip;
497334Skre 	ip->i_back = ip;
507334Skre 	for (i = ninode; --i > 0; ) {
517334Skre 		++ip;
527334Skre 		ip->i_forw = ip;
537334Skre 		ip->i_back = ip;
547334Skre 		*ifreet = ip;
557334Skre 		ip->i_freeb = ifreet;
567334Skre 		ifreet = &ip->i_freef;
577334Skre 	}
587334Skre 	ip->i_freef = NULL;
5924Sbill }
6024Sbill 
617334Skre #ifdef notdef
6224Sbill /*
637334Skre  * Find an inode if it is incore.
647334Skre  * This is the equivalent, for inodes,
657334Skre  * of ``incore'' in bio.c or ``pfind'' in subr.c.
667334Skre  */
677334Skre struct inode *
687334Skre ifind(dev, ino)
697334Skre 	dev_t dev;
707334Skre 	ino_t ino;
717334Skre {
727334Skre 	register struct inode *ip;
737334Skre 	register union  ihead *ih;
747334Skre 
757334Skre 	ih = &ihead[INOHASH(dev, ino)];
767334Skre 	for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
777334Skre 		if (ino==ip->i_number && dev==ip->i_dev)
787334Skre 			return (ip);
797334Skre 	return ((struct inode *)0);
807334Skre }
817334Skre #endif notdef
827334Skre 
837334Skre /*
8424Sbill  * Look up an inode by device,inumber.
8524Sbill  * If it is in core (in the inode structure),
8624Sbill  * honor the locking protocol.
8724Sbill  * If it is not in core, read it in from the
8824Sbill  * specified device.
8924Sbill  * If the inode is mounted on, perform
9024Sbill  * the indicated indirection.
9124Sbill  * In all cases, a pointer to a locked
9224Sbill  * inode structure is returned.
9324Sbill  *
9424Sbill  * panic: no imt -- if the mounted file
9524Sbill  *	system is not in the mount table.
9624Sbill  *	"cannot happen"
9724Sbill  */
9824Sbill struct inode *
996569Smckusic iget(dev, fs, ino)
1004818Swnj 	dev_t dev;
1016569Smckusic 	register struct fs *fs;
1024818Swnj 	ino_t ino;
10324Sbill {
1047335Skre 	register struct inode *ip;
1057335Skre 	register union  ihead *ih;
10624Sbill 	register struct mount *mp;
10724Sbill 	register struct buf *bp;
10824Sbill 	register struct dinode *dp;
1097334Skre 	register struct inode *iq;
11024Sbill 
11124Sbill loop:
1126569Smckusic 	if (getfs(dev) != fs)
1136569Smckusic 		panic("iget: bad fs");
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) {
1174818Swnj 			if ((ip->i_flag&ILOCK) != 0) {
11824Sbill 				ip->i_flag |= IWANT;
11924Sbill 				sleep((caddr_t)ip, PINOD);
12024Sbill 				goto loop;
12124Sbill 			}
1224818Swnj 			if ((ip->i_flag&IMOUNT) != 0) {
1236569Smckusic 				for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
1247334Skre 					if(mp->m_inodp == ip) {
1257334Skre 						dev = mp->m_dev;
1267334Skre 						fs = mp->m_bufp->b_un.b_fs;
1277334Skre 						ino = ROOTINO;
1287334Skre 						goto loop;
1297334Skre 					}
13024Sbill 				panic("no imt");
13124Sbill 			}
1327334Skre 			if (ip->i_count == 0) {		/* ino on free list */
1337334Skre 				if (iq = ip->i_freef)
1347334Skre 					iq->i_freeb = ip->i_freeb;
1357334Skre 				else
1367334Skre 					ifreet = ip->i_freeb;
1377334Skre 				*ip->i_freeb = iq;
1387334Skre 				ip->i_freef = NULL;
1397334Skre 				ip->i_freeb = NULL;
1407334Skre 			}
14124Sbill 			ip->i_count++;
14224Sbill 			ip->i_flag |= ILOCK;
14324Sbill 			return(ip);
14424Sbill 		}
1457334Skre 
1467334Skre 	if ((ip = ifreeh) == NULL) {
1472933Swnj 		tablefull("inode");
14824Sbill 		u.u_error = ENFILE;
14924Sbill 		return(NULL);
15024Sbill 	}
1517334Skre 	if (iq = ip->i_freef)
1527334Skre 		iq->i_freeb = &ifreeh;
1537334Skre 	ifreeh = iq;
1547334Skre 	ip->i_freef = NULL;
1557334Skre 	ip->i_freeb = NULL;
1567334Skre 	/*
1577334Skre 	 * Now to take inode off the hash chain it was on
1587334Skre 	 * (initially, or after an iflush, it is on a "hash chain"
1597334Skre 	 * consisting entirely of itself, and pointed to by no-one,
1607334Skre 	 * but that doesn't matter), and put it on the chain for
1617334Skre 	 * its new (ino, dev) pair
1627334Skre 	 */
1637335Skre 	remque(ip);
1647335Skre 	insque(ip, ih);
1657492Skre #ifdef	QUOTA
1667492Skre 	dqrele(ip->i_dquot);
1677492Skre #endif
16824Sbill 	ip->i_dev = dev;
1696569Smckusic 	ip->i_fs = fs;
17024Sbill 	ip->i_number = ino;
17124Sbill 	ip->i_flag = ILOCK;
17224Sbill 	ip->i_count++;
1736569Smckusic 	ip->i_lastr = 0;
1746569Smckusic 	bp = bread(dev, fsbtodb(fs, itod(fs, ino)), fs->fs_bsize);
17524Sbill 	/*
17624Sbill 	 * Check I/O errors
17724Sbill 	 */
1784818Swnj 	if ((bp->b_flags&B_ERROR) != 0) {
17924Sbill 		brelse(bp);
1807334Skre 		/*
1817334Skre 		 * the inode doesn't contain anything useful, so it would
1827334Skre 		 * be misleading to leave it on its hash chain.
1837334Skre 		 * 'iput' will take care of putting it back on the free list.
1847334Skre 		 */
1857335Skre 		remque(ip);
1867334Skre 		ip->i_forw = ip;
1877334Skre 		ip->i_back = ip;
1887334Skre 		/*
1897334Skre 		 * we also loose its inumber, just in case (as iput
1907334Skre 		 * doesn't do that any more) - but as it isn't on its
1917334Skre 		 * hash chain, I doubt if this is really necessary .. kre
1927334Skre 		 * (probably the two methods are interchangable)
1937334Skre 		 */
1947334Skre 		ip->i_number = 0;
1957492Skre #ifdef	QUOTA
1967492Skre 		ip->i_dquot = NODQUOT;
1977492Skre #endif
19824Sbill 		iput(ip);
19924Sbill 		return(NULL);
20024Sbill 	}
20124Sbill 	dp = bp->b_un.b_dino;
2026569Smckusic 	dp += itoo(fs, ino);
2036569Smckusic 	ip->i_ic = dp->di_ic;
20424Sbill 	brelse(bp);
2057492Skre #ifdef	QUOTA
2067492Skre 	if (ip->i_mode == 0)
2077492Skre 		ip->i_dquot = NODQUOT;
2087492Skre 	else
2097492Skre 		ip->i_dquot = inoquota(ip);
2107492Skre #endif
2116569Smckusic 	return (ip);
21224Sbill }
21324Sbill 
214*7533Sroot #ifdef MATISSE
215*7533Sroot int	badinum = 3197;
216*7533Sroot #else
2177504Sroot int	badinum = -1;
218*7533Sroot #endif
21924Sbill /*
22024Sbill  * Decrement reference count of
22124Sbill  * an inode structure.
22224Sbill  * On the last reference,
22324Sbill  * write the inode out and if necessary,
22424Sbill  * truncate and deallocate the file.
22524Sbill  */
22624Sbill iput(ip)
2274818Swnj 	register struct inode *ip;
22824Sbill {
2297118Smckusick 
2307118Smckusick 	if ((ip->i_flag & ILOCK) == 0)
2317118Smckusick 		panic("iput");
2327504Sroot /* XXX */
2337504Sroot 	if (ip->i_number == badinum && (ip->i_mode&IFMT) == IFCHR &&
2347504Sroot 	    (major(ip->i_dev) != 3 || minor(ip->i_dev) != 2))
2357504Sroot 		panic("/dev/null");
2367504Sroot /* XXX */
2377118Smckusick 	iunlock(ip);
2387118Smckusick 	irele(ip);
2397118Smckusick }
2407118Smckusick 
2417118Smckusick irele(ip)
2427118Smckusick 	register struct inode *ip;
2437118Smckusick {
24424Sbill 	register int i, x;
24524Sbill 	register struct inode *jp;
2466569Smckusic 	int mode;
24724Sbill 
2484818Swnj 	if (ip->i_count == 1) {
24924Sbill 		ip->i_flag |= ILOCK;
2504818Swnj 		if (ip->i_nlink <= 0) {
25124Sbill 			itrunc(ip);
2526569Smckusic 			mode = ip->i_mode;
25324Sbill 			ip->i_mode = 0;
2547351Skre 			ip->i_rdev = 0;
25524Sbill 			ip->i_flag |= IUPD|ICHG;
2566569Smckusic 			ifree(ip, ip->i_number, mode);
2577492Skre #ifdef	QUOTA
2587492Skre 			chkiq(ip->i_dev, ip, ip->i_uid, 0);
2597492Skre 			dqrele(ip->i_dquot);
2607492Skre 			ip->i_dquot = NODQUOT;
2617492Skre #endif
26224Sbill 		}
2631203Sbill 		IUPDAT(ip, &time, &time, 0);
2647118Smckusick 		iunlock(ip);
2657334Skre 		ip->i_flag = 0;
2667334Skre 		/*
2677334Skre 		 * Put the inode on the end of the free list.
2687334Skre 		 * Possibly in some cases it would be better to
2697334Skre 		 * put the inode at the head of the free list,
2707334Skre 		 * (eg: where i_mode == 0 || i_number == 0)
2717334Skre 		 * but I will think about that later .. kre
2727334Skre 		 * (i_number is rarely 0 - only after an i/o error in iget,
2737334Skre 		 * where i_mode == 0, the inode will probably be wanted
2747334Skre 		 * again soon for an ialloc, so possibly we should keep it)
2757334Skre 		 */
2767334Skre 		if (ifreeh) {
2777334Skre 			*ifreet = ip;
2787334Skre 			ip->i_freeb = ifreet;
27924Sbill 		} else {
2807334Skre 			ifreeh = ip;
2817334Skre 			ip->i_freeb = &ifreeh;
28224Sbill 		}
2837334Skre 		ip->i_freef = NULL;
2847334Skre 		ifreet = &ip->i_freef;
2857118Smckusick 	}
28624Sbill 	ip->i_count--;
28724Sbill }
28824Sbill 
28924Sbill /*
29024Sbill  * Check accessed and update flags on
29124Sbill  * an inode structure.
29224Sbill  * If any is on, update the inode
29324Sbill  * with the current time.
2941203Sbill  * If waitfor is given, then must insure
2951203Sbill  * i/o order so wait for write to complete.
29624Sbill  */
2971203Sbill iupdat(ip, ta, tm, waitfor)
2984818Swnj 	register struct inode *ip;
2994818Swnj 	time_t *ta, *tm;
3004818Swnj 	int waitfor;
30124Sbill {
30224Sbill 	register struct buf *bp;
30324Sbill 	struct dinode *dp;
3046569Smckusic 	register struct fs *fp;
30524Sbill 
3066569Smckusic 	fp = ip->i_fs;
3076569Smckusic 	if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) {
3086569Smckusic 		if (fp->fs_ronly)
30924Sbill 			return;
3106569Smckusic 		bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)),
3116569Smckusic 			fp->fs_bsize);
31224Sbill 		if (bp->b_flags & B_ERROR) {
31324Sbill 			brelse(bp);
31424Sbill 			return;
31524Sbill 		}
3164818Swnj 		if (ip->i_flag&IACC)
3176569Smckusic 			ip->i_atime = *ta;
3184818Swnj 		if (ip->i_flag&IUPD)
3196569Smckusic 			ip->i_mtime = *tm;
3204818Swnj 		if (ip->i_flag&ICHG)
3216569Smckusic 			ip->i_ctime = time;
32224Sbill 		ip->i_flag &= ~(IUPD|IACC|ICHG);
3237343Skre 		dp = bp->b_un.b_dino + itoo(fp, ip->i_number);
3247343Skre 		dp->di_ic = ip->i_ic;
3251203Sbill 		if (waitfor)
3261203Sbill 			bwrite(bp);
3271203Sbill 		else
3281203Sbill 			bdwrite(bp);
32924Sbill 	}
33024Sbill }
33124Sbill 
33224Sbill /*
33324Sbill  * Free all the disk blocks associated
33424Sbill  * with the specified inode structure.
33524Sbill  * The blocks of the file are removed
336*7533Sroot  * in reverse order.
33724Sbill  */
33824Sbill itrunc(ip)
3394818Swnj 	register struct inode *ip;
34024Sbill {
34124Sbill 	register i;
34224Sbill 	dev_t dev;
34324Sbill 	daddr_t bn;
3441203Sbill 	struct inode itmp;
3456569Smckusic 	register struct fs *fs;
3467492Skre #ifdef	QUOTA
3477492Skre 	register long cnt = 0;
3487492Skre 	long tloop();
3497492Skre #endif
35024Sbill 
3511203Sbill 	/*
3521203Sbill 	 * Clean inode on disk before freeing blocks
3531203Sbill 	 * to insure no duplicates if system crashes.
3541203Sbill 	 */
3551203Sbill 	itmp = *ip;
3561203Sbill 	itmp.i_size = 0;
3576569Smckusic 	for (i = 0; i < NDADDR; i++)
3586569Smckusic 		itmp.i_db[i] = 0;
3596569Smckusic 	for (i = 0; i < NIADDR; i++)
3606569Smckusic 		itmp.i_ib[i] = 0;
3611203Sbill 	itmp.i_flag |= ICHG|IUPD;
3621203Sbill 	iupdat(&itmp, &time, &time, 1);
3631203Sbill 	ip->i_flag &= ~(IUPD|IACC|ICHG);
3641203Sbill 
3651203Sbill 	/*
3667341Sroot 	 * Only plain files, directories and symbolic
3677341Sroot 	 * links contain blocks.
3687341Sroot 	 */
3697341Sroot 	i = ip->i_mode & IFMT;
3707341Sroot 	if (i != IFREG && i != IFDIR && i != IFLNK)
3717341Sroot 		return;
3727341Sroot 	/*
3731203Sbill 	 * Now return blocks to free list... if machine
3741203Sbill 	 * crashes, they will be harmless MISSING blocks.
3751203Sbill 	 */
37624Sbill 	dev = ip->i_dev;
3776569Smckusic 	fs = ip->i_fs;
3786569Smckusic 	/*
3796569Smckusic 	 * release double indirect block first
3806569Smckusic 	 */
3816569Smckusic 	bn = ip->i_ib[NIADDR-1];
3826569Smckusic 	if (bn != (daddr_t)0) {
3836569Smckusic 		ip->i_ib[NIADDR - 1] = (daddr_t)0;
3847492Skre #ifdef	QUOTA
3857492Skre 		cnt +=
3867492Skre #endif
3877492Skre 			tloop(ip, bn, 1);
3886569Smckusic 	}
3896569Smckusic 	/*
3906569Smckusic 	 * release single indirect blocks second
3916569Smckusic 	 */
3926569Smckusic 	for (i = NIADDR - 2; i >= 0; i--) {
3936569Smckusic 		bn = ip->i_ib[i];
3946569Smckusic 		if (bn != (daddr_t)0) {
3956569Smckusic 			ip->i_ib[i] = (daddr_t)0;
3967492Skre #ifdef	QUOTA
3977492Skre 			cnt +=
3987492Skre #endif
3997492Skre 				tloop(ip, bn, 0);
4006569Smckusic 		}
4016569Smckusic 	}
4026569Smckusic 	/*
4036569Smckusic 	 * finally release direct blocks
4046569Smckusic 	 */
4056569Smckusic 	for (i = NDADDR - 1; i>=0; i--) {
4067492Skre 		register size;
4077492Skre 
4086569Smckusic 		bn = ip->i_db[i];
4094818Swnj 		if (bn == (daddr_t)0)
41024Sbill 			continue;
4116569Smckusic 		ip->i_db[i] = (daddr_t)0;
4127492Skre 		fre(ip, bn, size = (off_t)blksize(fs, ip, i));
4137492Skre #ifdef	QUOTA
4147492Skre 		cnt += size / DEV_BSIZE;
4157492Skre #endif
41624Sbill 	}
41724Sbill 	ip->i_size = 0;
4181203Sbill 	/*
4191203Sbill 	 * Inode was written and flags updated above.
4201203Sbill 	 * No need to modify flags here.
4211203Sbill 	 */
4227492Skre #ifdef	QUOTA
4237492Skre 	(void) chkdq(ip, -cnt, 0);
4247492Skre #endif
42524Sbill }
42624Sbill 
4277492Skre #ifdef	QUOTA
4287492Skre long
4297492Skre #endif
4306569Smckusic tloop(ip, bn, indflg)
4316569Smckusic 	register struct inode *ip;
4326569Smckusic 	daddr_t bn;
4336569Smckusic 	int indflg;
43424Sbill {
43524Sbill 	register i;
43624Sbill 	register struct buf *bp;
43724Sbill 	register daddr_t *bap;
4386569Smckusic 	register struct fs *fs;
43924Sbill 	daddr_t nb;
4407492Skre #ifdef	QUOTA
4417492Skre 	register long cnt = 0;
4427492Skre #endif
44324Sbill 
44424Sbill 	bp = NULL;
4456569Smckusic 	fs = ip->i_fs;
4466569Smckusic 	for (i = NINDIR(fs) - 1; i >= 0; i--) {
4474818Swnj 		if (bp == NULL) {
4486569Smckusic 			bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize);
44924Sbill 			if (bp->b_flags & B_ERROR) {
45024Sbill 				brelse(bp);
45124Sbill 				return;
45224Sbill 			}
45324Sbill 			bap = bp->b_un.b_daddr;
45424Sbill 		}
45524Sbill 		nb = bap[i];
4564818Swnj 		if (nb == (daddr_t)0)
45724Sbill 			continue;
4587492Skre 		if (indflg) {
4597492Skre #ifdef	QUOTA
4607492Skre 			cnt +=
4617492Skre #endif
4627492Skre 				tloop(ip, nb, 0);
4637492Skre 		} else {
4646569Smckusic 			fre(ip, nb, fs->fs_bsize);
4657492Skre #ifdef	QUOTA
4667492Skre 			cnt += fs->fs_bsize / DEV_BSIZE;
4677492Skre #endif
4687492Skre 		}
46924Sbill 	}
4704818Swnj 	if (bp != NULL)
47124Sbill 		brelse(bp);
4726569Smckusic 	fre(ip, bn, fs->fs_bsize);
4737492Skre #ifdef	QUOTA
4747492Skre 	cnt += fs->fs_bsize / DEV_BSIZE;
4757492Skre 	return(cnt);
4767492Skre #endif
47724Sbill }
47824Sbill 
47924Sbill /*
4807334Skre  * remove any inodes in the inode cache belonging to dev
4817334Skre  *
4827334Skre  * There should not be any active ones, return error if any are found
4837334Skre  * (nb: this is a user error, not a system err)
4847334Skre  *
4857334Skre  * Also, count the references to dev by block devices - this really
4867334Skre  * has nothing to do with the object of the procedure, but as we have
4877334Skre  * to scan the inode table here anyway, we might as well get the
4887334Skre  * extra benefit.
4897334Skre  *
4907334Skre  * this is called from sumount()/sys3.c when dev is being unmounted
4917334Skre  */
4927492Skre #ifdef	QUOTA
4937504Sroot iflush(dev, iq)
4947492Skre 	dev_t dev;
4957504Sroot 	struct inode *iq;
4967492Skre #else
4977334Skre iflush(dev)
4987334Skre 	dev_t dev;
4997492Skre #endif
5007334Skre {
5017335Skre 	register struct inode *ip;
5027334Skre 	register open = 0;
5037334Skre 
5047334Skre 	for (ip = inode; ip < inodeNINODE; ip++) {
5057492Skre #ifdef	QUOTA
5067492Skre 		if (ip != iq && ip->i_dev == dev)
5077492Skre #else
5087334Skre 		if (ip->i_dev == dev)
5097492Skre #endif
5107334Skre 			if (ip->i_count)
5117334Skre 				return(-1);
5127334Skre 			else {
5137335Skre 				remque(ip);
5147334Skre 				ip->i_forw = ip;
5157334Skre 				ip->i_back = ip;
5167334Skre 				/*
5177334Skre 				 * as i_count == 0, the inode was on the free
5187334Skre 				 * list already, just leave it there, it will
5197334Skre 				 * fall off the bottom eventually. We could
5207334Skre 				 * perhaps move it to the head of the free
5217334Skre 				 * list, but as umounts are done so
5227334Skre 				 * infrequently, we would gain very little,
5237334Skre 				 * while making the code bigger.
5247334Skre 				 */
5257492Skre #ifdef	QUOTA
5267492Skre 				dqrele(ip->i_dquot);
5277492Skre 				ip->i_dquot = NODQUOT;
5287492Skre #endif
5297334Skre 			}
5307334Skre 		else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK &&
5317334Skre 		    ip->i_rdev == dev)
5327334Skre 			open++;
5337334Skre 	}
5347334Skre 	return (open);
5357334Skre }
5367334Skre 
5374818Swnj #ifdef ilock
5384818Swnj #undef ilock
5393617Sroot #endif
5407118Smckusick #ifdef iunlock
5417118Smckusick #undef iunlock
5423617Sroot #endif
5433617Sroot /*
5444818Swnj  * Lock an inode. If its already locked, set the WANT bit and sleep.
5453617Sroot  */
5464818Swnj ilock(ip)
5474818Swnj 	register struct inode *ip;
5483617Sroot {
5493617Sroot 
5504818Swnj 	while (ip->i_flag&ILOCK) {
5513617Sroot 		ip->i_flag |= IWANT;
5523617Sroot 		sleep((caddr_t)ip, PINOD);
5533617Sroot 	}
5543617Sroot 	ip->i_flag |= ILOCK;
5553617Sroot }
5563617Sroot 
5573617Sroot /*
5584818Swnj  * Unlock an inode.  If WANT bit is on, wakeup.
5593617Sroot  */
5607118Smckusick iunlock(ip)
5614818Swnj 	register struct inode *ip;
5623617Sroot {
5633617Sroot 
5643617Sroot 	ip->i_flag &= ~ILOCK;
5654818Swnj 	if (ip->i_flag&IWANT) {
5663617Sroot 		ip->i_flag &= ~IWANT;
5673617Sroot 		wakeup((caddr_t)ip);
5683617Sroot 	}
5693617Sroot }
570