xref: /csrg-svn/sys/ufs/lfs/lfs_inode.c (revision 7334)
1*7334Skre /*	lfs_inode.c	4.13	82/06/29	*/
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"
1324Sbill 
1424Sbill #define	INOHSZ	63
15*7334Skre #if	((INOHSZ&(INOHSZ-1)) == 0)
16*7334Skre #define	INOHASH(dev,ino)	(((dev)+(ino))&(INOHSZ-1))
17*7334Skre #else
1824Sbill #define	INOHASH(dev,ino)	(((dev)+(ino))%INOHSZ)
19*7334Skre #endif
2024Sbill 
21*7334Skre union ihead {				/* inode LRU cache, Chris Maltby */
22*7334Skre 	union  ihead *ih_head[2];
23*7334Skre 	struct inode *ih_chain[2];
24*7334Skre } ihead[INOHSZ];
25*7334Skre 
26*7334Skre struct inode *ifreeh, **ifreet;
27*7334Skre 
2824Sbill /*
2924Sbill  * Initialize hash links for inodes
3024Sbill  * and build inode free list.
3124Sbill  */
3224Sbill ihinit()
3324Sbill {
3424Sbill 	register int i;
352737Swnj 	register struct inode *ip = inode;
36*7334Skre 	register union  ihead *ih = ihead;
3724Sbill 
38*7334Skre 	for (i = INOHSZ; --i >= 0; ih++) {
39*7334Skre 		ih->ih_head[0] = ih;
40*7334Skre 		ih->ih_head[1] = ih;
41*7334Skre 	}
42*7334Skre 	ifreeh = ip;
43*7334Skre 	ifreet = &ip->i_freef;
44*7334Skre 	ip->i_freeb = &ifreeh;
45*7334Skre 	ip->i_forw = ip;
46*7334Skre 	ip->i_back = ip;
47*7334Skre 	for (i = ninode; --i > 0; ) {
48*7334Skre 		++ip;
49*7334Skre 		ip->i_forw = ip;
50*7334Skre 		ip->i_back = ip;
51*7334Skre 		*ifreet = ip;
52*7334Skre 		ip->i_freeb = ifreet;
53*7334Skre 		ifreet = &ip->i_freef;
54*7334Skre 	}
55*7334Skre 	ip->i_freef = NULL;
5624Sbill }
5724Sbill 
58*7334Skre #ifdef notdef
5924Sbill /*
60*7334Skre  * Find an inode if it is incore.
61*7334Skre  * This is the equivalent, for inodes,
62*7334Skre  * of ``incore'' in bio.c or ``pfind'' in subr.c.
63*7334Skre  */
64*7334Skre struct inode *
65*7334Skre ifind(dev, ino)
66*7334Skre 	dev_t dev;
67*7334Skre 	ino_t ino;
68*7334Skre {
69*7334Skre 	register struct inode *ip;
70*7334Skre 	register union  ihead *ih;
71*7334Skre 
72*7334Skre 	ih = &ihead[INOHASH(dev, ino)];
73*7334Skre 	for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
74*7334Skre 		if (ino==ip->i_number && dev==ip->i_dev)
75*7334Skre 			return (ip);
76*7334Skre 	return ((struct inode *)0);
77*7334Skre }
78*7334Skre #endif notdef
79*7334Skre 
80*7334Skre /*
8124Sbill  * Look up an inode by device,inumber.
8224Sbill  * If it is in core (in the inode structure),
8324Sbill  * honor the locking protocol.
8424Sbill  * If it is not in core, read it in from the
8524Sbill  * specified device.
8624Sbill  * If the inode is mounted on, perform
8724Sbill  * the indicated indirection.
8824Sbill  * In all cases, a pointer to a locked
8924Sbill  * inode structure is returned.
9024Sbill  *
9124Sbill  * panic: no imt -- if the mounted file
9224Sbill  *	system is not in the mount table.
9324Sbill  *	"cannot happen"
9424Sbill  */
9524Sbill struct inode *
966569Smckusic iget(dev, fs, ino)
974818Swnj 	dev_t dev;
986569Smckusic 	register struct fs *fs;
994818Swnj 	ino_t ino;
10024Sbill {
101*7334Skre 	register struct inode *ip;	/* known to be r11 - see "asm" below */
102*7334Skre 	register union  ihead *ih;	/* known to be r10 - see "asm" below */
10324Sbill 	register struct mount *mp;
10424Sbill 	register struct buf *bp;
10524Sbill 	register struct dinode *dp;
106*7334Skre 	register struct inode *iq;
10724Sbill 
10824Sbill loop:
1096569Smckusic 	if (getfs(dev) != fs)
1106569Smckusic 		panic("iget: bad fs");
111*7334Skre 	ih = &ihead[INOHASH(dev, ino)];
112*7334Skre 	for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
1134818Swnj 		if (ino == ip->i_number && dev == ip->i_dev) {
1144818Swnj 			if ((ip->i_flag&ILOCK) != 0) {
11524Sbill 				ip->i_flag |= IWANT;
11624Sbill 				sleep((caddr_t)ip, PINOD);
11724Sbill 				goto loop;
11824Sbill 			}
1194818Swnj 			if ((ip->i_flag&IMOUNT) != 0) {
1206569Smckusic 				for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
121*7334Skre 					if(mp->m_inodp == ip) {
122*7334Skre 						dev = mp->m_dev;
123*7334Skre 						fs = mp->m_bufp->b_un.b_fs;
124*7334Skre 						ino = ROOTINO;
125*7334Skre 						goto loop;
126*7334Skre 					}
12724Sbill 				panic("no imt");
12824Sbill 			}
129*7334Skre 			if (ip->i_count == 0) {		/* ino on free list */
130*7334Skre 				if (iq = ip->i_freef)
131*7334Skre 					iq->i_freeb = ip->i_freeb;
132*7334Skre 				else
133*7334Skre 					ifreet = ip->i_freeb;
134*7334Skre 				*ip->i_freeb = iq;
135*7334Skre 				ip->i_freef = NULL;
136*7334Skre 				ip->i_freeb = NULL;
137*7334Skre 			}
13824Sbill 			ip->i_count++;
13924Sbill 			ip->i_flag |= ILOCK;
14024Sbill 			return(ip);
14124Sbill 		}
142*7334Skre 
143*7334Skre 	if ((ip = ifreeh) == NULL) {
1442933Swnj 		tablefull("inode");
14524Sbill 		u.u_error = ENFILE;
14624Sbill 		return(NULL);
14724Sbill 	}
148*7334Skre 	if (iq = ip->i_freef)
149*7334Skre 		iq->i_freeb = &ifreeh;
150*7334Skre 	ifreeh = iq;
151*7334Skre 	ip->i_freef = NULL;
152*7334Skre 	ip->i_freeb = NULL;
153*7334Skre 	/*
154*7334Skre 	 * Now to take inode off the hash chain it was on
155*7334Skre 	 * (initially, or after an iflush, it is on a "hash chain"
156*7334Skre 	 * consisting entirely of itself, and pointed to by no-one,
157*7334Skre 	 * but that doesn't matter), and put it on the chain for
158*7334Skre 	 * its new (ino, dev) pair
159*7334Skre 	 */
160*7334Skre #ifndef	UNFAST
161*7334Skre 	asm("remque	(r11),r0");
162*7334Skre 	asm("insque	(r11),(r10)");
163*7334Skre #else
164*7334Skre 		/* remque */
165*7334Skre 	ip->i_back->i_forw = ip->i_forw;
166*7334Skre 	ip->i_forw->i_back = ip->i_back;
167*7334Skre 		/* insque */
168*7334Skre 	ip->i_forw = ih->ih_chain[0];
169*7334Skre 	ip->i_back = (struct inode *)ih;
170*7334Skre 	ih->ih_chain[0]->i_back = ip;
171*7334Skre 	ih->ih_chain[0] = ip;
172*7334Skre #endif
17324Sbill 	ip->i_dev = dev;
1746569Smckusic 	ip->i_fs = fs;
17524Sbill 	ip->i_number = ino;
17624Sbill 	ip->i_flag = ILOCK;
17724Sbill 	ip->i_count++;
1786569Smckusic 	ip->i_lastr = 0;
1796569Smckusic 	bp = bread(dev, fsbtodb(fs, itod(fs, ino)), fs->fs_bsize);
18024Sbill 	/*
18124Sbill 	 * Check I/O errors
18224Sbill 	 */
1834818Swnj 	if ((bp->b_flags&B_ERROR) != 0) {
18424Sbill 		brelse(bp);
185*7334Skre 		/*
186*7334Skre 		 * the inode doesn't contain anything useful, so it would
187*7334Skre 		 * be misleading to leave it on its hash chain.
188*7334Skre 		 * 'iput' will take care of putting it back on the free list.
189*7334Skre 		 */
190*7334Skre #ifndef	UNFAST
191*7334Skre 		asm("remque	(r11),r0");
192*7334Skre #else
193*7334Skre 		ip->i_back->i_forw = ip->i_forw;
194*7334Skre 		ip->i_forw->i_back = ip->i_back;
195*7334Skre #endif
196*7334Skre 		ip->i_forw = ip;
197*7334Skre 		ip->i_back = ip;
198*7334Skre 		/*
199*7334Skre 		 * we also loose its inumber, just in case (as iput
200*7334Skre 		 * doesn't do that any more) - but as it isn't on its
201*7334Skre 		 * hash chain, I doubt if this is really necessary .. kre
202*7334Skre 		 * (probably the two methods are interchangable)
203*7334Skre 		 */
204*7334Skre 		ip->i_number = 0;
20524Sbill 		iput(ip);
20624Sbill 		return(NULL);
20724Sbill 	}
20824Sbill 	dp = bp->b_un.b_dino;
2096569Smckusic 	dp += itoo(fs, ino);
2106569Smckusic 	ip->i_ic = dp->di_ic;
21124Sbill 	brelse(bp);
2126569Smckusic 	return (ip);
21324Sbill }
21424Sbill 
21524Sbill /*
21624Sbill  * Decrement reference count of
21724Sbill  * an inode structure.
21824Sbill  * On the last reference,
21924Sbill  * write the inode out and if necessary,
22024Sbill  * truncate and deallocate the file.
22124Sbill  */
22224Sbill iput(ip)
2234818Swnj 	register struct inode *ip;
22424Sbill {
2257118Smckusick 
2267118Smckusick 	if ((ip->i_flag & ILOCK) == 0)
2277118Smckusick 		panic("iput");
2287118Smckusick 	iunlock(ip);
2297118Smckusick 	irele(ip);
2307118Smckusick }
2317118Smckusick 
2327118Smckusick irele(ip)
2337118Smckusick 	register struct inode *ip;
2347118Smckusick {
23524Sbill 	register int i, x;
23624Sbill 	register struct inode *jp;
2376569Smckusic 	int mode;
23824Sbill 
2394818Swnj 	if (ip->i_count == 1) {
24024Sbill 		ip->i_flag |= ILOCK;
2414818Swnj 		if (ip->i_nlink <= 0) {
24224Sbill 			itrunc(ip);
2436569Smckusic 			mode = ip->i_mode;
24424Sbill 			ip->i_mode = 0;
24524Sbill 			ip->i_flag |= IUPD|ICHG;
2466569Smckusic 			ifree(ip, ip->i_number, mode);
24724Sbill 		}
2481203Sbill 		IUPDAT(ip, &time, &time, 0);
2497118Smckusick 		iunlock(ip);
250*7334Skre 		ip->i_flag = 0;
251*7334Skre 		/*
252*7334Skre 		 * Put the inode on the end of the free list.
253*7334Skre 		 * Possibly in some cases it would be better to
254*7334Skre 		 * put the inode at the head of the free list,
255*7334Skre 		 * (eg: where i_mode == 0 || i_number == 0)
256*7334Skre 		 * but I will think about that later .. kre
257*7334Skre 		 * (i_number is rarely 0 - only after an i/o error in iget,
258*7334Skre 		 * where i_mode == 0, the inode will probably be wanted
259*7334Skre 		 * again soon for an ialloc, so possibly we should keep it)
260*7334Skre 		 */
261*7334Skre 		if (ifreeh) {
262*7334Skre 			*ifreet = ip;
263*7334Skre 			ip->i_freeb = ifreet;
26424Sbill 		} else {
265*7334Skre 			ifreeh = ip;
266*7334Skre 			ip->i_freeb = &ifreeh;
26724Sbill 		}
268*7334Skre 		ip->i_freef = NULL;
269*7334Skre 		ifreet = &ip->i_freef;
2707118Smckusick 	}
27124Sbill 	ip->i_count--;
27224Sbill }
27324Sbill 
27424Sbill /*
27524Sbill  * Check accessed and update flags on
27624Sbill  * an inode structure.
27724Sbill  * If any is on, update the inode
27824Sbill  * with the current time.
2791203Sbill  * If waitfor is given, then must insure
2801203Sbill  * i/o order so wait for write to complete.
28124Sbill  */
2821203Sbill iupdat(ip, ta, tm, waitfor)
2834818Swnj 	register struct inode *ip;
2844818Swnj 	time_t *ta, *tm;
2854818Swnj 	int waitfor;
28624Sbill {
28724Sbill 	register struct buf *bp;
28824Sbill 	struct dinode *dp;
2896569Smckusic 	register struct fs *fp;
29024Sbill 
2916569Smckusic 	fp = ip->i_fs;
2926569Smckusic 	if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) {
2936569Smckusic 		if (fp->fs_ronly)
29424Sbill 			return;
2956569Smckusic 		bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)),
2966569Smckusic 			fp->fs_bsize);
29724Sbill 		if (bp->b_flags & B_ERROR) {
29824Sbill 			brelse(bp);
29924Sbill 			return;
30024Sbill 		}
3014818Swnj 		if (ip->i_flag&IACC)
3026569Smckusic 			ip->i_atime = *ta;
3034818Swnj 		if (ip->i_flag&IUPD)
3046569Smckusic 			ip->i_mtime = *tm;
3054818Swnj 		if (ip->i_flag&ICHG)
3066569Smckusic 			ip->i_ctime = time;
30724Sbill 		ip->i_flag &= ~(IUPD|IACC|ICHG);
3081203Sbill 		if (waitfor)
3091203Sbill 			bwrite(bp);
3101203Sbill 		else
3111203Sbill 			bdwrite(bp);
31224Sbill 	}
31324Sbill }
31424Sbill 
31524Sbill /*
31624Sbill  * Free all the disk blocks associated
31724Sbill  * with the specified inode structure.
31824Sbill  * The blocks of the file are removed
31924Sbill  * in reverse order. This FILO
32024Sbill  * algorithm will tend to maintain
32124Sbill  * a contiguous free list much longer
32224Sbill  * than FIFO.
32324Sbill  */
32424Sbill itrunc(ip)
3254818Swnj 	register struct inode *ip;
32624Sbill {
32724Sbill 	register i;
32824Sbill 	dev_t dev;
32924Sbill 	daddr_t bn;
3301203Sbill 	struct inode itmp;
3316569Smckusic 	register struct fs *fs;
33224Sbill 
33324Sbill 	i = ip->i_mode & IFMT;
3346569Smckusic 	if (i != IFREG && i != IFDIR && i != IFLNK)
33524Sbill 		return;
3361203Sbill 	/*
3371203Sbill 	 * Clean inode on disk before freeing blocks
3381203Sbill 	 * to insure no duplicates if system crashes.
3391203Sbill 	 */
3401203Sbill 	itmp = *ip;
3411203Sbill 	itmp.i_size = 0;
3426569Smckusic 	for (i = 0; i < NDADDR; i++)
3436569Smckusic 		itmp.i_db[i] = 0;
3446569Smckusic 	for (i = 0; i < NIADDR; i++)
3456569Smckusic 		itmp.i_ib[i] = 0;
3461203Sbill 	itmp.i_flag |= ICHG|IUPD;
3471203Sbill 	iupdat(&itmp, &time, &time, 1);
3481203Sbill 	ip->i_flag &= ~(IUPD|IACC|ICHG);
3491203Sbill 
3501203Sbill 	/*
3511203Sbill 	 * Now return blocks to free list... if machine
3521203Sbill 	 * crashes, they will be harmless MISSING blocks.
3531203Sbill 	 */
35424Sbill 	dev = ip->i_dev;
3556569Smckusic 	fs = ip->i_fs;
3566569Smckusic 	/*
3576569Smckusic 	 * release double indirect block first
3586569Smckusic 	 */
3596569Smckusic 	bn = ip->i_ib[NIADDR-1];
3606569Smckusic 	if (bn != (daddr_t)0) {
3616569Smckusic 		ip->i_ib[NIADDR - 1] = (daddr_t)0;
3626569Smckusic 		tloop(ip, bn, 1);
3636569Smckusic 	}
3646569Smckusic 	/*
3656569Smckusic 	 * release single indirect blocks second
3666569Smckusic 	 */
3676569Smckusic 	for (i = NIADDR - 2; i >= 0; i--) {
3686569Smckusic 		bn = ip->i_ib[i];
3696569Smckusic 		if (bn != (daddr_t)0) {
3706569Smckusic 			ip->i_ib[i] = (daddr_t)0;
3716569Smckusic 			tloop(ip, bn, 0);
3726569Smckusic 		}
3736569Smckusic 	}
3746569Smckusic 	/*
3756569Smckusic 	 * finally release direct blocks
3766569Smckusic 	 */
3776569Smckusic 	for (i = NDADDR - 1; i>=0; i--) {
3786569Smckusic 		bn = ip->i_db[i];
3794818Swnj 		if (bn == (daddr_t)0)
38024Sbill 			continue;
3816569Smckusic 		ip->i_db[i] = (daddr_t)0;
3826569Smckusic 		fre(ip, bn, (off_t)blksize(fs, ip, i));
38324Sbill 	}
38424Sbill 	ip->i_size = 0;
3851203Sbill 	/*
3861203Sbill 	 * Inode was written and flags updated above.
3871203Sbill 	 * No need to modify flags here.
3881203Sbill 	 */
38924Sbill }
39024Sbill 
3916569Smckusic tloop(ip, bn, indflg)
3926569Smckusic 	register struct inode *ip;
3936569Smckusic 	daddr_t bn;
3946569Smckusic 	int indflg;
39524Sbill {
39624Sbill 	register i;
39724Sbill 	register struct buf *bp;
39824Sbill 	register daddr_t *bap;
3996569Smckusic 	register struct fs *fs;
40024Sbill 	daddr_t nb;
40124Sbill 
40224Sbill 	bp = NULL;
4036569Smckusic 	fs = ip->i_fs;
4046569Smckusic 	for (i = NINDIR(fs) - 1; i >= 0; i--) {
4054818Swnj 		if (bp == NULL) {
4066569Smckusic 			bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize);
40724Sbill 			if (bp->b_flags & B_ERROR) {
40824Sbill 				brelse(bp);
40924Sbill 				return;
41024Sbill 			}
41124Sbill 			bap = bp->b_un.b_daddr;
41224Sbill 		}
41324Sbill 		nb = bap[i];
4144818Swnj 		if (nb == (daddr_t)0)
41524Sbill 			continue;
4166569Smckusic 		if (indflg)
4176569Smckusic 			tloop(ip, nb, 0);
4186569Smckusic 		else
4196569Smckusic 			fre(ip, nb, fs->fs_bsize);
42024Sbill 	}
4214818Swnj 	if (bp != NULL)
42224Sbill 		brelse(bp);
4236569Smckusic 	fre(ip, bn, fs->fs_bsize);
42424Sbill }
42524Sbill 
42624Sbill /*
42724Sbill  * Make a new file.
42824Sbill  */
42924Sbill struct inode *
43024Sbill maknode(mode)
4316569Smckusic 	int mode;
43224Sbill {
43324Sbill 	register struct inode *ip;
4346569Smckusic 	ino_t ipref;
43524Sbill 
4366569Smckusic 	if ((mode & IFMT) == IFDIR)
4376569Smckusic 		ipref = dirpref(u.u_pdir->i_fs);
4386569Smckusic 	else
4396569Smckusic 		ipref = u.u_pdir->i_number;
4406569Smckusic 	ip = ialloc(u.u_pdir, ipref, mode);
4414818Swnj 	if (ip == NULL) {
44224Sbill 		iput(u.u_pdir);
44324Sbill 		return(NULL);
44424Sbill 	}
44524Sbill 	ip->i_flag |= IACC|IUPD|ICHG;
4466569Smckusic 	if ((mode & IFMT) == 0)
44724Sbill 		mode |= IFREG;
44824Sbill 	ip->i_mode = mode & ~u.u_cmask;
44924Sbill 	ip->i_nlink = 1;
45024Sbill 	ip->i_uid = u.u_uid;
4515855Swnj 	ip->i_gid = u.u_pdir->i_gid;
4521203Sbill 
4531203Sbill 	/*
4541203Sbill 	 * Make sure inode goes to disk before directory entry.
4551203Sbill 	 */
4561203Sbill 	iupdat(ip, &time, &time, 1);
45724Sbill 	wdir(ip);
4586569Smckusic 	if (u.u_error) {
4596569Smckusic 		/*
4606569Smckusic 		 * write error occurred trying to update directory
4616569Smckusic 		 * so must deallocate the inode
4626569Smckusic 		 */
4636569Smckusic 		ip->i_nlink = 0;
4646569Smckusic 		ip->i_flag |= ICHG;
4656569Smckusic 		iput(ip);
4666569Smckusic 		return(NULL);
4676569Smckusic 	}
46824Sbill 	return(ip);
46924Sbill }
47024Sbill 
47124Sbill /*
47224Sbill  * Write a directory entry with
47324Sbill  * parameters left as side effects
47424Sbill  * to a call to namei.
47524Sbill  */
47624Sbill wdir(ip)
4774818Swnj 	struct inode *ip;
47824Sbill {
4796569Smckusic 	register struct direct *dp, *ndp;
4806569Smckusic 	struct fs *fs;
4816569Smckusic 	struct buf *bp;
4826569Smckusic 	int lbn, bn, base;
4836569Smckusic 	int loc, dsize, spccnt, newsize;
4846569Smckusic 	char *dirbuf;
48524Sbill 
48624Sbill 	u.u_dent.d_ino = ip->i_number;
48724Sbill 	u.u_segflg = 1;
4886569Smckusic 	newsize = DIRSIZ(&u.u_dent);
4896569Smckusic 	/*
4906569Smckusic 	 * if u.u_count == 0, a new directory block must be allocated.
4916569Smckusic 	 */
4926569Smckusic 	if (u.u_count == 0) {
4936569Smckusic 		u.u_dent.d_reclen = DIRBLKSIZ;
4946569Smckusic 		u.u_count = newsize;
4956569Smckusic 		u.u_base = (caddr_t)&u.u_dent;
4966569Smckusic 		writei(u.u_pdir);
4976569Smckusic 		iput(u.u_pdir);
4986569Smckusic 		return;
4996569Smckusic 	}
5006569Smckusic 	/*
5016569Smckusic 	 * must read in an existing directory block
5026569Smckusic 	 * to prepare to place the new entry into it.
5036569Smckusic 	 */
5046569Smckusic 	fs = u.u_pdir->i_fs;
5056569Smckusic 	lbn = lblkno(fs, u.u_offset);
5066569Smckusic 	base = blkoff(fs, u.u_offset);
5076569Smckusic 	bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count));
5086569Smckusic 	if (u.u_offset + u.u_count > u.u_pdir->i_size)
5096569Smckusic 		u.u_pdir->i_size = u.u_offset + u.u_count;
5106569Smckusic 	bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn));
5116569Smckusic 	if (bp->b_flags & B_ERROR) {
5126569Smckusic 		brelse(bp);
5136569Smckusic 		return;
5146569Smckusic 	}
5156569Smckusic 	dirbuf = bp->b_un.b_addr + base;
5166569Smckusic 	dp = (struct direct *)dirbuf;
5176569Smckusic 	dsize = DIRSIZ(dp);
5186569Smckusic 	spccnt = dp->d_reclen - dsize;
5196569Smckusic 	/*
5206569Smckusic 	 * if there is insufficient room to make an entry at this point
5216569Smckusic 	 * namei insures that compacting from u.u_offset for u.u_count
5226569Smckusic 	 * bytes will provide the necessary space.
5236569Smckusic 	 */
5246569Smckusic 	for (loc = dp->d_reclen; loc < u.u_count; ) {
5256569Smckusic 		ndp = (struct direct *)(dirbuf + loc);
5266569Smckusic 		if (dp->d_ino == 0) {
5276569Smckusic 			spccnt += dsize;
5286569Smckusic 		} else {
5296569Smckusic 			dp->d_reclen = dsize;
5306569Smckusic 			dp = (struct direct *)((char *)dp + dsize);
5316569Smckusic 		}
5326569Smckusic 		dsize = DIRSIZ(ndp);
5336569Smckusic 		spccnt += ndp->d_reclen - dsize;
5346569Smckusic 		loc += ndp->d_reclen;
5356569Smckusic 		bcopy(ndp, dp, dsize);
5366569Smckusic 	}
5376569Smckusic 	/*
5386569Smckusic 	 * Update the pointer fields in the previous entry (if any),
5396569Smckusic 	 * copy in the new entry, and write out the block.
5406569Smckusic 	 */
5416569Smckusic 	if (dp->d_ino == 0) {
5426569Smckusic 		if (spccnt + dsize < newsize)
5436569Smckusic 			panic("wdir: compact failed");
5446569Smckusic 		u.u_dent.d_reclen = spccnt + dsize;
5456569Smckusic 	} else {
5466569Smckusic 		if (spccnt < newsize)
5476569Smckusic 			panic("wdir: compact failed");
5486569Smckusic 		u.u_dent.d_reclen = spccnt;
5496569Smckusic 		dp->d_reclen = dsize;
5506569Smckusic 		dp = (struct direct *)((char *)dp + dsize);
5516569Smckusic 	}
5526569Smckusic 	bcopy(&u.u_dent, dp, newsize);
5536569Smckusic 	bwrite(bp);
5546569Smckusic 	u.u_pdir->i_flag |= IUPD|ICHG;
55524Sbill 	iput(u.u_pdir);
55624Sbill }
5573617Sroot 
558*7334Skre /*
559*7334Skre  * remove any inodes in the inode cache belonging to dev
560*7334Skre  *
561*7334Skre  * There should not be any active ones, return error if any are found
562*7334Skre  * (nb: this is a user error, not a system err)
563*7334Skre  *
564*7334Skre  * Also, count the references to dev by block devices - this really
565*7334Skre  * has nothing to do with the object of the procedure, but as we have
566*7334Skre  * to scan the inode table here anyway, we might as well get the
567*7334Skre  * extra benefit.
568*7334Skre  *
569*7334Skre  * this is called from sumount()/sys3.c when dev is being unmounted
570*7334Skre  */
571*7334Skre iflush(dev)
572*7334Skre 	dev_t dev;
573*7334Skre {
574*7334Skre 	register struct inode *ip;	/* known to be r11 - see 'asm' below */
575*7334Skre 	register open = 0;
576*7334Skre 
577*7334Skre 	for (ip = inode; ip < inodeNINODE; ip++) {
578*7334Skre 		if (ip->i_dev == dev)
579*7334Skre 			if (ip->i_count)
580*7334Skre 				return(-1);
581*7334Skre 			else {
582*7334Skre #ifndef	UNFAST
583*7334Skre 				asm("remque	(r11),r0");
584*7334Skre #else
585*7334Skre 				ip->i_back->i_forw = ip->i_forw;
586*7334Skre 				ip->i_forw->i_back = ip->i_back;
587*7334Skre #endif
588*7334Skre 				ip->i_forw = ip;
589*7334Skre 				ip->i_back = ip;
590*7334Skre 				/*
591*7334Skre 				 * as i_count == 0, the inode was on the free
592*7334Skre 				 * list already, just leave it there, it will
593*7334Skre 				 * fall off the bottom eventually. We could
594*7334Skre 				 * perhaps move it to the head of the free
595*7334Skre 				 * list, but as umounts are done so
596*7334Skre 				 * infrequently, we would gain very little,
597*7334Skre 				 * while making the code bigger.
598*7334Skre 				 */
599*7334Skre 			}
600*7334Skre 		else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK &&
601*7334Skre 		    ip->i_rdev == dev)
602*7334Skre 			open++;
603*7334Skre 	}
604*7334Skre 	return (open);
605*7334Skre }
606*7334Skre 
6074818Swnj #ifdef ilock
6084818Swnj #undef ilock
6093617Sroot #endif
6107118Smckusick #ifdef iunlock
6117118Smckusick #undef iunlock
6123617Sroot #endif
6133617Sroot /*
6144818Swnj  * Lock an inode. If its already locked, set the WANT bit and sleep.
6153617Sroot  */
6164818Swnj ilock(ip)
6174818Swnj 	register struct inode *ip;
6183617Sroot {
6193617Sroot 
6204818Swnj 	while (ip->i_flag&ILOCK) {
6213617Sroot 		ip->i_flag |= IWANT;
6223617Sroot 		sleep((caddr_t)ip, PINOD);
6233617Sroot 	}
6243617Sroot 	ip->i_flag |= ILOCK;
6253617Sroot }
6263617Sroot 
6273617Sroot /*
6284818Swnj  * Unlock an inode.  If WANT bit is on, wakeup.
6293617Sroot  */
6307118Smckusick iunlock(ip)
6314818Swnj 	register struct inode *ip;
6323617Sroot {
6333617Sroot 
6343617Sroot 	ip->i_flag &= ~ILOCK;
6354818Swnj 	if (ip->i_flag&IWANT) {
6363617Sroot 		ip->i_flag &= ~IWANT;
6373617Sroot 		wakeup((caddr_t)ip);
6383617Sroot 	}
6393617Sroot }
640